首先,我们知道js中的数字都是双精度的浮点数,在进行计算时,计算机会把十进制数转换成64位二进制,这个过程可能会导致精度丢失。
计算机存储是按照IEEE754标准来把64位分成3个区域
十进制浮点数转换成二进制,然后转换成指数格式,由于尾数部分只能保留52位,第53位0舍1入,所以截取52位导致精度丢失。
以0.1和0.5为例,0.1损失精度,0.5不损失精度
0.1转换成二进制:
0.00011001100110011001100110011001100110011001100110011001100110011001.....无限循环
然后转换成科学计数法表示,右移小数点移动4位,使小数点前的数字是1,变成:
1.1001100110011001100110011001100110011001100110011001100110011001.....无限循环 * 2 ^ -4
然后转换成IEEE754标准:
符号位是0代表正数,
上面得到的指数是-4,所以-4+1023=1019转成二进制,所以指数位就是01111111011
然后截取小数点后52位(0舍1入)放入尾数位,所以尾数位为:
1001100110011001100110011001100110011001100110011010
所以0.1的计算机存储为:
0011111110111001100110011001100110011001100110011001100110011010
由于截取52位导致了后续数据的丢失,也就导致精度丢失。
而0.5之所以不会丢失精度,是因为0.5转为二进制:0.1000,右移小数点移动1位,使小数点前数字是1,变成:1.00 * 2^-1,指数是-1,所以-1+1023=1022转成二进制指数位就是01111111110,所以0.5的计算机存储为:
0011111111100000000000000000000000000000000000000000000000000000,因为小数点后都是0,所以截取52位没有数据丢失,所以没有精度丢失。
关于为什么偏移量是1023,而不是11位能表示的最大范围2048(0~2047),是因为指数有正有负,所以能表示的范围是-1023~1024,所以偏移量是:
(11位表示的最大值)2047-(正指数的最大值)1024 = 1023,这样指数部分的值就都是无符号的正数值,便于比较数的大小。
特殊值:
指数位全0,根据符号位,这个数表示+0或-0;
指数位全1,尾数位全0,根据符号位,这个数表示+∞和-∞;
指数位全1,尾数位不是全0,这个数表示非数值NaN;
以上!