Skip to content

Instantly share code, notes, and snippets.

@shininglion
Last active September 13, 2022 12:59
Show Gist options
  • Save shininglion/fcf8d5ea513d59bc23a7f3b18c92d8ee to your computer and use it in GitHub Desktop.
Save shininglion/fcf8d5ea513d59bc23a7f3b18c92d8ee to your computer and use it in GitHub Desktop.
metaprogram for getting exponent part of power of 2
namespace util
{
template <unsigned N>
struct Exp2 {
// N & (~N + 1): get the right most set bit
// ex: 0x1010 -> N & (~N + 1) will obtain 0x0010
// Hence N ^ (N & (~N + 1)) will unset the rightmost set bit
// In the end, this value will be the exponent part of associated with the leftmost set bit
// ex: 0x1010 -> leftmost set bit is 0x1000 -> exponent part is 3 (2^3 = 0x1000)
static constexpr int val = Exp2<N ^ (N & (~N +1))>::val;
};
template <>
struct Exp2<0x0000'0000> {
static constexpr int val = 0;
};
template <>
struct Exp2<0x0000'0001> {
static constexpr int val = 0;
};
template <>
struct Exp2<0x0000'0002> {
static constexpr int val = 1;
};
template <>
struct Exp2<0x0000'0004> {
static constexpr int val = 2;
};
template <>
struct Exp2<0x0000'0008> {
static constexpr int val = 3;
};
template <>
struct Exp2<0x0000'0010> {
static constexpr int val = 4;
};
template <>
struct Exp2<0x0000'0020> {
static constexpr int val = 5;
};
template <>
struct Exp2<0x0000'0040> {
static constexpr int val = 6;
};
template <>
struct Exp2<0x0000'0080> {
static constexpr int val = 7;
};
template <>
struct Exp2<0x0000'0100> {
static constexpr int val = 8;
};
template <>
struct Exp2<0x0000'0200> {
static constexpr int val = 9;
};
template <>
struct Exp2<0x0000'0400> {
static constexpr int val = 10;
};
template <>
struct Exp2<0x0000'0800> {
static constexpr int val = 11;
};
template <>
struct Exp2<0x0000'1000> {
static constexpr int val = 12;
};
template <>
struct Exp2<0x0000'2000> {
static constexpr int val = 13;
};
template <>
struct Exp2<0x0000'4000> {
static constexpr int val = 14;
};
template <>
struct Exp2<0x0000'8000> {
static constexpr int val = 15;
};
template <>
struct Exp2<0x0001'0000> {
static constexpr int val = 16;
};
template <>
struct Exp2<0x0002'0000> {
static constexpr int val = 17;
};
template <>
struct Exp2<0x0004'0000> {
static constexpr int val = 18;
};
template <>
struct Exp2<0x0008'0000> {
static constexpr int val = 19;
};
template <>
struct Exp2<0x0010'0000> {
static constexpr int val = 20;
};
template <>
struct Exp2<0x0020'0000> {
static constexpr int val = 21;
};
template <>
struct Exp2<0x0040'0000> {
static constexpr int val = 22;
};
template <>
struct Exp2<0x0080'0000> {
static constexpr int val = 23;
};
template <>
struct Exp2<0x0100'0000> {
static constexpr int val = 24;
};
template <>
struct Exp2<0x0200'0000> {
static constexpr int val = 25;
};
template <>
struct Exp2<0x0400'0000> {
static constexpr int val = 26;
};
template <>
struct Exp2<0x0800'0000> {
static constexpr int val = 27;
};
template <>
struct Exp2<0x1000'0000> {
static constexpr int val = 28;
};
template <>
struct Exp2<0x2000'0000> {
static constexpr int val = 29;
};
template <>
struct Exp2<0x4000'0000> {
static constexpr int val = 30;
};
template <>
struct Exp2<0x8000'0000> {
static constexpr int val = 31;
};
}
template <unsigned N>
inline constexpr unsigned toPow2()
{
// convert the given value to the nearest (but not less than original) value
// which is power of 2.
if constexpr (N == util::Exp2<N>::val) {
return N;
}
else {
// ex: let say N = 8200, MASK = (1 << (13 + 1)) - 1 = 0x3FFF
// (N + MASK) & (~MASK) = (0x2008 + 0x3FFF) & (0xFFFF'C000) = 0x4000
constexpr auto MASK = (1 << (util::Exp2<N>::val + 1)) - 1;
return (N + MASK) & (~MASK);
}
}
int main()
{
auto i = toPow2<8200>();
return 0;
}
/* Associated assembly code: (by x86-64 gcc-12.2)
main:
push rbp
mov rbp, rsp
# toPow2<8200>() becomes a constant value 16384 here
mov DWORD PTR [rbp-4], 16384
mov eax, 0
pop rbp
ret
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment