【问题标题】:Increase elements inside std::vector<T> depending on std::bitset<N>根据 std::bitset<N> 增加 std::vector<T> 内的元素
【发布时间】:2016-07-07 12:34:59
【问题描述】:

我想将长度为256std::vector&lt;size_t&gt; 中的每个元素增加一,但取决于std::bitset&lt;256&gt; 的相同位置(如果等于1)。

下面的代码可以编辑/编译here

我的问题是,我可以摆脱for 循环并使用一些快速的逻辑运算符吗?

#include <iostream>
#include <bitset>
#include <vector>
#include <iterator>
#include <algorithm>

#define SIZE 3

int main() {

    size_t size=SIZE;
    std::vector<size_t> v(SIZE); v={3,0,7};
    std::bitset<SIZE> b("110");

    for (size_t i=0; i<size; ++i)
    {
        if (b[size-1-i]) // reverse
        {
            ++v[i];
        }
    }

    std::copy ( v.begin()
              , v.end()
              , std::ostream_iterator<size_t>(std::cout, ",") );

    //    3+1,0+1,7+0
    // => 4,1,7

    return 0;
}

【问题讨论】:

  • 你可以“矢量化”。一次读取 2 位,根据值生成 0 或 1 的 SSE 向量(使用表),然后通过直接访问向量缓冲区来添加它。如果您不喜欢if,可以将if(a)b+=1 替换为b+=a(因为a 是0 或1)。
  • 我不这么认为,如果你正在处理任意向量长度,在上面的编译器会做一个循环展开,对多个数据一个操作寄存器进行操作。
  • 如果循环很烦人,您可以随时尝试std::transform(v.begin(), v.end(), b.rbegin(), v.begin(), std::plus&lt;size_t&gt;())
  • @user1447257 bitset 不幸的是没有定义迭代器,所以这不起作用。
  • 我能想到的唯一加速(假设你要处理比大小 3 大得多的向量)是一次检查一个字节(或更多),并有快捷方式字节全为零或全一。不幸的是,对于这个想法,std::bitset 似乎不会一次公开字节,因此您必须使用其他东西。也许std::array

标签: c++ stdvector binary-data std-bitset


【解决方案1】:

由于bitset 没有迭代器,我们不能简单地使用std::transform。但我们可以围绕size_t 创建类似迭代器的包装器,并像索引一样使用它:

#include <iostream>
#include <bitset>
#include <vector>
#include <iterator>
#include <algorithm>

#define SIZE 3

class IntegralIterator
{
public:
    IntegralIterator(size_t v = 0) : value(v) {}

    size_t operator*()
    {
        return value;
    }

    IntegralIterator& operator++()
    {
        ++value;
        return *this;
    }

private:
    size_t value;
};

int main() {

    size_t size=SIZE;
    std::vector<size_t> v(SIZE); v={3,0,7};
    std::bitset<SIZE> b("110");

    std::transform(v.begin(), v.end(), IntegralIterator(), v.begin(), 
        [&](size_t s, size_t index)
        {
            return s + b[size-1-index];
        });

    std::copy(v.begin(), v.end(), 
                std::ostream_iterator<size_t>(std::cout, ",") );
    return 0;
}

【讨论】:

  • 您的IntegralInterator 类可能是一个方便的通用工具。添加operator-- 将允许您执行std::make_reverse_iterator(IntegralIterator(size)),然后您可以简单地执行b[index]
  • 无论如何,我想我应该指出,这不会比他的代码快,它只是改变了语法。
  • @GuyGreer,它可能更快也可能不会更快——op 的变体在循环内使用if,编译器可以使用条件跳转或标志操作来实现它。在一般情况下是的,它并没有更快,但问题即将摆脱for 循环并使用逻辑运算符。我的回答是近似不使用循环和if
猜你喜欢
  • 2011-12-27
  • 1970-01-01
  • 2020-05-21
  • 1970-01-01
  • 2018-02-02
  • 2017-09-01
  • 2019-10-24
  • 2019-10-20
  • 2011-05-08
相关资源
最近更新 更多