【问题标题】:How to ensure same float numbers on different systems?如何确保不同系统上的浮点数相同?
【发布时间】:2012-11-14 07:08:00
【问题描述】:

如果我在 windows 和 linux(ubuntu) 上编译以下 c 行,我会得到不同的结果。我想避免。我该怎么做?

 double a = DBL_EPSILON;
 double b = sqrt(a);
 printf("eps = %.20e\tsqrt(eps) = %.20e\n", a, b);

linux 输出:

eps = 2.22044604925031308085e-16        sqrt(eps) = 1.49011611938476562500e-08

窗口输出:

eps = 2.22044604925031310000e-016       sqrt(eps) = 1.49011611938476560000e-008

在 linux 上使用 gcc 和 clang 在 32 位和 64 位系统上测试的结果相同。 在 Windows 上使用 gcc-mingw 在 32 位和 visual-studio 上使用 32 位和 64 位进行测试,结果也相同。

【问题讨论】:

  • 各个系统的底层架构是什么?
  • 使用的 c 库的 printf 实现不同。 Windows 仅打印 17 位左右的有效数字,如果需要更多,则用零填充。 glibc 打印正确舍入的值。
  • 但对我来说,这似乎不仅仅是打印问题,我的数值算法也返回略有不同的结果。我指出了这条线,因为我认为它们是差异的根源。#
  • double 变量通常具有 about 16 significant decimal digits 的精度。打印或比较过去的数字是没有意义的。
  • @Blastfurnace:打印超过 16 位的数字并非毫无意义。它可能需要 54 个十进制数字来表示 64 位 IEEE 754 二进制浮点数的确切值,并且可能想要出于各种原因查看确切值,例如将值传输到能够处理更高精度或进行调试的数学软件。

标签: c floating-point platform-independent


【解决方案1】:

在您给出的示例中,似乎两个程序都有相同浮点数。他们只是以不同的方式打印它们。围绕这个特定问题最简单的解决方案是编写自己的浮点打印函数。如果您不期望输出太好,您可以使用函数here 作为伪代码来编写您自己的 C )。


您的问题暗示您遇到的一个更深层次的问题是浮点计算在不同平台上给出不同的结果。这是因为 C 标准不强制编译器准确地实现 IEEE 754 浮点标准,特别是允许更高的中间结果精度。 C 标准的这种相对宽松至少部分是由于历史悠久的 x86 浮点指令导致实现精确的 IEEE 754 语义成本高昂。

在 Linux 上,假设您使用的是 GCC,请尝试使用 -msse2 编译选项。 编辑:OP 评论说-msse2 -mfpmath=sse 为他工作。 这使得 GCC 生成现代 SSE2 指令,提供精确的 IEEE 754 浮点语义。如果在 Windows 上也使用 GCC,请在此处使用相同的选项。

如果您使用 Visual C:Visual C 使用另一个技巧来强制历史浮点指令与 IEEE 754 语义匹配:它告诉旧的 80 位浮点硬件仅使用与 IEEE 754 一样多的有效位双精度有。这给出了双精度数字的准确模拟,除了一些您不会遇到的极端情况。在这种情况下,如果您的程序仅使用双精度数字(C double 类型),它会有所帮助(*)。

(*) Visual C 编译器理论上可以生成代码,通过将每个中间结果从双精度舍入到单精度来计算精确的单精度算术,但这会很昂贵,我怀疑它是否这样做。

【讨论】:

  • 我不知道我是否会调用溢出和下溢“你不会遇到的极端情况”;它们在实际代码中经常出人意料地出现。
  • @StephenCanon 你抓住了我,我可能不完全诚实:可能会发生下溢和上溢。我的问题是,如果它们确实发生了,我没有任何解决方案可以提供,除了在程序中手动插入它们可能发生的任何地方,intermediate_result = intermediate_result >= 0x1.0p+1024 ? inf : intermediate_result;。下溢的情况更糟,我没有看到任何 portable 代码来截断有效数字。如果程序员知道他使用的是 x87,那么对 ldexp() 的两次调用就应该这样做,但这会将 IEEE 754 硬件上的非规范化刷新为零
  • @StephenCanon 另外,“两次调用 ldexp()` 解决方案引入了双舍入。
  • 是的,这是一个非常棘手的问题;让我们希望提问者有幸避免它。
  • 对于 gcc "-msse2 -mfpmath=sse" 似乎适用于我的问题。谢谢!
猜你喜欢
  • 2012-09-02
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
  • 2022-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多