【问题标题】:Copying array of ints vs pointers to bools复制整数数组与指向布尔值的指针
【发布时间】:2011-05-20 00:00:17
【问题描述】:

我正在开发一个需要将数组复制数千/数百万次的程序。现在我有两种方法来表示数组中的数据:

一个整数数组:

int someArray[8][8];

其中someArray[a][b] 的值可以是 0、1 或 2,或者

指向布尔值的指针数组:

bool * someArray[8][8];

其中someArray[a][b] 可以为0(空指针),否则*someArray[a][b] 可以为真(对应1)或假(对应2)。

哪个数组被复制得更快(是的,如果我将指针指向布尔数组,我每次复制数组时都必须声明新的布尔值)?

【问题讨论】:

  • 等等,什么?当然,在第二种情况下someArray[a][b] 的值应该是一个指针,而不是一个整数。你在说*someArray[a][b]吗?
  • @oli 哦,是的,你是对的,我会更新问题,谢谢!
  • enum boolean { false, true, FileNotFound };

标签: c++ arrays optimization boolean int


【解决方案1】:

复制速度更快不是重点,分配和释放条目以及取消引用指针以检索每个值的开销对于您的bool* 方法将淹没复制成本。

如果您只有 3 个可能的值,请使用 char 的数组,这将比 int 快 4 倍。好的,这不是经过科学证明的说法,但数组缩小 4 倍。

【讨论】:

  • “小 4 倍”并不是我们在尺寸方面能做到的最好的——请看我的帖子;)
  • @Kos - 明白。这是针对 OP 设计问题的务实建议,并非旨在优化空间使用。
【解决方案2】:

实际上,两者在复制方面看起来或多或少相同 - 32 位整数数组与 32 位指针数组。如果编译为 64 位,那么指针可能会更大。

顺便说一句,如果您存储指针,您可能不希望该数组的每个字段都有一个单独的“bool”实例,对吗?那肯定会慢得多。

如果您想要快速复制,请尽可能减小大小,无论是:

  • 使用char 代替int,或者
  • 为此数组设计一个带有位操作的自定义类。如果您将一个值表示为两位 - “null”位和“value-if-not-null”位,那么整个 64 个值的数组需要 128 位 = 4 个整数。这肯定会很快被复制!但是对任何单个位的访问会稍微复杂一些 - 只需多几个周期。

好吧,你让我很好奇 :) 我卷了这样的东西:

struct BitArray {
public:
    static const int DIMENSION = 8;

    enum BitValue {
        BitNull = -1,
        BitTrue = 1,
        BitFalse = 0
    };
    BitArray() {for (int i=0; i<DIMENSION; ++i) data[i] = 0;}
    BitValue get(int x, int y) {
        int k = x+y*DIMENSION; // [0 .. 64)
        int n = k/16;          // [0 .. 4)
        unsigned bit1 = 1 << ((k%16)*2);
        unsigned bit2 = 1 << ((k%16)*2+1);

        int isnull = data[n] & bit1;
        int value = data[n] & bit2;
        return static_cast<BitValue>( (!!isnull)*-1 + (!isnull)*!!value );
    }
    void set(int x, int y, BitValue value) {
        int k = x+y*DIMENSION; // [0 .. 64)
        int n = k/16;          // [0 .. 4)
        unsigned bit1 = 1 << ((k%16)*2);
        unsigned bit2 = 1 << ((k%16)*2+1);
        char v = static_cast<char>(value);

        // set nullbit to 1 if v== -1, else 0
        if (v == -1) {
            data[n] |= bit1;
        } else {
            data[n] &= ~bit1;
        }

        // set valuebit to 1 if v== 1, else 0
        if (v == 1) {
            data[n] |= bit2;
        } else {
            data[n] &= ~bit2;
        }
    }
private:
    unsigned data[DIMENSION*DIMENSION/16];
};

8x8数组的这个对象的大小是16字节,相比char array[8][8]的64字节和int array[8][8]的256字节的解决方案,这是一个很好的改进。

这可能是一个人可以在不深入研究更大魔法的情况下到达这里的最低水平。

【讨论】:

  • 关于“更大的魔力”- 从理论上讲,这个树状态布尔值仍然携带少于 2 位的信息。我怀疑这个事实是否真的有用(13 或 14 字节而不是 16 对机器没有帮助),但是否有可能在不到 16 字节的时间内真正实现它,只是为了好玩?身边有什么位福大师吗? :)
【解决方案3】:

我会说你需要重新设计你的程序。在int x[8][8]bool *b[8][8] 之间转换“数百万”次不可能是“正确的”,但是您对“正确”的定义是松懈的。

【讨论】:

  • 我不必在两者之间转换,只需要复制我选择的数组的任何实现
  • 啊,对不起,我读得太快了:/动态内存分配很慢。复制 int[8][8] 肯定更快。
【解决方案4】:

您问题的答案将与数据类型的大小相关联。通常bool 是一个字节,而int 不是。指针的长度因架构而异,但现在通常是 32 位或 64 位。

不考虑缓存或其他特定于处理器的优化,较大的数据类型将需要更长的复制时间。

鉴于您有三种可能的状态(0、1、2)和 64 个条目,您可以用 128 位表示整个结构。使用一些实用程序和两个无符号 64 位整数,您可以快速高效地复制数组。

【讨论】:

    【解决方案5】:

    我不是 100% 确定,但我认为它们将花费大致相同的时间,尽管我更喜欢使用堆栈分配(因为动态分配可能需要一些时间来寻找可用空间)。

    考虑使用short 类型而不是int,因为您不需要大量的数字。

    我认为如果您真的想要最大速度,最好使用一维数组,因为以错误的顺序使用 for 循环,编译器用于存储多维数组(原始主要或列主要)可能会导致性能损失!

    【讨论】:

      【解决方案6】:

      在不知道如何使用数组的情况下,这是一个可能的解决方案:

      typedef char Array[8][8];
      Array someArray, otherArray;
      memcpy(someArray, otherArray, sizeof(Array));
      

      这些数组只有 64 字节,复制速度应该很快。您可以将数据类型更改为int,但这意味着至少要复制 256 个字节。

      【讨论】:

        【解决方案7】:

        用指针“复制”这个数组需要一个深拷贝,否则改变拷贝会影响原始的,这可能不是你想要的。由于内存分配开销,这将大大减慢速度。

        您可以通过使用 boost::optional 表示“可选”数量来解决此问题 - 这是您在此处添加间接级别的唯一原因。在现代 C++ 中很少有使用原始指针的情况 :) 但是,由于无论如何您只需要 char 来存储值 {0, 1, 2},这可能会更好在空间方面。我很确定sizeof(boost::optional&lt;bool&gt;) &gt; 1,虽然我还没有测试过。如果他们专门从事这方面的工作,我会印象深刻:)

        您甚至可以对一个 2 位数量的数组进行位打包,或者使用两个位打包的布尔数组(一个“掩码”,然后是另一组实际的真假值) - 例如使用 std::bitset。这肯定会节省空间并减少复制时间,尽管它可能会增加访问时间(假设您确实需要一次访问一个值)。

        【讨论】:

          猜你喜欢
          • 2019-10-27
          • 1970-01-01
          • 2013-09-04
          • 2012-01-24
          • 1970-01-01
          • 2016-01-27
          • 1970-01-01
          • 2017-07-16
          • 1970-01-01
          相关资源
          最近更新 更多