【问题标题】:Floating point differences depending on how debug build is run浮点差异取决于调试构建的运行方式
【发布时间】:2013-08-24 11:06:49
【问题描述】:

无论我是否在调试器下运行,我都在使用调试版本并在同一台机器上获得不同的结果。我正在使用优秀的 TestDriven.Net 来运行单元测试。

  • 使用 TestDriven.Net 或外部 NUnit 运行器“运行”会产生相同的结果
  • “使用调试器运行”与 TestDriven.Net 产生不同的结果

代码是

  • 一个复杂的迭代网格变形例程,涉及在浮点精度限制下进行大量计算
  • C#、VS2012 面向 .Net 3.5。
  • 单线程
  • 仅调试版本,未构建发布版本
  • 同一台机器,没有省电\speedstep 或其他我知道的功能
  • Vanilla C# - 没有不安全的代码、非托管库、平台调用等。
  • 没有调试器检查代码或奇怪的第三方库

我还没有追踪到第一个差异(没有调试器就很棘手!)但是考虑到代码的迭代性,它的输入敏感和最小的差异将在足够的时间下增长到显着的比例。

我知道跨编译器、平台和架构的 fp 再现性是多么脆弱,但我很失望地发现调试器是导致这种情况失败的因素之一。

我是否必须接受这是生活中的事实,还是您可以提供任何建议?

【问题讨论】:

    标签: c# debugging visual-studio-2012 floating-point testdriven.net


    【解决方案1】:

    我是否必须接受这是生活中的事实,还是您可以提供任何建议?

    你必须接受它作为生活的事实。浮点代码可以在不同的情况下进行不同的优化。特别是,在某些情况下,JIT 编译器可以使用具有更精确/准确度的表示(例如 80 位浮点)进行操作。 JIT 编译器执行此操作的情况取决于体系结构、优化设置等。关于变量(以及它是否为局部变量)的操作可能存在许多微妙之处,这些都会影响到这一点。在调试器下运行通常会非常显着地影响 JIT 优化设置 - 不仅仅是浮点 - 所以我对此一点也不感到惊讶。

    如果您以一定的容差执行浮点比较,那应该没问题 - 无论如何,对浮点类型进行精确相等比较几乎不是一个好主意。当然,您可能实际上是在执行不等式比较,其中差异变得显着,但我很少将其视为问题。

    【讨论】:

    • 谢谢乔恩。该领域是计算几何,所涉及的代码是清除退化案例共线性、巧合等。它的所有容差都基于,但数量和迭代性质最终会导致微小的差异显着。
    • 当计算涉及单精度和双精度时,有没有办法让整个平台(JIT、调试器……)使用 SSE2 指令?多亏了这些说明,在所有语言中,浮点再现性问题被认为在 C 中得到了解决。
    • @PascalCuoq:这不仅仅是使用哪些指令。考虑一个本地的double 变量——它可以存储在一个 80 位的寄存器中,所以当有重复的操作时,如果它以 64 位的形式存储在普通内存中,你最终会得到一个不同的值。移除这种能力是可能的(就像 Java 对 strictfp 所做的那样),但要以优化为代价。
    • SSE2 指令有自己的 16 个“XMM”寄存器,它们可以用来存储精确的浮点数或精确的双精度数。即使预先存在的 ABI 需要使用旧的 FP 堆栈,只要仅使用 SSE2 指令进行计算,这些旧寄存器在用于根据 ABI 传递参数时,也只会包含可表示的 @ 987654322@s 读取时无损失地转换回来。
    • @PascalCuoq:是的,我明白了。不幸的是,我没有任何内部信息知道为什么 CLR 中不使用这些。大概这些指令不是跨架构通用的吗?请记住,CLR 也可以在 ARM 上运行 - ARM 有类似的东西吗?
    猜你喜欢
    • 2020-06-17
    • 2016-04-03
    • 1970-01-01
    • 1970-01-01
    • 2014-03-17
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多