10

我正在尝试对用 C++ 和 Matlab 编写的算法进行等价测试。该算法包含某种时间循环,运行次数超过 1000 次。它具有算术运算和一些数学函数。

我手动将初始输入提供给两个平台(如 a=1.767,b=6.65,...),当我检查这些输入的十六进制表示时,它们是相同的。所以输入没有问题。并通过 16 位十进制数字的文本文件将 c++ 的输出输出到 matlab。(我使用“setprecision(32)”语句)

但是问题来了;尽管在两个代码的第 614 步之后,所有结果都完全相同,但在 615 步上我得到了大约 2.xxx..xxe-19 的差异?在这一步之后,误差变得越来越大,在运行结束时它大约是 5.xx..xxe-14。

0x3ff1 3e42 a211 6cca--->[C++函数]--->0x3ff4 7619 7005 5a42

0x3ff1 3e42 a211 6cca--->[MATLAB函数]--->ans

答案 - 0x3ff4 7619 7005 5a42

= 2.xxx..xxe-19

我搜索了 matlab 如何处理数字,发现了非常有趣的东西,比如“非规范化尾数”。虽然 realmin 大约是 e-308,但通过对尾数进行非规范化,matlab 具有关于 e-324 的最小实数。此外,matlab 中“pi”或“exp(1)”的位数比 C++ 多得多。

另一方面,matlab help 说无论它显示什么格式,matlab 在内部都使用双精度。

所以,如果有人解释这些差异的确切原因是什么,我真的很感激?我们如何在 matlab 和 c++ 上进行等价测试?

4

3 回答 3

11

x86 CPU 中有关于浮点数的一件事。在内部,浮点单元使用 10 字节的寄存器,即 80 位。此外,CPU 有一个设置,它告诉浮点计算应该以 32 位 ( float)、64 位 ( double) 还是 80 位精度进行。较低的精度意味着更快地执行浮点运算。(32 位模式曾经在视频游戏中很流行,其中速度取代了精度)。

从这里我记得我在一个计算库(dll)中跟踪了一个错误,无论它是从测试 C++ 可执行文件还是从 MatLab 启动,给定相同的输入并没有给出相同的结果。此外,这在调试模式下没有发生,仅在发布!

最后的结论是 MatLab 确实将 CPU 浮点精度设置为 80 位,而我们的测试可执行文件没有(并保留默认的 64 位精度)。此外,这种计算不匹配不会发生在调试模式下,因为所有变量都被写入内存到 64 位double变量中,然后从那里重新加载,使额外的 16 位无效。在发布模式下,优化了一些变量(未写入内存),所有计算仅使用 80 位浮点寄存器完成,保持额外的 16 位非零值。

不知道这是否有帮助,但也许值得知道。

于 2012-06-22T07:47:23.210 回答
4

之前发生过类似的讨论,结论是IEEE 754容忍超越函数(cos、sin、exp 等)的最后一位错误。因此,您不能期望 MATLAB 和 C 之间的结果完全相同(甚至不能在不同编译器中编译相同的 C 代码)。

于 2012-06-23T05:18:35.070 回答
0

我可能在这里偏离了轨道,您可能已经研究过这种可能性,但是您提到的数学库函数(sin() cos() 和 exp() 的方式可能在 C++ 和 Matlab 之间存在差异) 在内部实现。最终,必须使用某种函数近似来生成函数值,如果这些方法之间存在一些差异,那么这可能会在大量迭代中以数值舍入误差的形式表现出来。

这个问题基本上涵盖了我试图建议的内容C 如何计算 sin() 和其他数学函数?

于 2012-06-22T21:12:53.053 回答