算法设计与分析:第三章 分治 3.3二进制大整数的乘法

/*
二进制大整数的乘法:
请设计一个有效的算法,可以进行两个n 位二进制大整数的乘法运算

设x = 3141, A = 31 B=41
  y = 5327,	C = 53,D=27
  x*y = AC*2^n + (AD + BC)*2^(n/2) + BD
      = AC*2^n + ((A-B)*(D-C) + A*C + B*D)*2^n + BD //少算一次乘法

递归基:当只有一个元素的时候

下面实现的是十进制大整数乘法
输入:
3141 5327 10(必须确保位数为偶数位)
9 11 2(必须确保该十进制数对应的二进制数是位数相同的)

输出:
16732107
99
731074749


*/

/*
这里其实没有用到分治,因为需要分解数字,下次考虑到x,y均小于10的时候再计算
*/

#include <stdio.h>
#include <iostream>

using namespace std;
bool g_valid;//全部标记变量

int sign(int a)//获取整数a的符号
{
	return a > 0 ? 1 : -1;
}

int myAbs(int a)
{
	return a > 0 ? a : -1*a;
}

int digitCount(int a,int iBase)
{
	int iTotalDigit = 0;
	do
	{
		a /= iBase;//获取下一位
		iTotalDigit++;
	}while(a);
	return iTotalDigit;
}

int getBack(int a,int iBase,int iTotalDigit)//iBase为基数
{
	if(a <= 0)//这里必须确保a是正数
	{
		g_valid = false;
		return -1;
	}

	/*只需要把后半段计算出来,然后用前半段去减。问题转化为如何求出后半段。1234:必须知道总共位数/2,求一个整数的位数,
	可以用它自己不断和它本身减一去取与,很快可以求解。
	设置一个计数器,当达到总位数一半的时候,停止计数,然后将数组中保存的从低位到高位的累加和输出
	*/
	int iCnt = 0;
	int iSum = 0;
	int iFactor = 1;
	do
	{
		iSum += iFactor*(a % iBase);
		iFactor *= iBase;
		a /= iBase;
		iCnt++;
		if(iCnt == iTotalDigit/2)
		{
			break;
		}
	}while(a);
	return iSum;
}

//返回iBase^iExp
int myPow(int iBase,int iExp)
{
	if(iExp == 1)//递归出口
	{
		return iBase;
	}
	int iRet = myPow(iBase,iExp/2);
	iRet *= iRet;
	if(iExp % 2 == 1)
	{
		iRet *= iBase;
	}
	return iRet;
}

int multiply(int x,int y,int iBase)
{
	//预处理符号
	int iSign = sign(x) * sign(y);
	x = myAbs(x);
	y = myAbs(y);

	//鲁棒性
	int iTotalDigitX = digitCount(x,iBase);
	int iTotalDigitY = digitCount(y,iBase);

	//
	if(iTotalDigitX != iTotalDigitY)
	{
		g_valid = false;
		return -1;
	}

	//递归出口,如果都为1,返回乘积的符号
	if(x == 1 && y == 1)
	{
		return iSign;
	}
	else
	{
		//计算每一个数的前半部分和后半部分
		int iDivideNum = myPow(iBase,iTotalDigitX/2);
		int iBackX = getBack(x,iBase,iTotalDigitX);

		//靠计算错了,例如5341计算出的是5300,还要除以100
		int iFrontX = ( x - iBackX ) / iDivideNum;
		int iBackY = getBack(y,iBase,iTotalDigitY);
		int iFrontY = ( y - iBackY ) / iDivideNum;

		//计算每一部分乘积
		int iM1 = iFrontX * iFrontY;
		int iM2 = iBackX * iBackY;
		int iM3 = (iFrontX - iBackX) * (iBackY - iFrontY) + iM1 + iM2;

		int iRet = iSign * ( iM1*myPow(iBase,iTotalDigitX) + iM3*myPow(iBase,iTotalDigitX/2) + iM2 ); 
		return iRet;
	}
}

void process()
{
	int x,y,iBase;
	while(EOF != scanf("%d %d %d",&x,&y,&iBase))
	{
		g_valid = true;
		int iRet = multiply(x,y,iBase);
		if(g_valid)
		{
			printf("%d\n",iRet);
		}
		else
		{
			printf("您输入的两个整数%d %d的位数不一致,请检查!\n",x,y);
		}
	}
}

int main(int argc,char* argv[])
{
	process();
	getchar();
	return 0;
}

    原文作者:大整数乘法问题
    原文地址: https://blog.csdn.net/qingyuanluofeng/article/details/47189237
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞