一个字节中的两个值
Two values in one byte
在一个半字节 (0-F) 中,我可以存储一个从 0 到 15 的数字。在一个字节中,我可以存储一个从 0 到 255 (00 - FF) 的数字。
我可以使用一个字节 (00-FF) 来存储两个不同的数字,每个数字都在 0-127 (00 - 7F) 范围内吗?
你的问题的答案是否定的。您可以将单个字节拆分为两个数字,但是两个数字中的位之和必须 <= 8。因为,范围 0-127 需要 7 位,另一个数字in byte只能是1位,即0-1.
显然 cardinality reasons, you cannot store two small integers in the 0 ... 127 range in one byte of 0 ... 255 range. In other words the cartesian product [0;127]×[0;127] 有 214 个元素大于 28([0;255]区间的基数,for bytes)
(如果你能承受失去精度的后果 - 你没有告诉 - 你可以,例如只存储最高位...)
也许你的问题是:我可以在一个字节中存储来自 [0;15] 的两个小整数吗?那么你当然可以:
typedef unsigned unibble_t; // unsigned nibble in [0;15]
uint8_t make_from_two_nibbles(unibble_t l, unibble_t r) {
assert(l<=15);
assert(r<=15);
return (l<<4) | r;
}
unibble_t left_nible (uint8_t x) { return x >> 4; }
unibble_t right_nibble (uint8_t) { return x & 0xf; }
但我认为您不应该总是那样做。首先,您可以在 struct
中使用位域。然后(也是最重要的)以这种方式处理半字节可能比使用字节更低效并且代码可读性更差。
并更新单个半字节,例如与
void update_left_nibble (uint8_t*p, unibble_t l) {
assert (p);
assert (l<=15);
*p = ((l<<4) | ((*p) & 0xf));
}
有时很昂贵(它涉及内存加载和内存存储,因此使用 CPU cache and cache coherence machinery), and most importantly is generally a non-atomic operation (what would happen if two different threads are calling simultaneously update_left_nibble
on the same address p
-i.e. with pointer aliasing- is undefined behavior)。
根据经验,避免在一个字节中打包多个数据项,除非您确定这样做是值得的(例如,您有十亿个此类数据项)。
您可以在单个字节中存储两个数据在 0-15 范围内,但您不应该这样做(一个 var = 一个数据是更好的设计)。
如果必须,您可以使用位掩码和位移来访问变量中的两个数据。
uint8_t var; /* range 0-255 */
data1 = (var & 0x0F); /* range 0-15 */
data2 = (var & 0xF0) >> 4; /* range 0-15 */
Can I use a byte to store two numbers in the range 0-127?
当然可以:
uint8_t storeTwoNumbers(unsigned a, unsigned b) {
return ((a >> 4) & 0x0f) | (b & 0xf0);
}
uint8_t retrieveTwoNumbers(uint8_t byte, unsigned *a, unsigned *b) {
*b = byte & 0xf0;
*a = (byte & 0x0f) << 4;
}
数字仍在 0...127 范围内(实际上是 0...255)。您只是失去了一些精度,类似于浮点类型。它们的值以 16 为步长递增。
一个字节对于 0…127 中的两个值是不够的,因为每个值都需要 log2(128) = 7 位,总共 14 个,但是一个字节只有8位。
您可以使用 C 和 C++ bitfield 语法声明具有位压缩存储的变量:
struct packed_values {
uint8_t first : 7;
uint8_t second : 7;
uint8_t third : 2;
};
在此示例中,sizeof(packed_values)
应等于 2,因为尽管具有三个字段,但仅使用了 16 位。
这比使用 <<
和 &
运算符的按位运算更简单,但它仍然与普通变量不完全相同:位域没有地址,所以你不能指向一个的指针(或 C++ 引用)。
在一个半字节 (0-F) 中,我可以存储一个从 0 到 15 的数字。在一个字节中,我可以存储一个从 0 到 255 (00 - FF) 的数字。 我可以使用一个字节 (00-FF) 来存储两个不同的数字,每个数字都在 0-127 (00 - 7F) 范围内吗?
你的问题的答案是否定的。您可以将单个字节拆分为两个数字,但是两个数字中的位之和必须 <= 8。因为,范围 0-127 需要 7 位,另一个数字in byte只能是1位,即0-1.
显然 cardinality reasons, you cannot store two small integers in the 0 ... 127 range in one byte of 0 ... 255 range. In other words the cartesian product [0;127]×[0;127] 有 214 个元素大于 28([0;255]区间的基数,for bytes)
(如果你能承受失去精度的后果 - 你没有告诉 - 你可以,例如只存储最高位...)
也许你的问题是:我可以在一个字节中存储来自 [0;15] 的两个小整数吗?那么你当然可以:
typedef unsigned unibble_t; // unsigned nibble in [0;15]
uint8_t make_from_two_nibbles(unibble_t l, unibble_t r) {
assert(l<=15);
assert(r<=15);
return (l<<4) | r;
}
unibble_t left_nible (uint8_t x) { return x >> 4; }
unibble_t right_nibble (uint8_t) { return x & 0xf; }
但我认为您不应该总是那样做。首先,您可以在 struct
中使用位域。然后(也是最重要的)以这种方式处理半字节可能比使用字节更低效并且代码可读性更差。
并更新单个半字节,例如与
void update_left_nibble (uint8_t*p, unibble_t l) {
assert (p);
assert (l<=15);
*p = ((l<<4) | ((*p) & 0xf));
}
有时很昂贵(它涉及内存加载和内存存储,因此使用 CPU cache and cache coherence machinery), and most importantly is generally a non-atomic operation (what would happen if two different threads are calling simultaneously update_left_nibble
on the same address p
-i.e. with pointer aliasing- is undefined behavior)。
根据经验,避免在一个字节中打包多个数据项,除非您确定这样做是值得的(例如,您有十亿个此类数据项)。
您可以在单个字节中存储两个数据在 0-15 范围内,但您不应该这样做(一个 var = 一个数据是更好的设计)。
如果必须,您可以使用位掩码和位移来访问变量中的两个数据。
uint8_t var; /* range 0-255 */
data1 = (var & 0x0F); /* range 0-15 */
data2 = (var & 0xF0) >> 4; /* range 0-15 */
Can I use a byte to store two numbers in the range 0-127?
当然可以:
uint8_t storeTwoNumbers(unsigned a, unsigned b) {
return ((a >> 4) & 0x0f) | (b & 0xf0);
}
uint8_t retrieveTwoNumbers(uint8_t byte, unsigned *a, unsigned *b) {
*b = byte & 0xf0;
*a = (byte & 0x0f) << 4;
}
数字仍在 0...127 范围内(实际上是 0...255)。您只是失去了一些精度,类似于浮点类型。它们的值以 16 为步长递增。
一个字节对于 0…127 中的两个值是不够的,因为每个值都需要 log2(128) = 7 位,总共 14 个,但是一个字节只有8位。
您可以使用 C 和 C++ bitfield 语法声明具有位压缩存储的变量:
struct packed_values {
uint8_t first : 7;
uint8_t second : 7;
uint8_t third : 2;
};
在此示例中,sizeof(packed_values)
应等于 2,因为尽管具有三个字段,但仅使用了 16 位。
这比使用 <<
和 &
运算符的按位运算更简单,但它仍然与普通变量不完全相同:位域没有地址,所以你不能指向一个的指针(或 C++ 引用)。