2011-06-03 52 views
6

有没有办法在JavaScript中正确乘以两个32位整数?有没有办法在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以防万一)

+2

供参考:它实际上是围绕[53个比特](http://groups.google.com/group/twitter-api-announce/browse_thread/thread/6a16efa375532182?pli=1)。 – Thai 2011-06-04 03:31:25

+1

你可以使用[Math.imul](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul) – 2016-03-25 13:52:05

回答

9

这似乎做什么,我想没有外部的依赖:

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,这是计算的正确的下半部分。一个类似的函数可以用来计算一个正确的上半部分并将其存储在一个单独的整数中(ah * bh似乎是正确的),但我并不需要这样做。

注意零漂。没有这个功能,当高位被设置时,该函数会产生负值。

+1

如果我运行'multiply_uint32(0xffffffff,0xffffffff)',则返回'0x100000001'。我想你的意思是在整个返回值之后再做一次'&0xffffffff'。 – 2014-06-27 01:01:26

3

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

在JavaScript中,它是10000000000000001%2 == 0

一个朋友也提到10000000000000001 == 10000000000000000的情况,这确实是由于规范(虽然整数用于优化,该规范还要求浮动类似的行为) 。

虽然一旦你在这个领域,你已经接近64位整数精度的极限了。

+1

因为整数实际上被存储为IEEE 754双精度值,精度(64位)浮点数,你不可能比54(或53类似于这样)的精度更好,但是在JavaScript需要做int类似的事情(数组索引)时,它会下降到31位无论如何。 – Pointy 2011-06-03 22:22:16

0

GWT模拟Java(64位)带符号长整数类型。我为它制作了一个JavaScript界面​​,here's a demo。使用默认数字,您可以看到该值与您在C中获得的值相同。

“仿真”列中的十六进制值应与您在调试器中看到的一致,但可能会有由于我使用原生JavaScript来创建它,所以在十六进制表示方面存在问题。它当然也可以在GWT中完成,这可能会使它更加正确。如果JavaScript Number可以表示GWT生成的所有字符串表示形式,则十六进制表示形式也应该是正确的。查看使用情况的来源。他们({sub,mod,div,mul} ss)带字符串的原因是因为我不知道如何使用JavaScript创建GWT Long对象。

4

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位整数。在第一种情况下,它被转换为有符号整数,在第二种情况下,它被转换为无符号整数。

在乘法的行的第一个|/>>>操作者使与48位有效(格式0x NNNN NNNN NNNN 0000)放弃其较高位的64位的中间结果,所以中间结果是在表格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; 
} 
相关问题