浮点等号的意外结果

本文关键字:意外 结果 | 更新日期: 2023-09-27 17:49:24

问题不是关于为什么0.1 + 0.9不等于1.0。这是关于等号的不同行为。

谁能解释一下为什么下面的例子不同?

float q = 0.1f;
float w = 0.9f;
float summ = q + w;
q + w == 1.0f; // False
summ == 1.0f; // True

为什么操作符==的工作方式不同?

浮点等号的意外结果

问题是由于中间计算正在以更高的精度执行,并且何时舍入到float精度的规则在每种情况下都是不同的。

根据文档

默认情况下,在x86架构的代码中,编译器使用协处理器的80位寄存器来保存浮点计算的中间结果。

…在赋值和强制类型转换以及将形参传递给函数时,编译器对float类型的变量执行舍入到正确的精度"

float summ = q + w是一个赋值,因此被四舍五入到最接近的float,在本例中为1。

q + w == 1.0f既不是强制转换、赋值也不是函数调用,所以加法的结果仍然是一个扩展的精度浮点数,它接近但不等于1。

进一步了解IL:

summ存储在float32

类型的本地
IL_000d:  ldloc.0
IL_000e:  ldloc.1
IL_000f:  add
IL_0010:  stloc.2

q + wq + w == 1.0f中使用的结果是not;它直接用于比较

IL_0011:  ldloc.0
IL_0012:  ldloc.1
IL_0013:  add
IL_0014:  ldc.r4     1.
IL_0019:  ceq

假定summ在本地存储意味着它失去了足够的精度,因此它等于1.0f