作者:Byte_Liu 來(lái)源:http://byteliu.com/categories/
題目:在不使用BigInteger類的情況下,如何計(jì)算兩個(gè)大正整數(shù)的和?
程序不可能通過(guò)一條指令計(jì)算出兩個(gè)大整數(shù)的和,但我們可以把一個(gè)大運(yùn)算拆分成多個(gè)小運(yùn)算, 像小學(xué)生一樣列豎式進(jìn)行按位運(yùn)算。這里還有一個(gè)問(wèn)題,我們都知道long類型的取值范圍是:
最小值:Long.MIN_VALUE=-9223372036854775808 (-2的63次方)
最大值:Long.MAX_VALUE=9223372036854775807 (2的63次方-1)
如果大整數(shù)超出了long類型能表示的范圍,我們?nèi)绾未鎯?chǔ)這樣的整數(shù)呢?
很容易想到,使用數(shù)組存儲(chǔ)即可,數(shù)組的每一個(gè)元素對(duì)應(yīng)大整數(shù)的每一個(gè)位數(shù)。
在程序中列出的 “豎式” 究竟是什么樣子呢?
我們以 426709752318 + 95481253129 為例,來(lái)看看大整數(shù)相加的詳細(xì)步驟:
第一步,把整數(shù)倒序存儲(chǔ),整數(shù)的個(gè)位存于數(shù)組0下標(biāo)位置,最高位存于數(shù)組長(zhǎng)度-1下標(biāo)位置。之所以倒序存儲(chǔ),更加符合我們從左到右訪問(wèn)數(shù)組的習(xí)慣。
第二步,創(chuàng)建結(jié)果數(shù)組,結(jié)果數(shù)組的最大長(zhǎng)度是較大整數(shù)的位數(shù)+1,原因很明顯。
第三步,遍歷兩個(gè)數(shù)組,從左到右按照對(duì)應(yīng)下標(biāo)把元素兩兩相加,就像小學(xué)生計(jì)算豎式一樣。
例子中,最先相加的是數(shù)組A的第1個(gè)元素8和數(shù)組B的第1個(gè)元素9,結(jié)果是7,進(jìn)位1。把7填充到Result數(shù)組的對(duì)應(yīng)下標(biāo),進(jìn)位的1填充到下一個(gè)位置:
第二組相加的是數(shù)組A的第2個(gè)元素1和數(shù)組B的第2個(gè)元素2,結(jié)果是3,再加上剛才的進(jìn)位1,把4填充到Result數(shù)組的對(duì)應(yīng)下標(biāo):
第三組相加的是數(shù)組A的第3個(gè)元素3和數(shù)組B的第3個(gè)元素1,結(jié)果是4,把4填充到Result數(shù)組的對(duì)應(yīng)下標(biāo):
第四組相加的是數(shù)組A的第4個(gè)元素2和數(shù)組B的第4個(gè)元素3,結(jié)果是5,把5填充到Result數(shù)組的對(duì)應(yīng)下標(biāo):
以此類推……一直把數(shù)組的所有元素都相加完畢:
第四步,把Result數(shù)組的全部元素再次逆序,去掉首位的,就是最終結(jié)果:
如果給定的大整數(shù)最長(zhǎng)位數(shù)是n,那么創(chuàng)建數(shù)組、按位運(yùn)算、結(jié)果逆序的時(shí)間復(fù)雜度各自都是O(n),整體時(shí)間復(fù)雜度就是O(n)。
/** * 類描述: 大整數(shù)求和 * * @author yugu.lx 2018/10/20 23:02 PM */ public class BigNumSum { public static void main(String args[]) { char c = '7'; int i = c; //如何把 char ‘7’ 轉(zhuǎn)為 int 7, 不能直接int i= '7'轉(zhuǎn)化,那樣得到是‘7’的Ascii值,即int 55 System.out.println(i); //可以采用如下方式進(jìn)行操作把 char ‘7’ 轉(zhuǎn)為 int 7;‘0’的Ascii值是48 int ii = c - '0'; System.out.println(ii); System.out.println(new BigNumSum().bigNumSum("426709752318", "95481253129")); } private String bigNumSum(String bigNum1, String bigNum2) { char[] num1Chars = new StringBuilder(bigNum1).reverse().toString().toCharArray(); char[] num2Chars = new StringBuilder(bigNum2).reverse().toString().toCharArray(); int[] result = new int[Math.max(num1Chars.length, num1Chars.length) + 1]; for (int i = 0; i < result.length; i++) { if (i < num1Chars.length) { result[i] += num1Chars[i] - '0'; carryCover(result, i); } if (i < num2Chars.length) { result[i] += num2Chars[i] - '0'; carryCover(result, i); } } return transferToIntString(result); } /** * 進(jìn)位操作 * * @param result * @param i */ private void carryCover(int[] result, int i) { if (i == result.length - 1) { return; } if (result[i] >= 10) { result[i] -= 10; result[i + 1] += 1; } } /** * 把數(shù)組轉(zhuǎn)化成字符串 * * @param array * @return */ private String transferToIntString(int[] array) { StringBuilder sb = new StringBuilder(); for (int i = array.length - 1; i >= 0; i--) { //如果最高位為0的話則去掉 if (i == array.length - 1 && array[i] == 0) { continue; } sb.Append(array[i]); } return sb.toString(); } }