int压缩编码

Varint编码

正常来说int在32位系统中,是4个字节长度,但如果你只需要存储100,1000这些比较小但数字但时候,依旧使用4个字节,这样其实就浪费了空间(其实提升了计算速度,因为不用计算)。换种思路,有没有一种编码能实现类似字符串的结构,不定长int呢,答案就是varint编码

Varint编码是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。

Varint 中的每个 byte 的最高位 bit 有特殊的含义,如果该位为 1,表示后续的 byte 也是该数字的一部分,如果该位为 0,则结束。其他的 7 个 bit 都用来表示数字。因此小于 128 的数字都可以用一个 byte 表示。大于 128 的数字,会用两个字节。每8位的第一位是最高有效位(most significant bit - msb)

例如整数1的表示,仅需一个字节:

采用 Varint,对于很小的 int32 类型的数字,则可以用 1 个 byte 来表示。但反过来,采用 Varint 表示法,大的数字则需要 5 个 byte 来表示。从统计和使用的角度来说,一般不会所有的消息中的数字都是大数,而且一般使用的时候都是从小到大,因此大多数情况下,采用 Varint 后,可以用更少的字节数来表示数字信息。

由于负数的高位为1,所以采用这种压缩处理的时候必须负数转成正数。

对数字666进行varint编码,666用二进制表示为

0000 0000 0000 0000 0000 0010 1001 1010

Varint编码就是每次从低向高取7位再加上最高有效位变成

1000 0101 0001 1010

zigzag编码

对于负数来说,因为最高位符号位始终为1,使用varint编码就很浪费空间,zigzag编码就是解决负数的问题的,同时其对正数也没有很大的影响。

int类型zigzag变换的公式 (n << 1) ^ (n >> 31)

步骤:

  • 左移1位可以消去符号位,低位补0
  • 有符号右移31位将符号位移动到最低位,负数高位补1,正数高位补0
  • 按位异或
  • 对于正数来说,最低位符号位为0,其他位不变
  • 对于负数,最低位符号位为1,其他位按位取反

-1的二进制表示为11111111 11111111 11111111 11111111,zigzag变换后00000000 00000000 00000000 00000001,再用varint编码,是不是很小了。

1的二进制表示为00000000 00000000 00000000 00000001,zigzag变换后00000000 00000000 00000000 00000010,再用varint编码,依然很小。

引用文章1

应用场景

levelDB就是将int存储为varint

添加新评论