众所周知,C的float、VB的Single都是32位浮点数变量类型(也叫单精度浮点数),C的double和VB的Double则都是64位的浮点数变量类型(也叫双精度浮点数)。有些编译器还支持更屌的long double(貌似是80位还是128位的我不清楚,总之存在这种变态玩意儿。)那么这些浮点数从最底层的角度来看,它们是怎么存储的呢?我来举个例子解释下。计算机用的是二进制,如果我用二进制跟大家解释大家可能觉得看不懂,那我就用十进制来跟大家解释。
浮点数分三个部分,第一个部分是有效数字,第二个部分给出小数点的位置,第三个部分用来判断这个数是正数还是负数。举例如下:
浮点数123.456
那么它用浮点数的存储格式来表示就是:有效数字就是123456,小数点的位置在3的后面,然后它是正数。
那么我们要做的就是先取出有效数字123456,然后在3的后面插入小数点.就成了123.456,最后给它加个正号,就是+123.456了。
从二进制的方面来理解也是一样的,比如我要表示-10101010.01010101,那么它的有效数字是1010101001010101,小数点在中间,然后它是负数。
上面我都只说了“小数点在中间”、“小数点在3后面”这种比较含糊的表达方法。那么浮点数到底是怎么存储小数点的位置呢?这里我们要注意一整个浮点数中用来表示小数点位置的位数是多少。
还是用十进制来给大家举个例子。假设我用两个位来表示小数点的位置,那么两个十进制位表示的最小的数是00,最大的数是99,我们总共能表达100个值。假设我要表达1234.5678,那么情况就是如下所示的:
有效数字是12345678
小数点的位置在中间。
这里我们用两个十进制位来表示小数点的位置,那么这个小数点从左往右数(原来的数字是1234.5678)是在第四个位的后面。因此这两个十进制位的值就是03。因为00表示从左往右数的第一个位的后面,01表示从左往右数的第二个位的后面,02表示从左往右数的第三个位的后面,那么03就表示从左往右数的第四个位的后面了。
有人可能会说“但是这样一来我们不就无法表现小数了嘛。”其实不然。比如我们要表现0.233,那么我们就把有效数字设置成“0233”,然后小数点位置是00就行了。
对应的,二进制表示也是这样的,比如我们用8个二进制位来表示小数点的位置,我们要表现的小数是10101010.01010101,那么小数点在从左往右数第八个位的后面,我们就用00001000来表示小数点的位置。
这里我就需要针对性地告诉大家,float和double是怎么回事。
float浮点数的有效数字是23位,小数点用8个位表示,然后符号(正、负)用一个位表示(0表示正、1表示负),总共组成32位。
因为float浮点数用8个位表示小数点的位置,因此小数点可以有256个位置。float浮点数规定从左往右数第127位的值必须是1,然后从第128位开始才是float的23位有效数字。因此float的浮点数的23位有效数字其实是从左往右数从第128位开始的。
我这里举个例子:浮点数1.0f是怎么存储的:
0 01111111 00000000000000000000000(0x3F800000)
其中蓝色的部分是符号位,0表示正数。
黄色的部分表示小数点的位置,在从左往右数第127位处。
绿色部分是有效数字,共23个0,也就是全零。如果转换为十进制,大约就是6、7个数位左右。
按照float浮点数的特性,第127位的值必须是1,然后存储的23位有效数字的位置是在第128位开始的,我们把这个浮点数展开为256位,是这样表示的:
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
前面的那些零和后面的那些零都是“虚构的”,也就是说这些零并没有被存储在float里面,而是同于补充位数的。第127位被强制设置为“1”,这是float的规定。
浮点数存储了它的小数点位置:01111111,也就是“127”这里。那么我们最终得到的浮点数是:1.0
同样的,double也是和float一样用三个部分表示浮点数:有效数字,小数点位置,符号。
double的有效数字是52位,小数点位置用11个位表示,符号位用一个位表示。十进制可以精确到16个数位左右。
我这里举个例子:浮点数1.0是怎么存储的:
0 01111111111 0000000000000000000000000000000000000000000000000000(0x3FF0000000000000)
其中蓝色的部分是符号位,0表示正数。
黄色的部分表示小数点的位置,在从左往右数第1023位处。
绿色部分是有效数字,共52个0,也就是全零。
按照double浮点数的特性,第1023位的值必须是1,然后存储的52位有效数字的位置是在第1024位开始的,我们把这个浮点数展开为2048位,是这样表示的:
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
在这2048位的数字中,我们的double存储的52个有效数字在其中的绿色部分,也就是从1024位开始处。1023位被强制设置为1。可以看出,double的精度比起float提高了不少。
小数点的位置:01111111111表示小数点在第1023位的后面,因此最终得到的浮点数的数值是1.0
除了float和double,还有其它格式的浮点数:
Minifloat:迷你浮点数(8位):
1位符号位,4位小数点位置,3位有效数字。(PS.真够“迷你”的)
Half:半精度(16位):
1位符号位,5位小数点位置,10位有效数字。
x86 Extended Precision Format:x86扩展精度格式(80位):
1位符号位,15位小数点位置,1位特殊位,63位有效数字。特殊位请看http://en.wikipedia.org/wiki/Extended_precision
Quadruple:四倍精度(128位):
1位符号位,15位小数点位置,112位有效数字。
IEEE规定:
1、表示小数点位置的部分如果全零,那么这个浮点数的值为0,而如果这个时候有效数字部分非零,那么这个浮点数就“不是一个数”(NaN)
2、表示小数点位置的部分如果全一,那么这个浮点数的值为无穷大。
3、浮点数能表示的最大数值:表示小数点位置的部分除了最低位为零其它均为一,有效数字全为1
4、浮点数能表示的最小数值:表示小数点位置的部分除了最低位为一其它均为零,有效数字全为0
参考资料
http://en.wikipedia.org/wiki/Minifloat
http://en.wikipedia.org/wiki/Half-precision_floating-point_format
http://en.wikipedia.org/wiki/Sin ... oating-point_format
http://en.wikipedia.org/wiki/Dou ... oating-point_format
http://en.wikipedia.org/wiki/Extended_precision
http://en.wikipedia.org/wiki/Qua ... oating-point_format
https://www.0xaa55.com/forum.php?mod=viewthread&tid=462