我写了一个示例来教导我的同事为什么测试浮点数的相等性通常是不好的。我选择的示例是将0.1加十次,然后与1.0进行比较(这是我在入门数值课程中学到的)。我很惊讶地发现这两个结果是相等的(代码+输出)。
float @float = 0.0f;
for(int @int = 0; @int < 10; @int += 1)
{
@float += 0.1f;
}
Console.WriteLine(@float == 1.0f);
经过一些调查,发现这个结果不能够被依赖(类似于浮点数相等性)。我认为最令人惊讶的是,在另外一个代码之后添加代码可以改变计算结果 (代码和输出)。请注意,这个示例有完全相同的代码和IL,只是多了一行C#代码。
float @float = 0.0f;
for(int @int = 0; @int < 10; @int += 1)
{
@float += 0.1f;
}
Console.WriteLine(@float == 1.0f);
Console.WriteLine(@float.ToString("G9"));
我知道在浮点数上使用等号是不对的,因此不应该太在意这个问题,但我发现这个问题相当令人惊讶,我的朋友们也都觉得很奇怪。在执行计算后进行其他操作会改变前面计算的值吗?我认为这不是人们通常心中的计算模型。
我并没有完全被难住,似乎可以安全地假设在“相等”情况下发生了某种优化,从而改变了计算的结果(在调试模式下构建可以避免“相等”情况)。显然,当CLR发现它稍后需要将float装箱时,就会放弃这种优化。
我搜索了一下,但找不到这种行为的原因。有人能给我指点一下吗?