C++ 高精度整型数四则运算

测试题目链接:https://www.luogu.com.cn/problem/P1932

注:用string去实现高精度的方法时间效率表现较差,若想进一步优化高精度的效率,可以参考我的下一篇博客:https://www.cnblogs.com/peichaoL/p/12520881.html

高精度运算的实现思路,就是模拟人们在进行运算时的方法步骤。

高精度的数数位比较多,用 int 数组实现的话会浪费很多空间,这里我们用 string 去实现。考虑到我们在手动做加减乘法的时候,都是从低位向高位做,只有除法是高位向低位做,为方便运算的实现,这里我们倒着去存一个数,例如,我们用 "65248" 来代表整型数 84256。

下面说一下大致思路,

加法:

记录一个进位值carry当前位的和temp,从低位向高位,temp = 两数当前位相加 + carry,结果的当前位 = temp % 10,carry = temp  / 10,如果此时当前位已经是较长的数的最高位且有进位,则结果上要进位,否则继续循环。

减法:

首先要保证被减数大于等于减数,记录一个借位值borrow,从低位向高位,如果被减数当前位 >= 减数当前位 + borrow,那就直接减去,借位置0,否则被减数当前位 + 10再去减减数当前位和借位,并将借位置1。由于减法的结果位数小于等于被减数位数,所以最后要消除一下结果的前导零。

乘法:

模拟乘法需要二重循环,记录进位值 carry, 记录 temp = 乘数1第 i 位 * 乘数2第 j 位 + carry,carry = (结果第 i + j 位 + temp) / 10,结果第 i + j 位 = (当前位 + temp) % 10。

乘法运算的结果位数可能是两数位数相加,也可能是两数位数相加再 + 1,要向加法一样考虑最终进位的情况。

除法:

手动模拟一下除法我们可以发现,除法是一个对齐->试商->减去当前积->再对齐->再试商....这样的过程,对齐,我们可以通过在除数低位补 0 来实现,试商,我们则通过一次次的减去除数,直到被除数小于除数来实现。

举个栗子:654178 / 25 = 26167  (整数除法舍去小数)

  • 我们首先对齐,将 25 扩展成250000,用654178 - 250000,可以减 2 次,剩下154178;
  • 我们再对齐,将 250000 去掉一个 0 变成25000,用154178 - 25000,可以减 6 次, 剩下4178;
  • 我们再对齐,将 25000 去掉一个 0 变成2500,用4178 - 2500,可以减 1 次,剩下1678;
  • 我们再对齐,将 2500 去掉一个 0 变成250, 用1678 - 250, 可以减6次,剩下178;
  • 我们再对齐,将 250 去掉一个 0 变成25,用178 - 25可以减7次,剩下3;
  • 这时候 3 已经小于除数25了,它就是余数,我们将每次减去的次数连起来,就得到了商 —— 26167。

除法的核心步骤 —— 不停地减,是比较耗费时间的,我们可以去二分找到应该减的次数,一次减去那么多,可以提高一些效率。

以上是核心的思路,具体实现时还需要注意一些边边角角的细节,可以参考代码。

为了方便使用,干脆写一个类,并且重载常用的运算符。

附上代码:

/**
* @brief 整型数高精度
* 要求无负数, 无前导零
*/
class HighPrecision{
private:
    string num;

    /**
     * @brief 高精度数乘一位 int 在除法运算中代替普通的乘法运算起加速作用
     * @param a 一位int乘数
     * @return 积
     */
    HighPrecision multiply_one_digit(const int& a) const{
        HighPrecision ans = *this;
        int carry = 0, temp;
        for(int i = 0; i < num.length(); i++){
            temp = (num[i] - '0') * a + carry;
            carry = temp / 10;
            ans.num[i] = temp % 10 + '0';
        }
        if(carry)ans.num += char(carry + '0');
        return ans;
    }
public:
    HighPrecision(){
        this->num = "0";
    }
    
    HighPrecision(const HighPrecision& a){
        this->num = a.num;
    }

    HighPrecision(const string& a){
        for(int i = a.length() - 1; i >= 0; i--){
            this->num += a[i];
        }
    }

    HighPrecision(const int& a){
        int temp1 = a;
        do{
            this->num += char(temp1 % 10 + '0');
            temp1 /= 10;
        }while(temp1);
    }

    bool operator== (const HighPrecision& a) const{
        return this->num == a.num;
    }

    bool operator== (const int& a) const{
        return *this == HighPrecision(a);
    }

    bool operator!= (const HighPrecision& a) const{
        return !(*this == a);
    }

    bool operator> (const HighPrecision& a) const{
        if(this->num.length() != a.num.length())return this->num.length() > a.num.length();
        for(int i = this->num.length() - 1; i >= 0; i--){
            if(this->num[i] != a.num[i])return this->num[i] > a.num[i];
        }
        return false;
    }
    
    bool operator> (const int& a) const{
        return *this > HighPrecision(a);
    }

    bool operator< (const HighPrecision& a) const{
        return a > *this;
    }

    bool operator>= (const HighPrecision& a) const{
        return *this > a || *this == a;
    }

    bool operator<= (const HighPrecision& a) const{
        return a >= *this;
    }

    HighPrecision operator= (const HighPrecision& a){
        this->num = a.num;
        return *this;
    }

/**
 * @brief 高精度加法
 * @param a 加数
 * @return 和
*/
    HighPrecision operator+ (const HighPrecision& a) const{
        string temp_short, temp_long;
        if(this->num.length() > a.num.length()){
            temp_short = a.num;
            temp_long = this->num;
        }
        else{
            temp_short = this->num;
            temp_long = a.num;
        }
        int carry = 0, temp1, max_len = max(temp_short.length(), temp_long.length());
        for(int i = 0; i < temp_short.length(); i++){
            if(i == temp_long.length()){
                temp_short[temp_short.length() - 1] = '1';
                break;
            }
            temp1 = int(temp_long[i] - '0') + int(temp_short[i] - '0') + carry;
            temp_short[i] = char(temp1 % 10 + '0');
            carry = temp1 / 10;
            if(i == temp_short.length() - 1 && (carry || i < max_len - 1))temp_short += '0';//最高位需要进位的情况 
        }
        HighPrecision ans;
        ans.num = temp_short;
        return ans;
    }

    HighPrecision operator+ (const int& a) const{
        return *this + HighPrecision(a);
    }

    HighPrecision operator+= (const HighPrecision& a){
        *this = *this + a;
        return *this;
    }

/**
* @brief 高精度减法 - 必须保证被减数大于等于减数
* @param a 减数
* @return 差
*/
    HighPrecision operator- (const HighPrecision &a) const{
        HighPrecision ans = HighPrecision("");
        string temp = a.num;
        while(temp.length() < this->num.length())temp += '0';
        int borrow = 0;
        for(int i = 0; i < this->num.length(); i++){
            if(this->num[i] < temp[i] + borrow){
                ans.num += this->num[i] + 10 - borrow - temp[i] + '0';
                borrow = 1;
            }
            else{
                ans.num += this->num[i] - temp[i] - borrow + '0';
                borrow = 0;
            }
        }
        while(ans.num[ans.num.length() - 1] == '0' && ans.num.length() > 1)ans.num.erase(ans.num.length() - 1);
        return ans;
    }

    HighPrecision operator- (const int& a) const{
        return *this - HighPrecision(a);
    }

    HighPrecision operator-= (const HighPrecision& a){
        *this = *this - a;
        return *this;
    }

/**
* @brief 高精度乘法
* @param a 乘数
* @return 积
*/    
    HighPrecision operator* (const HighPrecision& a) const{
        if(*this == 0 || a == 0)return HighPrecision();
        HighPrecision ans = HighPrecision("");
        ans.num.assign(this->num.length() + a.num.length() - 1, '0');
        int carry, temp1;
        for(int i = 0; i < a.num.length(); i++){
            carry = 0;
            for(int j = 0; j < this->num.length(); j++){
                temp1 = (a.num[i] - '0') * (this->num[j] - '0') + carry;
                carry = (ans.num[i + j] - '0' + temp1) / 10;
                ans.num[i + j] = (ans.num[i + j] - '0' + temp1) % 10 + '0';
                if(i + j != ans.num.length() - 1 && j == this->num.length() - 1 && carry)ans.num[i + j + 1] += carry;
                if(i + j == ans.num.length() - 1 && carry)ans.num += carry + '0';
            }
        }
        return ans;
    }

    HighPrecision operator* (const int& a) const{
        return *this * HighPrecision(a);
    }

    HighPrecision operator*= (const HighPrecision& a){
        *this = *this * a;
        return *this;
    }

/**
* @brief 高精度除法, 请自觉检测除 0 的错误
* @param a 除数
* @return 商
*/
    HighPrecision operator/ (const HighPrecision& a) const{
        if(*this < a)return HighPrecision(0);
        HighPrecision temp = a, dividend = *this;
        string ans;
        temp.num.insert(0, dividend.num.length() - a.num.length(), '0');
        do{
            ans += '0';
            if(dividend >= temp){
                int high = 10, low = 1;
                while(high - low > 1){
                    int mid = (high + low) / 2;
                    if(temp.multiply_one_digit(mid) > dividend)high = mid;
                    else low = mid;
                }
                dividend -= temp.multiply_one_digit(low);
                ans[ans.length() - 1] += low;
            }
            if(temp.num.length() == a.num.length())break;
            temp.num = temp.num.substr(1);
        }while(temp.num.length() >= a.num.length());
        while(ans[0] == '0')ans = ans.substr(1);
        return HighPrecision(ans);
    }

    HighPrecision operator/ (const int& a) const{
        return *this / HighPrecision(a);
    }

    HighPrecision operator/= (const HighPrecision& a){
        *this = *this / a;
        return *this;
    }

    HighPrecision operator% (const HighPrecision& a) const{
        return *this - (*this / a * a);
    }

    HighPrecision operator%= (const HighPrecision& a){
        *this = *this % a;
        return *this;
    }

    friend ostream& operator <<(ostream&, const HighPrecision&);
};

ostream& operator <<(ostream& os, const HighPrecision& a){
    for(int i = a.num.length() - 1; i >= 0; i--){
        os << a.num[i];
    }
    return os;
}

 

posted @ 2020-03-18 13:49  sheeeeeeep  阅读(386)  评论(0编辑  收藏  举报