1. 程式人生 > >【Java學習心得】之程式設計計算1!+2!+3!+...+100!

【Java學習心得】之程式設計計算1!+2!+3!+...+100!

昨天Java老師給我們佈置了一道Java的程式設計習題,題目是程式設計求解1!+2!+3!+…+100!,筆者剛拿到這道題第一反應就是一道白痴題,兩個迴圈巢狀不就完了嗎。但是後來仔細想想,不對,因為100!這個數絕對是個天文數字,在Java中long是長整型變數,其所能表示的數值範圍為-9223372036854775808~9223372036854775807,這已經很大了,但是,100!這個數算出來會遠遠大於long的最大值,更別說還要算一個累加了,結果必然會出現溢位。那麼問題來了,連long這種長整型的變數都放不下,難道這道題就算不出來了?答案當然是肯定有方法。
為了完成作業,筆者開始在網上搜索關於Java大資料方面的資料,偶然中發現了在Java中有兩個特別的類BigDecimal和BigInteger,他們分別可以儲存非常大的浮點型變數和整型變數,於是筆者便查閱了Java的API文件(1.6中文版),結果如下(本文以BigInteger為例說明):
API文件搜尋結果截圖


從中我們可以發現,用這個類可以表示任意精度的整數,只要你的電腦記憶體夠大。繼續往下翻,可以看到這個類提供了很多可呼叫的方法,結合這道題目,我覺得這麼幾個方法我們可能會用上:

*首先是一個構造方法,可以通過一個字串構造一個BigInteger變數

BigInteger
public BigInteger(String val)將 BigInteger 的十進位制字串表示形式轉換為 BigInteger。該字串表示形式包括一個可選的減號,後跟一個或多個十進位制數字序列。字元到數字的對映由 Character.digit 提供。該字串不能包含任何其他字元(例如,空格)。
 引數:
 val - BigInteger 的十進位制字串表示形式。 
 丟擲: 
 NumberFormatException - val 不是 BigInteger 的有效表示形式。

*然後是加法、乘法和除法運算方法

**add**
public BigInteger add(BigInteger val)返回其值為 (this + val) 的BigInteger。 
引數:
val - 將新增到此 BigInteger 中的值。 
返回:
this + val

**multiply**
public BigInteger multiply(BigInteger val)返回其值為 (this * val) 的 BigInteger。
引數:
val - 要乘以此 BigInteger 的值。 
返回:
this * val

**divide**
public BigInteger divide(BigInteger val)返回其值為 (this / val) 的 BigInteger。
引數:
val - 此 BigInteger 要除以的值。 
返回:
this / val 
丟擲: 
ArithmeticException - val==0

那麼如此一來,我們就可以輕易的計算出這個表示式了,下面貼上程式碼:

import java.math.BigInteger;
public class Task3_3 {
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    BigInteger bignum1 = new BigInteger("1");
    BigInteger bignum2 = new BigInteger("0");       
    int n=1;
    while(n<=100) {
        bignum1=bignum1.multiply(BigInteger.valueOf(n));            
        bignum2=bignum2.add(bignum1);
        n++;
    }
    System.out.println(bignum2.toString());
    }
}

這個程式中,筆者建立了兩個BigInteger的物件bignum1和bignum2,前者用於儲存階乘的結果,後者儲存累加的結果,對於這兩個變數的初始化可以通過上面提到的建構函式,以字串轉換的方式實現初始化:

  BigInteger bignum1 = new BigInteger("1");
  BigInteger bignum2 = new BigInteger("0");

為了提高程式執行的效率,根據題目的特點,沒有使用傳統的重複計算階乘的方法,因為我們注意到,當計算n!時實際上就等於是(n-1)!*n而 (n-1)!前面已經計算過了,我們就沒有必要再去計算一遍了,所以可以重複利用前一步計算的結果,每乘一個數就把前面的結果加一遍,通過一層迴圈就可以計算出結果,從而大大減小程式的時間複雜度,程式碼實現如下:

//重複利用前(n-1)次的計算結果以降低程式的時間複雜度
int n=1;
while(n<=100) {
    bignum1=bignum1.multiply(BigInteger.valueOf(n));            
    bignum2=bignum2.add(bignum1);
    n++;
}

最後在列印輸出的時候將bignum2轉換成字串後直接輸出即可:

System.out.println(bignum2.toString());

最後計算的結果就是這麼一個超級天文數字:
94269001683709979260859834124473539872070722613982672442938359305624
67822347950602340029409359913646698660912434743264762282687003822055
6442336528920420940313

小弟第一次寫部落格,都是一些自己在學習Java的過程中的心得與收穫,希望能與大家分享,但畢竟不是什麼高手,所以對於文章中的一些疏漏和錯誤還望大神們能幫忙指出。。謝謝!O(∩_∩)O~