软件乘法实现
【加密算法笔记之代码仓库】
------------
博文声明:本博文隶属加密算法笔记的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; }