Bit twiddling:用c ++中的模板找到下一个2的幂

时间:2009-08-24 14:38:33

标签: c++ templates bit-manipulation

这是我的一般问题的后续行动: bit-twiddling-find-next-power-of-two

我现在创建了以下模板函数:

template <typename T>
T nextPowerOfTwo(T n)
{
    std::size_t k=1;
    n--;
    do {
        n |= n >> k ;
        k <<=1;
    }
    while (k < sizeof(T)*8)
    return ++n;
}

2个问题:

  1. unsigned中将T指定为nextPowerOfTwo(unsigned T n)会引发编译错误。我可以以某种方式指定T是无符号的吗?
  2. 有没有可以磨练优雅或表现的东西?
  3. 编辑:更正了代码,开头是垃圾

    编辑:再次更正了代码。真的对不起。实际上很明显。但无论如何还要感谢提示。 我想删除它,但已经有太多的贡献了。

6 个答案:

答案 0 :(得分:7)

如果你希望你的功能是通用的,你明确想要的,你也希望能够使用用户定义的类型,它不会有关键字unsigned。相反,您应该使用std::numeric_limits来测试签名(或者,在这种情况下,缺少签名)。

您也不应该使用8 * sizeof (T),而是使用numeric_limits(再次)来确定您的类型有多少位。 : - )

答案 1 :(得分:4)

template <typename T>
T nextPowerOfTwo(T v)
{
    if (v < 1) return 0;

    --v;
    for (int i = 0; i < sizeof v; ++i)
        v |= v >> (1<<i);
    return v + 1;
}

答案 2 :(得分:2)

template<typename T>
T nextPowerOfTwo(T n) {
    --n;
    for(T k=1;!(k&(1<<(sizeof(n)+1));k<<=1) n|=n>>k;
    return ++n;
}

答案 3 :(得分:1)

要回答你的第一个问题,不,你不能。 T必须可以用完整的类型声明替换;在T之前放置unsigned会导致unsigned unsigned int或类似的东西。

这不完全是在幕后发生的事情,但它足以解释为什么你不能使用无符号。

答案 4 :(得分:1)

虽然@ hacker的版本在技术上是正确的,但我的Visual Studio 2008无法正确优化它。这是我的版本,完美无缺。它还根据您的请求仅执行对数数量的操作。尽管此版本不那么优雅,但Visual Studio实际上能够在不执行它的情况下计算nearestPowerOfTwo(value)的值。 (当然,您必须启用优化)。

template <typename T, T v>
struct value_holder
{
    static const T value = v;
};

template <typename T, typename value, typename partial_result>
struct ln_detail
{
    typedef typename ln_detail<T, value_holder<T, (value::value >> 1)>, value_holder<T, partial_result::value + 1> >::type type;
};

template <typename T, typename partial_result>
struct ln_detail<T, value_holder<T, 1>, partial_result>
{
    typedef partial_result type;
};

template <typename T, T value>
struct ln
{
    static const T value = ln_detail<T, value_holder<T, value>, value_holder<T, 0> >::type::value;
};

template <typename T>
T nearestPowerOfTwo(T v)
{
    if (v < 1) return 0;

    --v;
    for (int i = 0; i < ln<T, 8*sizeof v>::value; ++i)
        v |= v >> (1<<i);
    return v + 1;
}

答案 5 :(得分:0)

您可以通过更改循环测试来稍微改进一下,以检查数字是否小于2的幂:

template <typename T>
T nextPowerOfTwo(T n)
{
    std::size_t k=1;
    --n;
    do {
        n |= n >> k;
        k <<= 1;
    } while (n & (n + 1));
    return n + 1;
}

算法现在是O(log2(n))而不是O(width_of_T_in_bits)。这应该对小n有用,或者如果n通常包含许多1位(尽管后者不会出现在改进的时间范围内)。

当然它可能实际上更慢,因为循环测试现在可能是2个CPU指令而不是你的单个指令。

编辑25/8/2009:感谢黑客注意到一个非常愚蠢的错误!现在修好了。