7

We have some unit tests that check the result of the solution of linear system of equation, comparing floating point numbers with a delta.

Trying to adjust the delta, I noticed that the same number changes slightly between Visual Studio Run test and Debug test modes.

Why does this happen? When I debug a test the #if DEBUG sections are disabled, therefore the executed code should be the same.

Thanks.

4

4 回答 4

10

有关在典型 DEBUG 和 RELEASE 构建(未优化与优化)之间产生不同结果的代码的简单示例,请在LINQPad中尝试:

void Main()
{
    float a = 10.0f / 3;
    float b = 10;
    b /= 3;

    (a == b).Dump();
    (a - b).Dump();
}

如果您在优化的情况下执行此操作(确保 LINQPad 窗口中一直向下到右侧的小按钮变为“/o+”),您将得到以下结果:

False
-7,947286E-08

如果禁用它,关闭优化,你会得到:

True
0

请注意,生成的 IL 代码是相同的:

未优化和优化之间的比较

请注意,地址不同,这可能表明这里除了纯 IL 之外还有其他东西,尽管我不知道那可能是什么。

于 2013-09-05T08:22:47.300 回答
6

有各种各样的事情会影响浮点计算,其中最重要的是它是否真的将值写入本地/字段。对于优化的构建,JIT 可以将值保存在寄存器中 - FPU 寄存器为 80 位宽,以最大限度地减少累积错误。如果它需要将值实际写入 32 位 ( float) 或 64 位 ( double) 本地或字段,它必然会丢失其中的一些。所以是的,如果它可以在寄存器中完成所有工作 - 它可以给出不同(通常更“正确”)的结果,而不是将中间值写入本地等。

还有其他可用的寄存器,但我怀疑这些寄存器是否在这里使用:XMM/SSE 寄存器是 128 位的;SIMD 可以(取决于机器)高达 512 位。

于 2013-09-05T08:24:30.743 回答
2

如果您运行构建,它将使用完整的 jit 优化执行,即。在运行时,jit 编译器会做一些聪明的事情。

如果您调试相同的构建 jit 优化将被关闭。因此 jit 编译器会生成不同的机器码指令。

优化各不相同。一个例子是变量的存储。变量存储在寄存器中,并非所有寄存器的大小都相同。如果代码经过优化,一些步骤可能会被删除或按顺序打乱。因此,给定操作的寄存器选择可能会改变。因此,存储值的准确性会发生变化。

这导致浮点计算的不同输出。

编译器通常保证最小精度,但很少保证中间步骤的最大精度。

另请参阅CLR JIT 优化违反因果关系?

于 2013-09-05T08:37:06.597 回答
0

Ctrl+F5甚至Visual Studio 也会F5产生不同的浮点值。打印准确值的唯一选项是在Release模式下运行且不使用 Visual Studio ( Ctrl+F5) 时从您的代码创建一个文本文件。不同的机器会产生不同的浮点值,所以由你决定在哪里生成它。

这样,您所有的浮点数都将完全匹配!

于 2013-09-05T09:44:28.223 回答