访问和更改长布尔值数组的最快实现是啥?

Posted

技术标签:

【中文标题】访问和更改长布尔值数组的最快实现是啥?【英文标题】:What is the fastest implementation for accessing and changing a long array of boolean?访问和更改长布尔值数组的最快实现是什么? 【发布时间】:2016-09-24 06:38:35 【问题描述】:

我想实现一个很长的布尔数组(作为二进制基因组)并访问一些区间以检查该区间是否全部为真,此外我想更改一些区间值,

例如,我可以创建 4 个表示:

boolean binaryGenome1[10e6]=false;
vector<bool> binaryGenome2; binaryGenome2.resize(10e6);
vector<char> binaryGenome3; binaryGenome3.resize(10e6);
bitset<10e6> binaryGenome4;

并以这种方式访问​​:

inline bool checkBinGenome(long long start , long long end)
  for(long long i = start; i < end+1 ; i++)
    if(binaryGenome[i] == false)
        return false;
  return true;

inline void changeBinGenome(long long start , long long end)
  for(long long i = start; i < end+1 ; i++)
    binaryGenome[i] = true;

vector&lt;char&gt;normal boolean array(ass 将每个布尔值存储在一个字节中)似乎都是一个糟糕的选择,因为我需要在空间上保持高效。但是vector&lt;bool&gt;bitset有什么区别呢?

我在其他地方读到该向量有一些开销,因为您可以选择它的大小和编译时间 - 访问的“开销”是什么?那开销是多少?

由于我想使用CheckBinGenome()changeBinGenome() 多次访问数组元素,最快的实现是什么?

【问题讨论】:

你的功课还不够。 std::vector&lt;bool&gt; 很特别 - 它是一种节省空间的表示。还要查找std::bitset,它也是bool 数组的一种节省空间的表示,除了它的大小在编译时是固定的。 见***.com/questions/3806469/bit-array-in-c @Peter std::vector&lt;bool&gt; 被认为是一个糟糕的专业化,std::bitset 可能更好。 如何并行化进程? @ πάντα ῥεῖ - std::vector&lt;bool&gt; 被认为是一个糟糕的专业化,因为它在很多方面与其他标准容器的行为不同。但是,如果您在其限制范围内工作(特别是不要期望它像其他标准容器一样播放),它仍然很有用。 【参考方案1】:

使用std::bitset这是最好的。

【讨论】:

访问函数是否在恒定时间内运行?我的意思是 operator[] 和 .test 与 vecor 相比,std::bitset 有哪些优势?谢谢。 你能解释一下是什么特性使它成为“最好的”吗?您是否使用了一些客观的衡量标准,或者这只是一种观点? AFAICS,bitsetvector&lt;bool&gt;(是的,混蛋非容器专业化)之间唯一有意义的区别是 vector 是可调整大小的。是否有确保bitset 必须比bool[] 更节省空间的措辞?【参考方案2】:

如果在编译时知道数据的长度,请考虑std::array&lt;bool&gt;std::bitset。后者可能更节省空间(您必须衡量相关的访问时间额外工作是否超过了减少缓存压力带来的速度增益 - 这取决于您的工作量)。

如果您的数组长度不固定,那么您将需要std::vector&lt;bool&gt;std::vector&lt;char&gt;;还有boost::dynamic_bitset,但我从来没有用过。

如果您要立即更改大区域,正如您的示例所暗示的那样,那么构建您自己的表示并直接操作底层存储可能是值得的,而不是通过迭代器一次一位地操作。例如,如果您使用 char 的数组作为底层表示,那么将大范围设置为 0 或 1 主要是 memset()std::fill() 调用,仅计算开头和结尾的值范围。在尝试类似的事情之前,我会先从一个简单的实现和一组好的单元测试开始。

您的标准库有可能(至少在理论上)有专门的算法版本,用于 std::vector&lt;bool&gt;std::array&lt;bool&gt; 和/或 std::bitset 的迭代器,它们完全可以执行上述操作,或者您可以编写并贡献这些专业。如果可能的话,这是一条更好的道路 - 世界可能会感谢您,您将分担一些维护责任。

重要提示

如果使用std::array&lt;bool&gt;,您需要注意,与其他std::array&lt;&gt; 实例不同,它不实现标准容器语义。这并不是说不应该使用它,但请确保您了解它的弱点!

【讨论】:

您的答案中缺少:vector 和 bitset 之间有什么区别?在编译时超过固定长度或没有固定长度。你能解释一下速度的差异吗?为什么 bitset 更快?【参考方案3】:

例如,检查是否所有元素都是true

我真的不确定这是否会给我们带来比加速更多的开销。其实我觉得现在的CPU可以做到这一点相当快,你真的遇到性能差吗? (或者这只是你真正问题的一个骨架?)

#include <omp.h>
#include <iostream>
#include <cstring>

using namespace std;

#define N 10000000
bool binaryGenome[N];

int main() 
    memset(binaryGenome, true, sizeof(bool) * N);
    int shouldBreak = 0;
    bool result = true;
    cout << result << endl;
    binaryGenome[9999995] = false;

    bool go = true;
    uint give = 0;
#pragma omp parallel
    
        uint start, stop;

#pragma omp critical
        
            start = give;
            give += N / omp_get_num_threads();
            stop = give;

            if (omp_get_thread_num() == omp_get_num_threads() - 1)
                stop = N;
        

        while (start < stop && go) 
            if (!binaryGenome[start]) 
                cout << start << endl;
                go = false;
                result = false;
            
            ++start;
        
    

    cout << result << endl;

【讨论】:

以上是关于访问和更改长布尔值数组的最快实现是啥?的主要内容,如果未能解决你的问题,请参考以下文章

检查布尔数组中的所有值是不是为真的最优雅方法是啥?

如何在 Mongoose 中更改文档子数组的对象内的布尔值?

生成随机布尔值的最快方法

如何识别布尔数组中的值序列?

SQL - 基于记录中的布尔值更改查询输出

逻辑组合布尔值列表的最“pythonic”方式是啥?