表达式和指定对象之间的浮点不一致

时间:2012-11-08 14:18:24

标签: c# .net floating-point

这让我感到惊讶 - 同样的算法会根据其执行方式给出不同的结果:

> 0.1f+0.2f==0.3f
False

> var z = 0.3f;
> 0.1f+0.2f==z
True

> 0.1f+0.2f==(dynamic)0.3f
True

(在Linqpad中测试)

发生了什么事?


编辑:我理解为什么浮点运算不精确,但不是为什么不一致

古老的C可靠地确认 0.1 + 0.2 == 0.3 适用于单精度浮点数,但不适用于双精度浮点数。

1 个答案:

答案 0 :(得分:7)

我强烈怀疑您可能会发现使用和不使用调试器以及在发布配置和调试配置中运行此代码会得到不同的结果。

在第一个版本中,您要比较两个表达式。 C#语言允许以比源类型更高精度的算术计算这些表达式。

在第二个版本中,您将添加结果分配给局部变量。 在某些情况下,会强制将结果截断为32位 - 导致不同的结果。在其他情况下,CLR或C#编译器将意识到它可以优化掉局部变量。

来自C#4规范的第4.1.6节:

  

可以以比操作的结果类型更高的精度执行浮点运算。例如,某些硬件体系结构支持“扩展”或“长双”浮点类型,其范围和精度比double类型更大,并且隐式执行具有更高精度类型的所有浮点运算。只有在性能成本过高的情况下,才能使这种硬件架构以 less 精度执行浮点运算。 C#允许更高精度的类型用于所有浮点运算,而不是要求实现丧失性能和精度。除了提供更精确的结果外,这几乎没有任何可衡量的影响。

编辑:我没有尝试过编译,但是在评论中,Chris说第一个表单根本没有在执行时进行评估。上面的仍然适用(我稍微调整了我的措辞) - 它只是将常量的评估时间从执行时间转移到编译时。只要它的行为方式与 a 有效评估相同,这对我来说似乎没问题 - 所以编译器自己的常量表达式评估也可以使用更高精度的算法。