有一种可能的问题就是,两个巨大无比的整型数要做乘法。例如:
1234567890*2234567890
这样的乘法结果无论当前的哪一个数据类型都不能单独表示。
于是,如果你遇到抽疯的面试官问你这样的问题,你可以这样做(假设只处理无符号数):
第一步,将两个运算数从各位到最高位都存在一个数组里
第二步,申请一个足够大的数组来存放结果,将数组的所有数据都初始化成0
第三步,实现累加器函数,该函数的输入是结果数组和一个下标以及被累加的数,函数的流程是:
对该数组的该下标的数据和被累加数进行加法运算,如果需要进位,则计算出进位值后下标增1递归调用累加函数实现向下一位的累加和进位(多位数的乘法最后不就是按照各个位的乘法结果进行累加和进位的么)。
第四步,从乘数的个位开始(0号下标),对被乘数进行每一位的乘法运算,每一位的运算结果带入累加器。
具体代码实现如下:
#include <string.h>
/*
将一个长整数的字符串变成字节数组,只能处理正整数
参数:
pszNumber 数字字符串
nStrLen 数字字符串的ANSI编码的字符数,不包括 null结束符
pBuffer 目标字节数组,如果为空,则由参数4返回所需要的大小
nSize 目标字节数组的大小,如果为0或者空间不足,则返回所需要的大小
返回值:
转换成功返回true,否则返回false。
*/
bool PrepareNumberArray(const char* const pszNumber,size_t nStrLen,unsigned char* const pBuffer,size_t &nSize)
{
/*参数合法性判断*/
if(!pszNumber || nStrLen <= 0) return false;
if(!pBuffer || nSize ==0 || nSize<nStrLen) { nSize = nStrLen; return false; }
/*转化字符串到数组,0下标放置各位*/
for(size_t i =0;i<nStrLen;i++)
{
if (pszNumber[i]>'9' || pszNumber[i]<'0') return false;
pBuffer[nStrLen - i - 1] = pszNumber[i] - '0';
}
return true;
}
/*
将一个数累加到当前结果数组的相应位上,如果需要进位,则将进位值累加到结果数组的下一位上
参数:
pResult 结果数组
nSize 结果数组的总大小
nPos 将结果累加到哪一位(个位为下标0)
nNumToAdd 被累加数
返回值:
成功返回true,否则返回false。
*/
bool CarrayAdd(unsigned char* const pResult,const size_t nSize,size_t nPos,const unsigned char nNumToAdd)
{
if(!pResult || nPos >= nSize) return false; //参数不正确
pResult[nPos] += nNumToAdd;
unsigned char nCarry = pResult[nPos] / 10;
pResult[nPos] %= 10;
if (nCarry >0) return CarrayAdd(pResult,nSize,++nPos,nCarry);
return true;
}
/*
计算两个大数的乘法
参数:
pA 被乘数
nALen 被乘数的位数(例如100是三位)
pB 乘数
nBLen 乘数的位数
pResult 结果
nSize 结果数组的大小,如果为0或者空间不足,则返回所需要的大小
*/
bool BigIntMulti(const unsigned char* pA, const size_t nALen,const unsigned char* pB, const size_t nBLen,unsigned char* const pResult,size_t &nSize)
{
if(!pA || !pB || nALen == 0 || nBLen == 0) return false; //参数不合法
if(!pResult || nSize ==0 || nSize<(nALen+nBLen +3)) { nSize = nALen+nBLen+3; return false; }
memset(pResult,0,nSize*sizeof(unsigned char)); //初始化结果数组
for(size_t i =0; i<nBLen; i++)
{
for(size_t j =0; j<nALen; j++)
{
unsigned char nResult = pB[i] * pA[j];
if(!CarrayAdd(pResult,nSize,i+j,nResult)) return false;
}
}
return true;
}
这个算法比较简单,而且也有一些缺陷需要改进。
1. 计算结果需要翻转才能用于字符串显示,因为个位在下标0上,因此需要把整个运算结果翻转过来。
2.如果乘数或者被乘数是0。那么在字符串显示上就会有一点点问题。因为算法中还没有区分位数上的0是计算结果,还是初始值。
总结:你只要会小学乘法,这种算法就不难想到