我在C程序中有以下函数:
float invsqrt_32(float number) {
long int i; /* expected to be 32 bits */
float x2;
float y;
x2 = number * 0.5F;
i = * ( long int * ) &number;
i = 0x5f375a86 - ( i >> 1 );
y = * ( float * ) &i;
y *= ( 1.5F - ( x2 * y * y ) );
y *= ( 1.5F - ( x2 * y * y ) );
return (y * ( 1.5F - ( x2 * y * y ) )); }
它是从这里改编的,并根据我们的需求和进一步的研究进行了一些改进/改编。
使用输入
number = 4.52949917e-06
在幻数和位屏蔽操作之后,在Windows 10上的Visual Studio 2017(默认编译器)上,我得到
i = 1139498105
但在Ubuntu 18.04(Linux gcc)上的Eclipse 2021.09中,我得到了
i = -3074621553247560583
我不明白这是怎么发生的
我应该怎么做才能找到差异的来源?
此问题是由在64位Linux上使用64位长的long int
类型引起的,而在64位Windows上使用32位长的类型。类型应与IEEE 754float
的长度相同,后者为32位长。
正确的解决方案应该使用stdint.h
中的int32_t
,但从评论中可以看出,平台配置不正确,int32_t
实际上是64位长。
解决方法是使用int
,而不是在Linux和Windows平台上都是32位长的long int
。
float invsqrt_32(float number) {
int i; /* expected to be 32 bits */
float x2;
float y;
x2 = number * 0.5F;
i = * (int * ) &number;
i = 0x5f375a86 - ( i >> 1 );
y = * ( float * ) &i;
y *= ( 1.5F - ( x2 * y * y ) );
y *= ( 1.5F - ( x2 * y * y ) );
return (y * ( 1.5F - ( x2 * y * y ) )); }
注意,该解决方案在技术上违反了";严格混叠规则";其禁止经由指向CCD_ 9的指针来访问类型为CCD_。为了完全合规,重新解释应该通过其他方式进行,比如工会投票。
union {
float f;
int i;
} u = { number };
i = u.i;