使用 C++ 的 VS6 和 VS2008 之间的数值精度差异?

Posted

技术标签:

【中文标题】使用 C++ 的 VS6 和 VS2008 之间的数值精度差异?【英文标题】:Numerical precision differences between VS6 and VS2008 using C++? 【发布时间】:2010-07-28 15:01:34 【问题描述】:

我一直致力于将旧项目从 Visual Studio 6 移植到 2008 年。在克服了一些障碍后,我现在可以构建和执行新项目。但是,我注意到两个版本的程序的输出略有不同,就好像浮点计算不等价一样,尽管代码相同。

这些差异通常开始时很小 (

Visual Studio 6 表示: 0x4197D6CC85AC68D9 十进制等价物: 99988257.4183687120676040649414

Visual Studio 2008 表示: 0x4197D6CC85AC68EB 十进制等价物: 99988257.4183689802885055541992

我已尝试对此进行调试以追踪差异开始的位置,但输出来自迭代数值求解器,因此以如此高的精度进行追踪将是一个耗时的过程。

是否有人知道两个版本的编译器的双精度算术运算之间的任何预期差异? (或者关于可能导致这种情况的任何其他想法?)

目前,我的下一步可能是尝试创建一个简单的演示应用程序来显示问题并且更容易检查。

谢谢!

【问题讨论】:

【参考方案1】:

这只是一个猜测,但大多数现代 Intel/AMD CPU 都有两个单独的 FPU 型号:旧式 i386 FPU 和较新的基于 SSE/SSE2 的型号。后者具有更灵活的编程模型,通常是首选。

您应该检查 VS6 和 VS2008 是否为同一模型生成代码,因为老式 FPU 具有 80 位中间结果,这可能会导致舍入更少并可能导致更好的结果,但实际结果取决于优化器会。顺便说一句,这是科学界人士真正讨厌的东西。例如,如果操作数溢出到内存中,那么它们会被截断为 64 位,并且会丢失额外的精度。

IIRC 然后 VS6 无法生成 SSE/SSE2 代码,但它有一个 /fp:precise 选项可以将所有中间结果四舍五入到它们声明的大小。我认为 VS 2008 也有这个标志。因此,我建议您对两个编译器都尝试 /fp:precise 并再次比较结果。

【讨论】:

【参考方案2】:

您已经注意到浮点结果存在很多不一致的空间。您确定较新的版本不太正确吗?您是否对可以执行的结果进行了完整性检查?

首先,您的算法似乎对输入的细微变化有些敏感。您是否检查过您的代码(尤其是加法和减法)以确保没有引入错误的机会?

至少在 x86 上,大多数 FP 操作在 80 位内部寄存器中完成,但在内存中只有 64 位。如果两个不同的编译器在不同的点将中间结果复制到内存(并截断),那肯定会导致不同的答案。编译器优化逻辑肯定会导致其行为不同,尤其是如果较新的编译器利用了旧编译器没有的额外寄存器。

在某一时刻,我知道有一个“使用一致的浮点”选项,但我不记得它在哪个版本中。这导致每次操作后值被截断为 64 位,但确保结果在多次运行中保持一致。

【讨论】:

以上是关于使用 C++ 的 VS6 和 VS2008 之间的数值精度差异?的主要内容,如果未能解决你的问题,请参考以下文章

从 VS6 移植到 VS2008 时在不寻常的架构中使用单元测试?

.lib 和 .dll 向后兼容性

在 vs2008 中更新 ActiveX 包装器

如何从 VS2008 中的 C++ MFC 对话框中的日期/时间小部件中提取数据

使用 VS6 C++ GUI 编辑器、MFC 以屏幕(像素)为单位调整全屏窗口大小?

从 C# 调用非托管 C++ VS 6.0 MFC dll