(如何)调试会改变程序的工作流程?

(How) does debugging change the workflow of the program?

考虑以下简单程序:

var dblMax = Double.MaxValue;

var result = (dblMax * 1000) / 1800;
Console.WriteLine(result);

当我在调试模式下构建它并 运行 (Ctrl+F5) 或调试 (F5) 它时,它会打印 9.987140856842E+307.

当我切换到 Release 模式并 运行 (Ctrl+F5) 时,它会打印 8 表示无穷大。

据我所知,这种差异是由于在发布模式下进行的一些编译器优化造成的。

但是,如果我在 Release 模式下调试 (F5) same build,它会再次打印 9.987140856842E+307

我正在调试的事实如何改变计算结果?

编辑:

我不问为什么调试模式和发布模式会产生不同的结果。我想知道为什么发布模式会根据我是否调试 (F5) 或不调试 (Ctrl+F5) 产生不同的结果。

这与浮点精度密切相关。在调试模式下,编译器使用 80 位精度。在发布模式下,编译器使用 64 位截断结果。

这何时会发生取决于几个配置、设置和环境变量。例如,您可以关闭发布模式配置的优化。这应该有所帮助。

看看 Jon Skeet 的回答:

调试 JITter 时表现不同。

一方面,在许多情况下,局部变量的生命周期会发生变化以便于检查。考虑在计算期间使用变量后设置断点。

JITer 非常清楚什么时候变量仍然有用。如果在那段时间内有一个寄存器可用,它可能最终会使用这个寄存器来存储变量。

但是,在附加调试器的情况下,它可能会决定改用内存位置,因为生命周期发生了很大变化,以至于该部分代码无法使用寄存器。

CPU的浮点寄存器比相应的浮点存储格式具有更高的精度,这意味着一旦你将一个值从寄存器中取出并放入内存中,或者只是将它存储在内存中整个过程中,您将体验到较低的精度。

RELEASE 和 DEBUG 构建之间的差异最终会决定这些事情,调试器的存在也是如此。

此外,不同的 .NET 运行时版本之间可能存在差异,这可能会影响这一点。


正确编写浮点代码需要深入了解您正在尝试做什么以及机器和平台的各个部分将如何干扰。我会尽量避免编写这样的代码。