浮点数的二进制表示

Posted 哦...

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浮点数的二进制表示相关的知识,希望对你有一定的参考价值。

文章参考自:浮点数的二进制表示(IEEE 754标准)

1. 小数用二进制如何表示

首先,给出一个任意实数,整数部分用普通的二进制便可以表示,这里只说小数部分如何表示

例如0.6

将该数字乘以2,取出整数部分作为二进制表示的第1位;然后再将小数部分乘以2,将得到的整数部分作为二进制表示的第2位;以此类推,直到小数部分为0。 
特殊情况: 小数部分出现循环,无法停止,则用有限的二进制位无法准确表示一个小数,这也是在编程语言中表示小数会出现误差的原因

下面具体看一下小数0.6用二进制表示的计算过程

0.6 * 2 = 1.2 ——————- 1 
0.2 * 2 = 0.4 ——————- 0 
0.4 * 2 = 0.8 ——————- 0 
0.8 * 2 = 1.6 ——————- 1 
0.6 * 2 = 1.2 ——————- 1 
…………

我们可以发现在该计算中已经出现了循环,0.6用二进制表示为0.1001 1001 1001 1001 …… 
如果是10.6,那个10.6的完整二进制表示为 1010.100110011001……

2. 二进制表示的小数如何转换为十进制

再拿0.6的二进制表示举例:0.1001 1001 1001 1001 
文字描述:从左到右,v[i] * 2^( - i ), i 为从左到右的index,v[i]为该位对应的值,看例子:

0.6 = 1 * 2^-1 + 0 * 2^-2 + 0 * 2^-3 + 1 * 2^-4 + ……

3. 浮点数在计算机内存中的存储

浮点数是在内存中到底是怎么样保存的呢?

现代计算机中,一般都以IEEE 754标准存储浮点数,这个标准的在内存中存储的形式为:

 对于不同长度的浮点数,阶码与小数位分配的数量不一样,如下:

 对于32位的单精度浮点数,数符分配是1位,阶码分配了8位,尾数分配了是23位。而对于64位的双精度浮点数,数符分配是1位,阶码分配了11位,尾数分配了是52位

根据这个标准,我们来尝试把一个十进制的浮点数转换为IEEE754标准表示。

例如:178.125

先把浮点数分别把整数部分和小数部分转换成2进制

  • 整数部分用除2取余的方法,求得:10110010
  • 小数部分用乘2取整的方法,求得:001

合起来即是:10110010.001
转换成二进制的浮点数,即把小数点移动到整数位只有1,即为:1.0110010001 * 2^111111是二进制,由于左移了7位,所以是111,阶数即为111
把浮点数转换二进制后,这里基本已经可以得出对应3部分的值了

  • 数符:由于浮点数是正数,故为0(负数为1)。
  • 阶码 : 阶码需要作移码运算,阶码的计算公式是:阶数 + 偏移量。在转换出来的二进制数里,阶数是111(十进制为7),对于单精度的浮点数,偏移值为01111111(127)[注:偏移量的计算方法是:2^(e-1)-1 ,其中e为阶码的位数,单精度浮点数阶码位数为8,因此偏移值是127],即:111+01111111 = 10000110,当然也可以按10进制计算,即127+7 = 134,再将134转为8位二进制就是10000110。
  • 尾数:小数点后面的数,即0110010001

最终根据位置填到对位的位置上:

可能有个疑问:小数点前面的1去哪里了?由于尾数部分是规格化表示的,最高位总是“1”,所以这是直接隐藏掉,同时也节省了1个位出来多存1位尾数,提高精度。所以32位浮点数可以表示的精度是24位,64位浮点数可以表示的精度是53位。2进制24位精度转为10进制是7.22位(24*lg2),而53位精度转为10进制是15.95(53*lg2)。

在v2017中打开代码调试:

再试一下0.6吧,0.6转为二进制是0.10011001100110011001...,用二进制表示0.6只能无限接近,但是不能精确表示。现在为了满足尾数的要求,需要右移一位小数点,所以是2^(-1),然后偏移127转为8位二进制就是01111110,尾数去掉1并保留23位,在处理到最后一位的时候按照二进制的“四舍五入”规则,也就是零舍一入,此时的23位尾数就是00110011001100110011010(结尾的本来四个数字1001,再下一位是1,按照零舍一入原则,从1001入为1010)。

所以用float存储0.6的格式就是:

 在v2017中打开代码调试:

最后再试试负数-10.6

10.6转为二进制:1010.100110011001……

所以符号位1

阶数3偏移127为130,转为8位二进制是10000010

尾数保留23位,最后一位按照零舍一入原则处理是01010011001100110011010

所以用float保存-10.6就是:

 在v2017中打开代码调试:

 

最后是关于float和double取值范围的内容,IEEE754中浮点数的计算公式是:

s 是符号位的数字,如果 s 为0则浮点数V是整数,如果 s 为 1,则浮点数 V 为负数。

M 表示有效数字[1,2),而 E 是阶数位,float的E是8,而double的E是11。

阶数不包括全零和全一的情况(阶数为0,代表数字0;阶数为全1,代表无穷大),偏置常数是127,因此它的正常取值范围是-126-127(这样偏移后的数字是1~254)。尾数值等于1+尾数23位表示的小数,所以原则上尾数可取的范围是1(后面全零)到1.111...(后面全1),1.111...可表示为2-2^-23,可近似约等于2。

于是对于正浮点数:

 对于负浮点数:

 如果粗略的只取最大空间,那么float类型的取值范围是-3.4E38~3.4E38。

64位浮点数的计算方式与之类似,阶数不包括全零和全一的情况,偏置常数是1023,因此它的取值范围是-1022 - 1023(偏移后的数字是1~2046),尾数范围是1.0~2-2^-52,所以计算公式是:

对于正浮点数

 对于负浮点数:

  如果粗略的只取最大空间,那么double类型的取值范围是-1.79E308~1.79E308。

以上是关于浮点数的二进制表示的主要内容,如果未能解决你的问题,请参考以下文章

关于IEEE754中的浮点数的阶码的表示问题

某十六进制浮点数A3680000,将其表示成补码 ,字长32位,阶码8位(含1位阶符),尾数24位(含1 位数符),求该浮点数十进制的真值

C51浮点数显示浮点数表示方法

为啥python使用eval函数输出结果有很多尾数

将十进制数表示成ieee754标准的32浮点规格化数 27/64

浮点数在内存中的存放