软件乘法实现
【加密算法笔记之代码仓库】
------------
博文声明:本博文隶属加密算法笔记的Integer multiplication一节,提供算法的软件实现,不提供代码解释。
------------
1. 竖式乘法
#include <iostream>
#include <string>
using namespace std;
void Reverse(string &A){
int ALength = A.size();
for (int i = 0; i < ALength / 2; i++)
{
char temp = A[i];
A[i] = A[ALength - 1 - i];
A[ALength - 1 - i] = temp;
}
}
void StrToNum(string &A) {
for (int i = 0; i < A.size(); i++)
A[i] -= '0';
}
string GetProductOfTwoBigNum(string A, string B)
{
int ALength = A.size();
int BLength = B.size();
//转换为数字
StrToNum(A);
StrToNum(B);
//以字符串的形式存储整数,整数最高位在数组最低索引处。
//希望从0开始遍历数组,使最低位在低索引处,最故将元素倒序。
Reverse(A);
Reverse(B);
int CLength = ALength + BLength; //乘积最大字符数
string C(CLength, NULL); //最终乘积
char V = NULL; //每位乘积
char U = NULL; //进位
int c_i; //乘积索引
for (int i = 0; i < BLength; i++)
{
U = NULL;
for (int j = 0; j < ALength; j++)
{
V = (B[i] * A[j] + C[i + j] + U) % 10;
U = (B[i] * A[j] + C[i + j] + U) / 10; //进位用于下一位计算
C[i + j] = V; //乘积中当前位值更新
}
C[i + ALength] = U;
}
//乘积输出
string strResult;
int k = CLength - 1;
while (k >= 0 && C[k] == NULL)
--k;
//倒序,高位在左
for (; k >= 0; --k)
strResult.push_back(C[k] + '0');//转换为字符
if (strResult.empty())
strResult.push_back('0');
return strResult;
}
int main()
{
string A, B;
cout << "输入两个乘数:";
while (cin >> A >> B)
{
string strResult = GetProductOfTwoBigNum(A, B);
cout << "两数之积:" << strResult << endl;
cout << "-------------------------------------------------" << endl;
cout << "输入两个乘数:";
}
return 0;
}
2. Karatsuba分治优化
#include <iostream>
#include <string>
#include<sstream>
#include<windows.h>
using namespace std;
string mult(string num1, string num2);
string sub(string num1, string num2);
string add(string& num1, string& num2);
void trimPrefix(string& input);
string addTail(string input, int n);
string format(string& input, int n);
int maxLength(string& num1, string& num2);
int main() {
string num1 = "123435678432269335678432278456567843226978435678432269226567784565678432269784356784322692265677845656784322697843567843226922656778456567843226978435678432269226567935678432269";//
string num2 = "5678456567843226978435678432269784565678432269784356784322692265677845656784322697843567843226922656778456567843226978435678432269226567784565678432269784356784322692265672265678432269932269";//
string result = mult(num1, num2);
cout <<"\nresult="<< result;
cin >> num1;
return 0;
}
int maxLength(string& num1, string& num2) {
int length = num1.size() > num2.size() ? num1.size() : num2.size();
if (length == 1)
return 1;
length += length & 1;
return length;
}
//整数位数若不足n则高位补0,使长度为n
string format(string& input, int n) {
if (input.size() >= n)
return input;
string result(n, '0');
for (int i = 0; i < input.size(); i++)
result[n - input.size() + i] = input[i];
return result;
}
//整数尾部补0。相当于移位,扩大倍数
string addTail(string input, int n) {
string result(input.size() + n, NULL);
for (int i = 0; i < input.size(); i++)
result[i] = input[i];
for (int i = input.size(); i < result.size(); i++)
result[i] = '0';
return result;
}
void trimPrefix(string& input) {
int k = 0;
//禁止对最低位进行判断,全零时保留一位
while (k < input.size() - 1 && input[k] == '0')
k++;
input = input.substr(k, input.size() - k);
}
//整数相加
string add(string& num1, string& num2) {
int length = num1.size() > num2.size() ? num1.size() : num2.size();
//加数位对齐
num1 = format(num1, length);
num2 = format(num2, length);
//加法结果多一位存储空间
string result(length + 1, NULL);
int tmp;
int addOutput;//位加法结果
int carry = 0;//进位标识
for (int i = length - 1; i >= 0; i--) {
tmp = num1[i] + num2[i] - 96 + carry;//转换为数字 ‘0’对应48
addOutput = tmp % 10;
carry = tmp / 10;
/*
这个代码适合verilog
if (tmp >= 10) {
carry = 1;
tmp = tmp - 10;
}
else {
carry = 0;
}*/
result[i + 1] = addOutput + '0';
}
result[0] = carry + '0';//最后一次,最高位的进位
trimPrefix(result);
return result;
}
string sub(string num1, string num2) {
int length = num1.size() > num2.size() ? num1.size() : num2.size();
//减数位对齐
num1 = format(num1, length);
num2 = format(num2, length);
//要求num1>=num2
for (int i = 0; i < length; i++) {
if ((num1[i] == '0' && num2[i] == '0') || num1[i] == num2[i]) {
continue;
}
else if (num1[i] < num2[i]) {
MessageBox(NULL, "error", "提示", 64);
exit(0);
}
else break;
}
for (int i = length - 1; i >= 0; i--) {
if (num1[i] < num2[i]) {
num1[i] = num1[i] + '0' + 10 - num2[i];
num1[i - 1] = num1[i - 1] - 1;
}
else {
num1[i] = num1[i] + '0' - num2[i];
}
}
trimPrefix(num1);
return num1;
}
string mult(string num1, string num2) {
string x1, x0, y1, y0, x0y0, x1y1, sumX, sumY, sumXsumY, sum;
//两个2n位的数字相乘,不足2n高位补零
int N = maxLength(num1, num2);//求两数组中较大数组的长度,如果长度为奇数则+1变偶,方便二分成两部分
num1 = format(num1, N);//数组高位存整数的高位数;数字前面补0,使长度为n;
num2 = format(num2, N);
if (num1.size() > 1) {
//将大整数平均分成两部分
x1 = num1.substr(0, N / 2);
x0 = num1.substr(N / 2, N / 2);
y1 = num2.substr(0, N / 2);
y0 = num2.substr(N / 2, N / 2);
x0y0 = mult(x0, y0);//分治求大整数乘法
x1y1 = mult(x1, y1);
sumX = add(x1, x0);
sumY = add(y1, y0);
sumXsumY = mult(sumX, sumY);
string tmp1 = addTail(sub(sumXsumY, add(x0y0, x1y1)), N / 2);//尾部补0,相当于移位
string x1y1Temp = addTail(x1y1, N);
string tmp2 = add(x1y1Temp, x0y0);
sum = add(tmp1, tmp2);
trimPrefix(sum);//除去结果前面多余的0
}
else {
int singleMul = (num1[0] - 48) * (num2[0] - 48);
sum = std::to_string(singleMul);
}
return sum;
}

浙公网安备 33010602011771号