一、简介
项目名称:C++大整数类
开发环境:Visual Studio 2019/Visual Studio 2022 Preview 2.1
C++标准:C++20
最近更新:2021.11.7
点击此处转到gitee存储库
注:博主保证头文件和源文件是最新版的,C++20编译通过,并且目前测试无问题,但由于后期有很多修改,一些函数的用法可能变了,测试代码不保证没有错误,大家可以自行修改。最后,如果这篇博客对你有帮助,别忘了点个赞哦!
项目介绍
C++中是有整数类型的,最常用的就是int型。但是,C++自带的整数类型是有大小范围的,可能会溢出,产生很多令人头疼的错误。
示例:
#include<iostream>
//#include"CBigInt.h"
using namespace std;
int main()
{
int t = 1;
for (int i = 0; i < 100; i++)
{
t *= 10;
cout << t<<'\t';
}
return 0;
}
运行结果:
从中可见,int型保存大小是有限制的,否则会出错。
为此,我设计了一个大整数类,利用容器保存数据,实现了整数的加减乘除取余比较大小等功能。使用大整数类再次运行以上程序:
#include<iostream>
#include"CBigInt.h"
using namespace std;
int main()
{
CBigInt t = 1;
for (int i = 0; i < 100; i++)
{
t *= 10;
cout << t.ToString() << '\t';
}
return 0;
}
从中可见,大整数类型保存大小理论上来说是没有有限制的(除非这个数超大,把内存占满了)。
还有一点,这个大整数类是考虑负数的,可以对负数进行相同操作。
更新历史
2021-11-7:(重要更新)新建无符号大整数类CUnsignedBigInt,并将CBigInt设为其子类,并把所有相关类放到MyStd命名空间中。修改bug。
2021-10-15:优化加法减法性能,乘法分别存储n1乘以n2每一位的数字,避免重复计算。
2021-09-05:修改除法余数为“00”导致死循环的bug,以及多处由于使用重载的+、-运算符而没用CBigInt::Add,CBigInt::Sub函数,所产生的bug。
2021-09-04 :将求幂修改为静态函数,增加求最小公倍数、最大公因数的功能,修改bug,优化性能。
2021-08-20 :增加构造函数对不同进制的支持,修改bug。
2021-08-19 :增加对不同进制的支持。
2021-08-16:修改后置++的Bug。
2021-07-22:添加后置++ --运算符,优化程序性能。
2021-07-04:建立项目。
二、代码
关于大整数类,有很多种思路,其中主要有以下两种:
1.模拟十进制的计算
就像我们平时列竖式一样,满十进一,容器里每个元素的上限是9。
优点:简单,有效,不易出错,且一般使用10进制输出,转字符串时快。
缺点:内存利用率低,计算超大数据时,速度较慢。
2.使用比较大的进制
使用比较大的进制数,比如16384进制,容器里每个元素的上限是16383。
优点:内存利用率高,计算超大数据时计算次数少,速度快。
缺点:如果输出频繁,需要多次转进制(取模),速度慢。
总之,如果输出频繁,推荐使用第一种,如果计算量巨大而很少需要输出,或者不用输出,推荐使用第二种。在博主的代码里,解决方案是把进制定义为一个静态常量,可以自行修改。
这个代码很可能有Bug,如果大家发现漏洞,可以在评论区回复。
CBigInt.h:
#pragma once
#include<deque>
#include<string>
namespace MyStd
{
class CBigInt;
class CUnsignedBigInt;
class MulBuffer;
class CUnsignedBigInt
{
protected:
friend class MulBuffer;
using valueType = uint32_t;
std::deque<valueType> m_data;//数字
static CUnsignedBigInt Mul(CUnsignedBigInt n1, valueType n2);//计算CUnsignedBigInt与一位数相乘的结果
static const short m_radix = 10;//使用10进制存储,可以改,结果不会变
void Reduced();//化简(去掉前导0)
public:
CUnsignedBigInt();
CUnsignedBigInt(long long num);
CUnsignedBigInt(const CUnsignedBigInt& i);
CUnsignedBigInt(const std::string& source, uint8_t radix = 10);
size_t Size()const noexcept;//位数
valueType At(size_t index)const;
CUnsignedBigInt SubNum(size_t first, size_t count = 1)const;
std::string ToString(uint8_t radix = 10)const;//radix范围为2-16
CUnsignedBigInt& operator=(long long num);
CUnsignedBigInt& operator=(const CUnsignedBigInt& n);
CUnsignedBigInt& operator=(const std::string& source);
void Assign(const std::string& source, uint8_t radix = 10);
void Assign(long long num);
bool IsZero()const;
friend std::strong_ordering operator<=>(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2)noexcept;
static short Compare(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2);
friend bool operator==(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2);
friend bool operator!=(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2);
friend CUnsignedBigInt operator+(CUnsignedBigInt n1, const CUnsignedBigInt& n2);
friend CUnsignedBigInt operator-(CUnsignedBigInt n1, const CUnsignedBigInt& n2);//计算差的绝对值
friend CUnsignedBigInt operator*(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2);
static CUnsignedBigInt Division(const CUnsignedBigInt& n1, CUnsignedBigInt n2, CUnsignedBigInt& remainder);//除法,结果向0舍入,例如(-7)/5=-1
friend CUnsignedBigInt operator/(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2);
friend CUnsignedBigInt operator%(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2);
CUnsignedBigInt& operator+=(const CUnsignedBigInt& n);
CUnsignedBigInt& operator-=(const CUnsignedBigInt& n);
CUnsignedBigInt& operator*=(const CUnsignedBigInt& n);
CUnsignedBigInt& operator/=(const CUnsignedBigInt& n);
CUnsignedBigInt& operator%=(const CUnsignedBigInt& n);
CUnsignedBigInt& operator++();
CUnsignedBigInt& operator--();
CUnsignedBigInt operator++(int);
CUnsignedBigInt operator--(int);
static CUnsignedBigInt Add(CUnsignedBigInt n1, const CUnsignedBigInt& n2);
static CUnsignedBigInt Sub(CUnsignedBigInt n1, const CUnsignedBigInt& n2);
CBigInt operator-()const;
const CUnsignedBigInt& operator+()const noexcept;
static CUnsignedBigInt Pow(const CUnsignedBigInt& n, CUnsignedBigInt exponential);
static CUnsignedBigInt GCD(CUnsignedBigInt n1, CUnsignedBigInt n2);
static CUnsignedBigInt LCM(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2);
unsigned long long ToUnsignedLongLong()const;
long double ToLongDouble()const;
};
class CBigInt :public CUnsignedBigInt
{
private:
friend class MulBuffer;
bool m_sign;//1正0负
public:
CBigInt();
CBigInt(long long num);
CBigInt(const CBigInt& i);
CBigInt(const CUnsignedBigInt& i);
CBigInt(const std::string& source, uint8_t radix = 10);
CBigInt Abs()const;
std::string ToString(uint8_t radix = 10, bool ShowPlusSign = false)const;//radix范围为2-16
CBigInt& operator=(long long num);
CBigInt& operator=(const CBigInt& n);
CBigInt& operator=(std::string source);
void Assign(const std::string& source, uint8_t radix = 10);
friend std::strong_ordering operator<=>(const CBigInt& n1, const CBigInt& n2)noexcept;
friend bool operator==(const CBigInt& n1, const CBigInt& n2);
friend bool operator!=(const CBigInt& n1, const CBigInt& n2);
friend CBigInt operator+(CBigInt n1, const CBigInt& n2);
friend CBigInt operator-(CBigInt n1, const CBigInt& n2);
friend CBigInt operator*(CBigInt n1, const CBigInt& n2);
static CBigInt Division(const CBigInt& n1, const CBigInt& n2, CBigInt& remainder);//除法,结果向0舍入,例如(-7)/5=-1
friend CBigInt operator/(const CBigInt& n1, const CBigInt& n2);
friend CBigInt operator%(const CBigInt& n1, const CBigInt& n2);
CBigInt& operator+=(const CBigInt& n);
CBigInt& operator-=(const CBigInt& n);
CBigInt& operator*=(const CBigInt& n);
CBigInt& operator/=(const CBigInt& n);
CBigInt& operator%=(const CBigInt& n);
CBigInt& operator++();
CBigInt& operator--();
CBigInt operator++(int);
CBigInt operator--(int);
CBigInt operator-()const;
const CBigInt& operator+()const noexcept;
static CBigInt Pow(const CBigInt& n, CBigInt exponential);
long long ToLongLong()const;
long double ToLongDouble()const;
};
class MulBuffer//乘法缓存(保存该数乘以每一位的结果,防止重复计算)
{
public:
MulBuffer(const CUnsignedBigInt& number);
const CUnsignedBigInt& GetResult(uint32_t a);
void Recalculate()noexcept;
private:
CUnsignedBigInt results[CBigInt::m_radix];
bool b[CBigInt::m_radix];
const CUnsignedBigInt& num;
};
//const CUnsignedBigInt UNSIGNEDLONGLONG_MAX("18446744073709551615");
//const CUnsignedBigInt LONGLONG_MAX("9223372036854775807");
#define UNSIGNEDLONGLONG_MAX CUnsignedBigInt("18446744073709551615")
#define LONGLONG_MAX CUnsignedBigInt("9223372036854775807")
}
CBigInt.cpp:
#include "CBigInt.h"
#include<stdexcept>
namespace MyStd
{
CBigInt::CBigInt()
{
m_sign = true;
m_data.push_back(0);
}
CBigInt::CBigInt(long long num):CUnsignedBigInt(num)
{
m_sign = (num >= 0);
}
CBigInt::CBigInt(const CBigInt& i)
{
m_data = i.m_data;
m_sign = i.m_sign;
}
CBigInt::CBigInt(const CUnsignedBigInt& i):CUnsignedBigInt(i)
{
m_sign = true;
}
CBigInt::CBigInt(const std::string& source, uint8_t radix)
{
Assign(source, radix);
}
CBigInt CBigInt::Abs() const
{
CBigInt tmp = *this;
tmp.m_sign = true;
return tmp;
}
std::string CBigInt::ToString(uint8_t radix, bool showPlusSign)const
{
if (radix < 2 || radix > 16)
throw std::invalid_argument("进制参数无效!");
if (IsZero())
return "0";
std::string result;
if (!m_sign)
result += '-';
else if (showPlusSign)
result += '+';
if (radix == m_radix)
{
for (auto i : m_data)
{
result += (i >= 10 ? i - 10 + 'A' : i + '0');
}
}
else
{
CBigInt temp(*this);
std::string t;
while (!temp.IsZero())
{
CBigInt rem;
temp = Division(temp, radix, rem);
rem.m_sign = true;
int8_t i = rem.ToLongLong();
t += (i >= 10 ? i - 10 + 'A' : i + '0');
}
for (size_t i = 0; i < t.size() / 2; ++i)
{
char tmp = t[i];
t[i] = t[t.size() - i - 1];
t[t.size() - i - 1] = tmp;
}
result += t;
}
return result;
}
CBigInt& CBigInt::operator=(long long num)
{
if (!(m_sign = (num >= 0)))
num = -num;
if (num == 0)
m_data.push_back(0);
for (long long i = 1; i <= num; i *= m_radix)
{
m_data.push_front(num / i % m_radix);
}
return *this;
}
CBigInt& CBigInt::operator=(const CBigInt& n)
{
m_data = n.m_data;
m_sign = n.m_sign;
return *this;
}
CBigInt& CBigInt::operator=(std::string source)
{
Assign(source);
return *this;
}
void CBigInt::Assign(const std::string& source, uint8_t radix)
{
m_data.clear();
m_data.push_back(0);
if (radix < 2 || radix>16)
throw std::invalid_argument("进制参数无效!");
if (source.size() == 0)
{
m_data.push_back(0);
m_sign = true;
return;
}
if (radix == m_radix)
{
auto iter = source.begin();
if (source[0] == '-')
{
m_sign = false;
++iter;
}
else if (source[0] == '+')
{
m_sign = true;
++iter;
}
while (iter != source.end())
{
int8_t k = 16;
if (isdigit(*iter))
k = (*iter - '0');
else if (isalpha(*iter) == 1)
k = (*iter - 'A' + 10);
else if (isalpha(*iter))
k = (*iter - 'a' + 10);
if (k < radix)
m_data.push_back(k);
else
throw std::invalid_argument("参数中有无效字符!");
++iter;
}
}
else
{
auto rend = source.rend();
if (source[0] == '-')
{
m_sign = false;
--rend;
}
else if (source[0] == '+')
{
m_sign = true;
--rend;
}
CUnsignedBigInt tmp(1);
for (auto iter = source.rbegin(); iter != rend; ++iter)
{
int8_t k = 16;
if (isdigit(*iter))
k = (*iter - '0');
else if (isalpha(*iter) == 1)
k = (*iter - 'A' + 10);
else if (isalpha(*iter))
k = (*iter - 'a' + 10);
if (k >= radix)
throw std::invalid_argument("参数中有无效字符!");
CUnsignedBigInt::operator+=(k * tmp);
tmp *= radix;
}
}
while (m_data.size() > 0 && m_data.front() == 0)
m_data.pop_front();
if (m_data.empty())
{
m_data.push_back(0);
m_sign = true;
}
}
CBigInt& CBigInt::operator+=(const CBigInt& n)
{
if (m_sign == n.m_sign)//符号相同按加法算
{
CUnsignedBigInt::operator+=(n);
}
else//符号不同按减法算
{
CUnsignedBigInt::operator-=(n);
if (CUnsignedBigInt::Compare(*this, n) < 0)
m_sign = !m_sign;
}
return *this;
}
CBigInt& CBigInt::operator-=(const CBigInt& n)
{
if (m_sign == n.m_sign)//符号相同按减法算
{
CUnsignedBigInt::operator-=(n);
if (CUnsignedBigInt::Compare(*this, n) < 0)
m_sign = !m_sign;
}
else//符号不同按加法算
{
CUnsignedBigInt::operator+=(n);
}
return *this;
}
CBigInt& CBigInt::operator*=(const CBigInt& n)
{
CUnsignedBigInt::operator*=(n);
m_sign = (m_sign == n.m_sign);
return *this;
}
CBigInt& CBigInt::operator/=(const CBigInt& n)
{
CBigInt rem;
return *this = Division(*this, n, rem);
}
CBigInt& CBigInt::operator%=(const CBigInt& n)
{
CBigInt temp(*this);
Division(temp, n, *this);
return *this;
}
CBigInt& CBigInt::operator++()
{
return operator+=(1);
}
CBigInt& CBigInt::operator--()
{
return operator-=(1);
}
CBigInt CBigInt::operator++(int)
{
CBigInt temp(*this);
this->operator+=(1);
return temp;
}
CBigInt CBigInt::operator--(int)
{
CBigInt temp(*this);
this->operator-=(1);
return temp;
}
CBigInt CBigInt::operator-() const
{
CBigInt temp(*this);
temp.m_sign = !m_sign;
return temp;
}
const CBigInt& CBigInt::operator+()const noexcept
{
return *this;
}
CBigInt CBigInt::Pow(const CBigInt& n, CBigInt exponential)
{
if (exponential.IsZero())
{
if (n.IsZero())
throw std::invalid_argument("0的0次方无意义!");
return 1;
}
if (!exponential.m_sign)
throw std::invalid_argument("暂不支持计算负数次方!");
CBigInt t(n);
while (!(--exponential).IsZero())
t *= n;
return t;
}
long long CBigInt::ToLongLong() const
{
if (CUnsignedBigInt::Compare(*this, LONGLONG_MAX) > 0)
throw std::overflow_error("该数超出long long类型的范围!");
long long result = 0, t = 1;
for (auto iter = m_data.rbegin(); iter != m_data.rend(); ++iter)
{
result += *iter * t;
t *= m_radix;
}
if (m_sign)
return result;
return -result;
}
long double CBigInt::ToLongDouble() const
{
long double result = 0, t = 1;
for (auto iter = m_data.rbegin(); iter != m_data.rend(); ++iter)
{
result += static_cast<long double>(*iter) * t;
t *= m_radix;
}
if (m_sign)
return result;
return -result;
return 0;
}
std::strong_ordering operator<=>(const CBigInt& n1, const CBigInt& n2)noexcept
{
if (n1.IsZero() && n2.IsZero())
return std::strong_ordering::equivalent;
if (n1.IsZero())
{
if (n2.m_sign)
return std::strong_ordering::less;
else
return std::strong_ordering::greater;
}
if (n2.IsZero())
{
if (n1.m_sign)
return std::strong_ordering::greater;
else
return std::strong_ordering::less;
}
if (n1.m_sign > n2.m_sign)
return std::strong_ordering::greater;
if (n1.m_sign < n2.m_sign)
return std::strong_ordering::less;
if (n1.m_sign)//正数
{
if (n1.Size() > n2.Size())
return std::strong_ordering::greater;
if (n2.Size() > n1.Size())
return std::strong_ordering::less;
for (size_t i = 0; i < n1.Size(); ++i)
{
if (n1.m_data[i] > n2.m_data[i])
return std::strong_ordering::greater;
if (n1.m_data[i] < n2.m_data[i])
return std::strong_ordering::less;
}
return std::strong_ordering::equivalent;
}
else//负数,就是正数反过来
{
if (n1.Size() > n2.Size())
return std::strong_ordering::less;
if (n2.Size() > n1.Size())
return std::strong_ordering::greater;
for (size_t i = 0; i < n1.Size(); ++i)
{
if (n1.m_data[i] > n2.m_data[i])
return std::strong_ordering::less;
if (n1.m_data[i] < n2.m_data[i])
return std::strong_ordering::greater;
}
return std::strong_ordering::equivalent;
}
}
bool operator==(const CBigInt& n1, const CBigInt& n2)
{
return (n1.IsZero() && n2.IsZero()) || (n1.m_sign == n2.m_sign && n1.m_data == n2.m_data);
}
bool operator!=(const CBigInt& n1, const CBigInt& n2)
{
return !(n1 == n2);
}
CBigInt operator+(CBigInt n1, const CBigInt& n2)
{
return n1 += n2;
}
CBigInt operator-(CBigInt n1, const CBigInt& n2)
{
return n1 -= n2;
}
CBigInt operator*(CBigInt n1, const CBigInt& n2)
{
return n1 *= n2;
}
CBigInt CBigInt::Division(const CBigInt& n1, const CBigInt& n2, CBigInt& remainder)
{
CBigInt&& result = CUnsignedBigInt::Division(n1, n2, remainder);
result.m_sign = (n1.m_sign == n2.m_sign);
remainder.m_sign = true;
return result;
}
CBigInt operator/(const CBigInt& n1, const CBigInt& n2)
{
CBigInt remainder;//余数(无用)
return CBigInt::Division(n1, n2, remainder);
}
CBigInt operator%(const CBigInt& n1, const CBigInt& n2)
{
CBigInt remainder;
CBigInt::Division(n1, n2, remainder);
return remainder;
}
MulBuffer::MulBuffer(const CUnsignedBigInt& number) :num(number)
{
for (bool& i : b)
i = false;
}
const CUnsignedBigInt& MulBuffer::GetResult(uint32_t a)
{
if (!b[a])
{
results[a] = CUnsignedBigInt::Mul(num, a);
b[a] = true;
}
return results[a];
}
void MulBuffer::Recalculate() noexcept
{
for (auto& i : b)
i = false;
}
CUnsignedBigInt CUnsignedBigInt::Mul(CUnsignedBigInt n1, valueType n2)
{
if (n2 == 0)
return 0;
int carry = 0;
for (int i = n1.Size() - 1; i >= 0; --i)
{
int t = n1.m_data[i] * n2;
n1.m_data[i] = (t + carry) % m_radix;
carry = (t + carry) / m_radix;
}
if (carry)
n1.m_data.push_front(carry);
return n1;
}
void CUnsignedBigInt::Reduced()
{
while (m_data.size() > 0 && m_data.front() == 0)
m_data.pop_front();
if (m_data.empty())
m_data.push_back(0);
}
CUnsignedBigInt::CUnsignedBigInt()
{
m_data.push_back(0);
}
CUnsignedBigInt::CUnsignedBigInt(long long num)
{
Assign(num);
}
CUnsignedBigInt::CUnsignedBigInt(const CUnsignedBigInt& i)
{
m_data = i.m_data;
}
CUnsignedBigInt::CUnsignedBigInt(const std::string& source, uint8_t radix)
{
Assign(source, radix);
}
size_t CUnsignedBigInt::Size() const noexcept
{
return m_data.size();
}
CUnsignedBigInt::valueType CUnsignedBigInt::At(size_t index) const
{
return m_data.at(index);
}
CUnsignedBigInt CUnsignedBigInt::SubNum(size_t first, size_t count) const
{
CUnsignedBigInt temp;
temp.m_data.clear();
for (size_t i = 0; i < count; ++i)
temp.m_data.push_back(m_data.at(first + i));
return temp;
}
std::string CUnsignedBigInt::ToString(uint8_t radix) const
{
if (radix < 2 || radix > 16)
throw std::invalid_argument("进制参数无效!");
if (IsZero())
return "0";
std::string result;
if (radix == m_radix)
{
for (auto i : m_data)
{
result += (i >= 10 ? i - 10 + 'A' : i + '0');
}
}
else
{
CUnsignedBigInt temp(*this);
std::string t;
while (!temp.IsZero())
{
CBigInt rem;
temp = Division(temp, radix, rem);
int8_t i = rem.ToLongLong();
t += (i >= 10 ? i - 10 + 'A' : i + '0');
}
for (size_t i = 0; i < t.size() / 2; ++i)
{
int8_t tmp = t[i];
t[i] = t[t.size() - i - 1];
t[t.size() - i - 1] = tmp;
}
result += t;
}
return result;
}
CUnsignedBigInt& CUnsignedBigInt::operator=(long long num)
{
Assign(num);
return *this;
}
CUnsignedBigInt& CUnsignedBigInt::operator=(const CUnsignedBigInt& n)
{
m_data = n.m_data;
return *this;
}
CUnsignedBigInt& CUnsignedBigInt::operator=(const std::string& source)
{
Assign(source);
return *this;
}
void CUnsignedBigInt::Assign(const std::string& source, uint8_t radix)
{
m_data.clear();
m_data.push_back(0);
if (radix < 2 || radix>16)
throw std::invalid_argument("进制参数无效!");
if (source.size() == 0)
{
m_data.push_back(0);
return;
}
if (radix == m_radix)
{
auto iter = source.begin();
if (source[0] == '+')
{
++iter;
}
while (iter != source.end())
{
int8_t k = 16;
if (isdigit(*iter))
k = (*iter - '0');
else if (isalpha(*iter) == 1)
k = (*iter - 'A' + 10);
else if (isalpha(*iter))
k = (*iter - 'a' + 10);
if (k < radix)
m_data.push_back(k);
else
throw std::invalid_argument("参数中有无效字符!");
++iter;
}
}
else
{
auto rend = source.rend();
if (source[0] == '+')
{
--rend;
}
CUnsignedBigInt tmp(1);
for (auto iter = source.rbegin(); iter != rend; ++iter)
{
int8_t k = 16;
if (isdigit(*iter))
k = (*iter - '0');
else if (isalpha(*iter) == 1)
k = (*iter - 'A' + 10);
else if (isalpha(*iter))
k = (*iter - 'a' + 10);
if (k >= radix)
throw std::invalid_argument("参数中有无效字符!");
*this += (k * tmp);
tmp *= radix;
}
}
while (m_data.size() > 0 && m_data.front() == 0)
m_data.pop_front();
if (m_data.empty())
{
m_data.push_back(0);
}
}
void CUnsignedBigInt::Assign(long long num)
{
m_data.clear();
if (num == 0)
m_data.push_back(0);
while (num)
{
m_data.push_front(num % m_radix);
num /= m_radix;
}
}
bool CUnsignedBigInt::IsZero() const
{
return m_data.front() == 0;
}
short CUnsignedBigInt::Compare(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2)
{
if (n1.Size() > n2.Size())
return 1;
if (n2.Size() > n1.Size())
return -1;
for (size_t i = 0; i < n1.Size(); ++i)
{
if (n1.m_data[i] > n2.m_data[i])
return 1;
if (n1.m_data[i] < n2.m_data[i])
return -1;
}
return 0;
}
std::strong_ordering operator<=>(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2) noexcept
{
if (n1.Size() > n2.Size())
return std::strong_ordering::greater;
if (n2.Size() > n1.Size())
return std::strong_ordering::less;
for (size_t i = 0; i < n1.Size(); ++i)
{
if (n1.m_data[i] > n2.m_data[i])
return std::strong_ordering::greater;
if (n1.m_data[i] < n2.m_data[i])
return std::strong_ordering::less;
}
return std::strong_ordering::equivalent;
}
bool operator==(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2)
{
return n1.m_data == n2.m_data;
}
bool operator!=(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2)
{
return n1.m_data != n2.m_data;
}
CUnsignedBigInt operator+(CUnsignedBigInt n1, const CUnsignedBigInt& n2)
{
return n1 += n2;
}
CUnsignedBigInt operator-(CUnsignedBigInt n1, const CUnsignedBigInt& n2)
{
return n1 -= n2;
}
CUnsignedBigInt operator*(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2)
{
if (n1.Size() > n2.Size())
return n2 * n1;//为了减少调用CUnsignedBigInt::Mul的次数
MulBuffer buf(n2);
CUnsignedBigInt result;
auto iter = n1.m_data.rbegin();
for (int t = 0; iter != n1.m_data.rend(); ++iter, ++t)
{
if (*iter)
{
CBigInt temp = buf.GetResult(*iter);
for (int j = 0; j < t; ++j)
temp.m_data.push_back(0);
result += temp;
}
}
return result;
}
CUnsignedBigInt operator/(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2)
{
CUnsignedBigInt rem;
return CUnsignedBigInt::Division(n1, n2, rem);
}
CUnsignedBigInt operator%(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2)
{
CUnsignedBigInt rem;
CUnsignedBigInt::Division(n1, n2, rem);
return rem;
}
CUnsignedBigInt CUnsignedBigInt::Division(const CUnsignedBigInt& n1, CUnsignedBigInt n2, CUnsignedBigInt& remainder)
{
if (n2.IsZero())
throw::std::invalid_argument("除数为0!");
if (n1 < n2)
{
remainder = n1;
return 0;
}
CUnsignedBigInt result;
result.m_data.clear();
size_t index = 1;
while (n1.SubNum(0, index)< n2)//找到可除的第一位
++index;
remainder = n1.SubNum(0, index--);
MulBuffer buf(n2);
for (; index < n1.Size(); ++index)
{
int quotient = 0, l = 0, r = m_radix - 1;
while (l < r - 1)
{
quotient = (l + r) / 2;
if (buf.GetResult(quotient) < remainder)
l = quotient;
else
r = quotient;
}
if (remainder >= buf.GetResult(r))
quotient = r;
else
quotient = l;
remainder = remainder - buf.GetResult(quotient);
if (index != (n1.Size() - 1))
{
if (remainder.IsZero())
remainder.m_data.clear();
remainder.m_data.push_back(n1.m_data.at(index + 1));//下一位落下
}
result.m_data.push_back(quotient);
}
result.Reduced();
return result;
}
CUnsignedBigInt& CUnsignedBigInt::operator+=(const CUnsignedBigInt& n)
{
bool carry = 0;//进位
auto iter1 = m_data.rbegin();
auto iter2 = n.m_data.rbegin();
for (; iter1 != m_data.rend() && iter2 != n.m_data.rend(); ++iter1, ++iter2)
{
int t = *iter1 + *iter2 + carry;
*iter1 = t % CUnsignedBigInt::m_radix;
carry = t / m_radix;
}
bool flag = (iter1 == m_data.rend());//容量用完了吗?
if (flag)//容量用完,同时说明n可能还有位没加!
{
while (iter2 != n.m_data.rend())
{
int t = *iter2 + carry;
carry = t / m_radix;
m_data.push_front(t % m_radix);
++iter2;
}
if (carry)
{
m_data.push_front(1);
}
}
else//容量没用完,说明n已经加完,直接考虑最后的进一就行
{
while (carry)
{
if (flag)
{
m_data.push_front(1);//进一
break;
}
else
{
int t = *iter1 + carry;
*iter1 = t % m_radix;
carry = t / m_radix;
flag = (++iter1 == m_data.rend());
}
}
}
return *this;
}
CUnsignedBigInt& CUnsignedBigInt::operator-=(const CUnsignedBigInt& n)
{
if (*this < n)
return *this = n - *this;
bool carry = 0;//借位
auto iter1 = m_data.rbegin();
auto iter2 = n.m_data.rbegin();
for (; iter2 != n.m_data.rend(); ++iter1, ++iter2)//n1的位数一定大于等于n2的位数
{
int t = static_cast<int>(*iter1) - *iter2 - carry;
carry = 0;
if (t < 0)
{
t += m_radix;
carry = 1;
}
*iter1 = t;
}
while (carry)//如果还有借位,从iter1继续减
{
int t = static_cast<int>(*iter1) - carry;
carry = 0;
if (t < 0)
{
t += m_radix;
carry = 1;
}
*iter1 = t;
++iter1;
}
Reduced();
return *this;
}
CUnsignedBigInt& CUnsignedBigInt::operator*=(const CUnsignedBigInt& n)
{
return *this = *this * n;
}
CUnsignedBigInt& CUnsignedBigInt::operator/=(const CUnsignedBigInt& n)
{
CUnsignedBigInt rem;
return *this = Division(*this, n, rem);
}
CUnsignedBigInt& CUnsignedBigInt::operator%=(const CUnsignedBigInt& n)
{
CUnsignedBigInt tmp(*this);
Division(tmp, n, *this);
return *this;
}
CUnsignedBigInt& CUnsignedBigInt::operator++()
{
return *this += 1;
}
CUnsignedBigInt& CUnsignedBigInt::operator--()
{
return *this -= 1;
}
CUnsignedBigInt CUnsignedBigInt::operator++(int)
{
CUnsignedBigInt temp(*this);
*this += 1;
return temp;
}
CUnsignedBigInt CUnsignedBigInt::operator--(int)
{
CUnsignedBigInt temp(*this);
*this -= 1;
return temp;
}
CUnsignedBigInt CUnsignedBigInt::Add(CUnsignedBigInt n1, const CUnsignedBigInt& n2)
{
return n1 += n2;
}
CUnsignedBigInt CUnsignedBigInt::Sub(CUnsignedBigInt n1, const CUnsignedBigInt& n2)
{
return n1 -= n2;
}
CBigInt CUnsignedBigInt::operator-() const
{
return -CBigInt(*this);
}
const CUnsignedBigInt& CUnsignedBigInt::operator+() const noexcept
{
return *this;
}
CUnsignedBigInt CUnsignedBigInt::Pow(const CUnsignedBigInt& n, CUnsignedBigInt exponential)
{
if (exponential.IsZero())
{
if (n.IsZero())
throw std::invalid_argument("0的0次方无意义!");
return 1;
}
CUnsignedBigInt t(n);
while (!(--exponential).IsZero())
t *= n;
return t;
}
CUnsignedBigInt CUnsignedBigInt::GCD(CUnsignedBigInt n1, CUnsignedBigInt n2)
{
CUnsignedBigInt t;
while (!n2.IsZero())
{
t = n1 % n2;
n1 = n2;
n2 = t;
}
return n1;
}
CUnsignedBigInt CUnsignedBigInt::LCM(const CUnsignedBigInt& n1, const CUnsignedBigInt& n2)
{
CUnsignedBigInt&& result = n1 * n2 / GCD(n1, n2);
return result;
}
unsigned long long CUnsignedBigInt::ToUnsignedLongLong() const
{
if (*this > UNSIGNEDLONGLONG_MAX)
throw std::overflow_error("该数超出unsigned long long类型的范围!");
unsigned long long result = 0, t = 1;
for (auto iter = m_data.rbegin(); iter != m_data.rend(); ++iter)
{
result += *iter * t;
t *= m_radix;
}
return result;
}
long double CUnsignedBigInt::ToLongDouble() const
{
long double result = 0, t = 1;
for (auto iter = m_data.rbegin(); iter != m_data.rend(); ++iter)
{
result += static_cast<long double>(*iter) * t;
t *= m_radix;
}
return result;
}
}
三、测试程序
#include<iostream>
#include"CBigInt.h"
using namespace std;
int main()
{
try
{
CBigInt n1, n2;
string str;
cin >> str;
n1 = str;
cin >> str;
n2 = str;
ULONGLONG StartTime = GetTickCount64();
cout << (n1 + n2).ToString() << endl;
cout << (n1 - n2).ToString() << endl;
cout << (n1 * n2).ToString() << endl;
cout << (n1 / n2).ToString() << endl;
cout << (n1 % n2).ToString() << endl;
cout << (n1.Pow(n2)).ToString() << endl;
cout << "程序运行时间:" << GetTickCount64() - StartTime << "毫秒" << endl;
}
catch(invalid_argument error)
{
cout << "出现参数无效异常!异常信息:" << error.what() << endl;
}
catch (...)
{
cout << "出现其他类型异常!" << endl;
}
return 0;
}
运行结果(上面是程序下面是Win10计算器)如下。
加法:
减法:
乘法(对不起,这个数太大,计算器直接用了科学计数法,大家自己转换吧):
除法(结果向下取整):
取余(下面的历史记录从下往上看是商×除数+余数):
乘方:
这个大家熟悉,就是unsigned int类型的范围。再来一个复杂的:
好家伙,这么长的结果,整整运行了42秒。这个结果很难验证,但我们可以通过尾数来大致判断是否正确。202164尾数是4(1次方),4*4=16(2次方),6*4=24(3次方)…
314%2=0,对应2次方,所以最后一位是6,尾数正确。再来一个:
73尾数是3(1次方),3*3=9(2次方),9*3=27(3次方),7*3=21(4次方),1*3=3(5次方)…
289%4=1,对应1次方,所以最后一位是6,尾数正确。
由此可见,乘方功能满足需求。