大整数乘法
声明:本文仅个人笔记
参考链接:
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);
}
}