javascript - 在 JavaScript 中将整数转换为任意排序的字节数组的最快方法?

标签 javascript numbers bitmask

我希望将 MIN_SAFE_INTEGERMAX_SAFE_INTEGER 范围内的 JavaScript 数字(53 位,不包括符号)转换为分布在 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]

(如果您希望每个数组条目中的 bits 以相反的顺序排列,这会稍微复杂一些。将 (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);
}

)

最后,这只适用于正整数。但是你的 shifting-by-two 想法很容易实现。 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/

相关文章:

iOS9 beta 中 Javascript 数组总是返回空数组

javascript - dc.js - dataTable -- 组合数据行

algorithm - 给定 x,我怎样才能找到加起来为 x 的所有四个数字的集合

c - 如何在 C 中将给定位从一个位掩码设置为另一个位掩码?

android - 在 Android 开发中使用位掩码自动匹配玩家

Java从函数中去除零

javascript - 设置输入值显示 [object HTMLInputElement] Angular

javascript - 从 Google 结果页面查找 javascript 片段

安卓号码选择

javascript - 为什么 00.0 会导致语法错误?