美文网首页程序员
5分钟讲清楚浮点数的底层表示

5分钟讲清楚浮点数的底层表示

作者: elon_wen | 来源:发表于2021-01-26 09:47 被阅读0次

    浮点数的二进制表示,基本上就是用二进制的科学计数法来表示。

    一个十进制的数0.75,用科学计数法表示是+7.5*10^-1,分为3个部分,正负号、7.5和-1。

    其中小数点前的部分,一定是一个1-9之间的数。也就是你不能写成+75*10^-2。

    好了,换成2进制(以下均以float类型为例),由于它占用的位数有限(一般是32位),因此我们需要仿照十进制科学计数法的方式,把这些位切分为3部分。

    符号只有正负,因此用1位表示。

    指数和尾数部分的划分决定了数字能表示的最大值和精度。IEEE的标准,指数位是8位,剩下是尾数位。

    8位可以表示的范围是[0, 255],或者[-127, 128](这里埋个坑),为了能表示2^-1的概念,选择后者。

    尾数的精髓在于跟十进制的表示一样,刚才说十进制的小数点之前是(0, 9),那么二进制就是(0, 2),也就是小数点之前的数一定是1。

    二进制转十进制

    以下面这一串比特位为例:

    0-01111110-10000000000000000000000

    0是符号位,代表正数。

    中间是指数位,写成十进制是126,减去127之后得到-1。

    最后是尾数,忽略末尾的0,同时在小数点前补1,得到1.1,转成十进制是1.5。

    我们把三个部分拼起来,得到+1.5*2^-1=0.75

    十进制转二进制

    以2.75为例子,先把小数点前后都写成二进制形式,得到10.11。

    10.11*2^0不满足要求,为了让小数点前的数是1,所以我们向左挪一下小数点,得到1.011*2^1。

    (上面这步和把75*10^0写成7.5*10^1是一个意思)

    最后我们把3个部分提取出来,分别是符号位0,指数位1+127=10000000,尾数位0110…

    关于指数部分的补充

    零和无穷大

    刚才讲指数位有8位,可以表示的范围有256个数。这里我们再考虑一些特殊情况,比如我们如何用十进制的科学记数法表示0.0。因此当指数位全为0或者全为1时代表了3种特殊情况:

    • 全0代表0.0
    • 全1后接全0代表无穷大,比如2个大数相乘向上溢出
    • 全1后接非全0代表NaN(Not a Numble),比如-1取平方根

    为什么是减127

    因此砍掉2个数字之后,实际有效可以表示的范围变成了[1, 254]。

    前面讲到为了能支持指数取负数(正数越大能表示的数越大,负数越大能表示的精度越大),需要减去一个值,综合考虑精度和上限,这个值取中位数比较合适,否则要么能表示的数不够大,要么精度过低。

    128或者127都是中位数,可以表示[-127, 126]或者[-126, 127],最终取了127(个人觉得这里面就没有那么大的讲究了,只是取舍)。

    移码

    在底层存储的时候,这个数字并没有采用整数常用的补码形式,而是采用了称为移码的形式。

    移码跟补码只在符号位上有所不同,移码是1代表正,0代表负。这样做的好处在于比较浮点数大小时可以当做整数来处理,而不用处理两次符号位。

    相关文章

      网友评论

        本文标题:5分钟讲清楚浮点数的底层表示

        本文链接:https://www.haomeiwen.com/subject/kytgzktx.html