【问题标题】:different behaviour or sqrt when compiled with 64 or 32 bits使用 64 位或 32 位编译时的不同行为或 sqrt
【发布时间】:2012-05-30 00:38:06
【问题描述】:

我正在使用数学库中的 sqrt() 函数,当我使用 -m64 为 64 位构建时,我得到了正确的结果,但是当我为 32 位构建时,我的行为非常不一致。

例如在 64 位上

double dx = 0x1.fffffffffffffp+1023;
sqrt(dx); // => 0x1.fffffffffffffp+511
sqrt(0x1.fffffffffffffp+1023);// => 0x1.fffffffffffffp+511

(我认为是正确的四舍五入结果,已通过 mpfr 验证)

但在 32 位相同的输入值上,它的行为会有所不同。

double dx = 0x1.fffffffffffffp+1023;
sqrt(dx); // => 0x1.0p+512
sqrt(0x1.fffffffffffffp+1023); // => 0x1.fffffffffffffp+511

当在变量中传递相同的值时,我得到了错误的结果。 我在每次通话之前和之后检查了舍入模式,所有设置都设置为最近的舍入。 什么原因? 我在 64 位机器上使用 gcc 4.6,对于 x86 和 x64 两种情况,选项都是 -mfpmath=sse-march=pentium

【问题讨论】:

标签: c math 32bit-64bit sqrt mpfr


【解决方案1】:

您还没有说您使用的是哪个编译器或架构,但假设 gccx86 / x86-64 上,那么差异可能归结为默认情况下 gcc 在 32 上使用 387 个浮点指令这一事实位 x86,而它在 x86-64 上使用 SSE 指令。

387 个浮点寄存器是 80 位宽,而double 是 64 位宽。这意味着使用 387 指令的中间结果可以具有更高的精度,这可能会导致四舍五入后的结果略有不同。 (SSE2 指令对压缩的 64 位双精度进行操作)。

有几种方法可以更改编译器的运行方式,具体取决于您的需要:

  • 如果您在 x86 构建中使用 -ffloat-store 选项,则只要您将值存储在 double 变量中,编译器就会丢弃额外的精度;
  • 如果您在 x86 版本上使用 -mfpmath=sse 选项,以及指定支持 SSE2 的架构的 -msse2-march= 开关,编译器将使用 SSE 指令进行浮点运算,就像在 x86-64 上一样。不过,该代码只能在支持 SSE2 的 CPU 上运行(Pentium-M / Pentium 4 及更高版本)。
  • 如果您在 x86-64 版本上使用 -mfpmath=387 选项,编译器将像在 x86 上一样将 387 指令用于浮点。但不建议这样做 - x86-64 ABI 指定浮点值在 SSE 寄存器中传递,因此编译器必须使用此选项在 387 和 SSE 寄存器之间进行大量改组。

【讨论】:

  • 我在 64 位机器上使用 gcc 4.6,对于 x86 和 x64 两种情况,选项是 -mfpmath=sse-march=pentium。我不应该从两种情况下得到相同的结果吗?我对 32 位构建最感兴趣,所以我猜如果没有其他问题,-mfpmath=387 可能会给我正确的结果
  • @giridhart: -march=pentium 仅启用 SSE1,它仅执行单精度 - 对于双精度,它必须回退到具有额外精度的 387。您想要-msse2-march=pentium-m 或类似的以及-mfpmath=sse
  • 其实我用-mfpmath=sse-msse,现在我改成-mfpmath=sse2,但我仍然得到错误的结果。请建议解决此问题的正确选项。谢谢
【解决方案2】:

某些编译器,例如gcc,当他们看到某些数学库函数在静态文字上执行时,实际上会在编译时计算值,而与变量一样,它必须在运行时计算。编译时值通常由编译器使用 MPFR、GNU MP 等数学库计算,因此结果会更准确,或者至少在平台之间尽可能准确。

【讨论】:

  • 我似乎还记得 gcc 愿意在 x86 上使用 80 位精度对文字进行编译时数学运算,而存储到 double 中的值必须减少到 64-位精度。
  • 是的,我认为使用常量时结果正确的原因。有没有办法解决 32 位库的问题?堆栈溢出中列出了类似的问题,但它与 C# stackoverflow.com/questions/2461319/…
  • @giridhart :从您的帖子看来,您的 32 位和 64 位结果与文字是相同的……您是说它们不同吗?
  • @Jason 是的,我应该为 x64 添加这两种情况。在 x64 上,文字和变量大小写都给出正确的结果,而在 x86 上只有文字大小写
猜你喜欢
  • 2018-08-04
  • 1970-01-01
  • 2011-05-30
  • 2021-06-25
  • 2012-10-26
  • 2011-07-10
  • 2011-11-11
  • 1970-01-01
  • 2011-04-12
相关资源
最近更新 更多