0

I want to increase each element in a std::vector<size_t> with length 256 by one, but depending on same position of a std::bitset<256> (if equal 1).

Code below can be edited / compiled here.

My question is, can I get away from the for loop and get in some fast logical operator?

#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;
}
cdomination
  • 605
  • 1
  • 7
  • 25
user1587451
  • 978
  • 3
  • 15
  • 30
  • You could kind of "vectorize". Read 2 bits at a time, generate an SSE vector of 0 or 1 depending on the value (use a table), then add that by accessing the vector buffer directly. If you don't like the `if`, you can replace `if(a)b+=1` with `b+=a` (since `a` is 0 or 1). – Marc Glisse Jul 07 '16 at 12:53
  • I don't think so, if you are handling arbitrary vector lengths, in the above the compiler would do an loop unrolling with operating on multiple data one operation registers. – Philipp H. Jul 07 '16 at 13:01
  • If the loop is annoying you could always try `std::transform(v.begin(), v.end(), b.rbegin(), v.begin(), std::plus())` – Philipp H. Jul 07 '16 at 13:03
  • @user1447257 `bitset` doesn't define iterators unfortunately, so that won't work. – SirGuy Jul 07 '16 at 13:19
  • The only speedup I can think of here (assuming you're going to be working on vectors much larger than size 3) is to check a byte (or more) at a time and have shortcuts for when the byte is all zeros or all ones. Unfortunately for that idea, `std::bitset` doesn't seem to expose bytes at a time so you would have to use something else. Perhaps `std::array`? – SirGuy Jul 07 '16 at 13:23
  • You might prefer the `for` - e.g. you can parallelize it pretty simply with OpenMP, which could be harder with other solutions. – Toby Speight Jul 07 '16 at 16:40

1 Answers1

1

Since bitset doesn't have iterators we can't simply use std::transform. But we can create iterator-like wrapper around size_t and use it like index:

#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;
}
user2807083
  • 2,962
  • 4
  • 29
  • 37
  • Your `IntegralInterator` class could be a handy general-purpose tool. Adding an `operator--` would allow you to do `std::make_reverse_iterator(IntegralIterator(size))` and then you could simply do `b[index]`. – SirGuy Jul 07 '16 at 13:27
  • Anyway, I think I should point out that this won't be faster than his code, it just changes the syntax around. – SirGuy Jul 07 '16 at 13:28
  • @GuyGreer, it may or may not be faster - op's variant uses `if` inside loop and compiler could use conditional jumps or flag operations to implement it. In common case yes, it's not faster, but question was about to get away `for` loop and use logical operator. My answer is approximation to not use loop and `if`. – user2807083 Jul 07 '16 at 13:44