使用 64 位或 32 位编译时的不同行为或 sqrt [英] different behaviour or sqrt when compiled with 64 or 32 bits

查看:20
本文介绍了使用 64 位或 32 位编译时的不同行为或 sqrt的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm using sqrt() function from math library, when I build for 64 bit using -m64 I'm getting correct result but when I build for 32 bit I have very inconsistent behaviour.

例如在 64 位

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

(我认为这是正确舍入的结果,已用 mpfr 验证)

(which I believe is the correctly rounded result, verified with mpfr)

但是在 32 位相同的输入值上,它的行为不同.

But on 32 bit same input value it behaves differently.

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

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

When the same value passed in a variable I'm getting wrong result. I checked rounding mode before and after each call and all are set to round to nearest. What the reason? I'm using gcc 4.6 on a 64bit machine, and options are -mfpmath=sse and -march=pentium for both x86 nad x64 cases.

推荐答案

您还没有说明您使用的是哪种编译器或架构,但假设 x86 上的 gcc/x86-64 那么区别可能在于默认情况下 gcc 在 32 位 x86 上使用 387 条浮点指令,而它在 x86-64 上使用 SSE 指令.

You haven't said which compiler or architecure you're using, but assuming gcc on x86 / x86-64 then the difference is likely down to the fact that by default gcc uses 387 floating point instructions on 32 bit x86, whereas it uses SSE instructions on x86-64.

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

The 387 floating point registers are 80 bits wide, whereas double is 64 bits wide. This means that intermediate results can have higher precision using the 387 instructions, which can result in a slightly different answer after rounding. (The SSE2 instructions operate on packed 64 bit doubles).

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

There's a few ways to change the way the compiler operates, depending on what you want:

  • 如果您在 x86 版本上使用 -ffloat-store 选项,则每当您将值存储在 double 变量中时,编译器都会丢弃额外的精度;
  • 如果您在 x86 版本上使用 -mfpmath=sse 选项,以及 -msse2 或指定一个 -march= 开关SSE2 支持架构,编译器将使用 SSE 指令进行浮点运算,就像在 x86-64 上一样.不过,该代码只能在支持 SSE2 的 CPU 上运行(Pentium-M/Pentium 4 及更高版本).
  • 如果您在 x86-64 版本上使用 -mfpmath=387 选项,编译器将使用 387 条浮点指令,就像在 x86 上一样.但是,不建议这样做 - x86-64 ABI 指定在 SSE 寄存器中传递浮点值,因此编译器必须使用此选项在 387 和 SSE 寄存器之间进行大量改组.
  • If you use the -ffloat-store option on x86 builds, the compiler will discard extra precision whenever you store a value in a double variable;
  • If you use the -mfpmath=sse options on x86 builds, along with -msse2 or an -march= switch that specifies an SSE2-supporting architecture, the compiler will use SSE instructions for floating point just as on x86-64. The code will only run on CPUs that support SSE2, though (Pentium-M / Pentium 4 and later).
  • If you use the -mfpmath=387 option on x86-64 builds, the compiler will use 387 instructions for floating point just as on x86. This isn't recommended, though - the x86-64 ABI specifies that floating point values are passed in SSE registers, so the compiler has to do a lot of shuffling between 387 and SSE registers with this option.

这篇关于使用 64 位或 32 位编译时的不同行为或 sqrt的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆