位运算
二进制和十进制转换函数
function tranformBinary(item) {
var s = null,
array = null,
type = typeof item,
symbol = !/^-/.test(item + '')
switch (type) {
case 'number':
s = Math.abs(item).toString(2)
if (symbol) {
return s
}
break
case 'string':
if (symbol) {
return parseInt(item, 2)
}
s = item.substring(1)
break
default:
return false
}
//按位取反
array = [].map.call(s, function(v) {
return v ^ 1
})
//+1
array.reduceRight(function(previousValue, value, index, array) {
var v = previousValue + value == 2
array[index] = previousValue ^ value
return +v
}, 1)
s = array.join('')
return type == 'number' ? '-' + s : -parseInt(s, 2)
}
tranformBinary(-12) //"-0100"
tranformBinary('-0100') //-12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
对非整数取整
// 按位与
console.log(5.2 & 5.2) //5
console.log(-5.2 & -1) //-5
console.log(Math.trunc(-5.2) === (-5.2 & -1)) //true
// 按位或
console.log(5.2 | 0) //5
console.log(-5.2 | 0) //-5
console.log(Math.trunc(-5.2) === (-5.2 | 0)) //true
// 按位非
console.log(~~5.2) //5
console.log(~~-5.2) //-5
console.log(Math.trunc(-5.2) === ~~-5.2) //true
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
判断奇偶数
if ((x & 1) === 1) {
console.log('x为奇数')
} else {
console.log('x为偶数')
}
1
2
3
4
5
2
3
4
5
交换两个数的值
var a = 1,
b = 2
// 常规方法
var tmp = a
a = b
b = tmp
console.log(a, b) //2 1
// 按位异或方法
a = a ^ b // 假设a,b的原始值分别为a0,b0
b = a ^ b // 等价于 b=a0^b0^b0 ==> b=a0
a = a ^ b // 等价于 a=a0^b0^a0 ==> a=b0
console.log(a, b) //2 1
// 以上可简写为
a ^= b
b ^= a
a ^= b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
实现加法运算
同位相加的运算, 完全可由按位异或(^)代替, 即: x^y
. 按位与只有在同位都是 1 的情况下才返回 1, 其他情况均返回 0. 如果对其运算结果再做左移一位的运算, 即: (x&y)<<1
, 刚好满足了遇 2 进 1 的场景. 最终的加法运算结果应该还要做一次加法. 如下: x + y = x^y + (x&y)<<1
.
这个公式并不完美, 因为它还是使用了加法, 而绕过这个问题有一个前提, 那就是只要 x^y
或 (x&y)<<1
中有一个值为 0 就行了, 这样便不用进行加法运算了. 讲了这么多, 不如看代码.
function add(x, y) {
const a = x ^ y
const b = (x & y) << 1
// a=0则返回b,b=0则返回a,否则继续执行函数
return (!a && b) || (!b && a) || arguments.callee(a, b)
}
add(12345678, 87654321) //999999999
add(9527, -12) //9515
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
计算绝对值
function abs(num) {
// 保留32二进制中的符号位,根据num的正负性分别返回0或-1
const x = num >> 31
// 若num为正数,num^0则返回num本身;若num为负数,则相当于num^-1,此时返回-num-1
const y = num ^ x
// 若num为正数,则返回num-0即num;若num为负数则返回-num-1-(-1)即|num|
return y - x
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
判断两个数符号是否相同
通常, 比较两个数是否符号相同, 我们使用 x*y>0
来判断即可. 但如果利用按位异或(^), 运算速度将更快.
console.log((-17 ^ 9) > 0) //false
1
对正整数 2n 取模(n 为正整数)
比如 123%8
, 实际上就是求一个余数, 并且这个余数还不大于 8, 最大为 7. 然后剩下的就是比较二进制值里, 123 与 7 有几成相似了. 便不难推出公式: x%(1<<n)==x&(1<<n)-1
.
console.log(123 % 8) //3
console.log(123 & ((1 << 3) - 1)) //3
1
2
2
统计正整数二进制形式中 1 的个数
先判断 n 的奇偶性, 为奇数时计数器增加 1, 然后将 n 右移一位, 重复上面步骤, 直到递归退出.
function getCountForOne(n) {
return n ? (n & 1) + arguments.callee(n >> 1) : 0
}
getCountForOne(9) //2
1
2
3
4
2
3
4