快速冪算法

2021-02-24 凌雲網絡實驗室

循環算法:

long long normalPower(long long base,long long power){

    long long result=1;

    for(int i=1;i<=power;i++){

        result=result*base;

    }

    return result%1000;

}

但是仔細思考後會發現,當a和b很大的時候,這有很大的缺點,指數關係很容易爆炸。這道題其實出的很有意思,題目要求你輸出結果的後三位,為什麼不讓你直接輸出結果呢?難道僅僅只是為了增大題目的難度嗎?

我們可以看一下關於取模的規律

對於取模來說

(a + b) % p =(a % p + b % p) % p (1)

(a - b) % p = (a % p - b % p ) % p (2)

(a * b) % p = (a % p * b % p) % p (3)

其中我們只要關注第「3」條法則即可:(a * b) % p = (a % p * b % p) % p ,我們仔細研究一下這個運算法則,會發現多個因子連續的乘積取模的結果等於每個因子取模後的乘積再取模的結果。也就是說,我們如果要求:

 

(a*b*c)%d=(a%d*b%d*c%d)%d;

因此,我們可以藉助這個法則,只需要在循環乘積的每一步都提前進行「取模」運算,而不是等到最後直接對結果「取模」,也能達到同樣的效果。

所以,我們的代碼可以變成這個樣子:

long long normalPower(long long base,long long power){

    long long result=1;

    for(int i=1;i<=power;i++){

        result=result*base;

        result=result%1000;

    }

    return result%1000;

}


    但是時間複雜度依然是O(N),有什麼方法可以更快一點呢?(看標題)

快速冪:

快速冪算法能幫我們算出指數非常大的冪,傳統的求冪算法之所以時間複雜度非常高(為O(指數n)),就是因為當指數n非常大的時候,需要執行的循環操作次數也非常大。所以我們快速冪算法的核心思想就是每一步都把指數分成兩半,而相應的底數做平方運算。這樣不僅能把非常大的指數給不斷變小,所需要執行的循環次數也變小,而最後表示的結果卻一直不會變。讓我們先來看一個簡單的例子:

3^10=3*3*3*3*3*3*3*3*3*3

儘量想辦法把指數變小來,這裡的指數為10

3^10=(3*3)*(3*3)*(3*3)*(3*3)*(3*3)

3^10=(3*3)^5

 3^10=9^5

此時指數由10縮減一半變成了5,而底數變成了原來的平方,求3^10原本需要執行10次循環操作,求9^5卻只需要執行5次循環操作,但是3^10卻等於9^5,我們用一次(底數做平方操作)的操作減少了原本一半的循環量,特別是在冪特別大的時候效果非常好,例如2^10000=4^5000,底數只是做了一個小小的平方操作,而指數就從10000變成了5000,減少了5000次的循環操作。

現在我們的問題是如何把指數5變成原來的一半,5是一個奇數,5的一半是2.5,但是我們知道,指數不能為小數,因此我們不能這麼簡單粗暴的直接執行5/2,然而,這裡還有另一種方法能表示9^5

 9^5=(9^4)*(9^1)

此時我們抽出了一個底數的一次方,這裡即為9^1,這個9^1我們先單獨移出來,剩下的9^4又能夠在執行「縮指數」操作了,把指數縮小一半,底數執行平方操作

9^5=(81^2)*(9^1)

把指數縮小一半,底數執行平方操作

9^5=(6561^1)*(9^1)

此時,我們發現指數又變成了一個奇數1,按照上面對指數為奇數的操作方法,應該抽出了一個底數的一次方,這裡即為6561^1,這個6561^1我們先單獨移出來,但是此時指數卻變成了0,也就意味著我們無法再進行「縮指數」操作了。

9^5=(6561^0)*(9^1)*(6561^1)=1*(9^1)*(6561^1)=(9^1)*(6561^1)=9*6561=59049

我們能夠發現,最後的結果是9*6561,而9是怎麼產生的?是不是當指數為奇數5時,此時底數為9。那6561又是怎麼產生的呢?是不是當指數為奇數1時,此時的底數為6561。所以我們能發現一個規律:最後求出的冪結果實際上就是在變化過程中所有當指數為奇數時底數的乘積。 

代碼

```

long long fastPower(long long base, long long power) {

    long long result = 1;

    while (power > 0) {

        if (power % 2 == 0) {

            //如果指數為偶數

            power = power / 2;//把指數縮小為一半

            base = base * base % 1000;//底數變大成原來的平方

        } else {

            //如果指數為奇數

            power = power - 1;//把指數減去1,使其變成一個偶數

            result = result * base % 1000;//此時記得要把指數為奇數時分離出來的底數的一次方收集好

            power = power / 2;//此時指數為偶數,可以繼續執行操作

            base = base * base % 1000;

        }

    }

    return result;

}

``` 

優化:

```

long long fastPower(long long base, long long power) {

    long long result = 1;

    while (power > 0) {

        if (power % 2 == 1) {

            result = result * base % 1000;

        }

        power = power / 2;

        base = (base * base) % 1000;

    }

    return result;

}

按位運算:

在C語言中,power%2==1可以用更快的「位運算」來代替,例如:power&1。因為如果power為偶數,則其二進位表示的最後一位一定是0;如果power是奇數,則其二進位表示的最後一位一定是1。將他們分別與1的二進位做「與」運算,得到的就是power二進位最後一位的數字了,是0則為偶數,是1則為奇數。例如5是奇數,則5&1=1;而6是偶數,則6&1=0;因此奇偶數的判斷就可以用「位運算」來替換了。

而且,對於power=power/2來說,也可以用更快的「位運算」進行替代,我們只要把power的二進位表示向右移動1位就能變成原來的一半了。

代碼:

```

long long fastPower(long long base, long long power) {

    long long result = 1;

    while (power > 0) {

        if (power & 1) {//此處等價於if(power%2==1)

            result = result * base % 1000;

        }

        power >>= 1;//此處等價於power=power/2

        base = (base * base) % 1000;

    }

    return result;

}

相關焦點

  • 快速冪與位運算
    << Pow(base, power) << endl; finish = clock(); cout << "the time cost is " << double(finish - start) / CLOCKS_PER_SEC; return 0;}雖然可以求出來,但時間非常長,因此引入了更好的算法
  • 快速區分指數函數與冪函數
    通過本文您可以快速區分指數函數與冪函數,同時了解「冪函數」叫法的由來。 y=x^a與y=a^x哪一個是指數函數,哪一個是冪函數?一句話就可以區分:自變量在指數部分的為指數函數,底為自變量的是冪函數。我們常說某種物體呈指數式增長,就是指它的增長曲線為指數函數,表示增長迅速!
  • 一分鐘算法 —— Miller-Rabin 質數判斷法
    實際上這就是著名的Miller-Rabin算法的基礎。1975年時,有個名叫 Miller 的年輕人,正在寫他的博士論文,前面就是他的論文的結論。現在的問題來了,如何快速地求出 a ^ ( P-1) 呢(邊做邊去 mod P)?這時,就可以用到快速冪了(圖文頂部的連結),折半求再平方,遞歸比較合適。這樣的話,複雜度是log(P),很小呀!
  • 冪的運算小結+測驗(同底數冪的乘法、冪的乘方、積的乘方)
    冪的運算包括同底數冪的乘法、冪的乘方和積的乘方。同底數冪的乘法即相同底數的冪相乘,冪的乘方即乘方再乘方,積的乘方即乘積的乘方。要理解這三個概念,首先要明白什麼是乘方和冪。求幾個相同因數的積的運算叫做乘方,乘方的結果叫做冪。乘方是一種運算,強調過程;冪是結果,強調整體。很多時候二者可以通用,比如2^3可以讀作2的3次方,也可以讀作2的3次冪。
  • 初中數學:冪運算(同底數冪乘除、冪的乘方、積的乘方)經典題
    冪的運算是整式的乘法和除法的基礎,同學們計算易出錯,主要就是在冪的運算上出錯多,一是對冪的內涵理解不夠,導致計算方法(公式)混淆;二是思路不明確,無從下手。冪的運算:同底數冪的乘法、冪的乘方、積的乘方。
  • 二次函數與冪函數題型歸納
    二次函數與冪函數是高中數學經常考的內容,冪函數圖像的畫法很重要,一定要把它掌握,注意區分冪函數與指數函數的區別。二次函數圖像根的分布也是考察的重點,尤其是二次函數含參問題的分類討論,討論的過程和步驟都是很固定的。多做一些相似的題型,把固定的討論解題步驟總結在筆記本上。
  • 快速色彩平衡算法分析
    摘 要: 在圖像處理中,為了提高傳統色彩平衡算法的計算速度、降低算法的複雜度,提出了一種全新的快速色彩平衡算法,即過濾少量極端像素顏色值並按比例提高剩餘的非極端像素顏色值的方法
  • 計算機入門必備算法——快速排序法
    準備停止學習一周,等把項目這一關過了,再繼續深入學習分享算法。後來吧今天遇到的事情都比較鬱悶,也無心情繼續開發項目。便想轉移一下注意力,繼續學習快速排序算法的內容。昨天了解了遞歸的使用原理。今天可以使用這個新技能來解決一個新的問題————快速排序。快速排序是一種排序算法,這個算法比前天學習的選擇排序要快得多,實屬優雅代碼的典範。
  • 冪律分布
    前幾天我們聊了正態分布,今天我們來聊另一種重要的分布,這就是冪律分布。而這個二八法則,正是冪律分布最為直觀的表現。冪律分布的曲線圖十分簡單,橫坐標代表隨機變量的取值,縱坐標代表發生的概率,而冪律分布就是一條向下延伸的曲線,就好像拖著一條長長的尾巴,所以它告訴我們的就是,在隨機變量中,越小的數值,出現的概率就越大,越大的數值,出現的概率就越小。
  • 數字推理—冪次數列之冪次修正數列
    上一篇文章中,濤哥給大家講了關於冪次數列中純冪次數列的解法。今天這堂課給大家分享冪次數列中冪次修正數列的相關知識點。
  • 基於高速定點FFT算法的FPGA設計方案
    引 言 快速傅立葉變換(FFT)作為計算和分析工具,在眾多學科領域(如信號處理、圖像處理、生物信息學、計算物理、應用數學等)有著廣泛的應用。在高速數位訊號處理領域,如雷達信號處理,FFT的處理速度往往是整個系統設計性能的關鍵所在。
  • 冪律:自然界中的一個普遍規律
    冪律,又稱冪定律、冪法則,英文:Power law,表述兩個量之間的一種函數關係,描述其中一個量的相對變化導致另一個量相對變化的關係,而與這些量的初始大小無關:一個量隨另一個量的冪而冪律變化,例如,正方形的邊長,如果長度加倍,則面積乘以四;如計算機摩爾定律的冪數增長;又如量子計算機的能力隨量子比特數呈冪數增長。
  • 18歲華裔少年顛覆量子加速優勢,推動量子算法經典化
    如百度量子實驗室負責人段潤堯在朋友圈評論說,「這是有關經典推薦算法的非常有意思的進展。原先 Kerenidis 和 Prakash 證明了量子計算機能夠比任何已知算法以指數級的速度解決推薦問題,但他們並沒有證明快速的經典算法不存在。而 18 歲的 Ewin 則給出了一個快速的經典推薦算法,從而說明 KP 量子算法其實相對於經典算法並無實際優勢。
  • 冪函數是奇函數嗎?是增函數嗎?所有冪函數具有的性質都在這!
    冪函數的奇偶性⑴當冪函數的冪指數a是奇數時,冪指數y=x^a是奇函數。⑷當冪函數的冪指數a是分數且分母是偶數時,冪函數y=x^a是非奇非偶函數。當冪指數為分數且分母是偶數時說明該冪指數要開偶次方根,所以x取值範圍是(0,+∞),所以此時的冪函數的定義域並不關於原點對稱,即冪函數y=x^a此時是非奇非偶函數。
  • 盤點20世紀最偉大的十大算法
    七、1962 快速排序算法[1962: Tony Hoare of Elliott Brothers, Ltd., London, presents Quicksort.]1962年:倫敦的,託尼埃利奧特兄弟有限公司,霍爾提出了快速排序。哈哈,恭喜你,終於看到了可能是你第一個比較熟悉的算法~。
  • 冪級數是個什麼鬼?
    1.冪級數的形式先來看看冪級數的一般形式:冪級數其實是特殊的多項式,其最高次冪是無窮大量。在學習微分中值定理,其實就已經接觸了冪級數,那泰勒展開式就是冪級數。2.冪級數的阿貝爾定理阿貝爾定理的內容可以分為兩部分,第一部分:若冪級數在點x=b處收斂,其中b>0,那麼冪級數在區間(-b, b)內絕對收斂。
  • 其實冪零矩陣是高等代數最核心的東西
    冪零矩陣是矩陣論極為重要的知識點, 這是因為任何方陣都可以相似於一個若爾當形矩陣, 而每一個若爾當塊都是 aE+J 的形式, 這裡
  • 51單片機整數二一十進位轉換的快速算法
    提出的快速算法思路是,首先求出整數中包含的1000的個數,方法是採用二進位整數的高6位作為其預估,再通過2次校正得到準確值。算法的關鍵是充分利用89C51單片機的兩條特殊指令――單字節乘和單字節除。其耗費時間不及使用sprintf()函數的1/10。
  • 二十世紀最偉大的十大經典算法
    七、1962 快速排序算法[1962: Tony Hoare of Elliott Brothers, Ltd., London, presents Quicksort.]1962年:倫敦的,託尼埃利奧特兄弟有限公司,霍爾提出了快速排序。哈哈,恭喜你,終於看到了可能是你第一個比較熟悉的算法~。
  • 2021年初中八年級代數考點:整數指數冪,分數指數冪的運算
    中考網整理了關於2021年初中八年級代數考點:整數指數冪,分數指數冪的運算,希望對同學們有所幫助,僅供參考。   整數指數冪,分數指數冪的運算   考核要求:   (1)掌握冪的運算法則;   (2)會用整數指數冪及負整數指數冪進行運算;   (3)掌握負整數指數式與分式的互化;   (4)知道分數指數式與根式的互化。