簡體   English   中英

你如何在 C# 中做*整數* 取冪?

[英]How do you do *integer* exponentiation in C#?

.NET 中的內置Math.Pow()函數將double提升為double指數並返回double結果。

對整數執行相同操作的最佳方法是什么?

補充:似乎可以將Math.Pow()結果轉換為 (int),但這會始終產生正確的數字並且沒有舍入錯誤嗎?

一個非常快的可能是這樣的:

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

請注意,這不允許負權力。 我將把它留給你作為練習。 :)

補充:哦,是的,差點忘了 - 還要添加上溢/下溢檢查,否則您可能會遇到一些令人討厭的驚喜。

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);

使用約翰庫克博客鏈接中的數學,

    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);
    }

怎么樣:

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

這是一篇博客文章 ,解釋了將整數提升為整數冪的最快方法。 正如其中一條評論指出的那樣,其中一些技巧是內置於芯片中的。

非常有趣.. .net 5.0 SimplePower() 現在快 350 倍。 我會說在便攜性/性能/可讀性方面最好......

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

這是我過去建造的另一個速度很快的...

    public static int PowerWithSwitch(int x, int pow)
    {
        switch ((uint)pow)
        {
            case 0: return 1;
            case 1: return x;
            case 2: return x * x;
            case 3: return x * x * x;
            case 4: { int t2 = x * x; return t2 * t2; }
            case 5: { int t2 = x * x; return t2 * t2 * x; }
            case 6: { int t3 = x * x * x; return t3 * t3; }
            case 7: { int t3 = x * x * x; return t3 * t3 * x; }
            case 8: { int t3 = x * x * x; return t3 * t3 * x * x; }
            case 9: { int t3 = x * x * x; return t3 * t3 * t3; }
            case 10: { int t3 = x * x * x; return t3 * t3 * t3 * x; }
            case 11: { int t3 = x * x * x; return t3 * t3 * t3 * x * x; }
            case 12: { int t3 = x * x * x; return t3 * t3 * t3 * t3; }
            case 13: { int t3 = x * x * x; return t3 * t3 * t3 * t3 * x; }
            case 14: { int t4 = x * x * x * x; return t4 * t4 * t4 * x * x; }
            case 15: { int t4 = x * x * x * x; return t4 * t4 * t4 * x * x * x; }
            case 16: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4; }
            case 17: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * x; }
            case 18: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * x * x; }
            case 19: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * x * x * x; }
            case 20: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * t4; }
            case 21: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * t4 * x; }
            case 22: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * t4 * x * x; }
            case 23: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * t4 * x * x * x; }
            case 24: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * t4 * t4; }
            case 25: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * t4 * t4 * x; }
            case 26: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * t4 * t4 * x * x; }
            case 27: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * t4 * t4 * x * x * x; }
            case 28: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * t4 * t4 * t4; }
            case 29: { int t4 = x * x * x * x; return t4 * t4 * t4 * t4 * t4 * t4 * t4 * x; }
            default:
                if (x == 0)
                    return 0;
                else if (x == 1)
                    return 1;
                else
                    return (x % 1 == 0) ? int.MaxValue : int.MinValue;
        }
        return 0;
    }

性能測試 (.Net 5)


  • MathPow(Sunsetquest):11 毫秒(.net 4 = 3693 毫秒)<- 快 350 倍!!!

  • PowerWithSwitch(Sunsetquest):145 毫秒(.net 4 = 298 毫秒)

  • 維爾克斯:148 毫秒(.net 4 = 320 毫秒)

  • Evan Moran-遞歸除法:249 毫秒(.net 4 = 644 毫秒)

  • 迷你我:288 毫秒(.net 4 = 194 毫秒)

  • Charles Bretana(又名庫克的):536 毫秒(.net 4 = 950 毫秒)

  • LINQ 版本:4416 毫秒(.net 4 = 3693 毫秒)

(測試說明:AMD Threadripper Gen1,.Net 4 & 5,發布版本,未附加調試器,bases:0-100k,exp:0-10)

注意:在上述測試中幾乎沒有進行准確性檢查。

使用雙版本,檢查溢出(超過 max int 或 max long)並轉換為 int 或 long?

我最喜歡這個問題的解決方案是經典的分而治之的遞歸解決方案。 它實際上比乘 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。

我將結果轉換為 int,如下所示:

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

在這種情況下,沒有舍入錯誤,因為基數和指數是整數。 結果也將是整數。

對於一個簡短的快速單線。

int pow(int i, int exp) => (exp == 0) ? 1 : i * pow(i, exp-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));
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM