JavaScript:将52位整数转换为20位和32位整数

JavaScript:将52位整数转换为20位和32位整数,javascript,bit-manipulation,Javascript,Bit Manipulation,在其他可以表示64位整数的语言中,很容易做到这一点 但是JavaScript不能表示64位整数。它没有问题 这意味着不可能将一个64位整数转换为两个32位整数,因为首先 但是,我们仍然有52位剩余。我的问题是:如何将JavaScript中的52位整数拆分为两个32位整数(20高位和32低位) 有人能建议像上面这样的位操作代码在JavaScript中进行20位和32位拆分吗 相关的: 你可以这样做: function numeric(n) { return { hi:

在其他可以表示64位整数的语言中,很容易做到这一点

但是JavaScript不能表示64位整数。它没有问题

这意味着不可能将一个64位整数转换为两个32位整数,因为首先

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

有人能建议像上面这样的位操作代码在JavaScript中进行20位和32位拆分吗

相关的:

你可以这样做:

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)
    }
}
现在,哪个更快。为了找到答案,我在这里设置了一个测试平台:(你也可以使用你最喜欢的JS分析器)

结果(100000个电话):

我本以为字符串更快,不知道是不是parseInt调用,但不是:

Function: stringPadNoParse completed in 386 ms
现在,这不是很精确,因为它取决于许多其他因素(同样,探查器可能更好),但它确实看起来数字版本更快,我已经运行了几次以进行测试

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

在我们开始之前 首先,你的陈述有点不准确 “任何小于252[…]的整数都可以安全地放入一个JavaScript数字。”虽然技术上是正确的,但这并不是一个严格的界限:JavaScript数字可以存储253(而不是253+1)以下的每个正整数,这一点可以不用太多麻烦就得到验证

一些代码 无需进一步ado,您所请求的函数将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 };
}
不过,您可能不想创建对象。这些应该是内联的(如果你真的对函数感到烦恼的话):

要从低部分和高部分创建数字:

function int52_30_new_safe(hi, lo) {
    return (hi & 0x3fffff) * 0x40000000 + (lo & 0x3fffffff);
}
如果您确实确定hi和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在范围内:

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

/* set low part of i to lo */
i += lo - (i & 0x3fffffff);
(这些不是函数,因为它们修改
i

为了增加乐趣,提供了一个拉出任意位字段的函数:

function int52_30_get_bits(i, lsb, nbits) {
    while (lsb >= 32) {
        i /= 4294967296;
        lsb -= 32;
    }
    return (i / (1<<lsb)) & ((1<<nbits)-1);
}
函数int52\u 30\u get\u位(i、lsb、nbits){
而(lsb>=32){
i/=4294967296;
lsb-=32;
}
return(i/(1可用于获得双精度值的两半

var buf = new ArrayBuffer(8);
(new Float64Array(buf))[0] = f;
fl = (new Uint32Array(buf))[0];
fh = (new Uint32Array(buf))[1];
现在您有了尾数。如果需要,只需提取并移位即可得到整数部分

var exp = ((fh >> 20) & 0x7FF) - 1023;
var mant_h = (fh & 0xFFFFF) | (1 << 20);
var mant_l = fl;
if (exp > 52)
    throw new Error ("overflow int53 range");
else if (exp >= 32)
{
    L = mant_h >> (exp - 32);
    H = 0;
}
else if (exp >= 0)
{
    L = (mant_l >> exp) | (mant_h << (32 - exp));
    H = mant_h >> exp;
}

虽然它可以处理任意精度的整数,但将其引入标准的一个基本原理是,我想它应该有

我不确定这会有什么用,因为Javascript根本没有整数。所有数字都是浮点。@dandavis不,我不能使用大的十进制解。我需要一个非常有效的ent解决方案。我可以很容易地使用字符串来实现这一点,例如:
n.toString(2).slice(0,20)
,但我想更快。好吧,听起来你有答案了。由于大多数JS引擎中的类型转换非常慢,我怀疑任何东西都会比字符串快。@MikeW JavaScript没有整数,但它能完美地表示高达52位的整数,所以没问题。@good_computer:JS中的字符串速度很快。你可以试试bit移位,但需要几个fork和ifs才能可靠,而且整个例程可能比切片和切割字符串慢得多,在V8中,一旦加载和解析字符串,这些字符串至少会直接映射到ram序列。感谢这个非常详细的答案。你说得对,JS实际上可以存储52+1位整数。我找到了我的解决方案,谢谢。第53位是隐藏的,不是符号位。谢谢你的代码。
numeric()
函数工作得很好。
/* 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);
}
var buf = new ArrayBuffer(8);
(new Float64Array(buf))[0] = f;
fl = (new Uint32Array(buf))[0];
fh = (new Uint32Array(buf))[1];
var exp = ((fh >> 20) & 0x7FF) - 1023;
var mant_h = (fh & 0xFFFFF) | (1 << 20);
var mant_l = fl;
if (exp > 52)
    throw new Error ("overflow int53 range");
else if (exp >= 32)
{
    L = mant_h >> (exp - 32);
    H = 0;
}
else if (exp >= 0)
{
    L = (mant_l >> exp) | (mant_h << (32 - exp));
    H = mant_h >> exp;
}
const previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER);
// ↪ 9007199254740991

const maxPlusOne = previousMaxSafe + 1n;
// ↪ 9007199254740992n