我有一些 C++ 图像处理代码,它可以计算梯度并使用霍夫变换算法在其中找到直线。该程序使用浮点数进行大部分计算。
当我在两台不同计算机上的同一个映像上运行此代码时,一台运行最新的 Fedora 奔腾 IV,另一台运行最新的 Core i5 Ubuntu,均为 32 位,我得到的结果略有不同。例如。经过一番漫长的计算,一台机器上的某个变量得到了 1.3456f,另一台机器上得到了 1.3457f。这是预期的行为还是我应该在程序中搜索错误?
我的第一个猜测是,我正在访问一些未初始化或越界的内存,但我确实通过 valgrind 运行了程序,它找不到任何错误,而且在同一台机器上运行多次总是给出相同的结果.
这并不罕见,这取决于您的编译器、优化设置、数学库、CPU,当然还有您正在使用的算法的数值稳定性。
您需要充分了解您的准确性要求,如果您没有满足这些要求,那么您可能需要查看您的算法,例如在需要时考虑使用 double 而不是 float。
有关为什么给定源代码可能不会在不同计算机上产生相同输出的背景信息,请参阅每个计算机科学家应该了解的浮点运算知识。 我怀疑这是由于代码的任何缺陷造成的,除非它以非确定性的方式执行聚合,例如。通过集中整理多个线程的计算结果。
浮点行为通常可以根据编译器选项进行调整,甚至可以调整到不同 CPU 的级别。 检查您的编译器文档,看看是否可以减少或消除这种差异。在 Visual C++ 上(例如),这是通过 /fp 完成的。
是由于一种称为机器ε的现象吗?
http://en.wikipedia.org/wiki/Machine_epsilon
浮点数有限制。浮点数不能精确地表示所有实数,并且浮点运算不能精确地表示真正的算术运算,这一事实导致了许多令人惊讶的情况。这与计算机通常表示数字的有限精度有关。
基本上,相同的 C++ 指令可以根据大量因素编译为不同的机器指令(甚至在相同的 CPU 上,当然也可以在不同的 CPU 上),并且相同的机器指令可以导致不同的低级 CPU 操作,具体取决于很多因素。理论上,它们在语义上应该是等效的,但对于浮点数,存在一些边缘情况,但它们并非如此。
阅读 David Monniaux 的“验证浮点计算的陷阱”了解详细信息。
我过去花了很多时间试图解决同样的问题。
我建议使用
decimal
代替
float
和
double
,只要你的数字不是指科学计算而是指价格、数量、汇率等值。
有些库可以在任何地方产生相同的结果 - 有关示例,请参阅
http://www.mpfr.org/。但性能成本是巨大的,并且可能不值得,除非完全相同的结果是“最重要”的标准。 我实际上编写了一个闭源库,它以整数单元实现浮点数学,以便使浮点数在不同编译器的多个平台(Intel、AMD、PowerPC)上提供相同的结果。我们有一个应用程序,如果浮点结果发生变化,它就无法运行。但这是一个很大的挑战。如果我们能再做一次,我们就会以定点方式设计原始应用程序,但当时需要重写的代码太多了。
这要么是浮动的内部表示之间的差异,导致结果略有不同,要么是浮动打印到屏幕的方式不同?我怀疑这是你的错...