日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

快速求幂(Quick Exponentiation)

發布時間:2024/6/14 编程问答 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 快速求幂(Quick Exponentiation) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

接觸ACM沒幾天,向各路大神求教,聽說ACM主要是研究算法,所以便開始了苦逼的算法學習之路。話不多說,RT所示,學習快速求冪。

在頭文件<math.h>或是<cmath>中,double pow( double x, double y );函數是用來快速求x^y,于是便從pow函數來說起,以下大體上是pow的函數代碼:

  • int?pow(int?x,?int?n)
  • {??
  • ????int?num?=?1;??
  • ????while?(n?!=?0){??
  • ????????num?=?num?*x;??
  • ????????n?=?n?-1;??
  • ????}??
  • ????return?num;??
  • }?
  • 通過以上程序,2^5 = 2*2*2*2*2的流程中一共進行了4次乘法。試想若是大數2^99999999.......,這樣循環的算下來肯定要計算到猴年馬月。那么我們有什么辦法可以簡化我們的冪指運算呢?

    ?

    分析數據

    2^4=2^2 * 2^2;

    2^5=2^2 * 2^2 * 2

    2^6=2^3 * 2^3

    2^7=2^3 * 2^3 * 2

    ……

    x^n = x^(n/2) * x^(n/2) (n為偶數)

    x^n = x^(n/2) * x^(n/2) * n (n為奇數)

    ?

    顯然這種算法分析利用分治思想(divide and conquer)。通過這種方式,我們可以根據通項公式寫出遞歸函數求分制冪指運算的函數代碼:

  • int?DC_pow(int?x,?int?n)
  • {??
  • ????if?(n==1)?return?x;??
  • ????if?(n==0)?return?1;??
  • ????else?if?(n & 1)??return DC_pow(x,n/2)*DC_pow(x,?n/2)*x;??????//??對應公式x^(n/2) * x^(n/2) * n
  • ????else???????????? return?DC_pow(x,n/2)*DC_pow(x,?n/2);??????? //? 對應公式x^(n/2) * x^(n/2)
  • }
  • 由此我們以分治思想,減少了運算量。接下來,我們研究此遞歸代碼的一些細節。對于n/2,我們在二進制位運算中還有其他的處理方式,倘若一個數是二進制數,只要我們將該數右移一位(x>>1),即可對其真值除以2。也許你又會想,DG想表述的是什么意思,即使我把代碼中的n/2換成n>>1運算量有沒有改變,到底意義何在呢?我們從一個例子引出:

    ?問題:請求出3^999=?(問題目的在于感受不同求解方法的復雜程度)

    ?

    分析:我們先調用最最基本的方式進行求解,即為求:3 * 3 * …… * 3(999個3),這樣一共要進行998次乘法運算。這種方法顯然是太麻煩,反復的遞歸,計算機心里定會默念“我靠,坑爹啊!”

    ?

    接下來,我們使用簡單分制思想來做此題,這樣就可以大大簡少運算次數,使得計算次數僅為9次。但是,如果你也在學習ACM的話,你會懂得遞歸做法運行速度之慢。即使遞歸函數通俗易懂,即使寫法簡單,但是并不推薦。你若不信,我給大家舉一個簡單的例子:

    ?

    利用歐幾里德算法(輾轉相除法)計算兩數的gcd(最大公約數)

    遞歸形式:

  • int gcd(int a,int b)
  • {
  • ??? if(a == 0) return b;
  • ??? else return b == 0?a:gcd(b,a%b);
  • }
  • 非遞歸形式:

  • int gcd(int a,int b)
  • {
  • ??? int c;
  • ??? if(a == 0) return b;
  • ??? while(b!=0) c = b,b = a % b,a = c;
  • ??? return a;
  • }
  • ?

    以上利用相同的思想進行求解a,b的gcd,但是效率有很大偏差,大家可以嘗試。

    那么,還有什么方法來求解這個問題呢,接下來便是經典的快速求冪法。我們將3^999進行分解,即為:?(3 ^ 512) * (3 ^ 256) * (3 ^ 128) * (3 ^ 64) * (3 ^ 32) * (3 ^ 4) * (3 ^ 2) * 3。這時候,我們可以整理出3的指數部分形式:2^9+2^8+2^7+2^6+2^2+2^1+2^0。然后,我們再把999轉換成2進制為1111100111,2進制的轉換作為指數位置的數。由此,我們同樣的利用了分治思想,將指數分成了2的n次方和的形式。配合上右移運算,我們只要將其二進制數與1做與運算,為真則將此位上的2^n次方加入,為假則不加入。下面放出代碼:

  • int?spow(int?x,?int?n)??
  • {??
  • ????int?result?=?1;??
  • ????while?(n?>?0)?
  • ??? {
  • ????????if?(n?&?1)???result?*=?x;??
  • ????????x?*=?x;??
  • ????????n?>>=?1;????????//n=n/2?
  • ????}??
  • ????return?result;??
  • }??
  • ?

    以上便是全部內容,第一次發文,多有錯誤。多多包含。

    ?

    學習本塊知識參考過的博文:

    http://blog.csdn.net/zhizichina/article/details/7573342

    http://blog.csdn.net/hkdgjqr/article/details/5381028

    關于快速求冪的ACM題集:

    HDU1575、HDU1852、HDU2817、HDU2035.

    ?

    轉載于:https://www.cnblogs.com/Destiny-Gem/p/qpow.html

    總結

    以上是生活随笔為你收集整理的快速求幂(Quick Exponentiation)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。