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

Col*_*nic 7 .net c# 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
Run Code Online (Sandbox Code Playgroud)

(在Linqpad测试)

这是怎么回事?


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

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

Jon*_*eet 7

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

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

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

从C#4规范的4.1.6节:

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

编辑:我没有尝试编译这个,但在评论中,克里斯说第一个表格根本没有在执行时进行评估.以上仍然适用(我稍微调整了我的措辞) - 它只是将常量的评估时间从执行时间转移到编译时.只要它的行为方式同一个有效的评价,似乎还好我-所以编译器本身常量表达式的评价可以用更高的精度运算了.