为何Go中fmt.Print(0.1+0.2)未出现IEEE754浮点舍入误差?
为什么Go中直接打印
0.1+0.2会输出0.3 按照IEEE754浮点数运算标准,二进制浮点数无法精确表示0.1、0.2这类十进制小数,计算时存在固有舍入误差,常见的测试代码运行结果符合这个规律:
a := 0.1 b := 0.2 fmt.Println(a+b) // 输出 0.30000000000000004
但很多人会碰到反直觉的情况:逻辑几乎完全一样,直接在打印函数里写计算表达式,输出就成了0.3,看不到预期的舍入误差:
fmt.Print(0.1 + 0.2) // 输出 0.3
核心原因
这个差异和浮点数计算逻辑本身没关系,本质是Go的类型规则和fmt包的格式化逻辑共同导致的:
- 第一段代码用
:=赋值时,字面量0.1、0.2会被默认推导为float64(双精度浮点数)类型,a+b的结果自然也是float64。fmt包打印float64类型值时,默认会输出足够多的有效位,保证打印出的十进制串能无损转回原float64值,所以会把舍入产生的末尾误差完整打出来,就是我们看到的0.30000000000000004。 - 第二段代码里,直接写在
fmt.Print参数里的0.1 + 0.2是无类型浮点常量,Go里的无类型浮点数精度远高于float64,编译阶段计算常量表达式时,会用高精度存储结果。传给fmt.Print做格式化时,默认逻辑只会输出能代表该值的最短十进制串,不会拉满到float64的全精度输出,所以最终显示为0.3。
做个简单测试就能验证:把常量表达式里的数值强制转成float64再计算打印,输出结果就和变量写法完全一致:
fmt.Print(float64(0.1) + float64(0.2)) // 输出 0.30000000000000004
内容的提问来源于stack exchange,提问作者sprutex
相关产品推荐
相关产品推荐

