在讨论float-point之前,我们先看int型在计算机内部是怎么表示的:
int i = 5;
上面的statement声明了一个int型变量 i,并赋值为 5,其二进制为101。在32位计算机中,4个字节表示int变量,所以,5被以32位二进制的方式保存在了计算机里 ”00000000 00000000 00000000 00000101“,其16进制表示为 0x00000005。
那么当这个int型的i被转换为float型的时候,怎么表示?
根据 ”IEEE 754“ 国际标准,任意一个二进制浮点数V可以表示为:
V = (-1)^S x M x 2^E
S M E这三个将被存入计算机内部。 其中S是符号位,当S=0时,表示正数,S=1时,表示负数。M是有效数字,2>M>=1。E是指数位。
上面的例子中 i 的十进制是 5, 二进制为 101, 表示成IEEE 754形式为:(-1)^0 x 1.01 x 2^2。 则:S = 0, M = 1.01, E = 2。
1. 在32位计算机中,最高位是S=0,接下来的8位为指数E=2 (0000 0010),剩下的23位是M=1.01
2. 在64位计算机中,最高位是S=0,接下来的11位为指数E=2 (0000 0000 010),剩下的52位是M=1.01
-
S没啥好说的, 要么1,要么0.
-
先说M,因为比E简单。我们知道M的值介于1和2之间,IEEE 754就觉得 M=1.xxxxx中的1也可以省略掉,于是就只保存xxxxx部分,读出来的时候再加上1。于是,在32位计算机中,M的有效位变成了24位;64位系统中变成了53位。
-
说到E,在32位和64位计算机中,它的位数不同所以真实值也不同,但又因为其有正负之分,为了平均表示正负,IEEE 754 规定要减去一个中位数。8位E的情况下,E可以表示0~255,其中位数为 127;11位E的情况下,E可以表示0~2047,其中位数为1023。这个中位数就是正负的分界线。
例如:101 = (-1)^0 x 1.01 x 2^2,E=2,在保存成64位的时候会变成2+1023=1025 (1000 0000 001 );
接下来我解释一下为啥javascript中 0.5-0.25=0.25
而 0.4-0.1=0.30000000000...04
这样怪东西。
首先呢,有两个概念,一个是定点小数,一个是浮点小数。
- 定点小数有个问题是,一些小数不可能用二进制准确表达出来,比如说0.2。总有舍弃一些末位。在javascript中,能在console显示或者其他print出来的都是定点小数。
- 浮点小数就相对精确一些,因为它舍弃的位更低,所以表示的范围也更大一点。
一个非2的幂级数的倒数的数, 无论定点还是浮点小数,都不能在计算机中100%准确表示。
所以减出来就不是精确的了。