大数运算(C++)

来源:互联网 发布:谷阿莫华尔街之狼 知乎 编辑:程序博客网 时间:2024/04/28 19:45

大数就是指十几位,几十位或者几百位的数字,反正对于这样的数,任何计算机本身的变量类型(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实现大数减法:

//用来清除数字字符串前多余的0string 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,我们只需要调用就行了。

0 0