我希望将JavaScript编号的MIN_SAFE_INTEGER
到MAX_SAFE_INTEGER
范围(不包括符号的53位)转换为分布在7个字节的位字符串,移位2以允许用于符号和空标识符。
到目前为止,我提出的最好的是:
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);
}
正如你所知道的那样,这将是非常缓慢的(并且这些位仍然在所有7个活动字节中被移位两个位置。)
有没有办法更快地完成这项工作?理想情况下,完全避免字符串解析?
答案 0 :(得分:5)
javascript中的按位运算只有32位宽。但是,移位相当于乘以2或除以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]
。
如果您想要big-endian,即相反顺序的字节,请将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);
}
答案 1 :(得分:1)
我打了书,还有几个数学方面的CS朋友,我们目前的判决是,这不能在你描述它的时候完成。
我认为你已经坚持使用字符串解析了。