1.测试程序及结果
- 程序
#include"stdio.h"
int main()
{
float a = 7.5, b = 1.23, c = 1.24, d = 1.25;
double a1 = 7.5, b1 = 1.23, c1 = 1.24, d1 = 1.25;
int e = 0, f = 1,g= 0x7fffffff;
unsigned int h = 0xffffffff;
unsigned long long i = 0x401E000000000000,j= 0x3FF3AE147AE147AE,k= 0x3FF3D70A3D70A3D7,l= 0x3FF4000000000000;
printf("7.5_ d:%d\n7.5_x:0x%x\n7.5_llx:0x%llx\n", a,a,a);
printf("7.5_ d:%d\n7.5_x:0x%x\n7.5_llx:0x%llx\n\n",a1,a1 ,a1);
printf("1.23_ d:%d\n1.23_x:0x%x\n1.23_llx:0x%llx\n", b,b,b);
printf("1.23_ d:%d\n1.23_x:0x%x\n1.23_llx:0x%llx\n\n", b1,b1,b1);
printf("1.24_ d:%d\n1.24_x:0x%x\n1.24_llx:0x%llx\n", c,c,c);
printf("1.24_ d:%d\n1.24_x:0x%x\n1.24_llx:0x%llx\n\n",c1,c1, c1);
printf("1.25_ d:%d\n1.25_x:0x%x\n1.25_llx:0x%llx\n",d,d, d);
printf("1.25_ d:%d\n,1.25_x:0x%x\n1.25_llx:0x%llx\n\n",d1,d1, d1);
printf("0_f:%f\n\n",e);
printf("1_f:%f\n\n", f);
printf("0x7fffffff_f:%f\n\n",g);
printf("0xffffffff_f:%f\n\n", h);
printf("0x401E000000000000_f:%f\n\n", i);
printf("0x3FF3AE147AE147AE_f:%f\n\n",j);
printf("0x3FF3D70A3D70A3D7_f:%f\n\n", k);
printf("0x3FF4000000000000_f:%f\n\n",l);
return 0;
}
- 结果:
2.结果分析
- IEEE754标准
名称 长度 比特位置
符号位 Sign (S) : 1bit (b31)
指数部分Exponent (E) : 8bit (b30-b23)
尾数部分Mantissa (M) : 23bit (b22-b0)
其中的指数部分(E)采用的偏置码(biased)的形式来表示正负指数,若E<127则为负的指数,否则为非负的指数。
另外尾数部分M存储的是当把一个浮点数规范化表示后的1.zozooz...(二进制的)形式的zozooz的部分的比特串,共23位.
求值方法: (-1)^S*(1.M)*2^(E-127) (公式1)
注意:%f输出float类型,输出6位小数,有效位数一般为7位;
(2) 双精度(64位)浮点数的结构:名称 长度 比特位置
符号位 Sign (S) : 1bit (b63)
指数部分Exponent (E) : 11bit (b62-b52)
尾数部分Mantissa (M) : 52bit (b51-b0)
双精度的指数部分(E)采用的偏置码为1023
求值方法:(-1)^S*(1.M)*2^(E-1023) (公式2)
注意:双精度数也可用%f格式输出,它的有效位一般为16位,给出小数6位。(这一点在计算金额的时候尤为重要,超过有效位的数字是无意义的,一般会出错。)
- 具体分析过程
1. float a=7.5, doule a1=7.5 结果解释:
(7.5)10=(111.1)2=1.111*2^2;
以Float在内存中存储:
S=0;
E=(2+127)10=10000001;
M=111;
图4
以Double在内存中存储:
S=0;
E=(2+1023)10=( 10000000001)2
M=111;
图5
虽然7.5在内存中以float(32Bit)存储,但是在printf函数输出的时候要转换为double(64Bit)位的结构(原因:因为float和double类型的数据用printf函数输出的时候都是以%f,没有区别,所以编译器在输出的时候,无论是double还是float类型都已double存储形式输出),所以在程序运行结果中无论是以float类型还是double类型存储的7.5用%llx输出出来都是0x401E000000000000,但是用%d和%x输出的都是0,这是因为%d和%x只取内存的低32位,从图5可以看出低32全为0,所以取出来为0.
2.float b=1.23,double b1= 1.23 结果解释:
(1.23)10=( 1.0011101011100001010001111010111)2= 1.0011101011100001010001111010111*2^0
以float类型在内存中存储:
S=0;
E=(0+127)10=01111111
M=0011101 0111000010100100
图6
以double类型在内存中存储:
S=0;
E=(0+1023)10=(01111111111)2
M=0011 10101110 00010100 01111010 11100001 01000111 10101110
图7
可以发现图1中将1.23定义为float类型和double类型打印出来的结果不一样,为什么会有这一现象的发生呢?有两个原因,第一:千万不要以为凡是计算机输出的数字都是精确的。必须知道有些浮点数是没法用二进制精确表示的,例如这里的1.23,在内存中是近似保存的;第二:回到前面解释过的一个问题,float类型在内存中是以(32BIt)存储,首先将1.23以float的形式存储在内存中,存进去的是一个近似的数字,如图8所示,近似为1.230000019073486328125,16进制表示为:0x3f9d70a4,当用printf函数打印的时候,将1.230000019073486328125(而不是1.23)转换为double类型,然后输出,所以结果为图9所示;
图8
3. 1.24类似1.23 1.25类似7.5 这里不再解释
4. 整形数字以 %f 输出 的结果说明
3.总结
进制转换工具:
http://tool.oschina.net/hexconvert/
单精度浮点数内存中编码:
https://www.h-schmidt.net/FloatConverter/IEEE754.html
双精度浮点数内存中编码:
http://www.binaryconvert.com/convert_double.html