我有一个在超级计算机上进行模拟的算法,需要使用大量的位操作。有些操作需要掩码,特别是这样的函数:
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[
范围内的位设置为1
(first
和last
是运行时变量)
例如:
mask<unsigned char>(3, 6) -> 00111000
我需要数千亿这些掩码,所以我需要尽可能优化这个功能(但在普通的标准C ++ 11中)。怎么做?
答案 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给出的示例中first
和last
的含义(在我的理解中)。
#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;
}