秦九韶算法是中國南宋時期的數學家秦九韶提出的一種多項式簡化算法,在西方被稱作霍納算法。它是一種將一元n次多項式的求值問題轉化為n個一次式的算法。
一般地,我們用系數表達一個一元n次多項式(對應的,還有點值表達),在這種表達方式下直接求值需要執行n(n+1)/2次乘法和n次加法,時間復雜度為O(n2);而秦九韶算法只需要n次乘法和n次加法,時間復雜度為O(n),大大簡化了計算過程,即使在現代,利用計算機解決多項式的求值問題時,秦九韶算法依然是最優的算法。
題目:寫程序計算給定多項式在給定點x處的值 f(x) = a0 + a1x + … + an-1xn-1 + anxn
分析:對比使用常規算法和秦九韶算法求解多項式,並輸出它們各自消耗的時間進行比較。
這里用到了time.h頭文件中的clock()函數,它的函數原型如下:
_CRTIMP clock_t __cdecl __MINGW_NOTHROW clock (void); // 可以把它直接視為clock_t clock(void);
返回值clock_t是用來保存時間的數據類型,它是一個長整型數。這個函數返回從開啟這個程序進程到程序中調用clock()函數之間的CPU時鍾計時單元(clock tick,即時鍾打點)數
在time.h文件中,還定義了一個常量CLOCKS_PER_SEC,它用來表示一秒鍾會有多少個時鍾計時單元(clock tick)。其定義如下:
#define CLOCKS_PER_SEC ((clock_t)1000)
可以看到每過千分之一秒(1毫秒),調用clock()函數返回的值就加1。所以想要得到一段程序從開始到現在執行的時間(以秒為單位),只需用 (double)clock()/CLOCKS_PER_SEC ,也可以使用CLK_TCK替代CLOCKS_PER_SEC,詳見官方文檔
這里我們只需測試我們自定義函數執行的時間,這個時間往往不足一個clock tick,所以我們必須重復調用被測函數,使得測出的總的時鍾打點間隔充分長,最后在除以調用次數,才能得到被測函數的單次執行時間
源碼:
#include<stdio.h> #include<time.h> #include<math.h> #define MAXK 1e7 // 被測函數重復調用次數1*10^7 #define MAXN 10 // 多項式最大項數,即多項式階數+1(n階多項式有n+1個項,包括一個常數項) clock_t start,stop; // clock_t是clock()函數的返回變量類型 double duration; // 記錄被測函數運行時間,以秒為單位 double f1(int n,double a[],double x); // 常規算法聲明 double f2(int n,double a[],double x); // 秦九韶算法函數聲明 int main() { int i; double a[MAXN]; // 存儲多項式的系數(系數暫且賦值為i) for(i=0; i<MAXN; i++) a[i] = (double)i; /* 不再測試范圍內的准備工作寫在clock()調用之前 */ start = clock(); // 開始計時 for(i=0; i<MAXK; i++) f1(MAXN-1,a,1.1); // 重復調用測試函數f1以獲得充分多的時間打點數 stop = clock(); // 停止計時 /* 其他不再測試范圍的處理寫在后面 */ duration = (double)(stop - start)/CLOCKS_PER_SEC/MAXK;// 計算測試函數單次運行時間 printf("ticks1 = %ld\t",stop-start); printf("duration1 = %6.2e\n",duration); /* 不再測試范圍內的准備工作寫在clock()調用之前 */ start = clock(); // 開始計時 for(i=0; i<MAXK; i++) f2(MAXN-1,a,1.1); // 重復調用測試函數f2以獲得充分多的時間打點數 stop = clock(); // 停止計時 /* 其他不再測試范圍的處理寫在后面 */ duration = (double)(stop - start)/CLOCKS_PER_SEC/MAXK;// 計算測試函數單次運行時間 printf("ticks2 = %ld\t",stop-start); printf("duration2 = %6.2e\n",duration); return 0; } double f1( int n, double a[], double x ) // 常規算法 { int i; double p = a[0]; for (i=1; i<=n; i++) p += (a[i] * pow(x, i)); return p; } double f2( int n, double a[], double x ) // 秦九韶算法 { int i; double p = a[n]; for (i=n; i>0; i-- ) p = a[i-1] + p*x; return p; }
運行結果:
從結果看出,兩種方法的運行時間不在一個數量級之上,利用秦九韶算法f2計算多項式大大的提高了效率。