演算法 階乘之和 資料溢位以及時間測試

2021-07-25 07:49:57 字數 3619 閱讀 3331

階乘之和

例題:輸入n,計算s = 1!+2!+3!+...+n!的未6位(不含前導0)。n<=10^6,n!表示前n個正整數之積。

樣例輸入:

樣例輸出:

分析:這個任務看似不難,實際卻有陷阱。先看如下**:

**1(有缺陷):

//abc
#include#includeint main()

printf("%ld\n",s % 1000000);

return 0;

}

#include#includeint main()

printf("%d\n",s);

printf("time used = %.2f\n",(double)clock() / clocks_per_sec);

return 0;

}

首先是演算法改進:對每部階乘進行求餘,隨後的結果s再進行求餘。先看測試結果:

輸入20,輸出結果:820313; 輸入40,輸出結果:940313; 輸入100,輸出:940313;

輸入160,輸出結果:940313; 輸入1600,輸出結果:940313..........

可以發現從40開始,答案始終不變。這是因為當25!末尾有6個0,所以從第5項開始,後面的所有項都不會影響和的末6位數字。

什麼意思呢:1!-10!舉例如下:

1~10的階乘如下:

1!=1

2!=2

3!=6

4!=24

5!=120

6!=720

7!=5040

8!=40320

9!=362880

10!=3628800

所以有此可見。。。。所以只需要在程式的最前面加一條語句「if(n>25) n=25;」,效率和溢位將都不存在問題。

下面來看程式中其他的東西:這個程式的真正特別之處在於計時函式clock()的使用。該函式返回程式目前為止執行的時間。

這樣,在程式結束之前呼叫此函式,便可獲得整個程式的執行時間。這個時間除以常熟clocks_per_sec之後得到的值以「秒」為單位。

c語言函式clock()  功 能:

返回處理器呼叫某個程序或函式所花費的時間。

用 法:clock_tclock(void);

說明:clock_t其實就是long,即長整形。該函式返回值是硬體滴答數,要換算成秒或者毫秒,需要除以clk_tck或者 clk_tck

clocks_per_sec。比如,在vc++6.0下,這兩個量的值都是1000,這表示硬體滴答1000下是1秒,因此要計算乙個程序的時間,用clock()除以1000即可。

輸入「20」,按enter鍵後,系統瞬間給出了答案820313。但是,輸出的time used居然不是0!其原因在於,鍵盤輸入的時間也被使計算在內——這的確

是程式啟動之後才進行的。為了避免輸入資料的時間影響測試結果,可以使用一種稱為「管道」的小技巧;在windows命令列下執行echo 20|abc,作業系統

會自動把20輸入,其中abc是程式名。

測試可知,程式的執行時間和n的平方成正比。(即程式的時間複雜度為o(n^2))).

我們來測試一下這個程式(測試環境為dev-c++):

當輸入10時,輸出37913,結果正確。 但當輸入100時,輸出-961703。

我們知道int最大值為2^31-1,沒錯,在乘法累加的過程中,整形s的資料溢位。因為我們只求的是階乘之和

的最後六位,沒必要求出階乘s的結果,所以可以從如下進行改進(過求出s的結果,難度更大)。

想要解決這個問題,需要運用這個數學知識:

只要計算包含加法,減法和乘法的整數表示式除以正整數n的餘數,可以在每部計算之後對n取餘,結果不變。

下面請看改進過後的**2,還會有新的東西:

#include#includeint main()

printf("%d\n",s);

printf("time used = %.2f\n",(double)clock() / clocks_per_sec);

return 0;

}

首先是演算法改進:對每部階乘進行求餘,隨後的結果s再進行求餘。

先看測試結果:

輸入20,輸出結果:820313; 輸入40,輸出結果:940313; 輸入100,輸出:940313;

輸入160,輸出結果:940313; 輸入1600,輸出結果:940313..........

可以發現從40開始,答案始終不變。這是因為當25!末尾有6個0,所以從第5項開始,後面的所有項都不會影響和的末6位數字。

什麼意思呢:1!-10!舉例如下:

1~10的階乘如下:

1!=1

2!=2

3!=6

4!=24

5!=120

6!=720

7!=5040

8!=40320 

9!=362880 

10!=3628800

所以有此可見。。。。所以只需要在程式的最前面加一條語句「if(n>25) n=25;」,效率和溢位將都不存在問題。

下面來看程式中其他的東西:這個程式的真正特別之處在於計時函式clock()的使用。該函式返回程式目前為止執行的時間。

這樣,在程式結束之前呼叫此函式,便可獲得整個程式的執行時間。這個時間除以常熟clocks_per_sec之後得到的值以「秒」為單位。

(c語言函式clock()  功 能:

返回處理器呼叫某個程序或函式所花費的時間。

用 法: clock_t clock(void);

說明:clock_t其實就是long,即長整形。該函式返回值是硬體滴答數,要換算成秒或者毫秒,需要除以clk_tck或者 clk_tck

clocks_per_sec。比如,在vc++6.0下,這兩個量的值都是1000,這表示硬體滴答1000下是1秒,因此要計算乙個程序的時間,用clock()除以1000即可。)

輸入「20」,按enter鍵後,系統瞬間給出了答案820313。但是,輸出的time used居然不是0!其原因在於,鍵盤輸入的時間也被使計算在內——這的確

是程式啟動之後才進行的。為了避免輸入資料的時間影響測試結果,可以使用一種稱為「管道」的小技巧;在windows命令列下執行echo 20|abc,作業系統

會自動把20輸入,其中abc是程式名。

測試可知,程式的執行時間和n的平方成正比。(即程式的時間複雜度為o(n^2))).

演算法實現求n的階乘(防止溢位)

求大整數n階乘,在找工作筆試和面試的過程中,不止一次遇到這個問題,用乙個for迴圈迭代出的結果肯定是不行的,即直接用int,預設是32位,它能表示的最大值為2,147,483,647,但是12的階乘為479,001,600,13的階乘為6,227,020,800,所以當n為13的時候已經溢位了。所以...

演算法實現求n的階乘(防止溢位)

求大整數n階乘,在找工作筆試和面試的過程中,不止一次遇到這個問題,用乙個for迴圈迭代出的結果肯定是不行的,即直接用int,預設是32位,它能表示的最大值為2,147,483,647,但是12的階乘為479,001,600,13的階乘為6,227,020,800,所以當n為13的時候已經溢位了。所以...

階乘之和 防止int型別溢位的小技巧 計時函式

計算前n個正整數階乘之和的後六位 注意點是,用乙個int型別儲存階乘之和時,要防止溢位 一,在每一次處理階乘 fa 或者階乘之和 s 時,都對10 6取餘,這樣最終結果不變,還避免了越界 二,計時函式可以用來觀察程式執行時間 用法 printf f double clock clocks per s...