使用 Karatsuba 乘法(递归高斯 "trick")将两个大数相乘时无法得到正确答案
can't get the right answer when multiplying two large numbers using Karatsuba multiplication(recursive Gauss "trick")
我一直在尝试使用字符串来实现整数乘法问题。较小数字的乘积总是正确的,但对于较大数字,结果是错误的。
谁能告诉我是哪部分代码导致了问题?
一个:3141592653589793238462643383279502884197169399375105820974944592
b: 2718281828459045235360287471352662497757247093699959574966967627
答案:8539734222646569768352026223696548756537378365658178539814559622482948999279606844390394705148206869490910283679004[84736215]
正确答案:853973422267356706546355086954657449503488853576511496187960112706774304489320484861787507221624907301333748951871211=854[720=854]
int getEquallength(string &a,string &b)
{
int n1=a.length();
int n2=b.length();
if(n1>n2)
{
for(int i=0;i<n1-n2;i++)
{
b='0'+b;
}
}
else if(n2>n1)
{
for(int i=0;i<n2-n1;i++)
{
a='0'+a;
}
}
return n1;
}
string addstrings(string a,string b)
{
int n=getEquallength(a,b);
n=a.length();
string result="";
int carry=0;
for(int i=n-1;i>=0;i--)
{
int f=a[i]-'0';
int s=b[i]-'0';
int sum=f+s+carry;
carry=sum/10;
sum=sum%10+'0';
result=char(sum)+result;
}
if(carry) result=char(carry+'0')+result;
return result;
}
string substract_str(string a,string b)
{
int n=getEquallength(a,b);
int carry=0;
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
string result;
for(int i=0;i<a.length();i++)
{
int f=a[i]-'0';
int s=b[i]-'0';
int sub=0;
sub=f-s-carry;
if(sub<0)
{
sub+=10;
carry=1;
}
else
carry=0;
result=char(sub+'0')+result;
}
return result;
}
string karatsuba(string a,string b)
{
int n=getEquallength(a,b);
if(n==0) return "0";
if(n==1)
{
return to_string(atoi(a.c_str())*atoi(b.c_str()));
}
int fh=n/2;
int sh=n-n/2;
string Xl=a.substr(0,fh);
string Xr=a.substr(fh,sh);
string Yl=b.substr(0,fh);
string Yr=b.substr(fh,sh);
string P1=karatsuba(Xl,Yl);
string P2=karatsuba(Xr,Yr);
string res=addstrings(P1,P2);
string P3=karatsuba(addstrings(Xl,Xr),addstrings(Yl,Yr));// (Xl+Xr)*(Yl+Yr)
P3=substract_str(P3,res);//P3=Xl*Yr+Xr.Yl
for(int i=0;i<2*sh;i++)
{
P1.push_back('0');
}
for(int i=0;i<sh;i++)
{
P3.push_back('0');
}
P1= addstrings(P1,P2);
string result=addstrings(P1,P3);
return result;
}
您在 getEqualLength 中有一个简单的错误。它应该 return a.length() 或 b.length()。这是更正后的代码:
//#include <bits/stdc++.h>
#include <string>
#include <iostream>
using namespace std;
int getEquallength(string& a, string& b)
{
int n1 = a.length();
int n2 = b.length();
if (n1 > n2)
{
for (int i = 0; i < n1 - n2; i++)
{
b = '0' + b;
}
}
else if (n2 > n1)
{
for (int i = 0; i < n2 - n1; i++)
{
a = '0' + a;
}
}
return a.length();
}
string addstrings(string a, string b)
{
int n = getEquallength(a, b);
n = a.length();
string result = "";
int carry = 0;
for (int i = n - 1; i >= 0; i--)
{
int f = a[i] - '0';
int s = b[i] - '0';
int sum = f + s + carry;
carry = sum / 10;
sum = sum % 10 + '0';
result = char(sum) + result;
}
if (carry) result = char(carry + '0') + result;
return result;
}
string substract_str(string a, string b)
{
int n = getEquallength(a, b);
int carry = 0;
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
string result;
for (int i = 0; i < a.length(); i++)
{
int f = a[i] - '0';
int s = b[i] - '0';
int sub = 0;
sub = f - s - carry;
if (sub < 0)
{
sub += 10;
carry = 1;
}
else
carry = 0;
result = char(sub + '0') + result;
}
return result;
}
string karutsuba(string a, string b)
{
int n = getEquallength(a, b);
if (n == 0) return "0";
if (n == 1)
{
return to_string(atoi(a.c_str()) * atoi(b.c_str()));
}
int fh = n / 2;
int sh = n - n / 2;
string Xl = a.substr(0, fh);
string Xr = a.substr(fh, sh);
string Yl = b.substr(0, fh);
string Yr = b.substr(fh, sh);
string P1 = karutsuba(Xl, Yl);
string P2 = karutsuba(Xr, Yr);
string res = addstrings(P1, P2);
string P3 = karutsuba(addstrings(Xl, Xr), addstrings(Yl, Yr));// (Xl+Xr)*(Yl+Yr)
P3 = substract_str(P3, res);//P3=Xl*Yr+Xr.Yl
for (int i = 0; i < 2 * sh; i++)
{
P1.push_back('0');
}
for (int i = 0; i < sh; i++)
{
P3.push_back('0');
}
P1 = addstrings(P1, P2);
string result = addstrings(P1, P3);
return result;
}
int main()
{
string a, b;
cout << "a:" << '\n';
cin >> a;
cout << "b:" << '\n';
cin >> b;
int n = getEquallength(a, b);
cout << karutsuba(a, b);
}
我一直在尝试使用字符串来实现整数乘法问题。较小数字的乘积总是正确的,但对于较大数字,结果是错误的。
谁能告诉我是哪部分代码导致了问题?
一个:3141592653589793238462643383279502884197169399375105820974944592
b: 2718281828459045235360287471352662497757247093699959574966967627
答案:8539734222646569768352026223696548756537378365658178539814559622482948999279606844390394705148206869490910283679004[84736215]
正确答案:853973422267356706546355086954657449503488853576511496187960112706774304489320484861787507221624907301333748951871211=854[720=854]
int getEquallength(string &a,string &b)
{
int n1=a.length();
int n2=b.length();
if(n1>n2)
{
for(int i=0;i<n1-n2;i++)
{
b='0'+b;
}
}
else if(n2>n1)
{
for(int i=0;i<n2-n1;i++)
{
a='0'+a;
}
}
return n1;
}
string addstrings(string a,string b)
{
int n=getEquallength(a,b);
n=a.length();
string result="";
int carry=0;
for(int i=n-1;i>=0;i--)
{
int f=a[i]-'0';
int s=b[i]-'0';
int sum=f+s+carry;
carry=sum/10;
sum=sum%10+'0';
result=char(sum)+result;
}
if(carry) result=char(carry+'0')+result;
return result;
}
string substract_str(string a,string b)
{
int n=getEquallength(a,b);
int carry=0;
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
string result;
for(int i=0;i<a.length();i++)
{
int f=a[i]-'0';
int s=b[i]-'0';
int sub=0;
sub=f-s-carry;
if(sub<0)
{
sub+=10;
carry=1;
}
else
carry=0;
result=char(sub+'0')+result;
}
return result;
}
string karatsuba(string a,string b)
{
int n=getEquallength(a,b);
if(n==0) return "0";
if(n==1)
{
return to_string(atoi(a.c_str())*atoi(b.c_str()));
}
int fh=n/2;
int sh=n-n/2;
string Xl=a.substr(0,fh);
string Xr=a.substr(fh,sh);
string Yl=b.substr(0,fh);
string Yr=b.substr(fh,sh);
string P1=karatsuba(Xl,Yl);
string P2=karatsuba(Xr,Yr);
string res=addstrings(P1,P2);
string P3=karatsuba(addstrings(Xl,Xr),addstrings(Yl,Yr));// (Xl+Xr)*(Yl+Yr)
P3=substract_str(P3,res);//P3=Xl*Yr+Xr.Yl
for(int i=0;i<2*sh;i++)
{
P1.push_back('0');
}
for(int i=0;i<sh;i++)
{
P3.push_back('0');
}
P1= addstrings(P1,P2);
string result=addstrings(P1,P3);
return result;
}
您在 getEqualLength 中有一个简单的错误。它应该 return a.length() 或 b.length()。这是更正后的代码:
//#include <bits/stdc++.h>
#include <string>
#include <iostream>
using namespace std;
int getEquallength(string& a, string& b)
{
int n1 = a.length();
int n2 = b.length();
if (n1 > n2)
{
for (int i = 0; i < n1 - n2; i++)
{
b = '0' + b;
}
}
else if (n2 > n1)
{
for (int i = 0; i < n2 - n1; i++)
{
a = '0' + a;
}
}
return a.length();
}
string addstrings(string a, string b)
{
int n = getEquallength(a, b);
n = a.length();
string result = "";
int carry = 0;
for (int i = n - 1; i >= 0; i--)
{
int f = a[i] - '0';
int s = b[i] - '0';
int sum = f + s + carry;
carry = sum / 10;
sum = sum % 10 + '0';
result = char(sum) + result;
}
if (carry) result = char(carry + '0') + result;
return result;
}
string substract_str(string a, string b)
{
int n = getEquallength(a, b);
int carry = 0;
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
string result;
for (int i = 0; i < a.length(); i++)
{
int f = a[i] - '0';
int s = b[i] - '0';
int sub = 0;
sub = f - s - carry;
if (sub < 0)
{
sub += 10;
carry = 1;
}
else
carry = 0;
result = char(sub + '0') + result;
}
return result;
}
string karutsuba(string a, string b)
{
int n = getEquallength(a, b);
if (n == 0) return "0";
if (n == 1)
{
return to_string(atoi(a.c_str()) * atoi(b.c_str()));
}
int fh = n / 2;
int sh = n - n / 2;
string Xl = a.substr(0, fh);
string Xr = a.substr(fh, sh);
string Yl = b.substr(0, fh);
string Yr = b.substr(fh, sh);
string P1 = karutsuba(Xl, Yl);
string P2 = karutsuba(Xr, Yr);
string res = addstrings(P1, P2);
string P3 = karutsuba(addstrings(Xl, Xr), addstrings(Yl, Yr));// (Xl+Xr)*(Yl+Yr)
P3 = substract_str(P3, res);//P3=Xl*Yr+Xr.Yl
for (int i = 0; i < 2 * sh; i++)
{
P1.push_back('0');
}
for (int i = 0; i < sh; i++)
{
P3.push_back('0');
}
P1 = addstrings(P1, P2);
string result = addstrings(P1, P3);
return result;
}
int main()
{
string a, b;
cout << "a:" << '\n';
cin >> a;
cout << "b:" << '\n';
cin >> b;
int n = getEquallength(a, b);
cout << karutsuba(a, b);
}