前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++手搓大整数类

C++手搓大整数类

作者头像
叶茂林
发布2024-01-18 08:42:13
950
发布2024-01-18 08:42:13
举报

基本思路

实现大整数有两种方法,一种是将大数当成字符来处理,手动计算加减乘除,另一种则是将大数分成多个小部分用基本类型存储处理

我们这里实现第二种方法的,目前版本是支持非负整数

基本思路是将一个大整数切分成几段小的用int存储,用vector容器来存储每段,例如

1111222233334444 integer[1]=11112222 integer[0]=33334444

重载赋值运算符

重载赋值运算符,实现从基本数据类型到大整数的转换,通过和base取余切分出段

代码语言:javascript
复制
class BigInteger {
    static const int width = 8; // 切分段的长度
    static const int base = 1e8; // 切分段的数量级
    vector<int> integer; // 存储各个段
    int segments = 0; // 切分的段数
    BigInteger operator=(long long num) { // 重载赋值运算符,从基本数据类型转换大整数存储
        integer.clear();
        do {
            integer.emplace_back(num % base);
            num /= base;
            segments++;
        } while (num > 0);
        return *this;
    }
};

实现默认构造函数和带参构造函数,通过重载的赋值运算符直接赋值

代码语言:javascript
复制
    explicit BigInteger(long long num = 0) {
        *this = num;
    }

继续重载赋值运算符,实现从字符串到大整数的转换,首先计算出这个大整数有几段,这里的计算方法十分巧妙,如果直接除以width当不是整除的时候会少数一段,所以先减一再除最后加一的方法可以适用整除和不整除的情况

然后需要计算每段的开始和结束的位置,因为vector存储段的顺序是从后往前,所以这里计算段的位置也是从后往前,然后通过string取子串,再通过stoi函数将字符串转成整型存储

代码语言:javascript
复制
    BigInteger operator=(const string &num) { // 重载赋值运算符,从字符串类型转大整数存储
        integer.clear();
        int length = num.size();
        segments = (length - 1) / width + 1; // 这里计算段数的方法十分巧妙
        for (int i = 0; i < segments; i++) {
            int end = length - i * width; // 计算每段结束的地方,从最后一段开始
            int start = max(0, end - width); // 计算每段开始的地方
            integer.emplace_back(stoi(num.substr(start, end - start))); // 字符串转整数
        }
        return *this;
    }

重载输入输出运算符

接着重载输出运算符,重载输出运算符可以通过友元函数和成员函数两种方法实现,我们这里通过友元函数的方法实现,倒序输出vector

代码语言:javascript
复制
    ostream &operator<<(ostream &out) { // 重载输出运算符,vector倒着输出
        for (auto it = integer.rbegin(); it != integer.rend(); it++) {
            cout << *it;
        }
        return out;
    }

重载输入运算符,将输入当成字符串,通过重载的赋值运算符直接赋值

代码语言:javascript
复制
    istream &operator>>(istream &in) { // 重载输入运算符,当成字符串输入,用重载的赋值运算符直接赋值
        string num;
        in >> num;
        *this = num;
        return in;
    }

重载加运算符

大整数加运算的基本思想是将各个段相加,需要处理段相加的时候出现的进位情况,由于int型可以表示的范围大概是10个数量级,而我们给每段设置的位数是8,因此可以使用int型来存储段加的结果,然后继续存储加结果和base取余的结果,计算出和base整除的结果,留到下一个段继续相加

代码语言:javascript
复制
    BigInteger operator+(const BigInteger &bigInteger) const {
        BigInteger result;
        for (int i = 0, carry = 0; carry || i < segments || i < bigInteger.segments; i++) {
            if (i < segments)
                carry += integer[i];
            if (i < bigInteger.segments)
                carry += bigInteger.integer[i];
            result.integer.emplace_back(carry % base);
            result.segments++;
            carry = carry / base;
        }
        return result;
    }

顺便实现+=

代码语言:javascript
复制
    BigInteger operator+=(const BigInteger &bigInteger) {
        *this = *this + bigInteger;
        return *this;
    }

重载比较运算符

这个比较两个大整数的实现比较巧妙

我们先实现一个重载小于的判断,先比较两个大整数的段数,如果段数不同直接返回段数的比较就行,如果段数相同,由于大整数的低位存储在vector的前面,所以从后面段开始比较高位,如果高位不相同,那么返回高位的比较结果就行,如果都相同,那么说明相等

代码语言:javascript
复制
    bool operator <(const BigInteger&bigInteger) const{
        if(segments!=bigInteger.segments)
            return segments<bigInteger.segments;
        for(int i=segments-1;i>=0;i--){ // 倒着比较,因为低位在vector的前面,先比较高位
            if(integer[i]!=bigInteger.integer[i])
                return integer[i]<bigInteger.integer[i];
        }
        return false; // 相等
    }

然后接下来的大于、大于等于、小于等于、不等于、等于都可以通过小于实现

代码语言:javascript
复制
    bool operator>(const BigInteger &bigInteger) const {
        return bigInteger < *this; // a大于b等价于b小于a
    }

    bool operator<=(const BigInteger &bigInteger) const {
        return !(bigInteger < *this); // a<=b等价于b不小于a
    }

    bool operator>=(const BigInteger &bigInteger) const {
        return !(*this < bigInteger); // a>=b等价于a不小于b
    }

    bool operator!=(const BigInteger &bigInteger) const {
        return *this < bigInteger || bigInteger < *this; // a不等于b等价于a大于b或者小于b
    }

    bool operator==(const BigInteger &bigInteger) const {
        return !(*this < bigInteger) && !(bigInteger < *this); // a等于b等价于a既不大于b也不小于b
    }

巧妙

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本思路
  • 重载赋值运算符
  • 重载输入输出运算符
  • 重载加运算符
    • 重载比较运算符
    相关产品与服务
    对象存储
    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档