JavaScript中的二进制运算
整数
JavaScript中,将十进制数字转换为二进制的方法是使用toString(2)
方法,对于正整数的返回值是从不为零的首位开始返回:
(8).toString(2); // 1000
对于负数,不会返回其真正的二进制编码(即其相反数的补码),而是直接利用符号-
来表示:
(-8).toString(2); // -1000
所以,想要求出负数的二进制编码,需要首先求出反码,转换为十进制数字,加一后求出反码在转换为二进制数字:
// 求负数的二进制
const getNegativeBinary = num => {
// 求相反数的二进制编码
const positiveBinary = (-num).toString(2).padStart(32, '0');
// 求反码
const reverseBinary = positiveBinary.split('').map(v => +v === 1 ? 0 : 1).join('');
// 求反码的十进制数
const reverseDecimal = parseInt(reverseBinary, 2);
// 求补码
const complement = reverseDecimal + 1;
// 求补码的二进制
const str = complement.toString(2);
return handleString(str);
};
小数
上面是针对于整数部分,针对于小数部分,JavaScript处理时采用的是“乘二取整, 顺序排列”法获得的,具体做法是:用2乘十进制小数,可以得到积,将积的整数部分取出,再用2乘余下的小数 部分,又得到一个积,再将积的整数部分取出,如此进行,直到积中的小数部分为零,或者达到所要求的精度为止。然后把取出的整数部分按顺序排列起来,先取的整数作为二进制小数的高位有效位,后取的整数作为低位有效位。
在JavaScript使用的IEEE754的双精度数值,一个JavaScript的number表示应该是二进制如下格式:
1[-/+] 11[位指数-移动位数] 52[数值] 64位长
- -------- -----------------------
可以看到,由于二进制的精确位数只有52+1位,那么类似1/3
这样的无理数,那么肯定是无法表示的,而且二进制还有很多有理数0.1
这样的也无法在52位精度的范围内表示精确无误;都会被截取53位以后的所有数字。
JavaScript采用了17位来默认截取数据,根据四舍五入方法或者是说二进制中的0舎1进位的方式截取。所以这样的加法有的时候会出现精度问题,有的又不会。例如0.1 + 0.2 !== 0.3
,而0.1 + 0.3 === 0.4
小数使用toString(2)
方法时,会分别返回整数和小数的二进制表示:
(8.1).toString(2);
// "1000.0001100110011001100110011001100110011001100110011"
(-8.1).toString(2);
// "-1000.0001100110011001100110011001100110011001100110011"
有符号32位整数
所有按位操作符的操作数都会转换完成二进制的形式进行操作。左起第一位是