2013-10-06 53 views
5

在能够代表64位整数其它语言,有可能做到这一点很容易...JavaScript的:转换一个52位整数,20位和32位整数

How to store a 64 bit integer in two 32 bit integers and convert back again

How to store a 64 bit integer in two 32 bit integers in Ruby

// convert 64-bit n to two 32-bit x and y 
x = (n & 0xFFFFFFFF00000000) >> 32 
y = n & 0xFFFFFFFF 

但JavaScript不能代表64位整数。它can only represent 52-bit integers没有问题。

现在,这意味着不可能将64位整数转换为两个32位整数,因为首先是it is not even possible to have a 64-bit integer

但是,我们仍然有52位。我的问题是:我们如何在JavaScript中将这个52位整数分成两个32位整数(20位高位和32位低位)

有人可以建议像上面这样的位操作代码来做20位和32位整数,在JavaScript中分裂?

相关: How are 32 bit JavaScript numbers resulting from a bit-wise operation converted back to 64 bit numbers

+0

我不确定这是什么,因为JavaScript根本没有整数。所有数字都是浮点数。 – 2013-10-06 20:00:06

+0

js有UInt32s,但是你需要https://github.com/silentmatt/javascript-biginteger – dandavis

+0

@MikeW其实我需要使用大于32位的位域。因此我需要以这种方式分割给定的数字。 – treecoder

回答

11

在我们开始之前

首先,你link包含误差活动中指出, “任何整数小于2 [...]将安全适合在JavaScript数字。”虽然技术上是正确的,但它不是一个严格的限制:它可以被验证没有太多的麻烦,JavaScript数字可以存储每个正整数高达2 (但不是2 + 1)。

一些代码

事不宜迟,您所要求的功能,分裂52位数字进入底部32位和20个位:

function to_int52(hi, lo) { 
    /* range checking */ 
    if ((lo !== lo|0) && (lo !== (lo|0)+4294967296)) 
     throw new Error ("lo out of range: "+lo); 
    if (hi !== hi|0 && hi >= 1048576) 
     throw new Error ("hi out of range: "+hi); 

    if (lo < 0) 
    lo += 4294967296; 

    return hi * 4294967296 + lo; 
} 

function from_int52(i) { 
    var lo = i | 0; 
    if (lo < 0) 
    lo += 4294967296; 

    var hi = i - lo; 
    hi /= 4294967296; 
    if ((hi < 0) || (hi >= 1048576) 
     throw new Error ("not an int52: "+i); 
    return { lo: lo, hi: hi }; 
} 

哪里拆分

我不会建议使用这些。 JavaScript的按位老年退休金计划进行签名(@dandavis:JS不有UInt32s)和符号位引起头痛,当我们真正想要的正值。 Plus V8优化了可以存储在31位中的(带符号)整数。结合这两个事实,你应该在拆不超过30位,将适合在V8小整数(“SMI”)的最大正大小。

这里的代码,号码拆分成30位低22位高:

function int52_30_get(i) { 
    var lo = i & 0x3fffffff; 
    var hi = (i - lo)/0x40000000; 
    return { lo: lo, hi: hi }; 
} 

你可能不想虽然被创建对象。这些应该得到内联(如果你实际上功能困扰的话):

function int52_30_get_lo(i) { 
    return i & 0x3fffffff; 
} 

function int52_30_get_hi(i) { 
    return (i - (i & 0x3fffffff))/0x40000000; 
} 

,并从低和高的部分创建的数字:

function int52_30_new_safe(hi, lo) { 
    return (hi & 0x3fffff) * 0x40000000 + (lo & 0x3fffffff); 
} 

如果你真的确信喜和LO在范围内可以跳过掩蔽:

function int52_30_new(hi, lo) { 
    return hi * 0x40000000 + lo; 
} 

单独设置高,低部分:

/* set high part of i to hi */ 
i = (hi & 0x3fffff) * 0x40000000 + (i & 0x3fffffff); 

/* set low part of i to lo */ 
i += (lo & 0x3fffffff) - (i & 0x3fffffff); 

如果你确定HI和LO在范围内:(因为他们修改i这些都不是函数)

/* set high part of i to hi */ 
i = hi * 0x40000000 + (i & 0x3fffffff); 

/* set low part of i to lo */ 
i += lo - (i & 0x3fffffff); 

对于额外的乐趣,功能拉出任意位字段:

function int52_30_get_bits(i, lsb, nbits) { 
    while (lsb >= 32) { 
     i /= 4294967296; 
     lsb -= 32; 
    } 
    return (i/(1<<lsb)) & ((1<<nbits)-1); 
} 

(NBITS必须< = 31时NBITS是32是有趣的,是由于的RHS操作数的仅5位低的故障模式<是显著,一个漏洞的JavaScript规范股份与x86 ISA)比52位

更多?

完全可以使用符号位来存储53位二进制数作为整数,从-2 到2 -1。我没有这样做,但它应该很容易。之后,它开始变得有点毛茸茸的,你最终会碰到一个事实,即没有足够的漂浮走轮(很多都是NaN的),你到2 之前。包装63个二进制数字转换为一个float应该是理论上可行,但作为练习留给读者:)

其他方法

另一种方法是使用类型数组,并创建一个浮动视图和一个int观点:这可以让你直接操纵浮动的底层二进制表示。但是你必须开始担心endianness之类的问题。

所有提示字符串操作的人都疯了。

+0

谢谢你这个非常详尽的答案。你说得对,JS实际上可以存储52 + 1位整数。我得到了我的解决方案,谢谢你。 – treecoder

+0

第53位是隐藏的,而不是符号位 –

4

那么你可以做数字是这样的:

function numeric(n) { 
    return { 
     hi: Math.floor(n/4294967296), 
     lo: (n & 0xFFFFFFFF) >>> 0 
    } 
} 

或字符串版本可能是:

function strings(n) { 
    s = n.toString(16); 

    if (s.length > 8) { 

     return { 
      hi: parseInt(s.toString(16).slice(0, s.length - 8), 16), 
      lo: parseInt(s.toString(16).slice(s.length - 8), 16) 
     } 
    } else { 
     return { hi: 0, lo: n } 
    } 

} 

也许......

function stringPad(n) { 
    s = "00000000000"+n.toString(16); 
    return { 
     hi: parseInt(s.toString(16).slice(0, s.length - 8), 16), 
     lo: parseInt(s.toString(16).slice(s.length - 8), 16) 
    } 
} 

现在,速度更快。为了找出我在这里设置测试床:http://jsfiddle.net/SpaceDog/ZTJ2p/(你也可以使用你最喜欢的JS分析器)。

结果(100000个电话):

Function: numeric completed in 146 ms 
Function: strings completed in 379 ms 
Function: stringPad completed in 459 ms 

我还以为丝线更快,并想知道如果它是parseInt函数调用,但没有:

Function: stringPadNoParse completed in 386 ms 

现在,这个ISN不是非常精确,因为它依赖于很多其他的东西(再次,探查器可能会更好),但它似乎像数字版本更快,我已经运行了几次来测试。

但也许有人会来提供另一种做法。

+0

感谢您的代码。 'numeric()'函数完美工作。 – treecoder

+0

MB var hi = n >> 32; ??? – nim