表示与解析
表示
按照从左至右的顺序:第1位是符号位(sign),接下来的11位是指数位(exponent),剩余的52位是尾数位(fraction)。
解析
相当于二进制的科学计数法:
or
当e为1时,fraction前面的1会变成0:
exponent的特殊值(处理上、下溢出):
·00000000000 无视fraction的值,整体结果为0
·11111111111 无视fraction的值(全为1除外),整体结果为无穷
举例说明
MAX_VALUE
如何让这个64位二进制数表示一个最大的数?
·表示的数是正数
·其余所有位都是1
然而之前提到过,指数位全为1是一个特殊值,用来表示所有上溢出的数。
因此,最大的数是:
代入公式:
化简得:
即:
可以在浏览器中通过“Number.MAX_VALUE === (Math.pow(2, 53) - 1) * Math.pow(2, 971)”进行验证。
MIN_VALUE
如何让这个64位二进制数表示一个无限趋近于0的数?
·表示的数是正数
·让exponent和fraction的最低位是1,其余位是0
因此,最小的数是:
代入公式:
化简得:
即:
可以在浏览器中通过“Number.MIN_VALUE === Math.pow(2, -1074)”进行验证。
MAX_SAFE_INTEGER
如何让这个64位二进制数表示一个最大的、且安全的整数?
·表示的数是正数
·fraction全是1
·exponent的结果恰好是52,即e为1075
因此,最大的安全整数是:
代入公式:
化简得:
即:
可以在浏览器中通过“Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1”进行验证。
MIN_SAFE_INTEGER
MIN_SAFE_INTEGER是MAX_SAFE_INTEGER的相反数,只需将符号位改成1即可。
补充
NaN
当exponent和fraction全为1时,该数为NaN。
为何要在exponent上留出一位来表示所有上下溢出的数,而不是在fraction上留一位
在数值计算中,11111111111、00000000000是进位和退位的两个“尽头”,只要进位、退位后使exponent为11111111111、00000000000,就意味着它的计算结果已经到头了,无视它的fraction部分,直接把它当成无穷或者0。
而如果在fraction上留一位,无法达到这种效果,exponent的每个取值,fraction都有全是1和全是0的情况。就算规定一些条件达成同样的效果,也无法区分无穷和NaN。
为何exponent要用移码表示,且偏移量为1023
fraction为52位,如果不用移码,exponent最小是1,小数最多只能达到小数点后52位,这是二进制的,转化成十进制会更少一些,这样表示的数是不够小的。而使用移码,最小能表示小数点后1074位的数,转化成十进制为。
至于偏移量为什么是1023,这是因为,正负各分一半。
为何0.1 + 0.2 !== 0.3
首先声明,它们是否相等与它们是否被精确表示无关。例如0.1和0.2没有被精确表示,但是0.1 + 0.1 === 0.2。
十进制的浮点数在计算机底层是由二进制的数表示的,这意味着只有形如的数,和由多个形如的数累加得到的数,才能被精确表示。
显然0.1只能被近似表示,0.2只要将0.1乘2就行了,也就是说0.1和0.2的区别只是0.2的exponent多了1而已,这意味着形如0.1、0.2、0.4、0.8……的一组小数,即fraction相同的一组小数,取其中的某几个相加减,如果结果也在这组小数中,那么用“===”比较就可以得到“true”。例如“0.2 + 0.2 + 0.4 === 0.8”为true,但0.2、0.4、0.8皆为非精确表示。
0.3的fraction与它们不同,这种fraction不同的小数计算就会导致误差产生,这才使得“===”得到false。