在js中对大数值的整数作异或、与等位运算时,如果直接使用操作符(^、&、>>>),得到的结果可能与预期不符。通常情况下是因为结果超过了js支持的整数范围(即从-2147483648到+2147483647),此时只能自定义位运算函数。
总体思路是:把大数值转为二进制数组,每一位单独进行位运算,最后合并。
- 自定义异或函数
function xor(a, b) { // 没有超过js支持的整数范围(即从-2147483648到+2147483647), // 则使用本身支持的异或运算 if((a>=-2147483648 && a<=2147483647) && (b>=-2147483648 && b<=2147483647)){ return a ^ b; } // 获取a和b的二进制数组 let x = toBinarys(a); let y = toBinarys(b); let isNe = false; // 比较二进制运算的两个数字的大小,小的数字补齐 // 如果是负数,高位补齐1(因为是反码) // 如果是正数,高位补齐0 if (x.length != y.length) { if (x.length > y.length) { let size = x.length - y.length; for (let i = 0; i < size; i++) { if(b<0){ y.unshift(1); }else{ y.unshift(0); } } } else { let size = y.length - x.length; for (let i = 0; i < size; i++) { if(a<0){ x.unshift(1); }else{ x.unshift(0); } } } } let z = new Array(); let len = x.length > y.length ? x.length : y.length; // 每一个做异或运算,最后合并为字符串 for (let i = 0; i < len; i++) { z.push(x[i] ^ y[i]); } z = z.join(""); // 因为自带的parseInt转负数(补码)的时候,结果不对 // 使用自定义的函数 return parseIntWithNegative(z); }
- 自定义与函数
function and(a, b){ a = Number.parseInt(a); b = Number.parseInt(b); if((a>=-2147483648 && a<=2147483647) && (b>=-2147483648 && b<=2147483647)){ return a & b; } let x = toBinarys(a); let y = toBinarys(b); if(x.length != y.length){ if(x.length > y.length){ let size = x.length-y.length; for(let i=0; i<size; i++){ if(b<0){ y.unshift(1); }else{ y.unshift(0); } } }else{ let size = y.length-x.length; for(let i=0; i<size; i++){ if(a<0){ x.unshift(1); }else{ x.unshift(0); } } } } let res = new Array(); let len = x.length > y.length ? x.length : y.length; for(let i=0; i < len; i++){ res.push(x[i] & y[i]); } res = res.join(""); return parseIntWithNegative(res); }
- 整数转为二进制数组
function toBinarys(a) { a = Number.parseInt(a).toString(2); let bytes = []; var result = []; let firstChar = a.charAt(0); if(firstChar == '-'){ for (let i = 0; i < a.length; i++){ let v = a.substr(i, 1); if(i==0){ bytes.push(1); }else{ bytes.push(v==0?1:0); } } let res = parseInt(bytes.join(""), 2) + 1; a = Number.parseInt(res).toString(2); }else{ result.push(0); } for (let i = 0; i < a.length; i++){ result.push(a.substr(i, 1)); } return result; }
- 自定义二进制字符串转十进制函数(支持负数)
// 传入的是二进制字符串 function parseIntWithNegative(ne){ let bytes = []; let firstChar = ne.charAt(0); //如果是负数,则补码减一,然后取反,就是原码了 // 然后调用parseInt(),前面加负号 if(firstChar == 1){ for (let i = 0; i < ne.length; i++){ bytes.push(ne.substr(i, 1)); } for (let j = ne.length-1, x=ne.length-1; j >=0; j--){ let v = ne.substr(j, 1); if(j==0){ break; } if(v==1){ bytes[j] = 0; break; }else{ bytes[j] = 1; } } for (let k = 0; k < bytes.length; k++){ let v = bytes[k]; bytes[k] = (v==0?1:0); } let res = bytes.join(""); return '-' + parseInt(res, 2); } for (let i = 0; i < ne.length; i++){ bytes.push(ne.substr(i, 1)); } let res = bytes.join("") return parseInt(res, 2); }
- 自定义无符号右移函数
function rightShift(a, b){ a = Number.parseInt(a); if((a>=-2147483648 && a<=2147483647)){ return a >>> b; } let x = toBinarys(a); for(let i=0; i<b; i++){ x.pop(); } x = x.join(""); return parseInt(x, 2); }