大整數乘法
聲明:本文僅個人筆記
參考鏈接:
https://www.cnblogs.com/McQueen1987/p/3348426.html
https://blog.csdn.net/sinat_32716451/article/details/84174455
題目和分析:
這里面的O(n^2)就是下面的我自己畫的小學乘法計算復雜度示意圖
注意:
- T(n)代表規模為n的問題,系數4表示問題縮小到T(n/2)時,包含四次乘法(上式中AC/AD/BC/BD四次
- 這里第一次是進行了4次的n/2的整數乘法---->4T(n/2)
- 3次2n位的加法,2次移位----->O(n)
- 而后來的改進主要是改進的是遞歸孩子乘法的次數由4變為3
- 所以當n>1的時候主要有T(n)=4T(n/2)變成了3T(n/2)
- 此時T(n)從O(nlog4)變成了O(nlog3),這里的log4和log3其實是以2為底的
這里有個問題就是4次n/2乘法怎么變成n^log4的,等想好再來接着編輯吧
代碼上菜:
注意這里的代碼是十進制大整數進行相乘,而課本給出的是二進制機器數進行相乘
XY = (A10^(n/2) + B)( C10^(n/2) + D)
= AC10^n + AD10^(n/2) + BC10^(n/2) + BD
= AC10^n + ((A-B)(D-C) + AC + BD)10(n/2) + BD
上面的最后一行理解為“先減后加”
而且這里代碼里面是對AD+BC的另外一種形式的推導即“先加后減”
package cn.htu.test;
public class BigDataRide {
public static int sign(long a) {
return a < 0 ? -1 : 1;
}
public static double bigdataride(long x,long y,int n) {
x = Math.abs(x);//符號交給sign函數處理,我們只處理正數
y = Math.abs(y);
if (n == 1) {
return x * y;
}
else {
if (n%2==1) {
n = n - 1; //對奇數的操作;在課本的分析中,所做假設是n是2的冪
}
long a = x / Math.round(Math.pow( 10 , (n / 2)));//移位操作,可以理解為小數點相對左移了
long b = x - a * Math.round(Math.pow( 10 , (n / 2)));//得到的就是低位數值
long c = y / Math.round(Math.pow( 10 , (n / 2)));
long d = y - c * Math.round(Math.pow( 10 , (n / 2)));
double ac = bigdataride(a,c,n/2);//遞歸計算a*c
double bd = bigdataride(b,d,n/2);//計算b*d
long sum_ab = a + b;
long sum_cd = c + d;
double abcd = bigdataride(sum_ab,sum_cd,n/2);
//以上總共調用了3次遞歸函數即log3
//原來推導式里面的((A-B)(D-C)+AC+BD)的結果其實就是先減再加,下面的是先加再減
//即(A+B)(C+D)-AC-BD == AD+BC
return (ac*Math.pow(10,n) + (abcd - ac - bd)*Math.pow(10,n/2) +bd);
}
}
public static void main(String[] args) {
// 十進制大整數相乘(非用戶輸入型)
long x = 12234L;
long y = 45243L;
String xString = String.valueOf(x);//轉為字符串,計算位數存到n
int n = xString.length();
long sig = sign(x)*sign(y);//sign返回參數的正負,sig取值范圍為{1,-1}
double s = bigdataride(x,y,n);//s是數值部分
System.out.println("大數相乘的計算結果為:"+s*sig);
}
}