階乘程式設計
步驟一:自己模擬為計算機一步一步運算
N! = N * N-1 * N-2 * ...... * 2 * 1
1 * 2 --> 2
2 * 3 --> 6
6 * 4 --> 24
.
.
.
* N --> 結果
步驟二:
int i;
int iResult;
int iNum;
步驟三:個別語法測試
- scanf("%d",&iNum);
- iResult = 1;
- for (i=2; i<=iNum; i++) {...}
- iResult = iResult * i;
- printf("%d 階乘是 %d\n",iNum,iResult);
步驟四:整合程式、編譯、更正語法錯誤
步驟五:測試
- 輸入 4,答案是不是 24?
- 輸入 5,答案是不是 120?
- 輸入 6,答案是不是 720?
- 輸入 7,答案是不是 5040?
- 輸入 8,答案是不是 40320? 答案對嗎? 奇怪吧? 快找一個合理的解釋!
如果你的程式和我的一樣的話你會看到 "8 階乘是 -25216"
這樣的答案,差夠多的了,
其實這是因為 40320 已經超過 32767 (2^15-1),
32767 是 TURBO C 中 int 型態變數所能表示的最大正數,
超過了會斷頭的,
多出來的位元就不見了,
那為什麼是負的呢?
因為剩下的部份最高位元剛剛好是 1 啊。
請參考
二進位資料表示法、
二的補數表示法、
C 語言中各種變數的型態、
資料型態的轉換。
- 輸入 20,答案是...
這個答案沒什麼參考價值,
我們只是更加證實這個程式沒有辦法算出 8! 以上的階乘了。
- 輸入 -10,答案是.... 程式在做什麼呀?
這個數字其實是使用者很可能會輸入的數字,
你寫程式的時候千萬別怪使用者為什麼不弄清楚才輸入,
可能是使用者故意的,
也可能是不小心的,
你的程式應該要想辦法解決這樣子的輸入狀況,
是不是該做一些特殊的檢查來防止這樣子的輸入呢?
- 輸入 3.5,還會做耶! 你猜程式在做什麼?
scanf("%d",&iNum) 其實只讀到小數點的位置就停下來了,
因為它發現不是 0 到 9 的數字輸入時就做了一個判斷,
認為該輸入的整數已經結束了,
後面的字元是要給其它的變數的。
步驟六:只能做 7! 的程式實在是太沒用了,改一下看能不能多做一點
我用手算 (也許你是用心算的) 都很容易算到 10!,
如果只能算到 7! 的話,
為什麼還要寫程式呢?
如上面所說的,
既然是變數的資料型態的問題,
那我們來試看看用 long lResult; 儲存乘積,
....請動手修改
再來測試一下:
- 輸入 10,答案是不是 3628800?
- 輸入 11,答案是不是 39916800?
- 輸入 12,答案是不是 479001600?
- 輸入 13,答案是不是 6227020800?
又錯了吧!
這未免太沒用了,
才 13! 耶?
注意:其實 13 很小,
但是 13! 很大,
10 的 9 次方了呢?
在資訊系裡你一定要知道看到階乘要很尊敬,
隨隨便便叫你的電腦把一件事重複做 20! 次的話,
很可能還沒做完就已經進入二十一世紀了,
做完的時候你的電腦也該報廢了。
步驟七:再改一下看能不能多做一點
用 double dResult; 來試看看吧!
- 輸入 20,答案是不是 2432902008176640000?
- 輸入 21,答案是不是 51090942171709440000?
- 輸入 22,答案是不是 1124000727777607680000?
- 輸入 23,答案是不是 25852016738884976640000?
- 輸入 24,答案是不是 620448401733239439360000?
23 及 24 好像又不太對了,
還好以 23! 來說,
誤差不過是 10 的 7 次方而已,
和這個 10 的 23 次方的正確數值比起來算是小的了,
如果你再繼續試下去的話,
你會發現一直到 170! 都可以做,
不會有很離譜的數字出現了,
但是誤差與正確數值的比例會維持在 10 的負 16 次方附近,
勉強可以接受了吧?
為什麼會有這樣子的誤差請參考
C 語言中各種變數的型態
換一個角度來想,
如果你今天到一家銀行存入 23! 的錢,
銀行經理跑出來跟你說很抱歉因為電腦化的關係,
你的帳戶裡的錢會有一點點誤差,
大概在 10 的 7 次方左右而已,
才幾千萬嘛,
你就別計較了,
有可能比較少也有可能比較多哦!
你覺得這樣子合理嗎?
你會不會想要換一家銀行看看會不會有保證帳號內金額比存進去的要多的?
步驟八:還能夠再做得好一點嗎?
可以的,
但是要用程式自己定義的方法來儲存數值,
比方說一個位元組儲存一個十進位數字,
200 位數的數字就可以用 200 個變數來分別儲存,
同時也要定義這種數字的加減乘除方法,
請下載並執行大數之階乘程式範例。
我們需要陣列及迴圈兩種技術後才能撰寫上面這個範例。
注意:
-
請不要用 TURBO C/C++ 中的 long double 來表示數字,
這種方法不是 ANSI C 中的表示法,
也就是說並不是每一個 C 的編譯器都可以用這樣子的敘述,
程式習慣用這種特殊的資料型態的話,
你的軟體會限制在某一種平台上。
-
在數值計算中常常要算類似
的運算式的數值,
千萬別以為 30, 30!, 和 20! 都是整數就用 int 或是
long 型態的變數來運算啊!