简单介绍C++大整数类

目录

大整数类的引入与声明

大整数类的四则运算

大整数类的比较

总结


大整数类的引入与声明

在C语言中,长度较长的数字通常使用高精度——也就是使用数组存储该长数字的每一位。C++中也可以使用类似的方法,但是STL和类(结构体)的存在可以使高精度使用更加方便:

C++中STL的存在可以使用不定长数组vector代替C中的定长数组,不需要考虑数字位数且不会浪费空间;

C++中类的存在可以在vector的基础上添加构造函数和其他成员函数(多用运算符重载函数)

 所以可以定义以下的结构体BigInteger存储高精度的非负整数:

struct BigInteger{
    //首先定义两个静态成员变量————规定vector中每一个元素可以存储的最大数据
    static const int BASE = 100000000;  //应用于使用数字赋值
    static const int WIDTH = 8;         //应用于使用字符串赋值
    //接着定义vector
    vector<int> s;

    //构造函数
    BigInteger(long long num=0){*this=num;}
    //使用数字赋值的赋值运算符重载
    BigInteger operator=(long long num)
    {
        s.clear()    //赋值则先清除原有数据
        do{
            s.push_back(num%BASE);  //这里保证了vector中存储的每个元素都在int范围内
            num/=BASE;
        }while(num>0);
    }
    //使用字符串赋值的运算符重载
    BigInteger operator=(const string& str)
    {
        s.clear();
        int x,len=(str.length()-1)/WIDTH+1;  //判断需要几个元素来存储
        for(int i=0;i<len;i++){
            int end=str.length()-i*WIDTH;    //本次取字符串的终止下标
            int start=max(0,end-WIDTH);      //本次取字符串的起始下标
            //sscanf格式化录入,数据来源于字符串
            sscanf(str.substr(start,end-start).c_ctr(),"%d",&x);   
            s.push_back(x);
        }
        return *this;
    }
};

这段代码定义了两个静态成员变量,分别用于限制数字赋值和字符串赋值的情况下存储进vector的数字大小不超过int:

众所周知有符号的int型最大数据为2147483647(一共10位),所以取BASE为8位,且代码保证进入vector的数据都小于BASE,所以一定不会超限。

同理,取WIDTH为8保证了每一次只录入长度≤8的数据,小于int。

在字符串方式赋值中有一些比较重要的字符串处理函数,比如sscanf函数和sprintf函数:

sscanf和scanf的区别在于数据来源——scanf我们很熟悉,是以键盘为输入源;但是sscanf却是以字符串为输入源:
 

sscanf(const char* str1,"%d",&var);  //表示从str1中读取数据并自动转为数字存储在变量var中

这里“自动转为数据”是一个很奇妙的过程。比如字符串是字符“1234”的组合,通过上述步骤var中得到的是真正int型1234。还有一种方法是使用字符串流 strstringstream。

同理sprintf(const char* str2,"%d",var)就是将数字var转成字符串形式,“输出”目标不是屏幕而是str2。

同时注意如果第一个参数是个string类型,不适用,具体操作后面会介绍。

其次是C++字符串类型自带的substr函数,可以写为str.substr(start,n),表示取出原字符串中下标从start开始的长度为n的子字符串,返回值同样是string。

那很容易就可以想到,可以将本函数和上面的sscanf结合起来,把子字符串作为输入源。但是由于string类型不能作为sscanf的第一个参数,所以引入函数string类型的库函数c_str(),写作str.c_str(),作用是将string类型的第一个元素值返回,达到的是一个将C++风格字符串转换为C风格的字符数组的效果。

此处还可以定义大整数类的流运算符重载,即通过cin>>x和cout<<x的方式进行输入输出:

//流输入运算符>>的重载
istream& operator>>(istream &in,BigInteger& x)
{
    string s;
    if(!(in>>s))   //确保有输入
        return in;
    x=s;   //使用了赋值运算符的重载
    return in;
}
//流输出运算符<<的重载
ostream& operator<<(ostream &out,const BigInteger& x)
{
    out<<x.s.back();   //最后一个元素
    for(int i=x.s.size()-2;i>=0;i--){    //从倒数第二个元素开始,从后往前输入(存储反序)
        char buf[20];
        sprintf(buf,"%08d",x.s[i]);      //格式化输出,输出目标为buf
        for(int j=0;j<strlen(buf);j++)
            out<<buf[i];
    }
    return out;
}

这样一个大整数类的定义及赋值、输入输出运算符重载就算完成了。

大整数类的四则运算

以加法为例,核心步骤为 取余+进位

//以下内容定义在结构体内部定义
BigInteger operator+(const BigInteger& b) const
{
    BigInteger c;
    c.s.clear();
    for(int i=0,g=0;;i++){
        if(g==0&&i>=s.size()&&i>=b.s.size())   //判断计算完成
            break;
        int x=g;  //g为上一阶层保留下来的剩余值
        if(i<s.size())    //加数1
            x+=s[i];
        if(i<b.s.size())  //加数2
            x+=b.s[i];
        c.s.push_back(x%BASE);  //取余
        g=x/BASE;               //进位(留下待下一阶层使用)
}

根据+可以进一步定义+=:函数中调用+的重载实现

BigInteger operator+=(const BigInteger& b){
    *this=*this+b;
    return *this;
}

大整数类的比较

只需要定义一个小于,其他符号都可以通过小于的变化得到(类似于上面+=运用了+的性质)

//定义在结构体中
bool operator<(const BigInteger& b)const{
    if(s.size()!=b.s.size())
        return s.size()<b.s.size();  //位数不相等,直接判断
    for(int i=s.size()-1;i>=0;i--){  //位数相等,从后往前(此高位往低位)比较
        if(s[i]!=b.s[i])
            return s[i]<b.s[i];
    }
    return false;  //相等
}

上面算法成立的前提是没有前导零(不然计算正确但是比较乱套)。那么同理可以通过小于运算符定义出其他所有运算符:

bool operator > (const BigInteger& b) const{return b<*this;}
bool operator <=(const BigInteger& b) const{return !(b<*this);}
bool operator >=(const BigInteger& b) const{return !(*this<b);}
bool operator !=(const BigInteger& b) const{return b<*this||*this<b;}
bool operator ==(const BigInteger& b) const{return !(b<*this)&&!(*this<b);}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个简单C++函数,用于将大整数从一种进制转换为另一种进制: ```cpp #include <iostream> #include <string> #include <algorithm> #include <cmath> using namespace std; string convertBase(string num, int oldBase, int newBase) { int decimalNum = 0; int power = 1; bool isNegative = (num[0] == '-'); // Convert to decimal base for (int i = num.size() - 1; i >= isNegative ? 1 : 0; i--) { int digitValue = isdigit(num[i]) ? num[i] - '0' : num[i] - 'A' + 10; decimalNum += digitValue * power; power *= oldBase; } // Convert to new base string newNum; while (decimalNum > 0) { int remainder = decimalNum % newBase; char digitChar = (remainder < 10) ? remainder + '0' : remainder - 10 + 'A'; newNum += digitChar; decimalNum /= newBase; } if (newNum.empty()) { newNum = "0"; } if (isNegative) { newNum += '-'; } // Reverse the result and return reverse(newNum.begin(), newNum.end()); return newNum; } int main() { string num; int oldBase, newBase; cout << "Enter a number: "; cin >> num; cout << "Enter the old base: "; cin >> oldBase; cout << "Enter the new base: "; cin >> newBase; cout << num << " in base " << oldBase << " is " << convertBase(num, oldBase, newBase) << " in base " << newBase << endl; return 0; } ``` 该函数使用两个参数:要转换的数字和两个进制值(旧进制和新进制)。它首先将该数字转换为十进制,然后将其转换为新进制。在转换过程中,该函数会使用余数和商的计算来获得新进制下的每一位。最后,新数被反转并返回。 请注意,此函数仅适用于非负整数。如果输入数字为负数,则应在函数中进行适当的更改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zhqi HUA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值