计算机中的浮点数

计算机中的浮点数表示

计算机中的float类型,有一篇文章写的很好,这里把它的一部分放过来:https://www.duote.com/tech/cyuyan/14691.html

根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式:
  V = (-1)s×M×2E
  (1)(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
  (2)M表示有效数字,大于等于1,小于2。
  (3)2^E表示指数位。

这里的s来自单词sign,是正负符号的意思,m来自于单词mantissa,意思是尾数,E来自于单词Exponent,意思是指数。由于任何数都可以写成以下形式,所以任何数都可以表示为:
计算机中的浮点数_第1张图片

IEEE 754规定,对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。如下图所示
计算机中的浮点数_第2张图片

对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。如下图所示
计算机中的浮点数_第3张图片

多的东西就不说了,这里具体举一个例子,手动实现以下转换:

将3.14159转换为32位浮点数
3.14159分为小数部分和整数部分,整数部分是11,为了小数部分就是硬算了,可以通过计算器得到,如下图所示:
计算机中的浮点数_第4张图片
11.0010 0100 0011 1111 0011 1110....换算成科学记数法,小数点往前挪一位,所以是1.1001 0010 0001 1111 1001 111 * 2 ^1,这样就是小数点后面23位数,前面一位数,由于前面提到所有的数都可以写成(1 + M)* 2 ^E的方式,为了省一位的空间,这里整数部分的1我们可以不计,只选尾数部分(这就是mantissa叫做尾数的原因)

所以,符号位是0,尾数位是 1001 0010 0001 1111 1001 111,接下来差的就是指数位,这里的指数位很明显是1,因为我们刚刚只往前移了一位,所以值应该就是 1,再加上127的偏移量,得到的是1 + 127 = 1000 0000 = 128

到这里就完成了,换算后的计算机表示结果为:
0 1000 0000 1001 0010 0001 1111 1001 111

我们可以在计算机里验证一下:01000000010010010000111111001111 转换成16进制是 0xcf 0f 49 40 ,然后我们创建一个包含四个字节的byte数组,然后把里面的数字拷进一个float变量里,代码如下所示:

int main()
{
	float f;
	// 由于堆栈的原因,这里要倒着写
	unsigned char b[4] = { 0xcf, 0x0f, 0x49, 0x40 };
	memcpy(&f, &b, sizeof(f));
	cout << f <

就可以看到正确的结果啦!
计算机中的浮点数_第5张图片

顺便提一句32位float,即单精度浮点数的有效位数是7位,也就是说只含七个数字的数都能精确被float类型表示。

最后关于这个E还有一点要提,这个E有两个特殊的值,处理的时候是与正常结果不一样的,就是当E= 0000 0000 或 E = 1111 1111时,根据国际标准IEEE 754规定:
当E= 0000 0000 时
指数位为0了,如下图所示,意味着这里的指数达到了最小,
计算机中的浮点数_第6张图片

此时规定,这里的1不加了,此时的E -127不等于-127,而是等于-126,E全为0。这时,浮点数的指数E等于1-127(或者1-1023),有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。

当E= 1111 1111 时
E全为1。这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);如果有效数字M不全为0,表示这个数不是一个数(NaN)。

最难以理解的地方:E= 0000 0000 和E = 11111111

我始终理解不了,为什么有这么古怪的规定,后来慢慢明白了,有了这些规定,尽管int类型里我们无法表示无穷大和无穷小,但是通过浮点数,我们可以处理各种各样的数据类型,都不会报错

比如在C#代码中,下述操作不会报错:
计算机中的浮点数_第7张图片
C++也是同样没问题:
计算机中的浮点数_第8张图片
如果改变d1为0,则得到的结果是无效的,float对于这种数字,一样能处理:
计算机中的浮点数_第9张图片

所以说,这么设计浮点数,让浮点数能够广泛应用到所有的数字中,这样设计浮点数,容错率很高

你可能感兴趣的:(笔记)