浮点数的表示

c语言中的浮点数:float , double , long double

首先,为什么要使用浮点方法,为什么要使用浮点数而不使用定长小数。

这是因为如果小数定长,其精度就是固定的,也就是说,这样的表示方法就会有固定长度的整数位和小数位。一般这些位数都不会被全部用到,甚至很有可能牺牲精度,或者造成空间浪费,因此,需要创造一种小数点可以移动的数字表示方法,即浮点数。

其次,如何科学的表示二进制数。

这里引入二进制的科学计数法:
十进制有科学计数法,任何十进制数都可以表示为x.xxxx*10^n(x为0-9),同理,所有二进制数也可以表示为1.xxx*2^n(x为0-1),举个例子:

1
2
101101.11101101转化为科学计数法
1.0110111101101*2^5

那么按照这样的思路,一个二进制数,就能表示为一个整数位定长为1,且一定是1的数字1.0110111101101(因为整数位永远是1,因此其实可以默认),和另一个整数5,代表乘2的多少次方。

然后,再加入正负的可能性,我们就可以完全的表示一个二进制数。**

1
2
3
4
5
6
N=((-1)^S)*(R^E)*M
其中N是这个二进制数;
S有两种取值,0表示N为正数,1表示N为负数;
R恒为2;
E是科学计数法中2的指数;
M为科学计数法中以1.开头的二进制表示

最后,我们就可以开始设计浮点数了

S有两种取值,只需要一位;

R取值固定,不需要表示,默认即可;

E是指数(上例中的5),为一个不定长的整数(可能正,可能负),需要多位;

M一定以1开头,因此可以忽略1,直接记录小数点后面的小数(即只记录0110111101101);

我们看看官方的表示方法:

image-20220303091346438

IEEE754标准(规定了浮点数的表示格式,运算规则等)

​ 规则规定了单精度(32)和双精度(64)的基本格式.
​ 规则中,尾数(M)用原码,指数(E)用移码(便于对阶和比较)

源码顾名思义就是二进制数直接写出来,不含符号位。

移码是什么呢?

上面说过,指数是有正负的可能性的,移码其实就是取中间数为0,减少为负数,增加为正数。

比如说:

对于32位的浮点数来说,E的位数有八位(256),因此选择127(01111111)为0,那么相应的,1就是128(10000000),-1就是126(01111110)。因此,如果给出一个值E,E-127就是指数的真实值。

同理,对于64位的浮点数来说,E的位数有11位,那么把E换算成十进制后,E-1023就是指数的真实值。

这样我们就学会如何表示一个浮点数了。

我们给出一个例子:

1
2
3
4
5
6
7
8
9
20.59375转化为32位数浮点表示
首先分别将整数和分数部分转换成二进制数:
20.59375=10100.10011
然后移动小数点,使其在第1,2位之间
10100.10011=1.010010011×2^4
e=4于是得到:
S=0, E=4+127=131, M=010010011
因此最后得到32位浮点数的二进制存储格式为:
01000001101001001100000000000000=(41A4C000)16