7

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

> 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适用于单精度浮点数,但不适用于双精度浮点数。

4

1 回答 1

7

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

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

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

从 C# 4 规范的第 4.1.6 节:

浮点运算可以以比运算结果类型更高的精度执行。例如,某些硬件体系结构支持比该类型具有更大范围和精度的“扩展”或“长双精度”浮点double类型,并隐式执行具有更高精度类型的所有浮点运算。只有以过高的性能成本为代价,才能使这种硬件架构以较低的精度执行浮点运算。C# 不需要一个实现来牺牲性能和精度,而是允许将更高精度的类型用于所有浮点运算。除了提供更精确的结果之外,这很少有任何可衡量的影响。

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

于 2012-11-08T14:40:51.517 回答