大整数乘法
分治法
将一个规模为N的问题,分解成K个规模较小的子问题,这些子问题相互独立且月原问题性质相同,求解出子问题的解,合并得到原问题的解
java中的BigInteger总结
(1)程序有时需要处理大整数,java.math包中的BigInteger类提供任意精度的整数运算,可以使用构造方法:
public BigInteger(String VAL)构造一个十进制的BigInteger对象,该构造方法可以发生NumberFormatException异常,也就是说,字符串参数VAL中如果含有非数字字符就会发生NumberFormatException异常。
(2)BigInteger类的常用方法:
public BigInteger add(BigInteger val) 返回当前大整数对象与参数指定的大整数对象的和
public BigInteger subtract(BigInteger val) 返回当前大整数对象与参数指定的大整数对象的差
public BigInteger multiply(BigInteger val) 返回当前大整数对象与参数指定的大整数对象的积
public BigInteger devide(BigInteger val) 返回当前大整数对象与参数指定的大整数对象的商
public BigInteger remainder(BigInteger val) 返回当前大整数对象与参数指定的大整数对象的余
public int compareTo(BigInteger val) 返回当前大整数对象与参数指定的大整数对象的比较结果,返回值是1、-1、0,分别表示当前大整数对象大于、小于或等于参数指定的大整数。
public BigInteger abs() 返回当前大整数对象的绝对值
public BigInteger pow(int exponent) 返回当前大整数对象的exponent次幂。
public String toString() 返回当前当前大整数对象十进制的字符串表示。
public String toString(int p) 返回当前大整数对象p进制的字符串表示。
但是这篇文章不用这个java内置的方法来实现大数乘法
import java.util.*;
import java.math.*;
public class NumMul{
public static void main(String args[]){
Scanner cin = new Scanner(System.in);
BigInteger a, b;
while(cin.hasNext()){
a = cin.nextBigInteger();
b = cin.nextBigInteger();
System.out.println(a.multiply(b));
}
}
}
分治算法特征分析
分治法能解决的问题一般具有以下几个特征:
-
该问题的规模缩小到一定程度就可以容易的解决;
-
该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;
-
利用该问题分解出子问题的解,可以合并为该问题的解;
-
该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题;
分治算法大多采用递归实现,第二条特征就反应了递归思想的引用。
如果满足了第一条特征和第二条特征,不满足第三条特征,可以考虑用贪心法或动态规划法。
如果不满足第四条特征,也可以用分治法,但是要做很多不必要的工作,重复的解公共的子问题,所以一般用动态规划法比较好。
大整数乘法:十进制
解法一(分治法)
将两个整数分别一分为二:
X = A*10^(n/2) + B
Y = C*10^(n/2) + D
X*Y = (A*10^(n/2) + B)*( C*10^(n/2) + D) = A*C*10^n + A*D*10^(n/2) + B*C*10^(n/2) + B*D
但是这样做并没有减少直接相乘的的时间复杂度,所以要继续减少乘法的次数
X*Y = (A*10^(n/2) + B)*( C*10^(n/2) + D)
= A*C*10^n + A*D*10^(n/2) + B*C*10^(n/2) + B*D
= A*C*10^n + ((A+B)(C+D) – A*C – B*D)*10*(n/2) + B*D
或者:= A*C*10^n + ((A-B)(D-C) + A*C + B*D)*10*(n/2) + B*D
然后利用上面的公式写递归就好了
代码如下:
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);
y = Math.abs(y);
if (n == 1) {
return x * y;
}
else {
if (n%2==1) {
n = n - 1; //对奇数的操作
}
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 aJb = a + b;
long cJd = c + d;
double abcd = bigdataride(aJb,cJd,n/2);
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 sx = String.valueOf(x);
int n = sx.length();
long sig = sign(x)*sign(y);
double s = bigdataride(x,y,n);
System.out.println("大数相乘的计算结果为:"+s*sig);
}
}
解法二
模拟乘法
将两个数分别存入两个数组,然后根据乘法规则两层for循环分别让数字相乘,并存入一个新的数组,大致为这样:result[a+b] += num1[a]*num2[b];
,现在这个result里存储的就是一个非个位数的临时结果,只需要做后将这个临时结果分别进位便可得到最终结果
代码如下:
import java.util.Scanner;
//创建类largenumberOperationMultiply
public class largenumberOperationMultiply {
//定义方法multiply的功能
public String multiply(String str1,String str2){
int[] num1 = new int[str1.length()];
int[] num2 = new int[str2.length()];
int[] result = new int[str1.length() + str2.length()];
//将两个字符串转成整型数组,顺序转换,数组下标越小,数字对应的位数越高
for (int i = 0;i < str1.length(); i++){
num1[i] = Integer.parseInt(str1.substring(i,i+1));
}
for (int i = 0;i < str2.length(); i++){
num2[i] = Integer.parseInt(str2.substring(i,i+1));
}
//两大数相乘
for (int a = 0;a < str1.length(); a++){
for (int b = 0;b < str2.length(); b++){
result[a+b] += num1[a]*num2[b];
}
}
////判断是否需要进位,满10进1,因为存储顺序与位数高低相反,所以采用逆序进位
int temp;
for (int k = result.length-1; k > 0; k--){
temp=result[k]/10; //数组下标大的向数组下标小的进位
result[k-1] += temp;
result[k] = result[k]%10;
}
//将结果数组逆序转化为字符串
String resultstr = "";
for (int i = 0; i < result.length-1; i++){
resultstr += "" + result[i];
}
return resultstr;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入第一个数:");
String str1 = sc.next();
System.out.println("请输入第二个数:");
String str2 = sc.next();
largenumberOperationMultiply bn = new largenumberOperationMultiply();
//创建类largenumberOperationMultiply的对象bn
String output = bn.multiply(str1,str2);
//bn对象调用multiply方法对str1和str2进行操作
System.out.println(str1+"与"+str2+"的积为:"+output);
}
}
来个c版本的数组实现大数乘法
#include<stdio.h>
#include<string.h>
#include<math.h>
#define N 1005
char a[N],b[N];
int s1[N],s2[N],s3[N*N];
int main()
{
int len1,len2,max,i,j;
while(scanf("%s%s",a,b)!=EOF)
{
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
memset(s3,0,sizeof(s3));
len1=strlen(a);
len2=strlen(b);
max=0;
max=len1+len2;
for(i=0,j=len1-1;i<len1;i++,j--)
s1[i]=a[j]-'0';
for(i=0,j=len2-1;i<len2;i++,j--)
s2[i]=b[j]-'0';
for(i=0;i<len1;i++)
for(j=0;j<len2;j++)
s3[i+j]+=s1[i]*s2[j];
for(i=0;i<max;i++)
{
if(s3[i]>=10)
{
s3[i+1]+=s3[i]/10;
s3[i]%=10;
}
}
while(s3[max-1]==0)
{
if(s3[max-1]==0)
max--;
}
for(i=max-1;i>=0;i--)
printf("%d",s3[i]);
printf("
");
}
return 0;
}