Character encoding 用一个字节表示3个整数?
我有三个整数{Character encoding 用一个字节表示3个整数?,character-encoding,binary-data,primitive-types,Character Encoding,Binary Data,Primitive Types,我有三个整数{a,b,c},范围(比如)在以下值之间: a-{1到120,以1}的跳跃 b-{-100到100,跳跃5} c-{1到10,以1}的跳跃方式 出于空间考虑,我只想使用1字节来表示这三个值,也就是说,单个整数(范围为-127..128)将表示{a,b,c}的结果,并以二进制格式存储到磁盘 稍后,当我读取二进制数据时,我将知道如何“解析”这个1字节以获得{a,b,c}的值 你知道怎么做到吗?(注意:如果需要,为了支持此设计,我可以在范围上“折衷”;例如,a可以跳转5次。b也可以跳转10
a
,b
,c
},范围(比如)在以下值之间:
a
-{1到120,以1}的跳跃
b
-{-100到100,跳跃5}
c
-{1到10,以1}的跳跃方式
出于空间考虑,我只想使用1字节来表示这三个值,也就是说,单个整数(范围为-127..128)将表示{a
,b
,c
}的结果,并以二进制格式存储到磁盘
稍后,当我读取二进制数据时,我将知道如何“解析”这个1字节以获得{a
,b
,c
}的值
你知道怎么做到吗?(注意:如果需要,为了支持此设计,我可以在范围上“折衷”;例如,
a
可以跳转5次。b
也可以跳转10次等)仅从数字的角度来看,我们有:
a=120个值,b=41个值,c=10个值
这使得总共有49200个唯一值。一个字节只能表示256个值,因此您需要使用至少16位(两个字节)来表示您的范围
一种方法是通过位移位
例如,您可以在32位值中存储四个8位值,并按如下方式提取它们:
#include <iostream>
using namespace std;
int pack32(char *v)
{
return (v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3];
}
void unpack32(int a, char *v)
{
v[0] = a >> 24;
v[1] = a >> 16;
v[2] = a >> 8;
v[3] = a;
}
int main()
{
char v[4] = {32, 64, 16, 8};
cout << "Original values: ";
for (int i = 0; i < 4 ; i++)
cout << (int)v[i] << " ";
cout << endl;
int q = pack32(v);
cout << "Packed: " << q << endl;
unpack32(q, v);
cout << "Unpacked: ";
for (int i = 0; i < 4; i++)
cout << (int)v[i] << " ";
return 0;
}
#包括
使用名称空间std;
int pack32(字符*v)
{
返回(v[0]>16;
v[2]=a>>8;
v[3]=a;
}
int main()
{
charv[4]={32,64,16,8};
couta-{1到120,在1}=120的跳跃中,值=log2(120)=6.9位
b-{-100到100,在5}=41的跳跃中,值=log2(41)=5.4位
c-{1到10,在1}=10的跳跃中,值=log2(10)=3.3位
Total=15.6位,因此您可以将所有这些数据打包成一个16位值,但不能打包成一个8位字节。要将所有数据打包成一个字节,您需要在范围上做出很大让步
为简单起见,您可能希望将每个值存储在整数位中,因此请计算出每个值需要多少位。例如,您可以使用:
- a(3位)
- b(3位)
- c(2位)
这将为a
提供8个不同的值,为b
提供8个不同的值,为c
提供4个不同的值。当然,这比您最初拥有的信息要少得多。一旦您选择了这样的方案,剩下的只是:
- 将每个原始值转换为其“压缩”模式(例如,对于
a
,可以将1表示为0,将120表示为7)
- 将三个压缩值合并为一个字节(使用位移位和按位或)
- 随后将单个字节拆分为三个压缩值(使用位移位和掩蔽)
- 将每个压缩值转换为合理接近原始值的“未压缩”值
根据迈克的回答,但数字正确:
a=120个值,b=41个值,c=10个值
一个字节只能代表256个值,因此您需要至少使用16位(两个字节)来表示您的范围
现在让我们假设我们想要使用不同的位来表示这些数字中的每一个(即,没有以某种方式混合这些数字的压缩):
a
适合7位,b
适合6位,c
适合4位。(所谓“适合”,我的意思是这是数据可以容纳的最小整数位数。)这是17位,因此,在不应用某种压缩的情况下,您可以为每个值使用单独的字节
现在,让我们讨论一种方法,通过改变这些值中的步长,使其适合一个字符
您可以将这些值分成两个2位值(每个允许4个值)和一个4位值。或者您可以将这些值分成两个3位值(每个允许8个值)和一个2位值。您可以决定如何将它们分配给变量a
、b
和c
在C中存储这些数据的最佳方法是使用包含位字段的结构:
struct myvalues{
unsigned a:3;
signed b:3;
unsigned c:2;
};
//look at your compiler and platform documentation
//to make sure you can pack this properly
然后,您可以直接按名称访问字段a
、b
和c
(尽管您需要做一些数学运算来转换值)
其他语言(Java、C#等)在定义类型方面没有那么灵活,因此您需要在这些语言中使用位移位。如果我在范围上妥协会怎么样?使用与上述相同的方法,并使用新的范围再次计算位数。谢谢。我需要log2(X)
计算位数的说明。这篇文章讨论了给定所需范围的信息理论最小值。要真正实现这一点,需要使用某种压缩算法或映射表,可以适当地混合不同位数的位数。如果你想让简单的代码读和写这些值(即每个变量的位是分开的),您需要将位数四舍五入到最接近的整数,在这种情况下,此处显示的结果将是18位。@Ken:您不需要对每个组件的位数进行四舍五入,除非可能需要考虑打包/解包的效率。并且您不需要非常复杂的编码方案。例如,如果x、y和z的范围都为0..9然后你可以将其编码为100*x+10*y+z,也就是说,你不需要为每个字符使用4位,你可以用10位来完成整个过程。谢谢。如果我在范围上妥协怎么办?@Mike:你的代码向他展示了如何将信息打包成32位整数。你只需创建struct x{unsigned char a;signed char b;unsigned char c;}
如果你要用位移位来做这个,告诉他如何把它压缩成16位,而位移位不是8的倍数。我现在脑子里有个屁。我
struct myvalues{
unsigned a:3;
signed b:3;
unsigned c:2;
};
//look at your compiler and platform documentation
//to make sure you can pack this properly