Javascript 中的按位 AND 与 64 位整数

IT技术 javascript 64-bit integer bit-manipulation
2021-01-17 11:34:35

我正在寻找一种在 JavaScript 中对 64 位整数执行按位 AND 的方法。

JavaScript 会将其所有双精度值转换为有符号的 32 位整数以执行按位运算(详情请点击此处)。

6个回答

Javascript 将所有数字表示为 64 位双精度 IEEE 754 浮点数(请参阅ECMAscript 规范,第 8.5 节。)所有高达 2^53 的正整数都可以精确编码。较大的整数会剪掉它们的最低有效位。这留下了一个问题,即如何在 Javascript 中表示 64 位整数——本机数字数据类型显然不能精确表示 64 位整数。

下面说明了这一点。尽管 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 位数字,那么应用按位 AND 就像对低位和高位 32 位“字”应用 2 个按位 AND 一样简单。

例如:

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
谢谢。在这种情况下,我实际上是在读取一个包含 64 位值的二进制字符串。所以我可以以某种方式将其转换为两个 32 位数字并使用我自己的内部表示来管理该数据。
2021-03-19 11:34:35
如果您在 WinRT 中使用 javascript,这里有更多信息:msdn.microsoft.com/en-us/library/hh710232(v=vs.94).aspx Windows 运行时 Int64 是一个有符号的 64 位整数,表示为标准如果它在 [-2^53, 2^53] 范围内,则为数字。
2021-03-23 11:34:35
的确。迄今为止,我仍然不清楚 OP 的 64 位数字最初是如何表示的。“二进制字符串”,如第一条注释,可以表示 8 位字符、16 位字符,甚至 64 个“0”和“1”字符的字符串。
2021-03-27 11:34:35
@Orent Trutner:这里要小心:使用 Unicode,字符代码可能超过 255。我认为只要其中一个字节设置了高位,您的代码就会失败。
2021-03-30 11:34:35
嘿托比;二进制字符串是什么意思?如果这是一个字符序列,每个字符相当于一个 8 位字节的字符,你可以这样做: var a = [ s.charCodeAt(0) + (s.charCodeAt(1) << 8) + ( s.charCodeAt(2) << 16) + (s.charCodeAt(3) << 24), s.charCodeAt(4) + (s.charCodeAt(5) << 8) + (s.charCodeAt(6) < < 16) + (s.charCodeAt(7) << 24) ]; 只需注意事物的字节序即可。
2021-04-14 11:34:35

这是AND 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;
}
需要注意的是使用另一种位运算您将要替换&的表达式hl
2021-03-20 11:34:35
这很棒,左/右移位 << 和 >> 怎么样?
2021-04-01 11:34:35
@vanowm 示例:10 << 3 可以写 10 * (2 ** 3),而 10 >> 3 可以写 Math.floor(10 / (2 ** 3))
2021-04-11 11:34:35

现在可以使用新的 BigInt 内置数字类型来完成。BigInt 目前(2019 年 7 月)仅在某些浏览器中可用,详情请参见以下链接:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt

我已经在 Chrome 67 中使用 BigInts 测试了按位运算,并且可以确认它们在最多 64 位值的情况下按预期工作。

Javascript 不支持开箱即用的 64 位整数。这就是我最终做的:

  1. 在 github 上找到了long.js,一个自包含的 Long 实现。
  2. 将表示 64 位数字的字符串值转换为Long.
  3. 提取高低 32 位值
  4. 做32位按位高之间低位,分别
  5. Long从低位和高位初始化一个新的64
  6. 如果数字 > 0,则两个数字之间存在相关性

:下面工作的代码示例,你需要负载 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

00000000000000000000000000000000000000000000000000000000001000

2^3 + 2^63

00100000000000000000000000000000000000000000000000000000001000

2^3 & (2^3 + 2^63)

00000000000000000000000000000000000000000000000000000000001000

val1 和 val2 之间的相关性?

真的

Closure 库具有goog.math.Long按位add()方法。