C++大整数类BigInteger的四则运算

C++大整数类BigInteger的四则运算

前言

众所周知,C++是没有高精度运算的,想要用的时候现写结构体非常麻烦,所以这里写出一个库来以后调用比较方便。
这里借用了刘汝佳老师的《算法竞赛入门经典》中的基本写法
接下来的讲解我会将完整代码拆分成部分来讲,完整代码暂时还没有qwq
注:本人开发环境 Visual Studio 2019,所以中间有一些函数是 VS 专用函数

预备知识

  1. 重载运算符

  2. C++ STL vector

  3. 头文件的写法

  4. 最基本的面向对象

正文

头文件:BigInteger.h

引用其他头文件部分
#pragma once
#include <cstdio>
#include <iostream>
#include <istream>
#include <ostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
大整数类的初始化

这一步是将大整数的初值初始化为0

class BigInteger
{
    public:
        BigInteger(long long num = 0) { *this = num; };
大整数类的私有成员

这里的BASE记录的是进制的信息,这里 10000 就是指 10000 进制,通俗一点来说,就是把每个数当成一个字符串,从最后一位(即个位)每四位切割成一个数,并以整型变量的方式存储,例:
vector <int> s; //定义一个名称为s的vector便于举例

原数拆分后的vector存储方式
1s[0] = 1
12345s[0] = 2345, s[1] = 1
10010s[0] = 10, s[1] = 1
123456789s[0] = 6789, s[1] = 2345, s[2] = 1

如果还有不明白的小伙伴,可以把我的程序拿到本地跑一跑试试,这里不再过多列举了

    private:
        static const int BASE = 10000;
        static const int WIDTH = 4;
        vector <int> s;
        bool negetive = 0;
大整数类的公有成员(多为重载运算符和函数)
输入输出运算符的重载
    public:
        friend ostream& operator << (ostream& out, const BigInteger& x);
        friend istream& operator >> (istream& in, BigInteger& x);
逻辑运算符,赋值运算符,算术运算符,组合运算符的重载

这里有两类运算符重载,第一类是两个大整数类之间的运算符重载,第二类是一个大整数和一个整型变量之间的运算符重载,第二类的思路是将整型变量转换为大整数类,然后再执行第一类的运算

        bool operator < (const BigInteger& b) const;
        bool operator > (const BigInteger& b) const;
        bool operator <= (const BigInteger& b) const;
        bool operator >= (const BigInteger& b) const;
        bool operator != (const BigInteger& b) const;
        bool operator == (const BigInteger& b) const;

        bool operator < (const int& b) const;
        bool operator > (const int& b) const;
        bool operator <= (const int& b) const;
        bool operator >= (const int& b) const;
        bool operator != (const int& b) const;
        bool operator == (const int& b) const;

        BigInteger operator = (long long num);
        BigInteger operator = (const string& str);

        BigInteger operator + (const BigInteger& b) const;
        BigInteger operator - (const BigInteger& b) const;
        BigInteger operator * (const BigInteger& b) const;
        BigInteger operator / (const BigInteger& b) const;
        BigInteger operator % (const BigInteger& b) const;

        BigInteger operator += (const BigInteger& b);
        BigInteger operator -= (const BigInteger& b);
        BigInteger operator *= (const BigInteger& b);
        BigInteger operator /= (const BigInteger& b);
        BigInteger operator %= (const BigInteger& b);

        BigInteger operator + (const int& b) const;
        BigInteger operator - (const int& b) const;
        BigInteger operator * (const int& b) const;
        BigInteger operator / (const int& b) const;
        BigInteger operator % (const int& b) const;

        BigInteger operator += (const int& b);
        BigInteger operator -= (const int& b);
        BigInteger operator *= (const int& b);
        BigInteger operator /= (const int& b);
        BigInteger operator %= (const int& b);
一些比较杂碎的函数

函数功能看下面的注释吧

        static int to_int(BigInteger b);
        //将一个大整数类转换为一个整型变量,如果精度丢失会直接报错
        static BigInteger quick_pow(BigInteger x, BigInteger y, BigInteger mod);
        //快速幂,即计算 x^y % mod
        static BigInteger gcd(BigInteger x, BigInteger y);
        //计算两个大整数类的最大公约数
        static BigInteger lcm(BigInteger x, BigInteger y);
        //计算两个大整数类的最小公倍数
};

源文件:BigInteger.cpp

与头文件对应:引用其他头文件部分
#include <vector>
#include <istream>
#include <ostream>
#include <algorithm>
#include <cmath>
#include "BigInteger.h"
using namespace std;
与头文件对应:大整数类的公有成员(多为重载运算符和函数)
与头文件对应:输入输出运算符的重载

这里会涉及一些稍微底层的知识,就不详细介绍了(因为我也不会)

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_s(buf, "%04d", x.s[i]);
        for (int j = 0; j < strlen(buf); ++j)
            out << buf[j];
    }
    return out;
}

istream& operator >> (istream& in, BigInteger& x)
{
    string s;
    if (!(in >> s))  return in;
    x = s;
    return in;
}
与头文件对应:逻辑运算符,赋值运算符,算术运算符,组合运算符的重载

由于我非常懒,这里没有对代码进行分块(我错了…,过后会分的)大家自己费点劲,去下面的代码里自己找符号叭

逻辑运算符的重载

我们先来写小于号 ( < ) 的重载,思路如下:
两个大整数类,先比较位数,如果位数不同,那么大小自然明了;如果位数相同,那么按照位数从高位开始一位一位进行比较
写完后我们会发现,其他所有的逻辑运算符都可以用小于号的一定逻辑来表示,所以其他的函数就非常简单了(这里没有看懂我说的的同学去看下代码吧,应该还比较好理解)

赋值运算符的重载

这里直接读入,几位读入一个数,然后直接存到vector中的一位中去

算术运算符的重载

这里我也会说的很简略,因为只要会模拟这里就不难
四则运算的竖式大家都会吧,这里四则运算都可以直接模拟竖式的行为

组合运算符的重载

直接把赋值运算符和算术运算符组合起来就好啦

bool BigInteger::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 BigInteger::operator > (const BigInteger& b) const
{
    return b < *this;
}

bool BigInteger::operator <= (const BigInteger& b) const
{
    return !(b < *this);
}

bool BigInteger::operator >= (const BigInteger& b) const
{
    return !(*this < b);
}

bool BigInteger::operator != (const BigInteger& b) const
{
    return b < *this || *this < b;
}

bool BigInteger::operator == (const BigInteger& b) const
{
    return !(b < *this) && !(*this < b);
}

BigInteger BigInteger::operator = (long long num)
{
    s.clear();
    do
    {
        s.push_back(num % BASE);
        num /= BASE;
    } while (num > 0);
    return *this;
}

BigInteger 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_s(str.substr(start, end - start).c_str(), "%d", &x);
        s.push_back(x);
    }
    return *this;
}

BigInteger 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;
        if (i < s.size())  x += s[i];
        if (i < b.s.size())    x += b.s[i];
        c.s.push_back(x % BASE);
        g = x / BASE;
    }
    return c;
}

BigInteger BigInteger::operator - (const BigInteger& b) const
{
    BigInteger c;
    c.s.clear();
    int MAX = max(s.size(), b.s.size());
    if (*this > b)
    {
        for (int i = 0, g = 0; ; ++i)
        {
            bool borrow = 0;
            if (g == 0 && i >= MAX)  break;
            int x = g;
            if (i < s.size())  x += s[i];
            if (i < b.s.size())  x -= b.s[i];
            if (x < 0)  borrow = 1;
            c.s.push_back((x + BASE) % BASE);
            g = x / BASE;
            if (borrow)  --g;
        }
        return c;
    }
    else if (*this == b)
    {
        return c;
    }
    else
    {
        for (int i = 0, g = 0; ; ++i)
        {
            bool borrow = 0;
            if (g == 0 && i >= MAX)  break;
            int x = g;
            if (i < b.s.size())  x += b.s[i];
            if (i < s.size())  x -= s[i];
            if (x < 0)  borrow = 1;
            if (i == MAX - 1)
                c.s.push_back(-x % BASE);
            else
                c.s.push_back((x + BASE) % BASE);
            g = x / BASE;
            if (borrow)  --g;
        }
        return c;
    }
}

BigInteger BigInteger::operator * (const BigInteger& b) const
{
    BigInteger c;
    c.s.clear();
    if (s.size() == 1 && s[0] == 0)
    {
        c.s.clear();
        c.s.push_back(0);
        return c;
    }
    if (b.s.size() == 1 && b.s[0] == 0)
    {
        c.s.clear();
        c.s.push_back(0);
        return c;
    }
    int MAX = max(s.size(), b.s.size());
    for (int i = 0; i < (MAX * 2 + 2); ++i)
        c.s.push_back(0);
    for (int i = 0; i < s.size(); ++i)
        for (int j = 0; j < b.s.size(); ++j)
        {
            c.s[i + j + 1] += c.s[i + j] / BASE;
            c.s[i + j] %= BASE;
            c.s[i + j] += s[i] * b.s[j];
        }
    for (int i = 0; i < (MAX * 2 + 1); ++i)
    {
        c.s[i + 1] += c.s[i] / BASE;
        c.s[i] %= BASE;
    }
    while (!*(c.s.end() - 1))
        c.s.erase(c.s.end() - 1);
    return c;
}

BigInteger BigInteger::operator / (const BigInteger& b) const
{
    if (b.s.size() == 1 && b.s[0] == 0)
    {
        cerr << "Exception has occured." << endl;
        cerr << "Arithmetic exception: Divided by Zero." << endl;
        exit(1);
    }
    BigInteger c;
    c.s.clear();
    BigInteger substraction = *this;
    BigInteger tmp;
    tmp.s.clear();
    tmp.s.push_back(1);
    if (substraction > b)
    {
        while (substraction >= b)
        {
            substraction -= b;
            if (substraction.s.size() > 1)
                while (!*(substraction.s.end() - 1))
                    substraction.s.erase(substraction.s.end() - 1);
            c += tmp;
        }
    }
    else if (substraction == b)
        c.s.push_back(1);
    else
        c.s.push_back(0);
    return c;
}

BigInteger BigInteger::operator % (const BigInteger& b) const
{
    BigInteger c;
    c = *this - (*this / b) * b;
    return c;
}

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

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

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

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

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

BigInteger BigInteger::fast_pow(BigInteger x, BigInteger y)
{
    BigInteger ans = 1;
    while (y > 0)
    {
        if (y.s[0] & 1)
            ans *= x;
        x *= x;
        y /= 2;
    }
    return ans;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值