Quake3源码的Fast Inverse Sqrt()在VS与Eclipse运行结果不一致求助
Fast Inverse Sqrt跨平台数值差异排查方案
你实现的Fast Inverse Sqrt函数在Windows VS2017和Linux GCC下出现i值差异,核心原因及排查步骤如下:
1. 核心原因:long int的平台位数差异
Windows平台上long int是32位(4字节),和float的字节长度一致,因此*(long int *)&number能正确读取float的32位二进制数据作为整数。而Linux x86_64平台上long int是64位(8字节),远大于float的4字节:
- 执行
*(long int *)&number时,会从number的内存地址开始读取8字节数据,其中仅前4字节是float的有效二进制,后4字节是栈上的未初始化垃圾值,最终得到的64位整数自然完全错误(你得到的i = -3074621553247560583就是包含垃圾数据的64位值)。
2. 具体排查步骤
- 验证数据类型长度:在两个平台分别打印
sizeof(long int)和sizeof(float),确认Windows下long int为4字节,Linux下为8字节。代码示例:printf("long int size: %zu\n", sizeof(long int)); printf("float size: %zu\n", sizeof(float)); - 检查内存读取内容:在两个平台打印
number的二进制字节,对比是否一致。代码示例:
如果字节内容一致,说明问题确实出在float num = 4.52949917e-06; unsigned char *bytes = (unsigned char*)# for(int i=0; i<sizeof(float); i++){ printf("%02x ", bytes[i]); } printf("\n");long int的位数上。 - 关闭编译器优化测试:部分编译器优化可能导致内存布局异常,分别在VS(开启
/Od选项)和GCC(开启-O0选项)下重新编译运行,看i值是否仍有差异。
3. 修复方案
使用固定位数的整数类型替代long int,保证跨平台一致性,同时避免类型转换的未定义行为:
- 包含
<stdint.h>头文件,使用uint32_t或int32_t(32位整数类型); - 用
memcpy进行字节复制,替代直接强制类型转换(符合C标准,避免未定义行为)。
修复后的代码示例:
#include <stdint.h> #include <string.h> float invsqrt_32(float number) { uint32_t i; float x2; float y; x2 = number * 0.5F; memcpy(&i, &number, sizeof(i)); // 安全复制字节 i = 0x5f375a86 - ( i >> 1 ); memcpy(&y, &i, sizeof(y)); y *= ( 1.5F - ( x2 * y * y ) ); y *= ( 1.5F - ( x2 * y * y ) ); return (y * ( 1.5F - ( x2 * y * y ) )); }
内容的提问来源于stack exchange,提问作者Federico
相关产品推荐
相关产品推荐

