JavaScript:将52位整数转换为20位和32位整数
在其他可以表示64位整数的语言中,很容易做到这一点 但是JavaScript不能表示64位整数。它没有问题 这意味着不可能将一个64位整数转换为两个32位整数,因为首先 但是,我们仍然有52位剩余。我的问题是:如何将JavaScript中的52位整数拆分为两个32位整数(20高位和32低位) 有人能建议像上面这样的位操作代码在JavaScript中进行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:
你可以这样做:
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