zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    每个Java开发人员都应该知道的4个Spring注解
    JVM中的动态语言支持简介
    深入探索Java设计模式(五)之构建器模式
    Java——MVC模式
    程序出了问题,报错只能参考
    查看电脑端口占用情况
    Java——参数传递
    Python——关于定义过程
    Java——super的使用
    关于如何查看论文是否被SCI或者EI收录
  • 原文地址:https://www.cnblogs.com/peichaoL/p/12516987.html
Copyright © 2011-2022 走看看