上一篇中我们说过js的一个关于计算的奇葩问题,比如0.1+0.7居然不等于0.8,今天就来刨根挖底的解剖为什么会出现这样的问题,简单的讲就是因为计算机识别的是二进制语言,而我们常用的是十进制,十进制转换成二进制的时候可能会出现无限循环的情况,而js最多截取32位,所以会出现有误差,比如:
十进制:0.8 =》二进制:1100 1100 1100..... 这样无限循环,而js只截取到32位,所以再次转换成十进制的时候就会出现有误差,不是等于0.8而是0.7999999999...;
好了,道理都懂了,接下来顺便脑补一下基础知识,二进制和十进制之间的转换:
1.正整数转二进制:除以2取余数,一直到商为0或者1为止,然后把余数反序即可,例如:
89 / 2 = 44 ------余数为:1
44 / 2 = 22 ------余数为:0
22 / 2 = 11 ------余数为:0
11 / 2 = 5 ------余数为:1
5/ 2 = 2 ------余数为:1
2/ 2 = 1------余数为:0
1/2=0 ------余数为:1
所以:89转二进制后的数是:1011001,如果要求8位或者16位之类的可以在高位补零:01011001;
负整数:
负整数转换方法是先按整数方法转换然后取反然后再加1,例如:
-89转二进制:1.89转二进制:01011001, 2.取反:10100110 3.加上10100111
PS:由上面的转换我们可以得出一个结论,任何十进制的整数转换成二进制是可表达的,不会出现无限循环的情况(因为任何整数除以2最后肯定是可以得到商为1或者0的),这也给我们一个其实,处理js运算可以先把小数变成整数运算,这样就不会出现误差了:比如:0.1 + 0.7 =>(1+7)/10=0.8;
十进制小数转二进制:对小数点以后的数乘以2,取结果的整数部分,然后再用小数点部分乘以2,以此类推,直到小数部分为0或者取的位数已经够了就O了。然后把刚才去整数部分依次排列就是二进制的数,别忘记前面加上0.****;例如:
0.125转二进制:
0.125 * 2 =0.25 整数部分是0;
0.25 * 2 =0.5 整数部分是0;
0.5* 2 =1整数部分是1;
所以转二进制后得到的数是:0.001;
ps:由这个转换规则我们可以知道,只要小数不是由1除以2的N次方得到的数,最后转换成二进制的时候都会出现无限循环的情况(因为小数既然不是1除以2N次方得到的,那就说明乘以2N次方不可能是整数,所以会出现无限循环的二进制数);
如果数是由整数和小数组成的,那就整数按照整数的转,小数按照小数的转,然后合并起来;
好了,各位客官,唠叨完毕,以上观点仅仅代表个人意见,如果有不同见解的欢迎留言交流和指正。