5

有一种常见的方法是使用位掩码将多个值存储在一个变量中。例如,如果用户对某项具有读、写和执行权限,则可以通过说将其转换为单个数字read = 4 (2^2), write = 2 (2^1), execute = 1 (2^0),然后将它们相加得到 7。

我在几个 Web 应用程序中使用了这种技术,我通常将变量存储到一个字段中,并根据不同值的数量给它一种 MEDIUMINT 或其他类型。

我感兴趣的是,您可以像这样存储的值的数量是否有实际限制?例如,如果数字超过 64,则不能再使用(64 位)整数。如果是这样的话,你会用什么?它将如何影响您的程序逻辑(即:您仍然可以使用按位比较)吗?

我知道,一旦您开始获得非常大的值集,另一种方法将是最佳解决方案,但我对这种方法的边界感兴趣。

4

7 回答 7

3

在我的脑海中,我会编写一个set_bitandget_bit函数,它可以获取一个字节数组和数组中的一个位偏移,并使用一些位旋转来设置/获取数组中的适当位。像这样的东西(在 C 中,但希望你明白):

// sets the n-th bit in |bytes|. num_bytes is the number of bytes in the array
// result is 0 on success, non-zero on failure (offset out-of-bounds)
int set_bit(char* bytes, unsigned long num_bytes, unsigned long offset)
{
  // make sure offset is valid
  if(offset < 0 || offset > (num_bytes<<3)-1) { return -1; }

  //set the right bit
  bytes[offset >> 3] |= (1 << (offset & 0x7));

  return 0; //success 
}

//gets the n-th bit in |bytes|. num_bytes is the number of bytes in the array
// returns (-1) on error, 0 if bit is "off", positive number if "on"
int get_bit(char* bytes, unsigned long num_bytes, unsigned long offset)
{
  // make sure offset is valid
  if(offset < 0 || offset > (num_bytes<<3)-1) { return -1; }

  //get the right bit
  return (bytes[offset >> 3] & (1 << (offset & 0x7));
}
于 2008-10-07T03:03:48.797 回答
2

我在文件系统代码中使用了位掩码,其中位掩码比机器字大很多倍。把它想象成一个“布尔数组”;

(如果你想知道,闪存中的日志掩码)

许多编译器知道如何为您执行此操作。添加一点 OO 代码以使类型能够合理地运行,然后您的代码开始看起来像它的意图,而不是一些位敲打。

我的 2 美分。

于 2008-10-07T02:50:53.597 回答
1

使用 64 位整数,您最多可以存储 2^64-1 的值,64 仅为 2^6。所以是的,有一个限制,但如果你需要超过 64 个标志,我很想知道他们都在做什么 :)

你需要考虑多少个州?如果您有 64 个潜在状态,则它们可以存在的组合数是 64 位整数的完整大小。

如果您需要担心 128 个标志,那么一对位向量就足够了 (2^64 * 2)。

另外:在 Programming Pearls 中,有一个关于使用长度为 10^7 的位数组的扩展讨论,以整数实现(用于保存使用过的 800 个数字)——它非常快,非常适合该章中描述的任务。

于 2008-10-07T02:50:53.783 回答
1

某些语言(我相信 perl 确实如此,不确定)允许对字符串进行按位算术。为您提供更大的有效范围。( (strlen * 8bit chars) 组合)

但是,我不会使用单个值来叠加多个 /type/ 数据。3 位整数的基本 r/w/x 三元组可能是“实际”上限,不是出于空间效率原因,而是出于实际开发原因。

( PHP 使用这个系统来控制它的错误消息,我已经发现当你必须定义 php 的常量不驻留的值并且你必须手动生成整数时,它有点过头了,并且老实说,如果 chmod 不支持 'ugo+rwx' 风格的语法,我永远不想使用它,因为我永远记不起幻数)

当你必须打开一个常量表来调试代码时,你就知道你已经走得太远了。

于 2008-10-07T03:04:15.113 回答
1

旧线程,但值得一提的是,有些情况需要膨胀的位掩码,例如分子指纹,它们通常生成为 1024 位数组,我们将其打包在 32 个 bigint 字段中(SQL Server 不支持 UInt32)。位操作工作正常 - 直到您的表开始增长并且您意识到单独的函数调用的缓慢性。如果不是因为 T-SQL 禁止具有两个二进制操作数的位运算符,二进制数据类型将起作用。

于 2013-09-22T03:53:34.227 回答
0

例如,.NET 使用整数数组作为其 BitArray 类的内部存储。几乎没有其他办法。

话虽如此,在 SQL 中,您将需要不止一列(或使用 BLOBS)来存储所有状态。

于 2008-10-07T02:57:47.827 回答
0

您将此问题标记为 SQL,因此我认为您需要查阅数据库的文档以查找整数的大小。然后为符号减去一位,以防万一。

编辑:您的评论说您正在使用 MySQL。MySQL 5.0 Numeric Types的文档指出 NUMERIC 的最大大小为 64 或 65 位。那是 64 位的 212 位。

请记住,您选择的语言必须能够处理这些数字,因此无论如何您都可能被限制为 64 位整数。

于 2008-10-07T03:06:38.807 回答