前面我们已经了解整形一类的数据类型。
这次我们就说说浮点类型
要先记住一点:
整数、正数不一样哦
类型 | 说明 | 字节 |
float | 浮点型单精度数据类型,含有小数点的数字就是它 | 4字节 |
double | 浮点型双精度数据类型,主要双精度可以放更大的浮点值 | 8字节 |
上方表格,已经表明了浮点类型都有哪几个。
有没有注意到,一个是
单精度
另一个是
双精度
那么,浮点类型,是以单双精度来区别吗?
我们先来说说
float
float是4个字节,也即是32位。
但它有一个符号位,在32位的最左边,也叫最高位。
所以在没有unsigned的加持下,它的有效数据位是
31位。
![](https://qn.ddrrj.cn/ddbj/2023/11/20231117155319386.jpg-ddrrj)
那float在内存,它是怎么展示的?
列个内存为出来:
![](https://qn.ddrrj.cn/ddbj/2023/11/20231119222411184.png-ddrrj)
![](https://qn.ddrrj.cn/ddbj/2023/11/20231119222929400.png-ddrrj)
了解他们大概的位置后,我们再说说
什么是符号位
在没有unsigned的加持下,都有一个符号位。
0代表正数 1代表负数
什么是指数
在数学中,指数是表示幂运算的一种方式。一个指数是一个数字,它表示另一个数(底数)被乘以自身多少次。指数通常用上标的形式表示,写在底数的右上方。
![](https://qn.ddrrj.cn/ddbj/2023/11/20231117155507767.png-ddrrj)
没听懂是把,我就用float的8个指数位来解释下。
我们内存讲究二进制,也就是以2次幂来计算。
float有8个指数,也就是有8个次幂。
那么2的8次幂的表示就是。
28=256。
但我们的8个指数位不能全部打开,因为浮点的
内存标准
不一样。
浮点类型的标准是按
IEEE 754 标准
来做内存运算的。
![](https://qn.ddrrj.cn/ddbj/2023/11/20231111193828888.jpg-ddrrj)
IEEE 754 标准不知道的话,百度下。
也就是指数位在float开辟的32位里面是独立的,它也有自己的符号位。
如果你8个指数位全开,就会变成负数。也就成了-128.
所以为了表示正数、负数和零,以及保留一位用于表示特殊情况(如无穷大和非数值),需要对指数进行偏移,确保它可以表示负数。因此,选择的偏移值是
28-1−1=27−1=127
这个2的7次幂-1后面说到内存位运算就会明白,跟二进制位运算有关,想知道可以自己查下资料。
127这个数字要记住,我们还需要他运算。
什么是尾数位
尾数是一个二进制小数。在单精度浮点数中,通常占23位;在双精度浮点数中,通常占52位。
这一句就能很明白的说明,为什么双精度更精确了把,你用Π=3.14往后算,单精度只能记住23位尾数,而双精度可以记住小数点更后面的52个尾数。
![](https://qn.ddrrj.cn/ddbj/2023/11/20231115205040481.webp-ddrrj)
比如说,我们在编译器输入一个浮点数:
float num=-123.1234f;
那么-123.1234(注意看,有个负数)是怎么放入num的内存里呢?
如果它是正数,符号位为
0 00000000 00000000000000000000000
如果是负数,则:
1 00000000 00000000000000000000000
以这样的方式展示在内存。
重要的开始了:
符号我们已经记录在内存了,这个不管了。我们看123.1234
将123.1234拆开分为
整数部分123
小数部分0.1234
看清楚了,然后将整数123转为2进制。不懂转的,直接用二进制转换工具转,得出:
1111011
这样整数部分的二进制就得出
1111011
小数位是0.1234,就只要将0.1234用
短乘法 取整
让小数部分变成整数,没有小数点就结束,那就得出:
0.1234*2=0.2468这个得出了第一个二进制0(1)
括号里的1是我们用来计算算了几次,这个不用记。
取小数点左边的值,但还没有整数,就继续算。
0.2468*2=0.4936取0再继续(2)
0.4936*2=0.9872取0再继续(3)
0.9872*2=1.9744取1(4)
到这个位置出现了1,就取整数1。接下来不能再用1.9744*2了,而是取了个1之后,就要变成0.9744*2。
以后都是这样。
但还未变整数,再继续运算。
0.9744*2=1.9488取1再继续(5)
0.9488*2=1.8976取1再继续(6)记住,取1之后就不能再用1.8976*2。
0.8976*2=1.7952取1再继续(7)
0.7952*2=1.5904取1再继续(8)
0.5904*2=1.1808取1再继续(9)
0.1808*2=0.3616取0再继续(10)
0.3616*2=0.7232取0再继续(11)
0.7232*2=1.4464取1再继续(12)
0.4464*2=0.8928取0再继续(13)
0.8928*2=1.7856取1再继续(14)
0.7856*2=1.5712取1再继续(15)
0.5712*2=1.1424取1再继续(16)
0.1424*2=0.2848取0再继续(17)
0.2848*2=0.5696取0再继续(18)
0.5696*2=1.1392取1再继续(19)
0.1392*2=0.2784取0再继续(20)
0.2784*2=0.5568取0再继续(21)
0.5568*2=1.1136取1再继续(22)
0.1136*2=0.2272取0(23)
到这了,我们不再继续算了,因为单精度尾数就23位,得不出整数值,就只算到在这。
我们现在得出小数的二进制是:
00011111100101110010010
指数和尾数已经转化完毕,接下来就是再把他们合为一体得出:
1111011.00011111100101110010010
![](https://qn.ddrrj.cn/ddbj/2023/11/20231118205026279.jpg-ddrrj)
先别懵,别以为浮点数就是这样,还没完。
如果真的很懵,你在返回去看一遍。
不然接下来你会更懵。
接下来就是
科学计算法
![](https://qn.ddrrj.cn/ddbj/2023/11/20231112205216641.gif-ddrrj-ddrrj)
将得到的
1111011.00011111100101110010010
二进制科学计算法是小数点往左移,变成
1.11101100011111100101110010010
小数点移动了6位,就是得到了6个真实指数。
还记得我们说过的指数位吗?
float的指数位根据
IEEE 754 标准
偏移值是
127
就将127+6=
133
再把133转为2进制得出:
10000101
现在已经得到8个IEEE 754 标准规定的指数位二进制了,我们放在内存里就是:
1 10000101 00000000000000000000000
现在符号位有了,指数位有了。接下来就是尾数位了,尾数位就比较简单了。
尾数位就是刚才科学计算法得出的
1.11101100011111100101110010010
这个二进制,把小数点和小数点向左的数字都去掉,留下
11101100011111100101110010010
只要23位就是
11101100011111100101110
这部分就是尾数位了。
现在我们放在内存就是:
1 10000101 11101100011111100101110
不够23位就右边加0填满23位,如果够23位就直接放进去。
![](https://qn.ddrrj.cn/ddbj/2023/11/20231112205216641.gif-ddrrj-ddrrj)
那这串二进制,他们是怎么展现到屏幕给我们看的呢?
那就要看你是用整数提取符 %d去提取,还是浮点提取符%f提取了。
如果是整数提取符,数值肯定是错的。
但你要先问你自己,你定义了一个float数据类型,他在内存开辟了有指数和尾数的内存位,你用整数提取符提取,就是你自己错了。
整数的数据类型标准和浮点数的数据类型标准不一样
只有%f才能解释知道指数位和尾数位。
而且
%f浮点数提取符和整数提取符不一样,%f它是IEEE 754 标准 它只认指数位和尾数位。
不信你可以这个代码试一试:
int num=-1231234;
printf("%f",num);
看看浮点提取符能不能提取整数。
%f会查不到指数和尾数位的开关。
所以 %f 提取不到指数位和尾数位的话,那么它给你屏幕输出出的值要么是0,要么是错误的值。
这时有人会问我:
1 10000101 11101100011111100101110
这串二进制转换出来的值也不是-123.1234呀。
如果你二进制直接转十进制,得出的数字当然是错的。
再强调一遍
IEEE 754 标准
IEEE 754 标准
IEEE 754 标准
因为浮点数都说了,它有它自己的一个标准,就是:
IEEE 754 标准
这个标准里用了一个更有紧凑性、可读性和位操作性的执行方式来展现。
就是中间过程转了个
十六进制
所以1 10000101 11101100011111100101110 这个二进制,你要先用进制计算器转为十六进制,在转为十进制,就能得出我们所计算的这个值了。
![](https://qn.ddrrj.cn/ddbj/2023/11/20231116192405985.png-ddrrj)
double
数据类型呢?
它也一样。
我们说了,它的精度更准确,因为它的
指数位是11位,去掉符号位是1024-1=
1023+N指数值
而它的尾数位是
52个尾数位
所以算起来,double的浮点数值小数点值更精确。
计算方法与float一样。
但平常我们不怎么用double。
因为float 127+N的指数值就已经很大了。
![](https://qn.ddrrj.cn/ddbj/2023/11/20231120114639233.png-ddrrj)
发表回复