我有一个可以取任意 3 个值的变量。如果它只能取 2 个值,我会分配一个 bool 类型。但我的变量可以取 3 个值。如果我分配一个 int8_t 类型,我会浪费 6 位。虽然这看起来像是抢先优化,但我有数百万个这种类型的实例,这将对内存使用产生巨大影响。
我应该将变量分配给什么数据类型,以便总体使用最少的内存。
如果我用枚举来做,那会确保使用更少的内存吗?
特别是我应该在 C、Java、Python 和 MySQL 中使用什么数据类型。
这里有一点数学:天真地,您可以用两位来描述每个元素,因此您可以将四个元素打包到一个字节中并获得不错的随机访问。四个元素有 3 4 = 81 个状态,因此使用率为 81 / 256 ≈ 32%。如果您想停留在字节边界上,您可以寻找适合 2 8的最接近的 3 次幂,即 3 5 = 243。换句话说,如果您用一个字节来枚举五个连续元素的所有可能状态,您的空间效率为 243 / 256 ≈ 95%。
除非您正在处理大量数据并且无法将所有内容都放入物理内存并且无法将您的算法分区以一次在较小的块上运行,否则在内存中进行这种打包是没有意义的。为了高效计算,您至少应该使用一个字节 ( uint8_t
),甚至是一个机器字 ( uint8fast_t
) 来存储您的数据。只有当您将数据序列化到磁盘并发现您的 TB 数据对于您的 RAID-50 存储来说过于昂贵时,您才可能希望考虑使用复杂的打包方案。(虽然你可以再次通过管道传输你的数据gzip
,这基本上可以为你完成所有这些。)
这是一个基本的解码算法,用于从一个字节中获取五个元素:
unsigned int get_tristate(unsigned char const n, size_t const i)
{
/* Conditions: n in [0, 243)
i in [0, 5)
Returns: the i^th trivalent element encoded in n, in [0, 2).
*/
static unsigned int const powers[] = { 1, 3, 9, 27, 81, 243 };
return (n / powers[i]) % powers[i + 1];
}
如果你真的(虽然我不确定是不是这样)需要这种数据类型,你可以使用位域。但是,这可能会受到限制,因为您无法定义指向此类类型的指针。浪费一点:
struct s
{
int n:2; /* 4 states instead of 3 */
};