使用 C++ constexpr 对 N 位字进行位反转
Bit reversal for N bit word using c++ constexpr
我正在研究用于 fft 实现的位反转算法,目前我的实现是
//assume the proper includes
template<unsigned long bits>
unsigned long&& bitreverse(unsigned long value){
std::bitset<bits> input(value);
std::bitset<bits> result;
unsigned long j=input.size()-1;
for (unsigned long i=0; i<input.size(); ++i) {
result[i]=input[j];
j--;
}
return std::move(result.to_ulong());
}
我需要能够反转 N 位字中的位。我当前的实现是功能性的,但我想重写它以便结果可以用作 constexpr
,函数签名需要是:
template<unsigned long bits>
constexpr unsigned long&& bitreverse(unsigned long value);
或:
template<unsigned long bits,unsigned long value>
constexpr unsigned long&& bitreverse();
或接近...
我不确定如何开始实施。
我想尽可能避免按位运算,但我不反对它们。
谢谢
你可以这样做:
template <unsigned long bits>
constexpr unsigned long bitreverse(unsigned long value) {
unsigned long result = 0;
for (std::size_t i = 0, j = bits - 1; i < bits; ++i, --j) {
result |= ((value & (1 << j)) >> j) << i;
}
return result;
}
我不确定您为什么要对 return 类型使用 r-value 引用。它不会使任何事情更有效率,我认为 will result in a dangling reference.
好吧,这是显而易见的 "brute force" 方法。
这假设实现中的 unsigned long long
数据类型是 64 位整数。对于 32 位平台,代码显然可以精简。
观察到 bitreverse
最初总是可以作为 64 位 bitreverse
处理,然后右移以获得正确的位数。
这有点罗嗦,但它的优点是足够简单,大多数编译器可以在编译时咀嚼 bitreverse
常量。对于一个变量,这肯定会比迭代方法生成更多的代码,但现代 CPU 可能能够毫不拖延地处理它,因为它们不必处理循环和分支预测。
template<unsigned long bits>
constexpr unsigned long long bitreverse(unsigned long long v)
{
return (((v & 0x00000001ULL) << 63) |
((v & 0x00000002ULL) << 61) |
((v & 0x00000004ULL) << 59) |
((v & 0x00000008ULL) << 57) |
((v & 0x00000010ULL) << 55) |
((v & 0x00000020ULL) << 53) |
((v & 0x00000040ULL) << 51) |
((v & 0x00000080ULL) << 49) |
((v & 0x00000100ULL) << 47) |
((v & 0x00000200ULL) << 45) |
((v & 0x00000400ULL) << 43) |
((v & 0x00000800ULL) << 41) |
((v & 0x00001000ULL) << 39) |
((v & 0x00002000ULL) << 37) |
((v & 0x00004000ULL) << 35) |
((v & 0x00008000ULL) << 33) |
((v & 0x00010000ULL) << 31) |
((v & 0x00020000ULL) << 29) |
((v & 0x00040000ULL) << 27) |
((v & 0x00080000ULL) << 25) |
((v & 0x00100000ULL) << 23) |
((v & 0x00200000ULL) << 21) |
((v & 0x00400000ULL) << 19) |
((v & 0x00800000ULL) << 17) |
((v & 0x01000000ULL) << 15) |
((v & 0x02000000ULL) << 13) |
((v & 0x04000000ULL) << 11) |
((v & 0x08000000ULL) << 9) |
((v & 0x10000000ULL) << 7) |
((v & 0x20000000ULL) << 5) |
((v & 0x40000000ULL) << 3) |
((v & 0x80000000ULL) << 1) |
((v & 0x100000000ULL) >> 1) |
((v & 0x200000000ULL) >> 3) |
((v & 0x400000000ULL) >> 5) |
((v & 0x800000000ULL) >> 7) |
((v & 0x1000000000ULL) >> 9) |
((v & 0x2000000000ULL) >> 11) |
((v & 0x4000000000ULL) >> 13) |
((v & 0x8000000000ULL) >> 15) |
((v & 0x10000000000ULL) >> 17) |
((v & 0x20000000000ULL) >> 19) |
((v & 0x40000000000ULL) >> 21) |
((v & 0x80000000000ULL) >> 23) |
((v & 0x100000000000ULL) >> 25) |
((v & 0x200000000000ULL) >> 27) |
((v & 0x400000000000ULL) >> 29) |
((v & 0x800000000000ULL) >> 31) |
((v & 0x1000000000000ULL) >> 33) |
((v & 0x2000000000000ULL) >> 35) |
((v & 0x4000000000000ULL) >> 37) |
((v & 0x8000000000000ULL) >> 39) |
((v & 0x10000000000000ULL) >> 41) |
((v & 0x20000000000000ULL) >> 43) |
((v & 0x40000000000000ULL) >> 45) |
((v & 0x80000000000000ULL) >> 47) |
((v & 0x100000000000000ULL) >> 49) |
((v & 0x200000000000000ULL) >> 51) |
((v & 0x400000000000000ULL) >> 53) |
((v & 0x800000000000000ULL) >> 55) |
((v & 0x1000000000000000ULL) >> 57) |
((v & 0x2000000000000000ULL) >> 59) |
((v & 0x4000000000000000ULL) >> 61) |
((v & 0x8000000000000000ULL) >> 63)) >> (64 - bits);
}
我正在研究用于 fft 实现的位反转算法,目前我的实现是
//assume the proper includes
template<unsigned long bits>
unsigned long&& bitreverse(unsigned long value){
std::bitset<bits> input(value);
std::bitset<bits> result;
unsigned long j=input.size()-1;
for (unsigned long i=0; i<input.size(); ++i) {
result[i]=input[j];
j--;
}
return std::move(result.to_ulong());
}
我需要能够反转 N 位字中的位。我当前的实现是功能性的,但我想重写它以便结果可以用作 constexpr
,函数签名需要是:
template<unsigned long bits>
constexpr unsigned long&& bitreverse(unsigned long value);
或:
template<unsigned long bits,unsigned long value>
constexpr unsigned long&& bitreverse();
或接近...
我不确定如何开始实施。
我想尽可能避免按位运算,但我不反对它们。
谢谢
你可以这样做:
template <unsigned long bits>
constexpr unsigned long bitreverse(unsigned long value) {
unsigned long result = 0;
for (std::size_t i = 0, j = bits - 1; i < bits; ++i, --j) {
result |= ((value & (1 << j)) >> j) << i;
}
return result;
}
我不确定您为什么要对 return 类型使用 r-value 引用。它不会使任何事情更有效率,我认为 will result in a dangling reference.
好吧,这是显而易见的 "brute force" 方法。
这假设实现中的 unsigned long long
数据类型是 64 位整数。对于 32 位平台,代码显然可以精简。
观察到 bitreverse
最初总是可以作为 64 位 bitreverse
处理,然后右移以获得正确的位数。
这有点罗嗦,但它的优点是足够简单,大多数编译器可以在编译时咀嚼 bitreverse
常量。对于一个变量,这肯定会比迭代方法生成更多的代码,但现代 CPU 可能能够毫不拖延地处理它,因为它们不必处理循环和分支预测。
template<unsigned long bits>
constexpr unsigned long long bitreverse(unsigned long long v)
{
return (((v & 0x00000001ULL) << 63) |
((v & 0x00000002ULL) << 61) |
((v & 0x00000004ULL) << 59) |
((v & 0x00000008ULL) << 57) |
((v & 0x00000010ULL) << 55) |
((v & 0x00000020ULL) << 53) |
((v & 0x00000040ULL) << 51) |
((v & 0x00000080ULL) << 49) |
((v & 0x00000100ULL) << 47) |
((v & 0x00000200ULL) << 45) |
((v & 0x00000400ULL) << 43) |
((v & 0x00000800ULL) << 41) |
((v & 0x00001000ULL) << 39) |
((v & 0x00002000ULL) << 37) |
((v & 0x00004000ULL) << 35) |
((v & 0x00008000ULL) << 33) |
((v & 0x00010000ULL) << 31) |
((v & 0x00020000ULL) << 29) |
((v & 0x00040000ULL) << 27) |
((v & 0x00080000ULL) << 25) |
((v & 0x00100000ULL) << 23) |
((v & 0x00200000ULL) << 21) |
((v & 0x00400000ULL) << 19) |
((v & 0x00800000ULL) << 17) |
((v & 0x01000000ULL) << 15) |
((v & 0x02000000ULL) << 13) |
((v & 0x04000000ULL) << 11) |
((v & 0x08000000ULL) << 9) |
((v & 0x10000000ULL) << 7) |
((v & 0x20000000ULL) << 5) |
((v & 0x40000000ULL) << 3) |
((v & 0x80000000ULL) << 1) |
((v & 0x100000000ULL) >> 1) |
((v & 0x200000000ULL) >> 3) |
((v & 0x400000000ULL) >> 5) |
((v & 0x800000000ULL) >> 7) |
((v & 0x1000000000ULL) >> 9) |
((v & 0x2000000000ULL) >> 11) |
((v & 0x4000000000ULL) >> 13) |
((v & 0x8000000000ULL) >> 15) |
((v & 0x10000000000ULL) >> 17) |
((v & 0x20000000000ULL) >> 19) |
((v & 0x40000000000ULL) >> 21) |
((v & 0x80000000000ULL) >> 23) |
((v & 0x100000000000ULL) >> 25) |
((v & 0x200000000000ULL) >> 27) |
((v & 0x400000000000ULL) >> 29) |
((v & 0x800000000000ULL) >> 31) |
((v & 0x1000000000000ULL) >> 33) |
((v & 0x2000000000000ULL) >> 35) |
((v & 0x4000000000000ULL) >> 37) |
((v & 0x8000000000000ULL) >> 39) |
((v & 0x10000000000000ULL) >> 41) |
((v & 0x20000000000000ULL) >> 43) |
((v & 0x40000000000000ULL) >> 45) |
((v & 0x80000000000000ULL) >> 47) |
((v & 0x100000000000000ULL) >> 49) |
((v & 0x200000000000000ULL) >> 51) |
((v & 0x400000000000000ULL) >> 53) |
((v & 0x800000000000000ULL) >> 55) |
((v & 0x1000000000000000ULL) >> 57) |
((v & 0x2000000000000000ULL) >> 59) |
((v & 0x4000000000000000ULL) >> 61) |
((v & 0x8000000000000000ULL) >> 63)) >> (64 - bits);
}