更有效的方法将任意长的数量打包成7位的块?
我正在设计一个二进制协议,其中我需要在提供数据本身之前指定(任意长度)的一定数数据(任意长度)的长度。
我不能使用终结器字符(例如C弦),因为接下来的二进制数据可能包括该字符,并且逃脱 /删除的过程在计算上很昂贵。
在几乎所有情况下,数据的长度很小(小于128个字节),但是在某些情况下,数据的长度更大,我希望尽可能高效。
我采用了UTF-8位包装过程的简化版本,其中:
- 数据分为7位块,
- 每个字节的第一位表示它是否是最后一个字节(0 =最后一个字节,1 =更多字节要遵循)
这意味着可以写和读取127个或更少的数字,但较大的数字更为复杂。
这就是我要做的打包方式:
public writePackedNumber(num: bigint | number): void
{
if (num < 128)
{
this.writeUInt8(Number(num));
return;
}
let bitString = BigInt(num).toString(2);
const bitLength = bitString.length;
const blocks = Math.ceil(bitLength / 7);
// Pad the bit string to be divisible by 7
const remainder = blocks * 7 - bitLength;
if (remainder > 0)
{
bitString = '0'.repeat(remainder) + bitString;
}
for (let x = 0; x < bitString.length; x = x + 7)
{
// The first bit in every byte is a continuation indicator
// 0 = last byte
// 1 = more bytes to follow
let byte = parseInt(bitString.substring(x, x + 7), 2);
if (x + 7 !== bitString.length)
{
byte = byte | 0x80;
}
this.writeUInt8(byte);
}
}
这就是完成解箱的方式:
public readPackedNumber(): bigint | number
{
let byte = this.readUInt8();
if (byte < 128)
{
return byte;
}
let finalNumber = BigInt(byte & ~ 0x80);
while (byte & 0x80)
{
byte = this.readUInt8();
finalNumber = finalNumber << 7n;
finalNumber += BigInt(byte & ~ 0x80);
}
if (finalNumber <= Number.MAX_SAFE_INTEGER)
{
return Number(finalNumber);
}
return finalNumber;
}
但是,我担心的是包装过程,尤其是bigint(num).tostring(2)
和字符串操作在该功能中可能是性能猪。
理想情况下,我想找到一种无需二进制/字符串转换的方法,同时维持对bigint
的支持 - 没有Math.log2函数,而我在网上发现的功能只需ToString(2)
。
谁能提出任何绩效改进?
I'm designing a binary protocol where I have a need to specify the length of a chunk of data (of arbitrary length) before providing the data itself.
I cannot use a terminator character (like a c-string) because the binary data which follows might include that character, and the process of escaping / unescaping would be computationally expensive.
In almost all cases, the length of the data is small (less than 128 bytes), but in some cases it's much larger, and I want to be as efficient as possible.
I've adopted a simplified version of the UTF-8 bit packing process where:
- Data is divided into 7-bit chunks
- The first bit of each byte indicates whether it's the last byte (0 = last byte, 1 = more bytes to follow)
This means that numbers of 127 or less can be written and read trivially, but larger numbers are more complex.
This is how i'm doing the bit packing:
public writePackedNumber(num: bigint | number): void
{
if (num < 128)
{
this.writeUInt8(Number(num));
return;
}
let bitString = BigInt(num).toString(2);
const bitLength = bitString.length;
const blocks = Math.ceil(bitLength / 7);
// Pad the bit string to be divisible by 7
const remainder = blocks * 7 - bitLength;
if (remainder > 0)
{
bitString = '0'.repeat(remainder) + bitString;
}
for (let x = 0; x < bitString.length; x = x + 7)
{
// The first bit in every byte is a continuation indicator
// 0 = last byte
// 1 = more bytes to follow
let byte = parseInt(bitString.substring(x, x + 7), 2);
if (x + 7 !== bitString.length)
{
byte = byte | 0x80;
}
this.writeUInt8(byte);
}
}
And this is how the unpacking is done:
public readPackedNumber(): bigint | number
{
let byte = this.readUInt8();
if (byte < 128)
{
return byte;
}
let finalNumber = BigInt(byte & ~ 0x80);
while (byte & 0x80)
{
byte = this.readUInt8();
finalNumber = finalNumber << 7n;
finalNumber += BigInt(byte & ~ 0x80);
}
if (finalNumber <= Number.MAX_SAFE_INTEGER)
{
return Number(finalNumber);
}
return finalNumber;
}
However, my concern is the packing process, particularly BigInt(num).toString(2)
and the string operations in that function which are likely to be a performance hog.
Ideally, I would like to find a way to do this without binary/string conversions, whilst maintaining support for bigint
- there's no Math.log2 function for bigint, and the ones I've found online just do toString(2)
also.
Can anyone come up with any performance improvements?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论