在golang中使用big.Float进行一些计算后,我将精度设置为2。
即使这个数字只是一个简单的10,在设定精度后它是8。
package main
import (
"fmt"
"math/big"
)
func main() {
cost := big.NewFloat(10)
fmt.Println("COST NOW", cost)
perKWh := big.NewFloat(0)
cost.Add(cost, perKWh)
fmt.Println("COST ", cost.String())
perMinute := big.NewFloat(0)
cost.Add(cost, perMinute)
fmt.Println("COST ", cost.String())
discountAmount := big.NewFloat(0)
cost.Sub(cost, discountAmount)
floatCos, _ := cost.Float64()
fmt.Println(fmt.Sprintf("COST FLOAT %v", floatCos))
cost.SetPrec(2)
fmt.Println("COST ", cost.String())
}
点击这里的游乐场示例:https://play.golang.org/p/JmCRXkD5u49
想了解原因
答案 0 :(得分:3)
来自fine manual:
键入Float
[...]
每个Float值还具有精度,舍入模式和精度。精度是可用于表示该值的最大尾数位数。舍入模式指定如何舍入结果以适合尾数位,精确度描述与精确结果相关的舍入误差。
big.Float
在内部表示为:
sign × mantissa × 2**exponent
当您致电SetPrec
时,您正在为尾数设置位的数量,而不是该数字的十进制表示中的精度位数。
您不能在两位尾数中表示十进制10(1010二进制),因此它舍入到十进制8(1000二进制),可以容纳2位。你需要至少三位才能存储小数10的101
部分.8可以放入一个尾数位,所以如果你说cost.SetPrec(1)
,你会看到相同的8位。
在使用大包时,你需要考虑二进制。
答案 1 :(得分:2)
首先,丢弃所有不相关的代码。接下来,打印有用的诊断信息。
package main
import (
"fmt"
"math/big"
)
func main() {
cost := big.NewFloat(10)
fmt.Println("Cost ", cost.String())
fmt.Println("Prec", cost.Prec())
fmt.Println("MinPrec", cost.MinPrec())
fmt.Println("Mode", cost.Mode())
cost.SetPrec(2)
fmt.Println("Prec", cost.Prec())
fmt.Println("Accuracy", cost.Acc())
fmt.Println("Cost ", cost.String())
}
输出:
Cost 10
Prec 53
MinPrec 3
Mode ToNearestEven
Prec 2
Accuracy Below
Cost 8
第10轮到最近的偶数,可用符号,指数和2位尾数表示,得到8。
Rounding ToNearestEven是IEE754舍入。舍入到最近,连接到偶数 - 舍入到最接近的值;如果数字中间下降,则使用偶数(零)最低有效位四舍五入到最接近的值。