Golang基础乘法运算中的Bug问题探讨
Golang基础乘法运算中的Bug问题探讨 如果在 Go Playground 中运行以下简单代码: https://play.golang.org/p/vNTS-kaDuWe
f1 := 256.1
fmt.Println((f1*100 - f1*10*10) * 10e15)
你会得到 36379.78 而不是 0。 乘法运算不应该有任何舍入误差。
期待您对这个问题的看法。
5 回复
这是我所工作过的每种语言和每个平台中二进制浮点运算的一个特性,而且我工作过的平台非常多!这就是为什么你不能使用C语言或Go语言的浮点数来编写会计系统:当账目因为莫名其妙的原因差一分钱而对不上时,会计师们会非常恼火。
既然还没有人提供链接,我本想分享一篇包含大量公式的长文……但 https://floating-point-gui.de/ 看起来更容易理解,并且仍然链接了那篇深入的文章。对于任何期望浮点数运算完全精确的人来说,这是一篇非常重要的必读材料。
这是一个典型的浮点数精度问题,而不是Go语言的bug。由于IEEE 754浮点数表示法的限制,十进制小数在二进制中无法精确表示,导致计算时出现舍入误差。
示例代码演示了这个问题:
package main
import (
"fmt"
"math"
)
func main() {
f1 := 256.1
// 直接计算会显示误差
result := (f1*100 - f1*10*10) * 10e15
fmt.Printf("浮点数计算结果: %.2f\n", result)
// 查看256.1的实际二进制表示
fmt.Printf("256.1的精确值: %.20f\n", f1)
// 使用decimal包进行精确计算(需要导入第三方包)
// 或者使用整数运算避免精度问题
intValue := int64(f1 * 1000) // 转换为整数处理
exactResult := (intValue*100 - intValue*10*10) * 10e12
fmt.Printf("整数计算结果: %d\n", exactResult/1000)
// 比较浮点数应该使用容差
tolerance := 1e-10
diff := math.Abs(result - 0)
if diff < tolerance {
fmt.Println("在容差范围内可视为0")
}
}
在金融计算或需要精确十进制运算的场景中,建议使用:
math/big包处理高精度计算- 第三方decimal库(如
shopspring/decimal) - 转换为整数进行计算,最后再转换回小数
浮点数运算的舍入误差是所有遵循IEEE 754标准的编程语言(包括Go、Java、Python等)的共性问题,不是Go特有的bug。


