Java版超大整數(shù)階乘算法代碼詳解-10,0000級
當計算超過20以上的階乘時,階乘的結(jié)果值往往會很大。一個很小的數(shù)字的階乘結(jié)果就可能超過目前個人計算機的整數(shù)范圍。如果需求很大的階乘,比如1000以上完全無法用簡單的遞歸方式去解決。在網(wǎng)上我看到很多用C、C++和C#寫的一些關(guān)于大整數(shù)階乘的算法,其中不乏經(jīng)典但也有很多粗糙的文章。數(shù)組越界,一眼就可以看出程序本身無法運行。轉(zhuǎn)載他人文章的時候,代碼倒是仔細看看啊。唉,粗糙。過年了,在家閑來蛋疼,仔細分析分析,用Java實現(xiàn)了一個程序計算超大整數(shù)階乘。思想取自網(wǎng)上,由我個人優(yōu)化和改進。
這個方法采用“數(shù)組進位”算法。在超越計算機變量取值范圍的情況下,將多位數(shù)相乘轉(zhuǎn)化為一位數(shù)相乘。如11!=39916800,若需求12的階乘,則需要將39916800與12相乘,可利用乘法分配率。乘法豎式如下圖所示:
使用一個數(shù)組來保存階乘每一位的結(jié)果,一個數(shù)組元素保存一位數(shù)。例如:將11的階乘的結(jié)果399
16800保存到數(shù)組的8個元素中,要計算12的階乘就用每個數(shù)組元素中的值去乘以12,并將結(jié)果保存到原來的數(shù)組元素中。接下來去判斷每個數(shù)組元素是否需要進位,通過進位操作使數(shù)組中的每個元素保存的數(shù)都只有一位數(shù),示意圖如下:
理論上講,只要計算機內(nèi)存空間允許就可以保存任意多位的階乘結(jié)果,不再受變量的取值范圍的限制,只受到操作系統(tǒng)的尋址能力和計算機內(nèi)存的限制。友情提示:如果要求的階乘數(shù)字很大則可以將數(shù)組定義為long類型,以避免在計算單位數(shù)的乘積時出現(xiàn)溢出的情況。
實現(xiàn)代碼如下:
public class BigInteger { /** * 計算進位 * @param bit 數(shù)組 * @param pos 用于判斷是否是數(shù)組的最高位 */ private void carry(int[] bit, int pos) { int i ,carray = 0; for (i = 0 ; i<= pos ;i++)//從0到pos逐位檢查是否需要進位 { bit[i] += carray; //累加進位 if(bit[i] <= 9) //小于9不進位 { carray = 0; } else if(bit[i] >9 && i<pos)//大于9,但不是最高位 { carray = bit[i]/10; //保存進位值 bit[i] = bit[i]%10; //得到該位的一位數(shù) } else if(bit[i] > 9 && i >= pos)//大于9,且是最高位 { while(bit[i] > 9)//循環(huán)向前進位 { carray = bit[i]/10; //計算進位值 bit[i] = bit[i] % 10; //當前的第一位數(shù) i ++ ; bit[i] = carray; //在下一位保存進位值 } } } } /** * 大整數(shù)階乘 * @param bigInteger 所計算的大整數(shù) */ private void bigFactorial(int bigInteger) { int pos =0; // int digit; //數(shù)據(jù)長度 int a , b ; int m = 0 ; //統(tǒng)計輸出位數(shù) int n = 0 ; //統(tǒng)計輸出行數(shù) double sum = 0; //階乘位數(shù) for (a = 1 ; a <= bigInteger ; a ++)//計算階乘位數(shù) { sum += Math.log10(a); } digit = (int)sum + 1; //數(shù)據(jù)長度 int[] fact = new int[digit]; //初始化一個數(shù)組 fact[0] = 1; //設(shè)個位為 1 for (a = 2 ; a <= bigInteger ; a++ )//將2^bigInteger逐個與原來的積相乘 { for (b = digit-1 ; b >= 0 ; b--)//查找最高位{} { if( fact[b] != 0 ) { pos = b ; //記錄最高位 break; } } for (b = 0; b <= pos ; b++) { fact[b] *= a ; //每一位與i乘 } carry(fact,pos); } for (b = digit-1 ; b >= 0 ; b --) { if(fact[b] != 0) { pos = b ; //記錄最高位 break; } } System.out.println(bigInteger +"階乘結(jié)果為:"); for (a = pos ; a >= 0 ; a --)//輸出計算結(jié)果 { System.out.print(fact[a]); m++; if(m % 5 == 0) { System.out.print(" "); } if(40 == m ) { System.out.println(""); m = 0 ; n ++; if(10 == n ) { System.out.print("\n"); n = 0; } } } System.out.println("\n"+"階乘共有: "+(pos+1)+" 位"); } public void doBigFactorial(int bigInteger) { int timeBegin=(int) System.currentTimeMillis(); this.bigFactorial(bigInteger); int timeFinishi=(int) System.currentTimeMillis(); int time = timeFinishi-timeBegin; System.out.println("計算耗時: " + time +"毫秒" ); } public static void main(String[] args) { BigInteger bi = new BigInteger(); bi.doBigFactorial(100000); } }
計算10,0000的階乘,顯示結(jié)果如下:
這樣的結(jié)果,控制臺顯然已經(jīng)無法保存內(nèi)容了。10萬的階乘有45萬位之多,這就相當于一本有45萬字的小說一樣。對比1000的階乘結(jié)果如下:
控制臺可以完整顯示。
總結(jié)
以上就是本文關(guān)于Java版超大整數(shù)階乘算法代碼詳解-10,0000級的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:
《Java編程實現(xiàn)對十六進制字符串異或運算代碼示例》
《Java編程實現(xiàn)基于用戶的協(xié)同過濾推薦算法代碼示例》
如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
mybatis插入數(shù)據(jù)后返回自增主鍵ID的兩種實現(xiàn)方式
這篇文章主要介紹了mybatis插入數(shù)據(jù)后返回自增主鍵ID的兩種實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05JeecgBoot框架升級至Spring?Boot3的實戰(zhàn)步驟
本文主要介紹了JeecgBoot框架升級至Spring?Boot3的實戰(zhàn)步驟,從?2.7.10升級到3.1.5有以下幾個點需要注意,下面就來詳細的介紹一下,感興趣的可以了解一下2024-04-04SpringBoot實現(xiàn)各種參數(shù)校驗總結(jié)(建議收藏!)
本文深入解析了Spring?Validation的使用方法、實現(xiàn)原理及最佳實踐,詳細介紹了各種參數(shù)校驗場景,如requestBody和requestParam/PathVariable的使用,并探討了分組校驗、嵌套校驗和自定義校驗的高級應(yīng)用,需要的朋友可以參考下2024-09-09基于SpringBoot實現(xiàn)動態(tài)配置數(shù)據(jù)庫的加載
這篇文章主要介紹了Spring?Boot?如何動態(tài)配置數(shù)據(jù)庫的加載,現(xiàn)項目有一個需求,期望通過在application.yml配置文件中設(shè)置一個開關(guān),來決定是否加載數(shù)據(jù)庫,文中通過代碼示例講解的非常詳細,需要的朋友可以參考下2024-10-10java底層JDK?Logging日志模塊處理細節(jié)深入分析
這篇文章主要為大家介紹了java底層JDK?Logging日志模塊處理細節(jié)深入分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03