我正在调查浮点数的结构,我发现大多数编译器都使用IEEE 754标准来存储浮点数。 当我试图做的时候:
float a=0x3f520000; //have to be equal to 0.8203125 in IEEE 754
printf("value of 'a' is: %X [%x] %f\n",(int)a,(int)a, a);
它产生结果:
value of 'a' is: 3F520000 [3f520000] 1062338560.000000
但如果我尝试:
int b=0x3f520000;
float* c = (float*)&b;
printf("value of 'c' is: %X [%x] %f\r\n", *(int*)c, *(int*)c, c[0]);
它给出了:
value of 'c' is: 3F520000 [3f520000] 0.820313
第二次尝试给了我正确的答案。第一次尝试有什么问题?为什么结果与通过指针将int转换为float时的结果不同?
答案 0 :(得分:4)
[注意:这个答案假设C,而不是C ++,它们有不同的规则]
使用
float a=0x3f520000;
取整数值1062338560
,编译器会将其转换为1062338560.0f
。
如果您想要十六进制floating point constant,则必须使用字母p
使用指数格式。与0x1.a40010c6f7a0bp-1
中一样(0.820313
的十六进制表示法。)
会发生什么
int b=0x3f520000;
float* c = (float*)&b;
是你打破严格别名并告诉编译器c
指向一个浮点值(严格别名中断是因为b
不是 a浮点值)。然后,编译器将重新解释 *c
中的位作为float
值。
答案 1 :(得分:4)
区别在于第一个转换值(0x3f520000
是整数1062338560),并且相当于:
float a = 1062338560;
printf("value of 'a' is: %X [%x] %f\n",(int)a,(int)a, a);
第二个重新解释int
- 111111010100100000000000000000的表示 - 代替float
。
(它也是未定义的,所以你不应该指望它特别做任何事情。)
答案 2 :(得分:1)
0x3f520000是一个整数常量。分配给float时,将转换整数。
答案 3 :(得分:0)
在第二种情况下如何转换的更合适的示例:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
int main() {
uint32_t fi = 0x3f520000;
float f;
memcpy(&f, &fi, sizeof(f));
printf("%.7g\n", f);
}
打印:
0.8203125
这就是你所期望的。
我使用的方法是memcpy
,这对于所有编译器来说是最安全的,也是现代编译器的最佳选择(GCC自约4.6以来,Clang自3.x以来)将memcpy
解释为“位投“在这种情况下,并以有效和安全的方式优化它(至少在”托管“模式下)。对于较旧的编译器来说,这仍然是安全的,但在同样的方式上并不是那么有效;有些人可能更喜欢通过联合或通过不同的指针类型。有关这种方式的危险,请参阅here或一般搜索“类型惩罚和严格别名”。
(另外,可能有一些奇怪的平台遭遇字节序问题,整数字节序不同于浮点字节;字节不同于8位,依此类推。我在这里不考虑它们。)
更新:我开始回答问题的初始版本。是的,位转换和值转换将主要给出不同的结果。这就是浮点数的工作原理。