最快的函数,用于在无符号整数中将位设置为1

时间:2014-01-21 22:42:57

标签: c++ optimization c++11 bit-manipulation bitmask

我有一个在超级计算机上进行模拟的算法,需要使用大量的位操作。有些操作需要掩码,特别是这样的函数:

template <typename Type,
          class = typename std::enable_if<std::is_integral<Type>::value>::type,
          class = typename std::enable_if<std::is_unsigned<Type>::value>::type>
inline Type mask(const std::size_t first, const std::size_t last)
{
     // Something
}

将生成Type类型的掩码,其中[first, last[范围内的位设置为1firstlast是运行时变量)

例如:

mask<unsigned char>(3, 6) -> 00111000

我需要数千亿这些掩码,所以我需要尽可能优化这个功能(但在普通的标准C ++ 11中)。怎么做?

4 个答案:

答案 0 :(得分:8)

return (1 << last) - (1 << first);

答案 1 :(得分:2)

您可以创建一个查找表,并且成本将是单个内存读取。如果您使用的是32位元素,则表中只需要32x32 = 1024个字的内存(4千字节),因此如果您大量使用它,它将保留在缓存中。即使对于64位元素,64x64查找也只有4096个字(32千字节)。

答案 2 :(得分:2)

这是标准的摘录:

转移运营商

[expr.shift]

...如果右操作数为负数,或者大于或等于提升左操作数的位长度,则行为未定义。

这就是为什么当last == sizeof(Type)* CHAR_BIT时,表达式'(1&lt;&lt; last) - (1&lt;&lt; first)'不起作用。我建议你另一种在可能的情况下在编译时计算值的替代方法。请参阅以下示例:

#include <limits>
#include <iostream>
#include <bitset>


template <class Integer>
constexpr Integer ones()
{
    return ~static_cast<Integer>(0);
}


template <class Integer>
constexpr Integer mask(std::size_t first, std::size_t last)
{
    return (ones<Integer>() << first) &
           (ones<Integer>() >> (std::numeric_limits<Integer>::digits - last));
}


//Requires: first is in [0,8) and last is in (0,8]
void print8(std::size_t first, std::size_t last)
{
    std::cout << std::bitset<8>(mask<unsigned char>(first, last)) << '\n';
}

int main()
{
    print8(0,1); //000000001
    print8(2,6); //001111100
    print8(0,8); //111111111
    print8(2,2); //000000000

    static_assert(mask<unsigned char>(0,8) == 255,
                  "It should work at compile-time when possible");
}

答案 3 :(得分:0)

可能只是稍微改变以反映OP给出的示例中firstlast的含义(在我的理解中)。

#include <iostream>
#include <bitset>
using namespace std;

unsigned char mask( int first, int last) {
    return (1 << (8-first)+1) - (1 << (8-last));
}
/*
 * 
 */
int main(int argc, char** argv) {
    cout << bitset<8>(mask(3,6)) << endl; //prints:00111100
    cout << bitset<8>(mask(2,6)) << endl; //prints:01111100
    cout << bitset<8>(mask(1,3)) << endl; //prints:11100000
    cout << bitset<8>(mask(1,7)) << endl; //prints:11111110
    return 0;
}