基于上文,了解(原码,反码,补码)/((unsigned) 无符号常数)/ (大端,小端)
下面就了解
浮点型在内存中的存储;
浮点存储表示形式:
国际标志(IEEE) 电气和电子工程协会 ,任意一个二进制浮点数V,都可以以下面形式表示:
比如一个十进制浮点数(5.0):
写成:(-1)^0 * 1.01 * 2^2 ; //十进制转二进制5=0101
了解基本形式后。再了解其中的字母规则
列 : (-1)^S * M * 2^E / (-1)^0 * 1.01 * 2^2 ;
S表示符号位'1'表示真(数是整数)'0'表示假(数为负数)。
M:1≤M<2,也就是说,M可以写成1.xxxxxx的形式,其中xxxxxx表示小数部分, M中小数点前面默认是1,因此1存储在内存中无意义 (如果把1存储进内存反而多占了一位,会降低所保存数字的精度) 。其实只需要在内存中保存小数点后面的几位数字即可。( 1.01 == 0.01 )
E:IEEE规定为 (E) 开辟的空间只可以存储无符号整数,但是实际上E却可能是负数,比如0.5==((2)^-1)。因此IEEE规定E的真实值必须加上一个中间值(8(float)位的E中间值为127,11(duoble)位的为1023),在读取这个浮点数时又重新减去再减去中间值。
32位float示意图:
64位duoble跟上面差不多:
(3)将浮点数从内存中拿出
其中 E 有三种规则:
1. E 不是全1也不是全0:
S:不变拿出。
M:从内存中拿出后在前面加上1和小数点
E:减去中间值。
*ploat = 9.0; printf("n=:%d\n", n); //这玩意又不一样了,你见过浮点数永整形打印的? //所以啊,套公式得 //0 10000010 00100000000000000000000000 --二进制转换10进制 //--这个数 1,091,567,616 printf("*ploat=:%d\n", *ploat); //这个很正常打印浮点型(E 不是全1也不是全0:) // 0 10000010 00100000000000000000000000 // 0 130-127 取一 //(-1)^0 * 1.001 * 2^3
1. E 是全0:
E:E = 1-127 = -126 //(或者1-1023)
M:M前面不加1而是加0。
这样实际上是为了表示+-0与接近于0的很小的数字。
int n = 9; float* ploat = (float*)&n; printf("n=:%d\n", n); //第一个n就很正常就输出原码-00000000 00000000 00000000 00001001 (正数原,反,补相同) printf("ploat=:%d\n", *ploat); // (E 是全0); //重点第二个 //看好哦因为是一个整数,是吧但是要输出一个浮点数,这你肯定不行啊!你用原码 //刚刚好(32bit)一套组合拳进去你就会发现变这样了 //符号位 E的值 M的值 // 0 00000000 00000000 00000000 0001001 //现在(E)的值就是全0了,套公式 // (-1)^0 * 0.00000000 00000000 0001001 *(2)^-126次方
解码出来就是
(-1)^0 * 0.00000000 00000000 0001001 *(2)^-126这是一个很小的数字,远小于float类型默认的小数点后六位,所以printf打印的是0.000000
1. E 是全1:
S:不变拿出。
M:从内存中拿出后在前面加上1和小数点
E:减去中间值。
如果有效数字M全为0,表示±无穷大(正负取决于符号位s)
直接上代码,讲解上面(E 不是全1也不是全0)/ E 是全0 的情况:E1跟E0差不多的阿,不要担心!)