运行测试与调试测试=不同的结果

时间:2013-09-05 08:16:02

标签: c# .net visual-studio-2010 visual-studio unit-testing

我们有一些单元测试可以检查方程线性系统解的结果,将浮点数与delta进行比较。

尝试调整增量,我注意到Visual Studio Run testDebug test模式之间的相同数字略有变化。

为什么会这样?当我调试测试时,#if DEBUG部分被禁用,因此执行的代码应该是相同的。

感谢。

4 个答案:

答案 0 :(得分: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代码是相同的:

comparison between unoptimized and optimized

请注意,地址不同,这可能表明此处除了纯IL之外还有其他内容,但我不知道这可能是什么。

答案 1 :(得分:6)

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

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

答案 2 :(得分:1)

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

如果您调试相同的构建,则将关闭jit optimisations。因此,jit编译器将生成不同的机器代码指令。

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

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

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

另见CLR JIT optimizations violates causality?

答案 3 :(得分:0)

即使Visual Studio Ctrl+F5F5也会产生不同的浮点值。打印准确值的唯一选择是在Release模式下运行并且不使用Visual Studio(Ctrl+F5)时从代码创建文本文件。不同的机器会产生不同的浮点值,因此由您决定生成它的位置。

通过这种方式,您的所有浮点数都将完全匹配!