软件乘法实现

 

【加密算法笔记之代码仓库】

------------

博文声明:本博文隶属加密算法笔记的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;
}

  

  

posted @ 2019-11-07 20:41  谷谷非鼠  阅读(311)  评论(0编辑  收藏  举报