有没有办法在Javascript中正确地乘以两个32位整数?

ant*_*eme 6 javascript 64-bit

有没有办法在Javascript中正确地乘以两个32位整数?

当我从C中尝试使用时,long long我得到了这个:

printf("0x%llx * %d = %llx\n", 0x4d98ee96ULL, 1812433253,
      0x4d98ee96ULL * 1812433253);
==> 0x4d98ee96 * 1812433253 = 20becd7b431e672e
Run Code Online (Sandbox Code Playgroud)

但是从Javascript来看结果是不同的:

x = 0x4d98ee97 * 1812433253;
print("0x4d98ee97 * 1812433253 = " + x.toString(16));
==> 0x4d98ee97 * 1812433253 = 20becd7baf25f000
Run Code Online (Sandbox Code Playgroud)

尾随零使我怀疑Javascript具有奇怪限制的整数分辨率,介于32位和64位之间.

有没有办法得到正确的答案?(如果重要的话,我在x86_64 Fedora 15上使用Mozilla js-1.8.5.)

ant*_*eme 10

这似乎做了我想要的没有外部依赖:

function multiply_uint32(a, b) {
    var ah = (a >> 16) & 0xffff, al = a & 0xffff;
    var bh = (b >> 16) & 0xffff, bl = b & 0xffff;
    var high = ((ah * bl) + (al * bh)) & 0xffff;
    return ((high << 16)>>>0) + (al * bl);
}
Run Code Online (Sandbox Code Playgroud)

这将执行32位乘法模2 ^ 32,这是计算的正确下半部分.类似的函数可用于计算正确的上半部分并将其存储在单独的整数中(啊*bh似乎正确),但我不需要那样做.

注意零班.如果没有这个,只要设置了高位,该函数就会产生负值.

  • 如果我用这个运行`multiply_uint32(0xffffffff,0xffffffff)`,我会回到`0x100000001`.我认为你打算在整个返回值之后再做一次`&0xffffffff`. (2认同)

Chr*_*ong 5

您可能需要使用第三方Javascript库来处理大量精度.

例如,BigInt.js:http://www.leemon.com/crypto/BigInt.js


Rol*_*kas 5

来自论坛帖子:

没有必要使数字变小,只需将有效数字保持在53以下即可

function mult32s(n, m) //signed version
{
    n |= 0;
    m |= 0;
    var nlo = n & 0xffff;
    var nhi = n - nlo;
    return ( (nhi * m | 0) + (nlo * m) ) | 0;
}

function mult32u(n, m) //unsigned version
{
    n >>>= 0;
    m >>>= 0;
    var nlo = n & 0xffff;
    var nhi = n - nlo;
    return ( (nhi * m >>> 0) + (nlo * m) ) >>> 0;
}
Run Code Online (Sandbox Code Playgroud)

Both |>>>运算符都会导致结果转换为32位整数.在第一种情况下,它被转换为有符号整数,在第二种情况下,它被转换为无符号整数.

在乘法行中,第一个|/ >>>运算符导致64位中间结果与48位有效数字(在表单中0x NNNN NNNN NNNN 0000)丢弃其较高位,因此中间结果为形式0x NNNN 0000.
第二个|/ >>>运算符使第二乘法和加法的结果限制为32位.

如果其中一个被乘数是常数,则可以进一步简化乘法:

function mult32s_with_constant(m) //signed version
{
    m |= 0
    //var n = 0x12345678;
    var nlo = 0x00005678;
    var nhi = 0x12340000;
    return ( (nhi * m | 0) + (nlo * m) ) | 0;
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您知道结果将小于53位,那么您可以这样做:

function mult32s(n, m) //signed version
{
    n |= 0;
    m |= 0;
    return ( n * m ) | 0;
}
Run Code Online (Sandbox Code Playgroud)