• C++ 高精度整型数


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

    本篇博客主要讲位压缩策略,不懂高精度思路的可以参考我上一篇博客:https://www.cnblogs.com/peichaoL/p/12516987.html

    如果我们想存储一个高精度整型数:123456789

    假如我们这么存:

     一个 int 拿着 4 字节的资源却只存了一位数字,这无疑是对内存的极大浪费,于是我们可以让一个 int 多存几位,像这样:

    我们可以认为是将十进制变换成万进制,这便是位压缩的一个鲜明例子。

    用这种方式来实现高精度整型数,最强大的地方在于对时间效率的优化:别的高精度一次加法出 1 位的结果,这种高精度一次加法出 4 位的结果。我们知道高精除法的实现中,假如我们正在求商的某一位(已做好对齐操作),试商的过程有两种:(下面所提及的除数 、被除数并不是真正的除数、被除数,而是计算到了某个过程时的除数、被除数,疑惑的童鞋可以参考我上一篇博客中对除法运算的详细解释。)

    • 用被除数一次次地减除数,直到小于除数。商的当前位即为减去的次数。
    • 二分去求这个位数,使得 该位数 * 除数 <= 被除数 且 (该位数 + 1) * 除数 > 被除数。 

    假如我们采用传统的存储策略,即使二分地去找这个数,由于求的只是一位,所以只能在 1 ~ 9 之间二分,完全没有发挥二分的作用,对时间效率的提升极低。而如果我们用位压缩的策略去存储,就扩大了二分的范围,从而真正发挥其作用。(例如上图中,每一位所代表的权值 base = 10000,我们可以在 1 ~ 9999 之间二分,一次性求出商的 4 位)

    对于位压缩中每位的权值 base:

    base 的选取肯定是大越好,为了好实现,取10的整数次幂,对于 int[],考虑到乘法操作可能幂次翻倍,比较省事的取法是 base = 1e4,当然,如果细心点把可能溢出的地方用 long long 接住,可以取到 1e9。

    附上类代码:

    const int base = 10000;
    const int digit = 4;
    /**
     * @brief 高精度整型 - 采用位压缩策略
     * 要求无前导零 要求非负
     */ 
    class HighPrecision{
    private:
        int num[10000] = {0};
        int length = 1;
        int digital_num() const{
            HighPrecision temp = *this;
            int ans = (temp.length - 1) * digit;
            int temp2 = temp.num[temp.length - 1];
            while(temp2){
                ans++;
                temp2 /= 10;
            }
            return ans;
        }
    public:
        HighPrecision(){}
    
        HighPrecision(const HighPrecision& a){
            for(int i = 0; i < a.length; i++)this->num[i] = a.num[i];
            this->length = a.length;
        }
    
        HighPrecision(const int& a){
            int temp = a;
            this->num[0] = temp % base;
            temp /= base;
            while(temp){
                this->num[this->length++] = temp % base;
                temp /= base;
            }
        }
    
        HighPrecision(const string& a){
            string s = a;
            while(s.length() > digit){
                this->num[this->length - 1] = atoi(s.substr(s.length() - 4).c_str());
                s.erase(s.length() - 4);
                this->length++;
            }
            this->num[this->length - 1] = atoi(s.c_str());
        }
    
    /**
     * @brief 高精度加法
     * @param a 加数
     * @return 和
    */
        HighPrecision operator+ (const HighPrecision& a) const{
            HighPrecision ans;
            ans.length = max(this->length, a.length);
            int carry = 0;
            for(int i = 0; i < ans.length; i++){
                ans.num[i] = this->num[i] + a.num[i] + carry;
                carry = ans.num[i] / base;
                ans.num[i] %= base;
                if(i == ans.length - 1 && carry)ans.length++;
            }
            return ans;
        }
    
        HighPrecision operator+= (const HighPrecision& a){
            *this = *this + a;
            return *this;
        }    
    
    /**
    * @brief 高精度减法 - 必须保证被减数大于等于减数
    * @param a 减数
    * @return 差
    */
        HighPrecision operator- (const HighPrecision& a) const{
            HighPrecision ans = *this;
            int borrow = 0;
            for(int i = 0; i < this->length; i++){
                ans.num[i] -= a.num[i] + borrow;
                borrow = 0;
                if(ans.num[i] < 0){
                    ans.num[i] += base;
                    borrow = 1;
                }
            }
            while(!ans.num[ans.length - 1] && ans.length - 1)ans.length--;//去前导零
            return ans;
        }
    
        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(0);
            HighPrecision ans;
            int carry = 0;
            ans.length = this->length + a.length - 1;
            for(int i = 0; i < this->length; i++){
                carry = 0;
                for(int j = 0; j < a.length; j++){
                    ans.num[i + j] += this->num[i] * a.num[j] + carry;
                    carry = ans.num[i + j] / base;
                    ans.num[i + j] %= base;
                }
                if(carry)ans.num[i + a.length] += carry;
            }
            if(carry)ans.length++;
            return ans;
        }
    
        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 0;
            HighPrecision ans, dividend = *this, divisor = a;
            while(divisor * HighPrecision(base) <= dividend)divisor *= HighPrecision(base);//初次对齐
            while(true){
                int high = base, low = 1, mid = 0;
                if(dividend >= divisor){
                    while(high - low > 1){
                        mid = (high + low) / 2;
                        if(divisor * HighPrecision(mid) > dividend)high = mid;
                        else low = mid;
                    }
                    dividend -= divisor * HighPrecision(low);
                    ans.num[ans.length - 1] += low;
                }
                if(divisor == a)break; 
                ans.length++;
                for(int i = 1; i < divisor.length; i++)divisor.num[i - 1] = divisor.num[i];
                divisor.num[divisor.length - 1] = 0;
                divisor.length--;
            }
            reverse(ans.num, ans.num + ans.length);
            while(!ans.num[ans.length - 1])ans.length--;
            return ans;
        }
    
        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;
        }
    
        bool operator== (const HighPrecision& a) const{
            if(this->length != a.length)return false;
            for(int i = this->length - 1; i >= 0; i--){
                if(this->num[i] != a.num[i])return false;
            }
            return true;
        }
    
        bool operator> (const HighPrecision& a) const{
            if(this->length != a.length)return this->length > a.length;
            for(int i = this->length - 1; i >= 0; i--){
                if(this->num[i] != a.num[i])return this->num[i] > a.num[i];
            }
            return false;
        }
    
        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 *this < a || *this == a;
        }
    
        bool operator!= (const HighPrecision& a) const{
            return !(*this == a);
        }
    
        HighPrecision operator= (const HighPrecision& a){
            this->length = a.length;
            for(int i = 0; i < this->length; i++)this->num[i] = a.num[i];
            return *this;
        }
    
        friend ostream& operator<< (ostream&, const HighPrecision&);
    };
    
    ostream& operator <<(ostream& os, const HighPrecision& a){
        os << a.num[a.length - 1];
        for(int i = a.length - 2; i >= 0; i--){
            int temp_base = base / 10;
            while(a.num[i] < temp_base){
                cout << 0;
                temp_base /= 10;
            }
            if(a.num[i])cout << a.num[i];
        }
        return os;
    }
  • 相关阅读:
    [POJ1743]Musical Theme
    ubuntu qq
    Separate code and data contexts: an architectural approach to virtual text sharing
    Python3发送post请求,自动记住cookie
    python 异步协程
    豆瓣爬虫
    pandas 使用
    房天下爬虫
    计算英文文章词频的两种方法
    LOW版统计词频
  • 原文地址:https://www.cnblogs.com/peichaoL/p/12520881.html
Copyright © 2020-2023  润新知