使用 64 位或 32 位编译时的不同行为或 sqrt [英] different behaviour or sqrt when compiled with 64 or 32 bits
问题描述
我正在使用数学库中的 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 adouble
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屋!