我正在寻找将JavaScript编号(不包括符号的53位)的MIN_SAFE_INTEGER范围内的MAX_SAFE_INTEGER转换为分布在7个字节中的位字符串,将其移位两个,以允许使用符号和空标识符。

到目前为止,我想出的最好的方法是:

function toUint8Array(data) {
    data = data.toString(2);
    data = new Array(65 - data.length).join('0') + data;
    var ret = new Uint8Array(data.length / 8);
    for (var i = 0; i < 8; i++) {
        ret[i] = 0;
        ret[i] += (data[i * 8] == '1' ? 128 : 0);
        ret[i] += (data[(i * 8) + 1] == '1' ? 64 : 0);
        ret[i] += (data[(i * 8) + 2] == '1' ? 32 : 0);
        ret[i] += (data[(i * 8) + 3] == '1' ? 16 : 0);
        ret[i] += (data[(i * 8) + 4] == '1' ? 8 : 0);
        ret[i] += (data[(i * 8) + 5] == '1' ? 4 : 0);
        ret[i] += (data[(i * 8) + 6] == '1' ? 2 : 0);
        ret[i] += (data[(i * 8) + 7] == '1' ? 1 : 0);
    }
    return (ret);
}

Fiddle

正如您可以立即告诉您的那样,这将非常慢(并且在所有7个有效字节中,这些位仍未移位两个位置。)

有什么办法可以更快地做到这一点?理想情况下,完全避免字符串解析?

最佳答案

JavaScript中的按位操作只有32位宽。但是移位等效于乘以2的乘积或除法,并且这些移位以完全的浮点精度发生。

因此,您想要做的很简单。移位以获得有趣的部分在低阶位,并掩盖其余部分。
例如。您有一个大数字0x123456789abc(20015998343868)。

0x123456789abc/0x1 = 0x123456789abc。与0xff进行按位与运算,得出0xbc。

0x123456789abc/0x100 = 0x123456789a.bc。与0xff进行按位与运算,得出0x9a。

0x123456789abc/0x10000 = 0x12345678.9abc。与0xff进行按位与运算,得出0x78。

等等。代码:

function toUint8Array(d) {
    var arr = new Uint8Array(7);
    for (var i=0, j=1; i<7; i++, j *= 0x100) {
        arr[i] = (d / j) & 0xff;
    }
    return arr;
}

使用Uint8Array的生活更加轻松:使用0xff进行掩码是隐式的,因为Uint8Arrays只能存储0到255之间的整数。但是为了清楚起见,我将其保留了下来,因此对于不同的数组类型,结果将相同。

这段代码产生了一个小端数组,例如toUint8Array(0x123456789abc)返回[0xbc,0x9a,0x78,0x56,0x34,0x12,0]
如果要使用大端字节序,即字节顺序相反,则将arr[i]替换为arr[6-i]

(如果要以相反的顺序排列每个数组条目中的位,这会稍微复杂一些。用(d / j) & 0xff替换bitrev((d / j) & 0xff),其中bitrev看起来像这样:
function bitrev(byte) {
   var table = [ 0b0000, 0b1000, 0b0100, 0b1100, 0b0010, 0b1010, 0b0110, 0b1110,
                 0b0001, 0b1001, 0b0101, 0b1101, 0b0011, 0b1011, 0b0111, 0b1111 ];
   return table[byte >> 4] + (table[byte & 0xf] << 4);
}

)

最后,这仅适用于正整数。但是您的二分法想法很容易实现。 d*4向左移两位。 d < 0 ? -d : d(或Math.abs(d))是d的绝对值。因此arr = toUint8Array((d<0) ? 1-d*4 : d*4)返回d左移两位,符号位在最低有效位(LSB)中。

并且您可以使用isFinite()检查非数字,但您必须小心,只能在数字上调用它,因为由于隐式强制转换规则,因此isFinite(null)实际上是true(这在ES6中已修复):
function toUint8Array_shifted_signed(d) {
   /* bit 0 is sign bit (0 for +ve); bit 1 is "not-a-number" */
   if (typeof d !== 'number' || !isFinite(d)) {
       d = 2;
   } else {
       d = (d<0) ? 1-d*4 : d*4;
   }

   return toUint8Array(d);
}

关于javascript - 在JavaScript中将整数转换为任意排序的字节数组的最快方法?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34583357/

10-11 23:48