浮点等于的意外结果
Unexpected results for floating point equals
问题不是关于为什么 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
为什么运算符 ==
的工作方式不同?
深入了解 IL:
summ
存储在 float32
类型的本地
IL_000d: ldloc.0
IL_000e: ldloc.1
IL_000f: add
IL_0010: stloc.2
在q + w == 1.0f
中使用q + w
的结果不是;直接用于比较
IL_0011: ldloc.0
IL_0012: ldloc.1
IL_0013: add
IL_0014: ldc.r4 1.
IL_0019: ceq
据推测,summ
在本地的存储意味着它失去了足够的精度,以至于它变得等于 1.0f
。
问题是由于中间计算是以更高的精度执行的,而何时舍入到 float
精度的规则在每种情况下都不同。
根据the docs
By default, in code for x86 architectures the compiler uses the coprocessor's 80-bit registers to hold the intermediate results of floating-point calculations.
... the compiler performs rounding on variables of type float
to the correct precision for assignments and casts and when parameters are passed to a function"
float summ = q + w
是一项赋值,因此四舍五入到最接近的 float
,在本例中为 1。
q + w == 1.0f
既不是强制转换、赋值也不是函数调用,因此加法的结果仍然是扩展精度浮点数,接近但不等于 1。
问题不是关于为什么 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
为什么运算符 ==
的工作方式不同?
深入了解 IL:
summ
存储在 float32
IL_000d: ldloc.0
IL_000e: ldloc.1
IL_000f: add
IL_0010: stloc.2
在q + w == 1.0f
中使用q + w
的结果不是;直接用于比较
IL_0011: ldloc.0
IL_0012: ldloc.1
IL_0013: add
IL_0014: ldc.r4 1.
IL_0019: ceq
据推测,summ
在本地的存储意味着它失去了足够的精度,以至于它变得等于 1.0f
。
问题是由于中间计算是以更高的精度执行的,而何时舍入到 float
精度的规则在每种情况下都不同。
根据the docs
By default, in code for x86 architectures the compiler uses the coprocessor's 80-bit registers to hold the intermediate results of floating-point calculations.
... the compiler performs rounding on variables of type
float
to the correct precision for assignments and casts and when parameters are passed to a function"
float summ = q + w
是一项赋值,因此四舍五入到最接近的 float
,在本例中为 1。
q + w == 1.0f
既不是强制转换、赋值也不是函数调用,因此加法的结果仍然是扩展精度浮点数,接近但不等于 1。