在C++中将整数提升为正整数幂的正确方法是什么?

sta*_*tti 26 c++ math numerical

我们知道由于各种原因,C++中没有标准的整数幂函数.我用相当小的整数执行精确算术,计算能力的正确方法是什么?

Ker*_* SB 45

标准的快速取幂使用重复的平方:

uint_t power(uint_t base, uint_t exponent)
{
    uint_t result = 1;

    for (uint_t term = base; exponent != 0; term = term * term)
    {
        if (exponent % 2 != 0) { result *= term; }
        exponent /= 2;
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

步数是对数的exponent.该算法可以简单地扩展到模幂运算.


更新:这是算法的修改版本,它可以执行少一次乘法并更有效地处理一些简单的案例.此外,如果您知道指数永远不为零且基数从不为零或一,您甚至可以删除初始检查:

uint_t power_modified(uint_t base, uint_t exponent)
{
    if (exponent == 0) { return 1;    }
    if (base < 2)      { return base; }

    uint_t result = 1;

    for (uint_t term = base; ; term = term * term)
    { 
        if (exponent % 2 != 0) { result *= term; }
        exponent /= 2;
        if (exponent == 0)     { break; }
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

  • @Gorpik:这个答案对我来说看起来不是尾递归的.除了教育或理论工作外,我不会觉得这样做. (3认同)
  • @PeterWood:它是众所周知的,它是通用的(同样适用于乘法加法),它是快速的(对数),它很简单,它利用了一些不错的机器属性(整数除以2非常快) ...所以我说很难想出更好的东西. (2认同)

Pli*_*der 19

你可以用std::pow(double a, double b).如果两者都没有不准确a,b并且结果适合32位整数!

原因是64位双精度完全覆盖了32位整数的范围.

  • @NovaDenizen不,双打完全覆盖了32位整数.换句话说,对于每个整数,有一个双精度为零的小数部分.和其他算术运算一样,pow()必须给出"最接近的"双重答案,在这种情况下,它将等于整数. (15认同)
  • @static_rtti:对于完全符合尾数的所有整数都是如此,对于`float`是24位,对于`double`是53位,对于IEEE754中的'long double`是64位. (2认同)
  • @ user1698678 C标准要求所有计算精确到1 ULP(精度最低的单位),这意味着真正的答案可能是+/- 1 ULP,所以我的谨慎态度仍然存在.如果C使用1/2 ULP精度标准,那么你就是正确的. (2认同)
  • @static_rtti:快速测试,10M次7 ^ 11:整数(快速32位):0.5s.双倍:9.0秒. (2认同)