转载:https://mp.weixin.qq.com/s/VghDOJCJTN61y_6TqLDc2g
0.1(10)转化为二进制:整数部分的二进制就是整数部分除以2得余数压栈,商再除以2得余数压栈,直到商为零压栈最后一个余数,因此整数部分就是0(2);比如整数6的二进制表示就是压栈顺序为0、1、1,倒序弹出所得110(2)就是6的二进制表示。
小数部分与此相反,0.1*2=0.2取出整数部分0压栈,小数部分0.2继续0.2*2=0.4取出整数部分0压栈,小数部分0.4继续0.4*2=0.8取出整数部分0压栈,小数部分0.8继续0.8*2=1.6取出整数部分1压栈,小数部分0.6继续0.6*2=1.2取出整数部分1压栈,小数部分0.2...陷入循环,因此小数部分也就是.00011 00011 0011 0011。
综上,0.1(10)转换为二进制就是0.00011 0011 0011 ...(2),6.1(10)转换为二进制就是110.00011 0011 0011 ...(2)。
小数二进制转成浮点数:
浮点数分为单精度对应32位操作系统和双精度对应64位操作系统。这里解释一下二进制如何转成双精度浮点数二进制。
双精度浮点数用1位表示符号位,11位表示指数位,52位表示小数位,如下:
符号位:正数为0,负数为1;
指数位:阶数+偏移量,阶数是2^(e-1)-1,e为阶码的位数,也就是指数位的位数。偏移量是把小数点移动到整数位只有1时移动的位数,正数表示向左移,负数表示向右移;
小数位:即二进制小数点后面的数。
把0.1(10)转成的二进制0.00011 0011 0011 ...(2)转成浮点数形式的二进制:
1、先要把小数点移动到整数位只有1,要向右移动4位,故偏移量为-4,通过指数位的计算公式2^(e-1)-1+偏移量=2^(11-1)-1-4=1019,把1019转成二进制为1111111011,不够11位要补零,最终得出指数位位01111111011;
2、移位后的小数位为.1 0011 0011 ...,因为小数位只能保留52位,第50、51、52位、53位分别为0011,故对第52位进1使第51位为1,使第50、51、52位为010。
转换结果为:
链接还介绍了两个浮点数相加时让指数位小的浮点数指数位对齐(也就是增加到大的浮点数的指数位,相应地,小浮点数的精度位要左移)后再相加。
误差来源:1、浮点数存储的误差;2、浮点数计算时较小的浮点数精度位左移(指数位向较大数对齐)后"挤掉"小数位右边部分;3、浮点数相加时小数位舍去部分。
20210403:https://mp.weixin.qq.com/s/fMzU3PYPSi_BUT5MsGywRw介绍了JS的大数危机。