- 浏览: 202836 次
- 性别:
- 来自: 重庆
文章分类
最新评论
数值压缩存储方法Varint
- 博客分类:
- c++
转自:http://www.cnblogs.com/smark/archive/2012/05/03/2480034.html
在编写网络通讯的时候我们经常需要把一些数据存储到byte[]中然后再发送出去,数值则是我们经常处理的数据成员。发越少的东西意味着使用更少的IO和带宽 ,所以对传输数据进行压缩也是件非常重要的事情。接下来提到的就是一种基于数字存储的方式在大多数情况下可以节省数值存储空间。
Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。比如对于 int32 类型的数字,一般需要 4 个 byte 来表示。但是采用 Varint,对于很小的 int32 类型的数字,则可以用 1 个 byte 来表示。当然凡事都有好的也有不好的一面,采用 Varint 表示法,大的数字则需要 5 个 byte 来表示。从统计的角度来说,一般不会所有的消息中的数字都是大数,因此大多数情况下,采用 Varint 后,可以用更少的字节数来表示数字信息。下面就详细介绍一下 Varint。
Varint 中的每个 byte 的最高位 bit 有特殊的含义,如果该位为 1,表示后续的 byte 也是该数字的一部分,如果该位为 0,则结束。其他的 7 个 bit 都用来表示数字。因此小于 128 的数字都可以用一个 byte 表示。大于 128 的数字,比如 300,会用两个字节来表示:1010 1100 0000 0010
由于负数的高位为1,所以采用这种压缩处理的时候必须负数转成正数,可以通过以下代码实现int to uint的转换
private static int Zag(uint ziggedValue)
{
int value = (int)ziggedValue;
return (-(value & 0x01)) ^ ((value >> 1) & ~( 1<< 31));
}
private static uint Zig(int value)
{
return (uint)((value << 1) ^ (value >> 31));
}
以下操作是对一个uint进行编码处理
private static ArraySegment<byte> WriteUInt32Variant(uint value)
{
byte[] data = new byte[5];
int count = 0;
do
{
data[count] = (byte)((value & 0x7F) | 0x80);
count++;
} while ((value >>= 7) != 0);
data[count - 1] &= 0x7F;
return new ArraySegment<byte>(data, 0, count);
}
data[count] = (byte)((value & 0x7F) | 0x80); 得到头7位的数值, | 0x80是表明后面的byte也是数字的一部分。
while ((value >>= 7) != 0) 右移7位如果不为零的情况下则继续上面的工作。
data[count - 1] &= 0x7F 把最后byte的最高位设置成0;
接下来就是一个uint的解码过程
private static uint ReadUInt32Variant(ArraySegment<byte> data)
{
uint value = data.Array[0];
if ((value & 0x80) == 0) return value;
value &= 0x7F;
uint chunk = data.Array[1];
value |= (chunk & 0x7F) << 7;
if ((chunk & 0x80) == 0) return value;
chunk = data.Array[2];
value |= (chunk & 0x7F) << 14;
if ((chunk & 0x80) == 0) return value;
chunk = data.Array[3];
value |= (chunk & 0x7F) << 21;
if ((chunk & 0x80) == 0) return value;
chunk = data.Array[4]; ;
value |= chunk << 28;
if ((chunk & 0xF0) == 0) return value;
throw new OverflowException("ReadUInt32Variant Error!");
}
(value & 0x80) == 0 表示最高位为0,说明后面的byte已经不是数值组成部分。
(chunk & 0xF0) == 0 chunk只有4位,如果不是则表明这个byte不是数值存储的一部分。
测试一下看下编码效果
ArraySegment<byte> data = WriteUInt32Variant(Zig(0));
Console.WriteLine(data.Count);
data = WriteUInt32Variant(Zig(567));
Console.WriteLine(data.Count);
data = WriteUInt32Variant(Zig(10000));
Console.WriteLine(data.Count);
data = WriteUInt32Variant(Zig(-100000));
Console.WriteLine(data.Count);
分别是1byte,2byte,3byte,3byte
其实有人会有凝问,为什么不根据情况来用int16等来存储,如果一旦用了int16就说明以后需要转int32就是件非常麻烦的事情,双方程序都需要调整。如果采用Varint进行处理就能达到最好扩展效果和带宽利用率.
发表评论
-
C++的原子操作
2012-12-20 17:43 4660在多进程(线程)访问资源时,能够确保所有其他的进程(线程 ... -
匿名namespace的作用以及它与static的区别
2012-12-20 17:24 1774一。匿名namespace的作用 在C语言中,如果我们 ... -
C++类型萃取技术
2012-12-19 15:16 1118Traits技术可以用来获得一个 类型 的相关信息的。 ... -
TypeList
2012-12-19 13:49 1123转自:http://blog.csdn.n ... -
template <unsigned int N>
2012-12-19 11:51 1468详见:http://stackoverflow.com/ ... -
二维指针*(void **)的研究(uC/OS-II案例)
2012-12-19 22:20 3259原文 : http://blog.csdn ... -
多级指针和链表
2012-12-18 22:28 0如果看到一个声明:t ... -
理解*(void**)b
2012-12-18 22:03 0#include <stdio.h> ... -
STL标准库:Allocator能做什么
2012-12-18 20:10 0The Standard Librarian: Wha ... -
三种的allocator实现源代码的对比
2012-12-18 19:55 1288转自:http://blog.csdn.net ... -
结构体内变量相对便宜与list_entry()宏
2012-12-18 17:59 909#define list_entry(ptr, t ... -
声明与函数、函数指针---(*(void (*)( ) )0)( ) 解析
2012-12-18 17:33 1085概述 在很 ... -
c++模板(类型依赖)说明例子
2012-12-18 16:57 1132#include <iostream> # ... -
C++中三种new的用法
2012-12-18 16:44 1818我评价自己的C++水平还未入门的确不够准确,应该是远远未 ... -
C++,永久改变你写异常安全代码的方式(神奇的Loki::ScopeGuard)
2012-12-17 20:19 2484作者:Andrei Alexandrescu and P ... -
C++的make_pair函数
2012-12-17 17:19 3437Pairs C++标准程序库中凡是“必须返回两 ... -
C++的explicit构造函数
2012-12-13 15:59 628按照默认规定,只有一个参数的构造函数也定义了一个隐式转换 ...
相关推荐
实现Varint + ZigZag的编解码过程,里面有我自己对Vint编解码实现的算法 ,VInt编码为Varint编码和ZigZag编码的结合,为一种将64位二进制编码的有符号整型编码在最多10字节中的编码方式。Varint编码为一种将64位二...
实现Varint + ZigZag的编解码过程,里面有我自己对Vint编解码实现的算法 ,VInt编码为Varint编码和ZigZag编码的结合,为一种将64位二进制编码的有符号整型编码在最多10字节中的编码方式。Varint编码为一种将64位二...
前端开源库-signed-varint有符号变量,有效地将有符号整数存储在变量中
瓦林特一个小的 C 扩展,用于加速协议缓冲区中的 varint。安装将此行添加到应用程序的 Gemfile 中: gem 'varint'然后执行: $ bundle或者自己安装: $ gem install varint贡献分叉吧创建您的功能分支( git ...
前端开源库-signed-varint.zip
varint-simd是用Rust编写的快速SIMD加速的可变长度整数编码器和解码器。 它旨在用于协议缓冲区(protobuf),Apache Avro和类似的序列化格式的实现中。 varint-simd varint-simd是用Rust编写的快速SIMD加速的可变...
包含vcpkg安装cryptopp / ms-gsl / varint 所需下载的安装资源包,以及windows下cmd运行所需的PowerShell-6.2.1-win-x86安装包,解压出来放在vcpkg的downloads目录下即可使用。
flat-tree将二叉树映射到列表。 改编自mafintosh / flat-tree。 文档Crates.io用法extern crate flat_tree; let parent = flat_tree flat-tree将二叉树映射到列表。 改编自mafintosh / flat-tree。...
Varint编码和Fibonacci编码
戈瓦林特 该项目旨在为使用各种算法的 32 位和 64 位整数的高性能编码和解码提供一个简单的 API。 用法 每个整数编码算法都符合一个编码和解码接口。 接口还指定了无符号整数的大小,32 位或 64 位,下面将称为 XX。...
迷你版 protobuf 的迷你编解码器。 在 C 中实现。 例子: # include # include # include # include " pb_codec.h " /* message msg ... optional uint32 uint32_id = 1;... pb_encode_varint (enc_pb_buf,
StreamVByte是一种新的整数压缩技术,该技术将SIMD指令(矢量化)应用于Google的Group Varint方法。 最终结果比其他面向字节的压缩技术要快。 该方法是免专利的,代码可在Apache许可下获得。 它包括快速差分编码...
长度前缀缓冲区 将缓冲区数组编码和解码为单个长度前缀的二进制Blob 用于编码,将缓冲区数组转换为单个缓冲区 用于解码,将单个缓冲区转换为缓冲区数组 在nodejs和浏览器中工作,并且在为浏览器编译时不引入Buffer...
DECLARE @VARINT VARCHAR(50) --一定要赋初值,不然在循环中@NUM的值不会改变 SELECT @NUM = 0 OPEN T FETCH NEXT FROM T INTO @VARINT WHILE @@FETCH_STATUS = 0 BEGIN SELECT @NUM = @NUM+1
Varint: Varint最多可容纳64位数据(BitShares / Steem从32位增加)。 八位位组的第一位标志varint是否继续(1代表连续,0代表停止)。 为了对带符号的varint进行编码,在将现在无符号的值编码为varint之前,首先...
前言: Protobuf解析目前圈子没见过一个能[一次...①如果类型是Varint(0),那么key-value对应的就是varint-varint ②如果是类型Length_delimited(2),对应的就是varint-varint(valueLen)-value ③其他类型和Varint类型类似
这是检查变量是否已设置并evaluate默认值(取决于变量类型)的简单方法。安装方式npm install -- save evaluate如何使用评估(变量,类型,默认值) 评估函数需要一个变量和一个类型才能起作用。 在其他情况下,它...
整数编码 该板条箱提供了字节串表示形式与整数之间的整数编码和解码。 格式描述如下: 。 请随时使用cargo bench... VarInt以7位为块对整数进行编码; MSB会为每个字节(最后一个字节)清零,最后一个字节将被清零。
DENSE寄存器的位打包可实现更好的压缩。 带有位打包的序列化超日志大小,对于数百万个不同的项目,约为10KB,对于数十亿个不同的项目,约为12K。 禁用位打包时,序列化的大小为〜16KB。 SPARSE寄存器的增量编码和...
// encode 1000 as a varint into buf. returns how many bytes it wrotelet bytes_encoded = varinteger :: encode ( 1000 , buf);let mut value = 0u64 ;let bytes_decoded = varinteger :: decode (buf, & mut ...