大数就是指十几位,几十位或者几百位的数字,反正对于这样的数,任何计算机本身的变量类型(int,double,甚至long long)都表示不了。怎么存?最常用的就是用字符串string或者向量vector,然后的问题自然是要实现大数的四则运算。
大数加法
加法的实现很简单,就是从低位开始,模拟加法的计算过程,需要注意的就是计算过程中产生的进位。
string实现大数加法:
string BigIntPlus(string s1, string s2)
{
//把较长的数给s1,方便写程序
if (s1.size() < s2.size())
{
string tmp = s2;
s2 = s1;
s1 = tmp;
}
//从低位开始,模拟加法的过程,注意每次加法的进位即可
for (int i = s1.size()-1, j = s2.size()-1; i >= 0; i--, j--)
{
s1[i] = s1[i] + (j >= 0 ? s2[j] - '0' : 0);
if (s1[i] > '9')//表示有进位
{
s1[i] -= 10;
if (i) s1[i - 1]++;
else s1 = '1' + s1;//i=-1,表示超过了原来的长度,利用字符串加法
}
}
return s1;
}
大数减法
大数减法虽然看起来也就是模拟做减法的过程,但实际上比加法复杂的多。网上很多所谓的大数减法的程序,要么只能计算结果为正数的情况,要么2225-2227算下来结果显示-0002,什么鬼嘛,等于-2呀。
1.string实现大数减法:
//用来清除数字字符串前多余的0
string eraseZero(string s)
{
if (s.size() <= 1) return s;
if (*s.begin() != '0') return s;
s.erase(s.begin());
return eraseZero(s);
}
//返回s1-s2的值
//为了方便写程序,我们先保证计算的结果是正数,最后看情况是否需要转负数
string BigIntMinus(string s1, string s2)
{
bool tag = false;//用来标记s1 s2是否发生了交换
if (s1.size() < s2.size() || (s1.size()==s2.size() && s1 < s2))
{
tag = true;
string tmp = s2;
s2 = s1;
s1 = tmp;
}
for (int i = s1.size()-1, j = s2.size()-1; i >= 0; i--, j--)
{
if (j>=0){
if (s1[i] < '0' || s1[i] < s2[j])//需要借位
{
s1[i] = s1[i] + 10 - ((j < 0) ? 0 : s2[j] - '0');
s1[i - 1]--;
continue;
}
}
s1[i] = s1[i] - ((j<0) ? 0 : s2[j] - '0');
}
//处理计算结果字符串前面多余的0,比如0005应该显示5
string result = eraseZero(s1);
if (tag) result = '-' + result;
return result;
}
虽然我们用string可以实现大数减法,但写程序的过程总是很不舒服的。因为我们从头到尾都要记得我们处理的是字符’0’…..’9’,而不是真正的数字0,1……9。
大数乘法
大数的乘法就有多种算法思想。主要有分治法、快速傅里叶变换FFT法、中国剩余定理、简单方法(模拟乘法的过程)。前面几种看起来就NB,被吓住的赶紧去百度一下,我这里还是简单研究下简单方法……
这里我们从LeetCode的一道题目说起:Multiply Strings
这里我直接贴高票答案的代码,因为实在写的太好了,我自己写的不堪入目。
string multiply(string num1, string num2) {
string sum(num1.size() + num2.size(), '0');
for (int i = num1.size() - 1; 0 <= i; --i) {
int carry = 0;
for (int j = num2.size() - 1; 0 <= j; --j) {
int tmp = (sum[i + j + 1] - '0') + (num1[i] - '0') * (num2[j] - '0') + carry;
sum[i + j + 1] = tmp % 10 + '0';
carry = tmp / 10;
}
sum[i] += carry;
}
size_t startpos = sum.find_first_not_of("0");
if (string::npos != startpos) {
return sum.substr(startpos);
}
return "0";
}
GMP
其实关于大数运算,早就有高精度计算库GUN的GMP(Arithmetic without limitations)
GMP,我们只需要调用就行了。