如何在UInt16Array/UInt32Array单索引中存储两个数字并读写?
解决方案
要把0-8的小数值(记为smallNum)和0-50的大数值(记为bigNum)打包进同一个UInt16/UInt32数组索引,核心思路是利用位运算拆分和合并二进制位——两个数值的总二进制位数远小于16位(UInt16的容量),完全可以挤在同一个整数里。
位分配分析
smallNum范围0-8:二进制最多需要4位(2^4=16,足够覆盖0-15,远大于8)bigNum范围0-50:二进制最多需要6位(2^6=64,足够覆盖0-63,远大于50)
两者总占用10位,UInt16有16位剩余,完全够用;用UInt32Array的话逻辑完全一致,只是容量冗余更大。
打包与读取实现
我们约定:把bigNum放在高位(左移4位),smallNum放在低位,下面用UInt16Array举例:
1. 打包两个数值到数组索引
const arr = new UInt16Array(1); // 创建长度为1的UInt16数组 // 打包函数 function pack(small, big) { // 边界检查避免溢出 if (small < 0 || small > 8 || big < 0 || big > 50) { throw new Error('数值超出指定范围'); } arr[0] = (big << 4) | small; } // 示例:打包small=3,big=25 pack(3, 25);
2. 读取已打包的数值
// 读取小数值 function getSmall() { return arr[0] & 0b1111; // 用4位掩码提取低4位 } // 读取大数值 function getBig() { return (arr[0] >> 4) & 0b111111; // 右移4位后,用6位掩码提取对应值 } // 示例读取 console.log(getSmall()); // 输出3 console.log(getBig()); // 输出25
3. 重置单个数值
如果只需要修改其中一个值,不用重新打包两个数,直接针对性修改对应位即可:
// 重置小数值 function setSmall(newSmall) { if (newSmall < 0 || newSmall > 8) throw new Error('小数值超出范围'); // 先清零低4位,再和新值按位或 arr[0] = (arr[0] & ~0b1111) | newSmall; } // 重置大数值 function setBig(newBig) { if (newBig < 0 || newBig > 50) throw new Error('大数值超出范围'); // 先清零高6位(从第4位开始的6位),再把新值左移4位后按位或 arr[0] = (arr[0] & ~(0b111111 << 4)) | (newBig << 4); } // 示例重置 setSmall(7); console.log(getSmall()); // 输出7 setBig(42); console.log(getBig()); // 输出42
注意事项
- 位分配顺序可以调整(比如把小数值放在高位),只要读写逻辑对应即可,上面的示例是最直观的低位存小值方案
- 必须严格保证输入数值在指定范围内,否则会导致位溢出,覆盖另一个数值的位,造成数据错误
内容的提问来源于stack exchange,提问作者radio
相关产品推荐
相关产品推荐

