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

时间:2011-06-03 21:39:15

标签: javascript 64-bit

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

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

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

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

x = 0x4d98ee97 * 1812433253;
print("0x4d98ee97 * 1812433253 = " + x.toString(16));
==> 0x4d98ee97 * 1812433253 = 20becd7baf25f000

尾随零使我怀疑Javascript在32到64位之间的奇怪限制整数分辨率。

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

5 个答案:

答案 0 :(得分: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);
}

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

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

答案 1 :(得分:5)

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

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

答案 2 :(得分:5)

来自a forum post

  

没有必要让数字变小,只有   有效数字保持在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;
}

|>>>运算符都会导致结果转换为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;
}

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

function mult32s(n, m) //signed version
{
    n |= 0;
    m |= 0;
    return ( n * m ) | 0;
}

答案 3 :(得分:3)

你是对的。 Javascript整数被视为浮点数,在处理整数时精度较差。

在javascript中,情况是10000000000000001%2 == 0

一位朋友还提到10000000000000001 == 10000000000000000,这确实是由于规范(虽然整数用于优化,规范仍然需要浮点行为)。

虽然一旦你进入这个领域,你已经接近64位int精度的极限。

答案 4 :(得分:0)

GWT具有Java(64位)有符号长整数类型的仿真。我为它创建了一个JavaScript接口here's a demo。使用默认数字,您可以看到该值与您在C中获得的值相同。

“仿真”列中的十六进制值应与您在调试器中看到的值相对应,但由于我使用本机JavaScript来实现,因此十六进制表示可能存在问题。它当然也可以在GWT中完成,这可能会使它更正确。如果JavaScript Number可以表示GWT生成的所有字符串表示,则十六进制表示也应该是正确的。查看源代码以了解用法。他们({sub,mod,div,mul} ss)接受字符串的原因是因为我不知道如何从JavaScript创建一个GWT Long对象。