如何在JavaScript中以最佳方式从位数组读取位子集
假设我有一个这样的位数组如何在JavaScript中以最佳方式从位数组读取位子集,javascript,integer,bit-manipulation,Javascript,Integer,Bit Manipulation,假设我有一个这样的位数组 101110101010101010101111111011001100100100001011001111101000101001 我想做的两个操作是: 将连续的比特子集读入单个比特数组(对于JavaScript,则读入整数) 在JavaScript中将非连续的比特子集读入单个整数 对于(1),假设我想要这个: 1011[101010101010101011111]11011001100100100001011001111101000101001 == 101010
101110101010101010101111111011001100100100001011001111101000101001
我想做的两个操作是:
1011[101010101010101011111]11011001100100100001011001111101000101001
== 101010101010101011111
= 1398111 in decimal
第4-25位左右
对于(2),我希望以最佳方式选择一个不连续的比特子集,并将它们以最佳方式组合成最终值
1011[101]0101010101010[11]1111[1]011001100100100001011001111101000101001
== 101 ++ 11 ++ 1
= 101111
= 47 in decimal
位4-6、21-22和27左右
这样做的正确/最佳方式是什么?格式仍然有点模糊,但这里有一种方法可以做到这一点。我正在做一些使问题更容易解决的假设,即:
- 一次最多提取32位(因此它适合一个
数字
,没有奇怪的破解)
- 位位于
uint32阵列中(或兼容存储器,只要每个元素有32位)
- 数组第0项的最低有效位为数字0
- 以这种方式表示的位字符串是
例如…+tobits(数组[1])+tobits(数组[0])
表示[0256]
(下划线表示片段之间的边界)。也许这是错误的方法,它可以改变,但这种方法很简单00000000000000000000000000000000000000\u00000000000000000000000000000000000000000000
i&31
(akai%32
)处的i>-5
-th(akai/32
)字中。这就是为什么这个订单很容易处理的原因
根据第一个假设,数组中最多有2个条目/字由范围跨越,因此只有两种情况:
- 范围的底部在一个单词中,顶部在下一个单词中
- 这个范围完全包含在一个单词中。应避免触摸第二个单词,因为它可能超出数组的末尾。此外,即使第二个字可以被触摸,处理多余的位也不会那么容易,因为移位计数采用模32,因此
high是一个简化版本,在最后一步只使用生成器,从而避免将整个输入加载到内存中
// for single number function* gUintToBits(input, dim) { let i = 0; while (i < dim) { yield (input >> (dim - 1 - i++)) & 1; // or like this, if bits should bo from left to right: // yield (input >> i++) & 1; } } // for array of numbers function* gUintArrayToBits(input, dim) { for (let item of input) { yield* gUintToBits(item, dim); } } // apply intervals mask directly to generator function* genWithIntervalsApplied(iterOfBits, intervals) { // fast, if number of intervals is not so big const isInsideIntervals = (n, itrvs) => { for (let intv of itrvs) { if (n >= intv[0] && n < intv[1]) return true; } return false; }; let index = 0; for (let item of iterOfBits) { if (isInsideIntervals(index++, intervals)) { yield item; } } } // Finally consume the generator function extractIntervalsFromUint8Array(input, intervals) { let result = '' for (let x of genWithIntervalsApplied(gUintArrayToBits(input, 8), intervals)) { result += `${x}` } return result } const result = extractIntervalsFromUint8Array( [1, 3, 9, 127], [[8, 16], [24, 32]], ); const dec = parseInt(result, 2); console.log(result); console.log(dec);
请看一下API,它是否适用于位而不是字节?位存储的格式是什么?打包在UINT8阵列中?UINT32阵列?带32位“整数”的普通JS数组?BigInt?问得好。位将存储在UINT8阵列或32阵列中,可能是UINT32阵列。但这只是普通的bitarray/binaryarray之上的一个“视图”(尽管我不知道如何构造它,除了在http请求中返回binaryarray)?例如,哪些位存储在UINT32数组的第0个条目中(第0到第31位?或最高有效位?),哪些“方式”是位(第0个条目的最低有效位也是字符串的第0位)?索引是否应该像您的示例中那样工作(看起来是相反的)?即使间隔相互重叠或以随机顺序排列,此解决方案也应该工作。注意:此处的间隔确实作为整个掩码生效,请检查位的位置是否在任何间隔内。如果这不是期望的行为,则应对生成器函数应用掩码进行相应更改。[0xdeadbeef, 0xcafebabe] means that the string is really 0xcafebabedeadbeef (in bits) extractRange([0xdeadbeef, 0xcafebabe], 0, 31).toString(16) = deadbeef extractRange([0xdeadbeef, 0xcafebabe], 4, 35).toString(16) = edeadbee extractRange([0xdeadbeef, 0xcafebabe], 8, 39).toString(16) = bedeadbe extractRange([0xdeadbeef, 0xcafebabe], 60, 63).toString(16) = c extractRange([0xdeadbeef, 0xcafebabe], 30, 33).toString(16) = b // ...ed... in binary 11101101, taking the middle 4 bits, 1011 = b
// for single number function* gUintToBits(input, dim) { let i = 0; while (i < dim) { yield (input >> (dim - 1 - i++)) & 1; // or like this, if bits should bo from left to right: // yield (input >> i++) & 1; } } // for array of numbers function* gUintArrayToBits(input, dim) { for (let item of input) { yield* gUintToBits(item, dim); } } // apply intervals mask directly to generator function* genWithIntervalsApplied(iterOfBits, intervals) { // fast, if number of intervals is not so big const isInsideIntervals = (n, itrvs) => { for (let intv of itrvs) { if (n >= intv[0] && n < intv[1]) return true; } return false; }; let index = 0; for (let item of iterOfBits) { if (isInsideIntervals(index++, intervals)) { yield item; } } } // Finally consume the generator function extractIntervalsFromUint8Array(input, intervals) { let result = '' for (let x of genWithIntervalsApplied(gUintArrayToBits(input, 8), intervals)) { result += `${x}` } return result } const result = extractIntervalsFromUint8Array( [1, 3, 9, 127], [[8, 16], [24, 32]], ); const dec = parseInt(result, 2); console.log(result); console.log(dec);
// 0000001101111111 // 895