【问题标题】:Is there a practical limit to the size of bit masks?位掩码的大小是否有实际限制?
【发布时间】:2008-10-07 02:44:48
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: sql bit-manipulation bitmask


    【解决方案1】:

    在我的脑海中,我会编写一个 set_bitget_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));
    }
    

    【讨论】:

      【解决方案2】:

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

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

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

      我的 2 美分。

      【讨论】:

      • 那么您是否建议将其作为可变长度的二进制字段(BLOB?)存储在数据库中,然后在处理它时转换为布尔数组?这可以工作 - 您应该在数据库中使用什么数据类型?
      【解决方案3】:

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

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

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

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

      【讨论】:

      • 是的,我的意思是“64 个标志”(2 ^ 64),而不是“64 个组合”(2 ^ 6)。
      • 我想这就是你的意思,但想在我的回答中澄清:)
      【解决方案4】:

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

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

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

      当您必须打开一个常量表来调试代码时,您就知道自己做得太过分了。

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            【解决方案7】:

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

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

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

            【讨论】:

            • 是的,mysql 数据类型 BIGINT 是 64 位的。如果您需要超过 64 个标志,我想知道使用哪种字段类型。
            • Microsoft SQL Server 有一个有趣的优化,它可以将最多 8 位列打包到行中的一个字节中。文档中没有提到表可以拥有的位列数的上限。这种优化允许您将每个位视为一个单独的实体,并让引擎负责存储、检索和更新它。
            猜你喜欢
            • 2015-11-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-10-23
            相关资源
            最近更新 更多