上一篇寫的“[大整數乘法]分治算法的時間復雜度研究”,這一篇是基於上一篇思想的代碼實現,以下是該文章的連接:
http://www.cnblogs.com/McQueen1987/p/3348426.html
代碼主要實現大整數乘法,過程中也涉及到[大整數加法] 和 [大整數減法] 的計算,代碼如下:
類1
————————————————————————————————————————————————————————————
package bigIntNum;
public class NumDividEqual { public char[] A; public char[] B; int n; /** * 將數組均分為兩份,分別存入數組A和數組B中; * @param input */ public NumDividEqual(char[] input){ n = input.length/2; A = new char[n]; B = new char[n]; for(int i = 0; i<n;i++){ A[i] = input[i]; } for(int i = 0; i<n;i++){ B[i] = input[i + n]; } } public static void main(String[] args) { // TODO Auto-generated method stub } }
類2
————————————————————————————————————————————————————————————
package bigIntNum; import java.util.Arrays; public class bigIntMult { /** * 將字符數組倒序排列 * @param input * @return */ public char[] reverse(char[] input) { char[] output = new char[input.length]; for (int i = 0; i < input.length; i++) { output[i] = input[input.length - 1 - i]; } return output; } /** * 將大整數平均分成兩部分 * @param input * @return */ public NumDividEqual partition(char[] input) { return new NumDividEqual(input); } /** * 求兩數組中較大數組的長度,如果其長度為奇數則+1變偶 * @param num1 * @param num2 * @return */ public int calLength(char[] num1, char[] num2) { int len = num1.length > num2.length ? num1.length : num2.length; if (len == 1) return 1; len += len & 1; return len; } /** * 除去數字前面多余的0 * @param input * @return */ public static char[] trimPrefix(char[] input) { char[] ret = null; for (int i = 0; i < input.length; i++) { if (ret == null && input[i] == '0') continue; else { if (ret == null) { ret = new char[input.length - i];//出去數字前面多余的0 } ret[i - (input.length - ret.length)] = input[i]; } } if (ret == null) return new char[] { '0' }; return ret; } /** * 數組如果長度不足n,則在數組前面補0,使長度為n。 * @param input 輸入數組要求數字的最高位存放在數組下標最小位置 * @param n * @return */ public static char[] format(char[] input, int n) {//; if (input.length >= n) { return input; } char[] ret = new char[n]; for (int i = 0; i < n - input.length; i++) { ret[i] = '0'; } for (int i = 0; i < input.length; i++) { ret[n - input.length + i] = input[i]; } return ret; } /** * 大整數尾部補0。相當於移位,擴大倍數 * @param input * @param n * @return */ public char[] addTail(char[] input, int n) {// char[] ret = new char[input.length + n]; for (int i = 0; i < input.length; i++) { ret[i] = input[i]; } for (int i = input.length; i < ret.length; i++) { ret[i] = '0'; } return ret; } /** * 大整數加法 * @param num1 * @param num2 * @return */ public char[] add(char[] num1, char[] num2) { int len = num2.length > num1.length ? num2.length : num1.length; int carry = 0;//進位標識 num1 = format(num1, len); num2 = format(num2, len); char[] ret = new char[len + 1]; for (int i = len - 1; i >= 0; i--) { int tmp = num1[i] + num2[i] - 96; tmp += carry; if (tmp >= 10) { carry = 1; tmp = tmp - 10; } else { carry = 0; } ret[len - i - 1] = (char) (tmp + 48); } ret[len] = (char) (carry + 48);//最后一次,最高位的進位 return trimPrefix(reverse(ret)); } /** * 大整數減法: * @param num1 被減數,大整數乘法中只有一個減法(A+B)(C+D)-(AC+BD)=AC+BC>0,因此參數num1>num2且都為正 * @param num2 減數 * @return */ public static char[] sub(char[] num1, char[] num2) { int lenMax = num1.length > num2.length ? num1.length : num2.length; char[] newNum1 = Arrays.copyOf(format(num1, lenMax), lenMax);//字符串前面補0,使兩串長度相同 char[] newNum2 = Arrays.copyOf(format(num2, lenMax), lenMax); for(int i=0;i<lenMax;i++){//when num1-num2<0 return if((newNum1[i]=='0' && newNum1[i]=='0') || newNum1[i] == newNum2[i]){//newNum1 is bigger; continue; } else if(newNum1[i] < newNum2[i]){//不滿足參數num1>num2; System.out.println("The Parameter in sub(A,B).A MUST Bigger Than B!"); System.exit(0); } else break; } for(int i=lenMax-1;i>=0;i--){ if(newNum1[i] < newNum2[i]){//result < 0 newNum1[i] = (char) (newNum1[i] + '0' + 10 - newNum2[i]); newNum1[i-1] = (char) (newNum1[i-1] - 1); } else{ newNum1[i] = (char) (newNum1[i] + '0' - newNum2[i]); } } return trimPrefix(newNum1); } /** * 大整數乘法 * @param num1 * @param num2 * @return */ public char[] mult(char[] num1, char[] num2) { char[] A, B, C, D, AC, BD, AjB, CjD, ACjBD, AjBcCjD, SUM; int N = calLength(num1, num2);//求兩數組中較大數組的長度,如果長度為奇數則+1變偶,方便二分成兩部分 num1 = format(num1, N);//數組高位存整數的高位數;數字前面補0,使長度為n; num2 = format(num2, N); if (num1.length > 1) { NumDividEqual nu1 = partition(num1);//將大整數平均分成兩部分 NumDividEqual nu2 = partition(num2); A = nu1.A; B = nu1.B; C = nu2.A; D = nu2.B; AC = mult(A, C);//分治求大整數乘法 BD = mult(B, D); AjB = add(A,B); CjD = add(C,D); ACjBD = add(AC,BD); AjBcCjD = mult(AjB, CjD); char[] tmp1 = addTail(sub(AjBcCjD, ACjBD), N / 2);//尾部補0,相當於移位 char[] tmp2 = add(addTail(AC, N), BD); SUM = add(tmp1, tmp2); char[] test = trimPrefix(SUM);//除去結果前面多余的0 return test; } else { Integer ret = (num1[0] - 48) * (num2[0] - 48); return ret.toString().toCharArray(); } } public static void main(String[] args) { String st1 = "168746315641347979798"; String st2 = "164681654767446887797451316158"; char[] a = st1.toCharArray(); char[] b = st2.toCharArray(); bigIntMult bg = new bigIntMult(); char[] ret = bg.mult(a, b); System.out.println(ret); } }
代碼優化:
1.可以寫個hash表,存儲一些常見的乘法,從而避免每次都重復計算。比如9999x9999999,里面有重復的9x9計算,可以考慮hash表存儲這些計算的結果,用到時直接查詢結果,從而避免重復計算。
聲明:代碼是本人腦力勞動結果,請尊重他人勞動。轉載注明出處!