面试题答案
一键面试设计思路
- 使用
math/big
包:Go语言中math/big
包提供了高精度数字运算的支持。由于金融计算对精度要求极高,直接使用Go的常规浮点数类型(如float32
或float64
)在大量运算后会导致精度损失,因此math/big
包中的Float
类型是更好的选择。 - 利用字面常量的类型推断:Go语言的字面常量(如
1.23456789
)在赋值给变量前没有具体类型。在我们的场景中,可以利用这一特性,在初始化math/big.Float
类型变量时直接使用字面常量,编译器会根据上下文正确推断类型。
代码实现
package main
import (
"fmt"
"math/big"
)
// CalculateExchangeRate 计算一系列汇率相乘后的最终汇率
func CalculateExchangeRate(rates ...string) *big.Float {
result := big.NewFloat(1)
for _, rateStr := range rates {
rate, ok := new(big.Float).SetString(rateStr)
if!ok {
panic("invalid rate string")
}
result.Mul(result, rate)
}
return result
}
你可以这样调用这个函数:
func main() {
rates := []string{"1.23456789", "0.987654321", "1.000000001"}
finalRate := CalculateExchangeRate(rates...)
fmt.Println(finalRate)
}
对Go语言字面常量类型特性的运用
- 类型推断:在
SetString
方法中,虽然传入的是字符串形式的汇率,但Go语言的字面常量类型推断特性使得我们无需手动将字符串转换为特定的浮点数类型再传入。new(big.Float).SetString(rateStr)
能够直接根据字符串中的数字内容进行高精度浮点数的初始化。 - 避免中间类型转换精度损失:由于字面常量在赋值前无具体类型,在初始化
math/big.Float
变量时,无需经过中间的常规浮点数类型转换。这避免了像从float64
转换到math/big.Float
过程中可能出现的精度损失,因为float64
本身存在精度限制。
确保程序在复杂业务逻辑下的稳定性和高效性
- 稳定性:
- 错误处理:在
SetString
方法调用时进行了错误检查,如果无法将字符串解析为big.Float
,程序会panic
。在实际应用中,可以将panic
替换为更友好的错误返回,确保程序不会因为无效输入而崩溃。 - 不变性:
math/big.Float
的操作方法返回新的big.Float
值而不是修改原对象,这有助于避免意外的状态修改,保证了程序在复杂业务逻辑中的稳定性。
- 错误处理:在
- 高效性:
- 减少不必要的转换:通过直接使用字符串形式的字面常量初始化
big.Float
,减少了从其他浮点类型转换带来的额外开销。 - 优化算法:在
CalculateExchangeRate
函数中,采用简单的迭代相乘算法,避免了复杂且可能低效的递归等算法。同时,math/big.Float
的实现本身针对高精度运算进行了优化,在大量运算时能够保证相对较好的性能。
- 减少不必要的转换:通过直接使用字符串形式的字面常量初始化