JavaScript:将52位整数转换为20位和32位整数 [英] JavaScript: convert a 52-bit integer to 20-bit and 32-bit integers

查看:121
本文介绍了JavaScript:将52位整数转换为20位和32位整数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In other languages which can represent 64-bit integers, it is possible to do this very easily...

如何在Ruby中以两个32位整数存储一个64位整数

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

但是JavaScript无法表示64位整数.它只能表示52位整数,没有问题.

But JavaScript CAN NOT represent 64-bit integers. It can only represent 52-bit integers without problems.

现在,这意味着无法将64位整数转换为两个32位整数,因为

Now that means that it is not possible to convert a 64-bit integer into two 32 bit integers, because it is not even possible to have a 64-bit integer in the first place.

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

But still, we have 52 bits remaining. My question is: how can we split this 52-bit integer in JavaScript in two 32-bit integers (20 high bits and 32 low bits)

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

Can someone suggest bit manipulation code like above to do 20-bit and 32-bit split in JavaScript?

相关: 按位操作产生的32位JavaScript数字转换回64位数字

推荐答案

开始之前

首先,您的链接包含一个轻微的错误,说明 任何小于2 52 [...]的整数都可以安全地放入JavaScript数字中."尽管从技术上讲是正确的,但这并不是一个严格的界限:可以毫无疑问地验证javascript数字可以存储最多2 53 的每个正整数(但不能存储2 53 +1).

Before we start

First of all, your link contains a minor inaccuracy in stating that "Any whole number less than 252 [...] will safely fit in a JavaScript number. " While technically correct, it is not a tight bound: it can be verified without too much trouble that javascript numbers can store every positive integer up to 253 (but not 253+1).

事不宜迟,您要求的功能将52位数字分为低32位和高20位:

Without further ado, the functions you requested, splitting 52-bit numbers into the bottom 32 bits and the 20 top bits:

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").

Where to split

I would not suggest using these though. Javascript bitwise ops are signed (@dandavis: JS does not have UInt32s), and the sign bit causes headaches when we actually want the positive value. Plus V8 has optimizations for (signed) integers that can be stored in 31 bits. Combining these two facts, you should split at no more than 30 bits, the maximum positive size that will fit in a V8 small integer ("smi").

以下代码将数字分为30个低位和22个高位:

Here's code to split numbers into 30 low bits and 22 high bits:

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

您可能不想创建对象.这些应该内联(如果您实际上根本不喜欢函数):

You probably don't want to be creating objects though. These should get inlined (if you're actually bothering with functions at all):

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

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

并根据高低部分创建数字:

And to create the numbers from the low and high parts:

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

如果您真的确定hi和lo在范围内,则可以跳过掩蔽:

If you're really sure hi and lo are in range you can skip the masking:

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在范围内:

If you're sure that hi and lo are in range:

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

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

(这些不是函数,因为它们会修改i.)

(These aren't functions because they modify i.)

为了获得更多乐趣,该函数可以提取任意位域:

For extra fun, a function to pull out arbitrary bitfields:

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.)

(nbits must be <= 31. The failure mode when nbits is 32 is interesting, and is due to only the 5 low bits of the rhs operand of << being significant, a flaw the javascript spec shares with the x86 ISA.)

完全可以使用符号位将53位二进制数存储为-2 53 到2 53 -1的整数.我还没有做到这一点,但它应该很容易.之后,它开始变得有点毛茸茸,最终您会遇到这样一个事实,在到达2 64 之前,没有足够的浮点数可以绕行(很多是NaN).从理论上讲,将63位二进制数字打包为浮点数应该是可行的,但留给读者练习:)

It's perfectly possible to use the sign bit to store 53-bit binary numbers as integers from -253 to 253-1. I haven't done this but it should be easy enough. After that it starts to get a bit hairy, and you'll eventually run into the fact that there aren't enough floats to go round (many are NaNs) before you get to 264. Packing 63 binary digits into a float should be theoretically doable, but is left as an exercise for the reader :)

另一种方法是使用类型化数组并创建Float视图和Int视图:这使您可以直接操作浮点数的基础二进制表示形式.但是随后您必须开始担心 endianness 之类的东西.

Another approach is to use typed arrays and create a Float view and an Int view: this lets you manipulate the underlying binary representation of floats directly. But then you have to start worrying about endianness and the like.

所有建议对字符串进行操作的人都疯了.

All the people who are suggesting string manipulation are just crazy.

这篇关于JavaScript:将52位整数转换为20位和32位整数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆