【发布时间】:2011-02-28 07:39:18
【问题描述】:
我正在寻找一种在 JavaScript 中对 64 位整数执行按位与的方法。
JavaScript 会将其所有双精度值转换为带符号的 32 位整数以执行按位运算 (details here)。
【问题讨论】:
标签: javascript 64-bit integer bit-manipulation
我正在寻找一种在 JavaScript 中对 64 位整数执行按位与的方法。
JavaScript 会将其所有双精度值转换为带符号的 32 位整数以执行按位运算 (details here)。
【问题讨论】:
标签: javascript 64-bit integer bit-manipulation
Javascript 将所有数字表示为 64 位 double precision IEEE 754 floating point numbers(参见 ECMAscript spec,第 8.5 节。)所有 2^53 以内的正整数都可以精确编码。较大的整数会被剪掉它们的最低有效位。这就留下了一个问题,你怎么能在 Javascript 中表示一个 64 位整数——本机数字数据类型显然不能精确地表示一个 64 位 int。
以下说明了这一点。尽管 javascript 似乎 能够解析表示 64 位数字的十六进制数字,但底层数字表示不包含 64 位。在浏览器中尝试以下操作:
<html>
<head>
<script language="javascript">
function showPrecisionLimits() {
document.getElementById("r50").innerHTML = 0x0004000000000001 - 0x0004000000000000;
document.getElementById("r51").innerHTML = 0x0008000000000001 - 0x0008000000000000;
document.getElementById("r52").innerHTML = 0x0010000000000001 - 0x0010000000000000;
document.getElementById("r53").innerHTML = 0x0020000000000001 - 0x0020000000000000;
document.getElementById("r54").innerHTML = 0x0040000000000001 - 0x0040000000000000;
}
</script>
</head>
<body onload="showPrecisionLimits()">
<p>(2^50+1) - (2^50) = <span id="r50"></span></p>
<p>(2^51+1) - (2^51) = <span id="r51"></span></p>
<p>(2^52+1) - (2^52) = <span id="r52"></span></p>
<p>(2^53+1) - (2^53) = <span id="r53"></span></p>
<p>(2^54+1) - (2^54) = <span id="r54"></span></p>
</body>
</html>
在 Firefox、Chrome 和 IE 中,我得到以下内容。如果数字以完整的 64 位格式存储,则所有减法的结果都应该是 1。相反,您可以看到 2^53+1 和 2^53 之间的差异是如何丢失的。
(2^50+1) - (2^50) = 1
(2^51+1) - (2^51) = 1
(2^52+1) - (2^52) = 1
(2^53+1) - (2^53) = 0
(2^54+1) - (2^54) = 0
那你能做什么?
如果您选择将 64 位整数表示为两个 32 位数字,则应用按位与就像应用 2 个按位与一样简单,分别应用于低 32 位和高 32 位“字”。
例如:
var a = [ 0x0000ffff, 0xffff0000 ];
var b = [ 0x00ffff00, 0x00ffff00 ];
var c = [ a[0] & b[0], a[1] & b[1] ];
document.body.innerHTML = c[0].toString(16) + ":" + c[1].toString(16);
让你:
ff00:ff0000
【讨论】:
这里是与 int64 数字的代码,你可以用其他按位运算替换 AND
function and(v1, v2) {
var hi = 0x80000000;
var low = 0x7fffffff;
var hi1 = ~~(v1 / hi);
var hi2 = ~~(v2 / hi);
var low1 = v1 & low;
var low2 = v2 & low;
var h = hi1 & hi2;
var l = low1 & low2;
return h*hi + l;
}
【讨论】:
h 和 l 的表达式中替换 &。
现在可以使用新的 BigInt 内置数字类型来完成。 BigInt 目前(2019 年 7 月)仅在某些浏览器中可用,详情请参见以下链接:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
我已经在 Chrome 67 中使用 BigInts 测试了按位运算,并且可以确认它们在最多 64 位值的情况下按预期工作。
【讨论】:
Javascript 不支持开箱即用的 64 位整数。这就是我最终要做的:
Long。Long
注意:要使下面的代码示例正常工作,您需要加载 long.js.
// Handy to output leading zeros to make it easier to compare the bits when outputting to the console
function zeroPad(num, places){
var zero = places - num.length + 1;
return Array(+(zero > 0 && zero)).join('0') + num;
}
// 2^3 = 8
var val1 = Long.fromString('8', 10);
var val1High = val1.getHighBitsUnsigned();
var val1Low = val1.getLowBitsUnsigned();
// 2^61 = 2305843009213693960
var val2 = Long.fromString('2305843009213693960', 10);
var val2High = val2.getHighBitsUnsigned();
var val2Low = val2.getLowBitsUnsigned();
console.log('2^3 & (2^3 + 2^63)')
console.log(zeroPad(val1.toString(2), 64));
console.log(zeroPad(val2.toString(2), 64));
var bitwiseAndResult = Long.fromBits(val1Low & val2Low, val1High & val2High, true);
console.log(bitwiseAndResult);
console.log(zeroPad(bitwiseAndResult.toString(2), 64));
console.log('Correlation betwen val1 and val2 ?');
console.log(bitwiseAndResult > 0);
控制台输出:
2^3
00000000000000000000000000000000000000000000000000000000000001000
2^3 + 2^63
00100000000000000000000000000000000000000000000000000000000001000
2^3 & (2^3 + 2^63)
00000000000000000000000000000000000000000000000000000000000001000
val1 和 val2 之间的相关性?
是的
【讨论】:
闭包库有goog.math.Long 和一个按位的add() 方法。
【讨论】:
不幸的是,接受的答案(和其他)似乎没有经过充分测试。最近遇到这个问题,我最初尝试按照建议将我的 64 位数字拆分为两个 32 位数字,但还有一个小问题。
打开你的 JavaScript 控制台并输入:
0x80000001
当您按下 Enter 时,您将获得 2147483649,即十进制等值。下次尝试:
0x80000001 & 0x80000003
这给您 -2147483647,与您预期的不太一样。很明显,在执行按位与时,这些数字被视为有符号的 32 位整数。结果是错误的。即使你否定它。
我的解决方案是在拆分后将 ~~ 应用于 32 位数字,检查是否有负号,然后适当地处理。
这很笨拙。可能有一个更优雅的“修复”,但我在快速检查时看不到它。具有讽刺意味的是,可以通过几行汇编完成的事情在 JavaScript 中需要更多的劳动。
【讨论】: