你如何在C#中进行*整数*取幂?

时间:2008-12-20 18:40:29

标签: c# math integer exponentiation

.NET中的内置Math.Pow()函数将double基数提升为double指数并返回double结果。

使用整数执行相同操作的最佳方法是什么?

补充:似乎可以将Math.Pow()结果转换为(int),但这是否会产生正确的数字而没有舍入错误?

11 个答案:

答案 0 :(得分:42)

一个非常快的可能是这样的:

int IntPow(int x, uint pow)
{
    int ret = 1;
    while ( pow != 0 )
    {
        if ( (pow & 1) == 1 )
            ret *= x;
        x *= x;
        pow >>= 1;
    }
    return ret;
}

请注意,这不允许负功率。我会把它作为练习留给你。 :)

已添加:哦,是的,差点忘了 - 还要添加溢出/下溢检查,否则你可能会遇到一些令人讨厌的惊喜。

答案 1 :(得分:41)

LINQ任何人?

public static int Pow(this int bas, int exp)
{
    return Enumerable
          .Repeat(bas, exp)
          .Aggregate(1, (a, b) => a * b);
}

用作扩展名:

var threeToThePowerOfNine = 3.Pow(9);

答案 2 :(得分:19)

在John Cook的博客链接中使用数学,

    public static long IntPower(int x, short power)
    {
        if (power == 0) return 1;
        if (power == 1) return x;
        // ----------------------
        int n = 15;
        while ((power <<= 1) >= 0) n--;

        long tmp = x;
        while (--n > 0)
            tmp = tmp * tmp * 
                 (((power <<= 1) < 0)? x : 1);
        return tmp;
    }           

解决反对意见,如果你改变了权力的类型,代码将无法工作,那么......除了改变他们不理解的代码然后在没有测试的情况下使用它的任何人的观点...... <登记/> 但为了解决这个问题,这个版本可以保护愚蠢的人不受这个错误的影响...(但不是来自他们可能制造的其他人)注意:没有经过测试。

    public static long IntPower(int x, short power)
    {
        if (power == 0) return 1;
        if (power == 1) return x;
        // ----------------------
        int n = 
            power.GetType() == typeof(short)? 15:
            power.GetType() == typeof(int)? 31:
            power.GetType() == typeof(long)? 63: 0;  

        long tmp = x;
        while (--n > 0)
            tmp = tmp * tmp * 
                 (((power <<= 1) < 0)? x : 1);
        return tmp;
    }

也尝试这种递归等价物(当然慢一点):

    public static long IntPower(long x, int power)
    {
        return (power == 0) ? x :
            ((power & 0x1) == 0 ? x : 1) *
                IntPower(x, power >> 1);
    }

答案 3 :(得分:9)

lolz,怎么样:

public static long IntPow(long a, long b)
{
  long result = 1;
  for (long i = 0; i < b; i++)
    result *= a;
  return result;
}

答案 4 :(得分:7)

这是一个blog post,它解释了将整数提升为整数幂的最快方法。正如其中一条评论所指出的,其中一些技巧已内置于芯片中。

答案 5 :(得分:4)

使用双版本,检查溢出(超过max int或max long)并转换为int或long?

答案 6 :(得分:3)

另外两个......

    public static int FastPower(int x, int pow)
    {
        switch (pow)
        {
            case 0: return 1;
            case 1: return x;
            case 2: return x * x;
            case 3: return x * x * x;
            case 4: return x * x * x * x;
            case 5: return x * x * x * x * x;
            case 6: return x * x * x * x * x * x;
            case 7: return x * x * x * x * x * x * x;
            case 8: return x * x * x * x * x * x * x * x;
            case 9: return x * x * x * x * x * x * x * x * x;
            case 10: return x * x * x * x * x * x * x * x * x * x; 
            case 11: return x * x * x * x * x * x * x * x * x * x * x; 
            // up to 32 can be added 
            default: // Vilx's solution is used for default
                int ret = 1;
                while (pow != 0)
                {
                    if ((pow & 1) == 1)
                        ret *= x;
                    x *= x;
                    pow >>= 1;
                }
                return ret;
        }
    }

    public static int SimplePower(int x, int pow)
    {
        return (int)Math.Pow(x, pow);
    }

我做了一些快速的性能测试


  • 迷你我:32毫秒

  • Sunsetquest(快速):37 ms

  • Vilx:46 ms

  • Charles Bretana(aka Cook's):166 ms

  • Sunsetquest(简单):469 ms

  • 3dGrabber(Linq版):868 ms

(测试笔记:intel i7 2nd gen,.net 4,发布版本,发布版本,1M不同基础,exp仅0-10)

结论:mini-me在性能和简单性方面都是最好的

完成了非常小的准确度测试

答案 7 :(得分:2)

我最喜欢的解决方案是一个经典的分而治之的递归解决方案。它实际上比n倍乘以更快,因为它每次减少乘法的数量减半。

public static int Power(int x, int n)
{
  // Basis
  if (n == 0)
    return 1;
  else if (n == 1)
    return x;

  // Induction
  else if (n % 2 == 1)
    return x * Power(x*x, n/2);
  return Power(x*x, n/2);
}

注意:这不会检查溢出或负n。

答案 8 :(得分:1)

我将结果转换为int,如下所示:

double exp = 3.0;
int result = (int)Math.Pow(2.0, exp);

在这种情况下,没有舍入错误,因为base和exponent是整数。 结果也是整数。

答案 9 :(得分:0)

短暂的快速单行。

int pow(int i, int exp) => (exp == 0) ? 1 : i * pow(i, exp-1);

没有负指数也没有溢出检查。

答案 10 :(得分:-1)

另一种方法是:

int Pow(int value, int pow) {
    var result = value;
    while (pow-- > 1)
        result *= value;
    return pow == 0 ? result : pow == -1 ? 1 : throw new ArgumentOutOfRangeException(nameof(pow));
}