0

我想计算1在同一位置的多个位集中的出现。每个位置的计数存储在一个向量中。

例如

b0 = 1011
b1 = 1110
b2 = 0110
     ----
 c = 2231 (1+1+0,0+1+1,1+1+1,1+0+0)

我可以使用下面的代码轻松做到这一点,但这段代码似乎缺乏性能,但我不确定。所以我的问题很简单:有没有更快的方法来计算1

#include <bitset>
#include <vector>
#include <iostream>
#include <string>

int main(int argc, char ** argv)
{
  std::vector<std::bitset<4>> bitsets;
  bitsets.push_back(std::bitset<4>("1011"));
  bitsets.push_back(std::bitset<4>("1110"));
  bitsets.push_back(std::bitset<4>("0110"));

  std::vector<unsigned> counts;

  for (int i=0,j=4; i<j; ++i)
  {
    counts.push_back(0);
    for (int p=0,q=bitsets.size(); p<q; ++p)
    {
      if (bitsets[p][(4-1)-i]) // reverse order
      {
        counts[i] += 1;
      }
    }
  }

  for (auto const & count: counts)
  {
      std::cout << count << " ";
  }
}

for (int i=0,j=4; i<j; ++i)
{
  for (int p=0,q=b.size(); p<q; ++p)
  {
    if(b[p][i])
    {
      c[p] += 1;
    }
  }
}
4

4 回答 4

1

一种表驱动的方法。它显然有其局限性*,但根据应用程序可能证明非常合适:

#include <array>
#include <bitset>
#include <string>
#include <iostream>
#include <cstdint>

static const uint32_t expand[] = {
        0x00000000,
        0x00000001,
        0x00000100,
        0x00000101,
        0x00010000,
        0x00010001,
        0x00010100,
        0x00010101,
        0x01000000,
        0x01000001,
        0x01000100,
        0x01000101,
        0x01010000,
        0x01010001,
        0x01010100,
        0x01010101
};

int main(int argc, char* argv[])
{
        std::array<std::bitset<4>, 3> bits = {
            std::bitset<4>("1011"),
            std::bitset<4>("1110"),
            std::bitset<4>("0110")
        };

        uint32_t totals = 0;

        for (auto& x : bits)
        {
                totals += expand[x.to_ulong()];
        }

        std::cout << ((totals >> 24) & 0xff) << ((totals >> 16) & 0xff) << ((totals >> 8) & 0xff) << ((totals >> 0) & 0xff) << std::
endl;
        return 0;
}

编辑:: * 实际上,它的限制比人们想象的要少……

于 2016-07-04T13:19:51.223 回答
0

我会亲自转换您订购位的方式。

1011              110
1110    becomes   011
0110              111
                  100

两个主要原因:您可以使用 stl 算法,并且在处理更大尺寸时可以使用数据局部性来提高性能。

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

int main()
{
    std::vector<std::bitset<3>> bitsets_transpose;  
    bitsets_transpose.reserve(4);
    bitsets_transpose.emplace_back(std::bitset<3>("110"));
    bitsets_transpose.emplace_back(std::bitset<3>("011"));
    bitsets_transpose.emplace_back(std::bitset<3>("111"));
    bitsets_transpose.emplace_back(std::bitset<3>("100"));

    std::vector<size_t> counts;
    counts.reserve(4);
    for (auto &el : bitsets_transpose) {
        counts.emplace_back(el.count()); // use bitset::count()
    }

    // print counts result
    std::copy(counts.begin(), counts.end(), std::ostream_iterator<size_t>(std::cout, " "));
}

实时代码

输出是

2 2 3 1

于 2016-07-04T12:02:52.577 回答
0

通过重构将计数逻辑与向量管理分离,我们可以检查计数算法的效率:

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

__attribute__((noinline))
void count(std::vector<unsigned> counts, 
           const std::vector<std::bitset<4>>& bitsets)
{
  for (int i=0,j=4; i<j; ++i)
  {
    for (int p=0,q=bitsets.size(); p<q; ++p)
    {
      if (bitsets[p][(4-1)-i]) // reverse order
      {
        counts[i] += 1;
      }
    }
  }
}

int main(int argc, char ** argv)
{
  std::vector<std::bitset<4>> bitsets;
  bitsets.push_back(std::bitset<4>("1011"));
  bitsets.push_back(std::bitset<4>("1110"));
  bitsets.push_back(std::bitset<4>("0110"));

  std::vector<unsigned> counts(bitsets.size(), 0);

  count(counts, bitsets);

  for (auto const & count: counts)
  {
      std::cout << count << " ";
  }
}

带有 -O2 的 gcc5.3 会产生以下结果:

count(std::vector<unsigned int, std::allocator<unsigned int> >, std::vector<std::bitset<4ul>, std::allocator<std::bitset<4ul> > > const&):
        movq    (%rsi), %r8
        xorl    %r9d, %r9d
        movl    $3, %r10d
        movl    $1, %r11d
        movq    8(%rsi), %rcx
        subq    %r8, %rcx
        shrq    $3, %rcx
.L4:
        shlx    %r10, %r11, %rsi
        xorl    %eax, %eax
        testl   %ecx, %ecx
        jle     .L6
.L10:
        testq   %rsi, (%r8,%rax,8)
        je      .L5
        movq    %r9, %rdx
        addq    (%rdi), %rdx
        addl    $1, (%rdx)
.L5:
        addq    $1, %rax
        cmpl    %eax, %ecx
        jg      .L10
.L6:
        addq    $4, %r9
        subl    $1, %r10d
        cmpq    $16, %r9
        jne     .L4
        ret

这对我来说似乎一点也不低效。

于 2016-07-04T12:05:28.043 回答
0

您的程序中有多余的内存重新分配和一些其他代码。例如,在使用方法之前,push_back您可以首先在向量中保留足够的内存。

该程序可能如下所示。

#include <iostream>
#include <bitset>
#include <vector>

const size_t N = 4;

int main() 
{
    std::vector<std::bitset<N>> bitsets = 
    { 
        std::bitset<N>( "1011" ), 
        std::bitset<N>( "1110" ),
        std::bitset<N>( "0110" )
    };

    std::vector<unsigned int> counts( N );

    for ( const auto &b : bitsets )
    {
        for ( size_t i = 0; i < N; i++ ) counts[i] += b[N - i -1]; 
    }

    for ( unsigned int val : counts ) std::cout << val;
    std::cout << std::endl;

    return 0;
}

它的输出是

2231
于 2016-07-04T12:13:10.833 回答