【问题标题】:How to define 2-bit numbers in C, if possible?如果可能,如何在 C 中定义 2 位数字?
【发布时间】:2010-03-23 12:55:05
【问题描述】:

对于我的大学过程,我正在模拟一个称为随机顺序吸附的过程。 我必须做的一件事是将正方形(不能重叠)随机放置到格子上,直到没有更多空间为止,重复该过程几次以找到平均“干扰”覆盖率。

基本上,我正在对大量整数执行操作,其中存在 3 个可能的值:0、1 和 2。标有“0”的站点是空的,标有“1”的站点是满的。最初数组是这样定义的:

int i, j;
int n = 1000000000;
int array[n][n];

for(j = 0; j < n; j++)
{
    for(i = 0; i < n; i++)
    {
        array[i][j] = 0;
    }
}

假设我想在数组上随机放置 5*5 个方块(不能重叠),这样方块就用 '1' 表示。这可以通过随机选择 x 和 y 坐标,然后创建一个 5*5 的 '1' 正方形,正方形的左上角从该点开始。然后我会将广场附近的地点标记为“2”。这些代表不可用的站点,因为在这些站点上放置一个正方形会导致它与现有的正方形重叠。这个过程将一直持续到没有更多空间可以在数组上放置正方形(基本上,数组上不再有 '0')

不管怎样,切中要害。我想通过使用按位运算使这个过程尽可能高效。如果我不必在广场附近标记站点,这将很容易。我想知道是否可以创建一个 2 位数字,以便我可以考虑标有“2”的站点。

对不起,如果这听起来很复杂,我只是想解释一下我为什么要这样做。

【问题讨论】:

  • 大概,您确实意识到即使使用 2 位,您也需要大约 250,000 个大硬盘来存储阵列?由于在阵列的一个区域中发生/发生的事情不会影响其他区域超过几个方格,因此在如此大的范围内进行模拟将毫无意义,并且只会告诉您使用相当小的阵列所学到的更多信息。
  • 是的,这不是 PB 范围吗?即使每个三进制像素使用 2 位也有点“浪费”。有可能构建某种系统,将三进制像素“打包”成二进制类型,如 64 位整数或其他类型。前六个二进制数 000,001,010,011,100,101 占用 18 位...如果每个“数字”是两位,则前六个三进制 00,01,02,10,11,12 占用 24 位。但它可能太慢了?这让我想起了 90 年代关于 PC 上的汇编编程的旧 Michael Abrash 书籍。

标签: c bit-manipulation integer bitwise-operators


【解决方案1】:

您不能创建大小为 2 位的数据类型,因为它不可寻址。你可以做的是将几个 2 位数字打包到一个更大的单元格中:

   struct Cell {
      a : 2;
      b : 2;
      c : 2;
      d : 2;
   };

这指定每个成员abcd 应占用内存中的两位。

编辑:这只是一个如何创建 2 位变量的示例,对于有问题的实际问题,最有效的实现可能是创建一个 int 数组并结束在几个set/get 方法中摆弄。

【讨论】:

  • 但是你将如何通过索引来解决它们?
  • @Andrey 你必须围绕这个编写某种包装函数。
  • 我将如何结束这个摆弄?
【解决方案2】:

您可以将一维数组压缩为子整数单元格。将坐标(例如 x)转换为字节内的位置:

byte cell = array[i][ x / 4 ];
byte mask = 0x0004 << (x % 4);
byte data = (cell & mask) >> (x % 4);

写数据做逆向

【讨论】:

  • 当您要再次向下移动掩码时,向上移动掩码似乎有点多余(另外,掩码仅覆盖 1 位,应该是“3”)。可以做为 "data = (array[i][x/4] >> (x & 3)) & 3;"
  • 好的,同意 :) 但是写作过程看起来和阅读有点不同。
【解决方案3】:

您可以使用两个单独的 1 位数组来代替两位数组。一个持有实心方格,一个持有相邻方格(或可用方格,如果这样更有效)。

虽然将 2 位字段打包成单词,但我不确定这是否有任何好处。 除非你真的内存不足,否则我会选择字节数组。

【讨论】:

  • 他有一个十亿 x 十亿的数组 - 即使每个只是一个字节(8 位数字),那仍然是......很多内存。
  • 但将其从 8 位减少到 2 位仅是 4 倍。这可能意味着“适合 RAM”和“需要交换”之间的差异,因此在边界情况下,这可能是值得的。
【解决方案4】:

基本思路

不幸的是,在 C 中没有办法做到这一点。您可以创建 1 字节、2 字节等的数组,但不能创建位区域。

那么,您能做的最好的事情就是为自己编写一个新库,这使得您看起来像是在处理 2 位数组,但实际上做了很多艰苦的工作。与字符串库为您提供处理“字符串”(在 C 中只是数组)的函数相同的方式,您将创建一个处理“位数组”的新库(实际上将是整数数组,用一些特殊的函数来处理它们,就好像它们是位数组一样)。

注意:如果您是 C 新手,并且尚未了解“创建新库/模块”或“抽象”的概念,那么我建议您在继续学习之前了解它们这个项目。了解它们比优化程序以使用更少的空间更重要。

如何实现这个新的“库”或模块

根据您的需要,我会创建一个名为“2 位数组”的新模块,它会根据您的需要导出处理 2 位数组的函数。

它将有一些处理设置/读取位的函数,因此您可以像使用实际的位数组一样使用它(您实际上会有一个整数数组或其他东西,但模块会让它看起来像你有一个位数组)。

使用这个模块会像这样:

// This is just an example of how to use the functions in the twoBitArray library.
twoB my_array = Create2BitArray(size); // This will "create" a twoBitArray and return it.
SetBit(twoB, 5, 1); // Set bit 5 to 1 // 
bit b = GetBit(twoB, 5); // Where bit is typedefed to an int by your module.

该模块实际上要做的是使用常规的旧整数数组来实现所有这些功能。

例如,GetBit(my_arr, 17) 的函数 GetBit() 将计算出它是数组的第 4 个整数中的第 1 位(显然取决于 sizeof(int)),您可以使用按位返回它操作。

【讨论】:

  • 对不起,我对 C 有点陌生。你能澄清一下你的意思吗?为什么我们将第 5 位设置为 1?我使用哪些库?
  • 我建议您编写自己的库来处理“两位数组”的整个想法。我更新了我的答案,希望对您有所帮助。
猜你喜欢
  • 2015-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-24
  • 2011-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多