目录
前言
相信大家在初学C语言时,也会对单精度和双精度感到困惑。对于部分程序员,在浮点型的存储和取出是比较陌生的。了解浮点型的存储有助于提升知识储备,掌握特定误差的分析。
本文将从IEEE浮点型标准、浮点型在内存中的存储以及一道常见的题目来深入体会浮点型。
一、浮点数
浮点数与数学中的实数概念差不多,如3.14、3.14e7以及2e-8都是浮点数。所以在一个值后加上一个小数点,就成为浮点数,因此,7是整数,7.0是浮点数。
注意:
- 浮点数有小数部分,最高位是0.xx可省略0 写成 .xx
- 浮点数运算比整数慢
- 浮点数通常只是实际的近似值(稍后详解),如3.0可能被存储为2.999999
- 计算机默认浮点类型为double,在浮点数后加上 f 则为 float
常见的浮点型有float 、double、long double,精度向上增长,通常比整形的范围更大
二、IEEE规定
规定对于任意一个浮点数V,可表示为以下形式:
- (-1)^ S * M * 2^E
- S: 浮点数为正取0,为负取1
- M:任意一个浮点数可以写成二进制,将二进制写成大于1,小于2的指数形式
- E: 指数大小
1、将浮点数转换为二进制形式
每位的权重:
.......+2^4+2^3+2^2+2^1+2^0 . 2^(-1) + 2^(-2) +2^(-3)+......
1) 拆分 2^2 + 2^0 + 2^(-2) + 2^(-3)
2)根据权重 101.011
2、将二进制写成指数形式
101.011的指数形式就是 1.01011*10^2
3、确定S的符号,与E的值
5.375是正数,S为0
由第二步知E为2
当浮点数转换为二进制时,总会存在无法转换的数字,比如3.33333333就无法转换
所以我们可以理解,浮点数的存储,通常只是它的近似值
三、存储方式
规定:对于32位浮点数(通常指float类型),最高位存 S 次八位存E,剩下32存放M
1)放入M
对于M,首位总是1,那么在存储时就没有必要存入首位的 1 ,如此就可以提升存储的范围
原本M可以存23位,现在就可以存24位,提升了精度。
2)放入E
对于1bit空间的无符号数的范围是0~255,但由于指数可以为负数,同时我们又不希望出现负数,
就对E的存入加上127;
例如5.375
E为2,加上127,为129 129的二进制为 1000 0010
以1000 0010 存入
四、取出浮点数
E的数值决定取出的方式
1)E非全0、非全1
E减去127(64位浮点数减去1023)
M补上首位1
按照 (-1)^S * M * 2^E 得出结果
2)E为全1
E全为1,如果再算上2的次方,那就是一个特别大的数字
对于这种情况,编译器会判断为(-1)^S*无穷大的数字
3)E为全0
E为全零,再减去127,就会是一个非常小的数
规定就不再往M首位补上1,而是会解读为一个非常接近0的数字
五、习题讲解
int main()
{
int n = 1;
float* p1 = (float*)&n;
printf("p1的值%f\n", *p1);
*p1 = 1.0;
printf("n的值是:%d\n", n);
printf("*p1的值:%f\n", *p1);
return 0;
}
这道题,首先创建一个int 型变量 n ,
接着将n放进一个浮点型的指针,然后用浮点型的方式打印出n的值
通过浮点型指针修改n的值,分别用整形,浮点型,打印出 n
题解:
n: 1的二进制存储 00000000 00000000 00000000 00000001
在第一次打印,以浮点型取出,则编译器则认为n本就是浮点型存储,所以取出以SME的规定的方式
第一位是S 0 代表正数,紧着这8位代表E,E的取出分3种(不为全1\0,全0,全1)。
而这里是全0,代表一个非常接近0的数,则解读成0
通过指针存放浮点型
1.0 S为0,M为1.0,E为0,存放时,减去127 为 -127 ;
-127 的二进制为11111111(首位是符号位)
存入 0 11111111 000000000000000000000000
第二个打印,以整形的方式打印,则编译器认为n以整形存放 将存入的值以二进制方式转换出就是
1065353216
第三个打印
以浮点型的方式取出,编译器则认为数据就是以浮点型存入,而数据就是浮点型存入,取出就是1.000000
总结
这里再次熟悉浮点型的存储与取出,了解了S E M的规则;
这里再深入理解单精度和双精度,
单精度是32位存储,E存8位,M存23位
双精度是64位存储,E存11位,M存52位
因此双精度和范围远大于单精度。
代码++
offer++