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 回复

乘法不应有任何舍入误差

浮点数的乘法并非精确运算,会产生舍入误差。你可以验证,即使是 f1*100 == f1*10*10 的结果也是 false

更多关于Golang基础乘法运算中的Bug问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你说得对。这似乎是由于未明确定义 float32float64 而导致的精度错误。

我们必须使用以下方法来定义浮点变量:

var f1 float32
f1 = 256.1

这是我所工作过的每种语言和每个平台中二进制浮点运算的一个特性,而且我工作过的平台非常多!这就是为什么你不能使用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")
	}
}

在金融计算或需要精确十进制运算的场景中,建议使用:

  1. math/big包处理高精度计算
  2. 第三方decimal库(如shopspring/decimal
  3. 转换为整数进行计算,最后再转换回小数

浮点数运算的舍入误差是所有遵循IEEE 754标准的编程语言(包括Go、Java、Python等)的共性问题,不是Go特有的bug。

回到顶部