C++大整数类(支持多种进制)

一、简介

项目名称: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类型的溢出
从中可见,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:

扫描二维码关注公众号,回复: 13304375 查看本文章
#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计算器)如下。
加法:
加法
减法:
减法
乘法(对不起,这个数太大,计算器直接用了科学计数法,大家自己转换吧):
乘法
除法(结果向下取整):
除法
取余(下面的历史记录从下往上看是商×除数+余数):
取余
乘方:
2的32次方
这个大家熟悉,就是unsigned int类型的范围。再来一个复杂的:
202164的314次方
好家伙,这么长的结果,整整运行了42秒。这个结果很难验证,但我们可以通过尾数来大致判断是否正确。202164尾数是4(1次方),4*4=16(2次方),6*4=24(3次方)…
314%2=0,对应2次方,所以最后一位是6,尾数正确。再来一个:73的286次方
73尾数是3(1次方),3*3=9(2次方),9*3=27(3次方),7*3=21(4次方),1*3=3(5次方)…
289%4=1,对应1次方,所以最后一位是6,尾数正确。
由此可见,乘方功能满足需求。

猜你喜欢

转载自blog.csdn.net/qq_54121864/article/details/116804200
今日推荐