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"BigInt.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"BigInt.h"
using namespace std;
int main()
{
	BigInt t = 1;
	for (int i = 0; i < 100; i++)
	{
		t *= 10;
		cout << t.ToString() << '\t';
	}
	return 0;
}

大整数类不会溢出

从中可见,大整数类型保存大小理论上来说是没有有限制的(除非这个数超大,把内存占满了)。
还有一点,这个大整数类是考虑负数的,可以对负数进行相同操作。

更新历史

2022-12-11:(重要更新)修改大数类类名为BigInt和UnsignedBigInt;取消BigInt和UnsignedBigInt的继承关系,改为组合关系;整理成员函数的声明,对成员函数进行分类;增加求算术平方根和判断质数的功能;修改bug;整理完善测试程序。
2022-4-17:修改加法和减法由于先计算再比较导致结果不准确的bug;将一些常量改为懒汉模式。
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,如果大家发现漏洞,可以在评论区回复。


BigInt.h:

#pragma once
#include<deque>
#include<string>
namespace MyStd
{
	class UnsignedBigInt
	{
	private:
		friend class MulBuffer;
		friend class BigInt;
		using valueType = uint32_t;
		std::deque<valueType> m_data;//数字
		static UnsignedBigInt Mul(UnsignedBigInt n1, valueType n2);//计算UnsignedBigInt与一位数相乘的结果
		void Reduce();//化简(去掉前导0)
	public:
		static const short m_radix = 10;//使用10进制存储,可以改,结果不会变

		//常数部分
		static inline const UnsignedBigInt& UnsignedLongLongMax()noexcept;
		static inline const UnsignedBigInt& LongLongMax()noexcept;

		//构造函数
		UnsignedBigInt();
		UnsignedBigInt(unsigned long long num);
		UnsignedBigInt(const UnsignedBigInt& i);
		UnsignedBigInt(UnsignedBigInt&& i);
		UnsignedBigInt(const std::string& source, uint8_t radix = 10);

		//数字信息
		size_t Size()const noexcept;//位数
		UnsignedBigInt SubNum(size_t first, size_t count = 1)const;

		//赋值
		UnsignedBigInt& operator=(unsigned long long num);
		UnsignedBigInt& operator=(const UnsignedBigInt& n);
		UnsignedBigInt& operator=(UnsignedBigInt&& n);
		UnsignedBigInt& operator=(const std::string& source);
		void Assign(const std::string& source, uint8_t radix = 10);
		void Assign(unsigned long long num);

		//比较大小
		bool IsZero()const;
		friend std::strong_ordering operator<=>(const UnsignedBigInt& n1, const UnsignedBigInt& n2)noexcept;
		static std::strong_ordering Compare(const UnsignedBigInt& n1, const UnsignedBigInt& n2);
		friend bool operator==(const UnsignedBigInt& n1, const UnsignedBigInt& n2);
		friend bool operator!=(const UnsignedBigInt& n1, const UnsignedBigInt& n2);

		//运算
		friend UnsignedBigInt operator+(UnsignedBigInt n1, const UnsignedBigInt& n2);
		friend UnsignedBigInt operator-(UnsignedBigInt n1, const UnsignedBigInt& n2);//计算差的绝对值
		friend UnsignedBigInt operator*(const UnsignedBigInt& n1, const UnsignedBigInt& n2);
		static UnsignedBigInt Divide(const UnsignedBigInt& n1, UnsignedBigInt n2, UnsignedBigInt& remainder);//除法,结果向0舍入,例如(-7)/5=-1
		friend UnsignedBigInt operator/(const UnsignedBigInt& n1, const UnsignedBigInt& n2);
		friend UnsignedBigInt operator%(const UnsignedBigInt& n1, const UnsignedBigInt& n2);
		UnsignedBigInt& operator+=(const UnsignedBigInt& n);
		UnsignedBigInt& operator-=(const UnsignedBigInt& n);
		UnsignedBigInt& operator*=(const UnsignedBigInt& n);
		UnsignedBigInt& operator/=(const UnsignedBigInt& n);
		UnsignedBigInt& operator%=(const UnsignedBigInt& n);
		UnsignedBigInt& operator++();
		UnsignedBigInt& operator--();
		UnsignedBigInt operator++(int);
		UnsignedBigInt operator--(int);
		static UnsignedBigInt Add(UnsignedBigInt n1, const UnsignedBigInt& n2);
		static UnsignedBigInt Sub(UnsignedBigInt n1, const UnsignedBigInt& n2);
		BigInt operator-()const;
		const UnsignedBigInt& operator+()const noexcept;
		static UnsignedBigInt Pow(const UnsignedBigInt& n, unsigned long long exponential);//使用快速幂
		static UnsignedBigInt Pow(const UnsignedBigInt& n, UnsignedBigInt exponential);//不使用快速幂
		static UnsignedBigInt Sqrt(const UnsignedBigInt& n);//向下取整

		//数论函数
		static UnsignedBigInt GCD(UnsignedBigInt n1, UnsignedBigInt n2);
		static UnsignedBigInt LCM(const UnsignedBigInt& n1, const UnsignedBigInt& n2);
		static bool IsPrime(const UnsignedBigInt& n);

		//类型转换
		std::string ToString(uint8_t radix = 10)const;//radix范围为2-16
		unsigned long long ToUnsignedLongLong()const;
		long double ToLongDouble()const;
	};
	class BigInt 
	{
	private:
		friend class MulBuffer;
		UnsignedBigInt m_abs;
		bool m_sign;//1正0负
		void Reduce();//化简(去掉前导0,把0的符号设为+)
	public:
		static const short m_radix = UnsignedBigInt::m_radix;

		//构造函数
		BigInt();
		BigInt(long long num);
		BigInt(const BigInt& i);
		BigInt(BigInt&& i);
		BigInt(const UnsignedBigInt& i);
		BigInt(UnsignedBigInt&& i);
		BigInt(const std::string& source, uint8_t radix = 10);

		//赋值
		BigInt& operator=(long long num);
		BigInt& operator=(const BigInt& n);
		BigInt& operator=(BigInt&& n);
		BigInt& operator=(const std::string& source);
		void Assign(std::string source, uint8_t radix = 10);
		void Assign(long long num);
		void SetSign(bool sign)noexcept;

		//数字信息
		bool GetSign()const noexcept;

		//比较大小
		bool IsZero()const;
		static std::strong_ordering Compare(const BigInt& n1, const BigInt& n2);
		friend std::strong_ordering operator<=>(const BigInt& n1, const BigInt& n2)noexcept;
		friend bool operator==(const BigInt& n1, const BigInt& n2);
		friend bool operator!=(const BigInt& n1, const BigInt& n2);

		//运算
		BigInt Abs()const;
		friend BigInt operator+(BigInt n1, const BigInt& n2);
		friend BigInt operator-(BigInt n1, const BigInt& n2);
		friend BigInt operator*(BigInt n1, const BigInt& n2);
		static BigInt Divide(const BigInt& n1, const BigInt& n2, BigInt& remainder);//除法,结果向0舍入,例如(-7)/5=-1
		friend BigInt operator/(const BigInt& n1, const BigInt& n2);
		friend BigInt operator%(const BigInt& n1, const BigInt& n2);
		BigInt& operator+=(const BigInt& n);
		BigInt& operator-=(const BigInt& n);
		BigInt& operator*=(const BigInt& n);
		BigInt& operator/=(const BigInt& n);
		BigInt& operator%=(const BigInt& n);
		BigInt& operator++();
		BigInt& operator--();
		BigInt operator++(int);
		BigInt operator--(int);
		BigInt operator-()const;
		const BigInt& operator+()const noexcept;
		static BigInt Pow(const BigInt& n, unsigned long long exponential);//使用快速幂
		static BigInt Pow(const BigInt& n, UnsignedBigInt exponential);//不使用快速幂

		//类型转换
		const UnsignedBigInt& ToUnsignedBigInt()const noexcept;
		std::string ToString(uint8_t radix = 10, bool ShowPlusSign = false)const;//radix范围为2-16
		long long ToLongLong()const;
		long double ToLongDouble()const;
	};
	class MulBuffer//乘法缓存(保存该数乘以每一位的结果,防止重复计算)
	{
	public:
		MulBuffer(const UnsignedBigInt& number);
		const UnsignedBigInt& GetResult(uint32_t a);
		void Recalculate()noexcept;
	private:
		UnsignedBigInt results[BigInt::m_radix];
		bool b[BigInt::m_radix];
		const UnsignedBigInt& num;
	};

	UnsignedBigInt operator""_ubi(unsigned long long num)//_ubi后缀
	{
		return UnsignedBigInt(num);
	}

	BigInt operator""_bi(unsigned long long num)//_bi后缀
	{
		return BigInt(num);
	}

	std::strong_ordering operator-(std::strong_ordering n)
	{
		return std::strong_ordering(-n._Value);
	}

	void BigInt::Reduce()
	{
		m_abs.Reduce();
		if (IsZero())
			m_sign = true;
	}

	BigInt::BigInt()
	{
		m_sign = true;
		m_abs.m_data.push_back(0);
	}

	BigInt::BigInt(long long num) :m_abs(num > 0 ? num : -num)
	{
		m_sign = (num >= 0);
	}


	BigInt::BigInt(const BigInt& i):m_abs(i.m_abs),m_sign(i.m_sign)
	{
	}

	BigInt::BigInt(BigInt&& i) :m_abs(std::move(i.m_abs)), m_sign(i.m_sign)
	{

	}

	BigInt::BigInt(const UnsignedBigInt& i) : m_abs(i), m_sign(true)
	{
	}

	BigInt::BigInt(UnsignedBigInt&& i) : m_abs(std::move(i)), m_sign(true)
	{
	}

	BigInt::BigInt(const std::string& source, uint8_t radix)
	{
		Assign(source, radix);
	}

	const UnsignedBigInt& BigInt::ToUnsignedBigInt() const noexcept
	{
		return m_abs;
	}

	BigInt BigInt::Abs() const
	{
		BigInt temp(*this);
		temp.m_sign = true;
		return temp;
	}

	std::string BigInt::ToString(uint8_t radix, bool showPlusSign)const
	{
		std::string result;
		if (!m_sign)
			result += '-';
		else if (showPlusSign)
			result += '+';
		return result + m_abs.ToString(radix);
	}

	BigInt& BigInt::operator=(long long num)
	{
		Assign(num);
		return *this;
	}

	BigInt& BigInt::operator=(const BigInt& n)
	{
		if (this != &n)
		{
			m_abs = n.m_abs;
			m_sign = n.m_sign;
		}
		return *this;
	}

	BigInt& BigInt::operator=(BigInt&& n)
	{
		if (this != &n)
		{
			m_abs = std::move(n.m_abs);
			m_sign = n.m_sign;
		}
		return *this;
	}

	BigInt& BigInt::operator=(const std::string& source)
	{
		Assign(source);
		return *this;
	}

	void BigInt::Assign(std::string source, uint8_t radix)
	{
		m_sign = true;
		if (!source.empty())
		{
			if(source[0] == '-')
			{
				m_sign = false;
				source.erase(0, 1);
			}
			else if (source[0] == '+')
			{
				source.erase(0, 1);
			}
		}
		m_abs.Assign(source, radix);
		Reduce();
	}

	void BigInt::Assign(long long num)
	{
		m_sign = (num >= 0);
		if (!m_sign)
			num = -num;
		m_abs = num;
	}

	inline void BigInt::SetSign(bool sign) noexcept
	{
		m_sign = sign;
	}

	inline bool BigInt::GetSign() const noexcept
	{
		return m_sign;
	}

	inline bool BigInt::IsZero() const
	{
		return m_abs.IsZero();
	}

	inline std::strong_ordering BigInt::Compare(const BigInt& n1, const BigInt& n2)
	{
		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;
		return n1.m_sign ? UnsignedBigInt::Compare(n1.m_abs, n2.m_abs) : -UnsignedBigInt::Compare(n1.m_abs, n2.m_abs);
	}


	BigInt& BigInt::operator+=(const BigInt& n)
	{
		if (m_sign == n.m_sign)//符号相同按加法算
		{
			m_abs += n.m_abs;
		}
		else//符号不同按减法算
		{
			if (UnsignedBigInt::Compare(m_abs, n.m_abs) < 0)
				m_sign = !m_sign;
			m_abs -= n.m_abs;
		}
		return *this;
	}

	BigInt& BigInt::operator-=(const BigInt& n)
	{
		if (m_sign == n.m_sign)//符号相同按减法算
		{
			if (UnsignedBigInt::Compare(m_abs, n.m_abs) < 0)
				m_sign = !m_sign;
			m_abs -= n.m_abs;
		}
		else//符号不同按加法算
		{
			m_abs += n.m_abs;
		}
		return *this;
	}

	BigInt& BigInt::operator*=(const BigInt& n)
	{
		m_abs *= n.m_abs;
		m_sign = (m_sign == n.m_sign);
		return *this;
	}

	BigInt& BigInt::operator/=(const BigInt& n)
	{
		BigInt rem;
		return *this = Divide(*this, n, rem);
	}

	BigInt& BigInt::operator%=(const BigInt& n)
	{
		BigInt temp(*this);
		Divide(temp, n, *this);
		return *this;
	}

	BigInt& BigInt::operator++()
	{
		return operator+=(1);
	}

	BigInt& BigInt::operator--()
	{
		return operator-=(1);
	}

	BigInt BigInt::operator++(int)
	{
		BigInt temp(*this);
		this->operator+=(1);
		return temp;
	}

	BigInt BigInt::operator--(int)
	{
		BigInt temp(*this);
		this->operator-=(1);
		return temp;
	}

	BigInt BigInt::operator-() const
	{
		BigInt temp(*this);
		temp.m_sign = !m_sign;
		return temp;
	}

	const BigInt& BigInt::operator+()const noexcept
	{
		return *this;
	}
	BigInt BigInt::Pow(const BigInt& n, UnsignedBigInt exponential)
	{
		BigInt result = UnsignedBigInt::Pow(n.m_abs, exponential);
		if ((!n.m_sign) && !((exponential % 2).IsZero()))
			result.m_sign = false;
		return result;
	}
	BigInt BigInt::Pow(const BigInt& n, unsigned long long exponential)
	{
		BigInt result = UnsignedBigInt::Pow(n.m_abs, exponential);
		if ((!n.m_sign) && (exponential & 1))
			result.m_sign = false;
		return result;
	}

	long long BigInt::ToLongLong() const
	{
		if (UnsignedBigInt::Compare(m_abs, UnsignedBigInt::LongLongMax()) > 0)
			throw std::overflow_error("该数超出long long类型的范围!");
		return m_sign ? m_abs.ToUnsignedLongLong() : -static_cast<long long>(m_abs.ToUnsignedLongLong());
	}

	long double BigInt::ToLongDouble() const
	{
		return m_sign ? m_abs.ToLongDouble() : -m_abs.ToLongDouble();
	}

	std::strong_ordering operator<=>(const BigInt& n1, const BigInt& n2)noexcept
	{
		return BigInt::Compare(n1, n2);
	}
	bool operator==(const BigInt& n1, const BigInt& n2)
	{
		return (n1.IsZero() && n2.IsZero()) || (n1.m_sign == n2.m_sign && n1.m_abs == n2.m_abs);
	}

	bool operator!=(const BigInt& n1, const BigInt& n2)
	{
		return !(n1 == n2);
	}

	BigInt operator+(BigInt n1, const BigInt& n2)
	{
		return n1 += n2;
	}

	BigInt operator-(BigInt n1, const BigInt& n2)
	{
		return n1 -= n2;
	}

	BigInt operator*(BigInt n1, const BigInt& n2)
	{
		return n1 *= n2;
	}

	BigInt BigInt::Divide(const BigInt& n1, const BigInt& n2, BigInt& remainder)
	{
		BigInt&& result = UnsignedBigInt::Divide(n1.m_abs, n2.m_abs, remainder.m_abs);
		result.m_sign = (n1.m_sign == n2.m_sign);
		result.Reduce();
		remainder.m_sign = n1.m_sign;
		return result;
	}

	BigInt operator/(const BigInt& n1, const BigInt& n2)
	{
		BigInt remainder;//余数(无用)
		return BigInt::Divide(n1, n2, remainder);
	}

	BigInt operator%(const BigInt& n1, const BigInt& n2)
	{
		BigInt remainder;
		BigInt::Divide(n1, n2, remainder);
		return remainder;
	}

	MulBuffer::MulBuffer(const UnsignedBigInt& number) :num(number)
	{
		for (bool& i : b)
			i = false;
	}

	const UnsignedBigInt& MulBuffer::GetResult(uint32_t a)
	{
		if (!b[a])
		{
			results[a] = UnsignedBigInt::Mul(num, a);
			b[a] = true;
		}
		return results[a];
	}

	void MulBuffer::Recalculate() noexcept
	{
		for (auto& i : b)
			i = false;
	}
	UnsignedBigInt UnsignedBigInt::Mul(UnsignedBigInt n1, valueType n2)
	{
		if (n2 == 0)
			return 0;
		int carry = 0;
		for (auto iter = n1.m_data.rbegin(); iter != n1.m_data.rend(); ++iter)
		{
			int t = *iter * n2;
			*iter = (t + carry) % m_radix;
			carry = (t + carry) / m_radix;
		}
		if (carry)
			n1.m_data.push_front(carry);
		return n1;
	}
	void UnsignedBigInt::Reduce()
	{
		while (m_data.size() > 0 && m_data.front() == 0)
			m_data.pop_front();
		if (m_data.empty())
			m_data.push_back(0);
	}
	inline const UnsignedBigInt& UnsignedBigInt::UnsignedLongLongMax() noexcept
	{
		static const UnsignedBigInt UNSIGNEDLONGLONG_MAX("18446744073709551615");
		return UNSIGNEDLONGLONG_MAX;
	}
	inline const UnsignedBigInt& UnsignedBigInt::LongLongMax() noexcept
	{
		static const UnsignedBigInt LONGLONG_MAX("9223372036854775807");
		return LONGLONG_MAX;
	}
	UnsignedBigInt::UnsignedBigInt()
	{
		m_data.push_back(0);
	}
	UnsignedBigInt::UnsignedBigInt(unsigned long long num)
	{
		Assign(num);
	}
	UnsignedBigInt::UnsignedBigInt(const UnsignedBigInt& i)
	{
		if (this != &i)
			m_data = i.m_data;
	}
	UnsignedBigInt::UnsignedBigInt(UnsignedBigInt&& i):m_data((std::move(i.m_data)))
	{
	}
	UnsignedBigInt::UnsignedBigInt(const std::string& source, uint8_t radix)
	{
		Assign(source, radix);
	}
	size_t UnsignedBigInt::Size() const noexcept
	{
		return m_data.size();
	}
	UnsignedBigInt UnsignedBigInt::SubNum(size_t first, size_t count) const
	{
		UnsignedBigInt 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 UnsignedBigInt::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
		{
			UnsignedBigInt temp(*this);
			std::string t;
			while (!temp.IsZero())
			{
				UnsignedBigInt rem;
				temp = Divide(temp, radix, rem);
				uint8_t i = static_cast<int8_t>(rem.ToUnsignedLongLong());
				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;
	}
	UnsignedBigInt& UnsignedBigInt::operator=(unsigned long long num)
	{
		Assign(num);
		return *this;
	}
	UnsignedBigInt& UnsignedBigInt::operator=(const UnsignedBigInt& n)
	{
		if (this != &n)
			m_data = n.m_data;
		return *this;
	}
	UnsignedBigInt& UnsignedBigInt::operator=(UnsignedBigInt&& n)
	{
		m_data = std::move(n.m_data);
		return *this;
	}
	UnsignedBigInt& UnsignedBigInt::operator=(const std::string& source)
	{
		Assign(source);
		return *this;
	}
	void UnsignedBigInt::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;
			}
			UnsignedBigInt 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;
			}
		}
		Reduce();
	}
	void UnsignedBigInt::Assign(unsigned 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;
		}
	}
	inline bool UnsignedBigInt::IsZero() const
	{
		return m_data.front() == 0;
	}
	std::strong_ordering UnsignedBigInt::Compare(const UnsignedBigInt& n1, const UnsignedBigInt& n2)
	{
		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;
	}
	std::strong_ordering operator<=>(const UnsignedBigInt& n1, const UnsignedBigInt& n2) noexcept
	{
		return UnsignedBigInt::Compare(n1, n2);
	}
	bool operator==(const UnsignedBigInt& n1, const UnsignedBigInt& n2)
	{
		return n1.m_data == n2.m_data;
	}
	bool operator!=(const UnsignedBigInt& n1, const UnsignedBigInt& n2)
	{
		return n1.m_data != n2.m_data;
	}
	UnsignedBigInt operator+(UnsignedBigInt n1, const UnsignedBigInt& n2)
	{
		return n1 += n2;
	}
	UnsignedBigInt operator-(UnsignedBigInt n1, const UnsignedBigInt& n2)
	{
		return n1 -= n2;
	}
	UnsignedBigInt operator*(const UnsignedBigInt& n1, const UnsignedBigInt& n2)
	{
		if (n1.Size() > n2.Size())
			return n2 * n1;//为了减少调用CUnsignedBigInt::Mul的次数
		MulBuffer buf(n2);
		UnsignedBigInt result;
		auto iter = n1.m_data.rbegin();
		for (int t = 0; iter != n1.m_data.rend(); ++iter, ++t)
		{
			if (*iter)
			{
				UnsignedBigInt temp = buf.GetResult(*iter);
				for (int j = 0; j < t; ++j)
					temp.m_data.push_back(0);
				result += temp;
			}
		}
		return result;
	}
	UnsignedBigInt operator/(const UnsignedBigInt& n1, const UnsignedBigInt& n2)
	{
		UnsignedBigInt rem;
		return UnsignedBigInt::Divide(n1, n2, rem);
	}
	UnsignedBigInt operator%(const UnsignedBigInt& n1, const UnsignedBigInt& n2)
	{
		UnsignedBigInt rem;
		UnsignedBigInt::Divide(n1, n2, rem);
		return rem;
	}
	UnsignedBigInt UnsignedBigInt::Divide(const UnsignedBigInt& n1, UnsignedBigInt n2, UnsignedBigInt& remainder)
	{
		if (n2.IsZero())
			throw::std::invalid_argument("除数为0!");
		if (n1 < n2)
		{
			remainder = n1;
			return 0;
		}
		UnsignedBigInt 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.Reduce();
		return result;
	}
	UnsignedBigInt& UnsignedBigInt::operator+=(const UnsignedBigInt& 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 % UnsignedBigInt::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;
	}
	UnsignedBigInt& UnsignedBigInt::operator-=(const UnsignedBigInt& 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;
		}
		Reduce();
		return *this;
	}
	UnsignedBigInt& UnsignedBigInt::operator*=(const UnsignedBigInt& n)
	{
		return *this = *this * n;
	}
	UnsignedBigInt& UnsignedBigInt::operator/=(const UnsignedBigInt& n)
	{
		UnsignedBigInt rem;
		return *this = Divide(*this, n, rem);
	}
	UnsignedBigInt& UnsignedBigInt::operator%=(const UnsignedBigInt& n)
	{
		UnsignedBigInt tmp(*this);
		Divide(tmp, n, *this);
		return *this;
	}
	UnsignedBigInt& UnsignedBigInt::operator++()
	{
		return *this += 1;
	}
	UnsignedBigInt& UnsignedBigInt::operator--()
	{
		return *this -= 1;
	}
	UnsignedBigInt UnsignedBigInt::operator++(int)
	{
		UnsignedBigInt temp(*this);
		*this += 1;
		return temp;
	}
	UnsignedBigInt UnsignedBigInt::operator--(int)
	{
		UnsignedBigInt temp(*this);
		*this -= 1;
		return temp;
	}
	UnsignedBigInt UnsignedBigInt::Add(UnsignedBigInt n1, const UnsignedBigInt& n2)
	{
		return n1 += n2;
	}
	UnsignedBigInt UnsignedBigInt::Sub(UnsignedBigInt n1, const UnsignedBigInt& n2)
	{
		return n1 -= n2;
	}
	BigInt UnsignedBigInt::operator-() const
	{
		return -BigInt(*this);
	}
	const UnsignedBigInt& UnsignedBigInt::operator+() const noexcept
	{
		return *this;
	}
	UnsignedBigInt UnsignedBigInt::Pow(const UnsignedBigInt& n, unsigned long long exponential)
	{
		if (n == 1)
			return 1;
		UnsignedBigInt result = 1, t(n);
		while (exponential) {
			if (exponential & 1)
				result *= t;
			t = t * t;
			exponential >>= 1;
		}
		return result;
	}
	UnsignedBigInt UnsignedBigInt::Pow(const UnsignedBigInt& n, UnsignedBigInt exponential)
	{
		if (exponential.IsZero())
		{
			if (n.IsZero())
				throw std::invalid_argument("0的0次方无意义!");
			return 1;
		}
		if (n == 1)
			return 1;
		UnsignedBigInt t(n);
		while (!(--exponential).IsZero())
			t *= n;
		return t;
	}
	UnsignedBigInt UnsignedBigInt::Sqrt(const UnsignedBigInt& n)
	{
		//二分法
		UnsignedBigInt l = 0, r = n;
		while (l < r)
		{
			const UnsignedBigInt mid = (l + r) / 2;
			const auto res = Compare(mid * mid, n);
			if (res < 0)
				l = mid + 1;
			else if (res > 0)
				r = mid - 1;
			else
				return mid;
		}
		return l * l <= n ? l : l - 1;
	}
	UnsignedBigInt UnsignedBigInt::GCD(UnsignedBigInt n1, UnsignedBigInt n2)
	{
		UnsignedBigInt t;
		while (!n2.IsZero())
		{
			t = n1 % n2;
			n1 = n2;
			n2 = t;
		}
		return n1;
	}

	UnsignedBigInt UnsignedBigInt::LCM(const UnsignedBigInt& n1, const UnsignedBigInt& n2)
	{
		return n1 * n2 / GCD(n1, n2);
	}
	bool UnsignedBigInt::IsPrime(const UnsignedBigInt& n)
	{
		if (n <= 1)
			return false;
		if (n == 2)
			return true;
		const UnsignedBigInt max = Sqrt(n) + 1;
		for (UnsignedBigInt i = 2; i <= max; ++i)
		{
			if ((n % i).IsZero())
				return false;
		}
		return true;
	}
	unsigned long long UnsignedBigInt::ToUnsignedLongLong() const
	{
		if (*this > UnsignedLongLongMax())
			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 UnsignedBigInt::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<functional>
#include<vector>
#include<Windows.h>
#include"BigInt.h"
using namespace std;
using namespace MyStd;
void AddTest()
{
	string s1, s2;
	cout << "输入两个数,求它们的和:";
	cin >> s1 >> s2;
	ULONGLONG Time = GetTickCount64();
	BigInt&& res = (BigInt(s1) + s2);
	Time = GetTickCount64() - Time;
	cout << res.ToString() << endl;
	cout << "计算时间:" << Time << "毫秒" << endl;
}
void SubTest()
{
	string s1, s2;
	cout << "输入两个数,求它们的差:";
	cin >> s1 >> s2;
	ULONGLONG Time = GetTickCount64();
	BigInt&& res = (BigInt(s1) - s2);
	Time = GetTickCount64() - Time;
	cout << res.ToString() << endl;
	cout << "计算时间:" << Time << "毫秒" << endl;
}
void MulTest()
{
	string s1, s2;
	cout << "输入两个数,求它们的积:";
	cin >> s1 >> s2;
	ULONGLONG Time = GetTickCount64();
	BigInt&& res = (BigInt(s1) * s2);
	Time = GetTickCount64() - Time;
	cout << res.ToString() << endl;
	cout << "计算时间:" << Time << "毫秒" << endl;
}
void DivTest()
{
	string s1, s2;
	cout << "输入两个数,求它们的商和余数:";
	cin >> s1 >> s2;
	BigInt rem;
	ULONGLONG Time = GetTickCount64();
	BigInt&& res = BigInt::Divide(s1, s2, rem);
	Time = GetTickCount64() - Time;
	cout << res.ToString() << '\t' << rem.ToString() << endl;
	cout << "计算时间:" << Time << "毫秒" << endl;
}
void PowTest()
{
	string s1;
	unsigned long long s2;
	cout << "输入两个数,求a的b次方:";
	cin >> s1 >> s2;
	ULONGLONG Time = GetTickCount64();
	BigInt&& res = BigInt::Pow(s1, s2);
	Time = GetTickCount64() - Time;
	cout << res.ToString() << endl;
	cout << "计算时间:" << Time << "毫秒" << endl;
}
void GCD_LCMTest()
{
	string s1, s2;
	cout << "输入两个数,求它们的最大公约数和最小公倍数:";
	cin >> s1 >> s2;
	ULONGLONG Time = GetTickCount64();
	UnsignedBigInt a(s1), b(s2);
	auto&& gcd = UnsignedBigInt::GCD(a, b);
	auto&& lcm = a * b / gcd;//不用LCM是因为如果用LCM会造成重复计算
	Time = GetTickCount64() - Time;
	cout << gcd.ToString() << '\t' << lcm.ToString() << endl;
	cout << "计算时间:" << Time << "毫秒" << endl;
}
void SqrtTest()
{
	string s;
	cout << "输入一个数,求它的算术平方根:";
	cin >> s;
	ULONGLONG Time = GetTickCount64();
	auto&& res = UnsignedBigInt::Sqrt(s);
	Time = GetTickCount64() - Time;
	cout << res.ToString() << endl;
	cout << "计算时间:" << Time << "毫秒" << endl;
}
void PrimeTest()
{
	string s;
	cout << "输入一个数,判断是否为质数:";
	cin >> s;
	ULONGLONG Time = GetTickCount64();
	const bool res = UnsignedBigInt::IsPrime(s);
	Time = GetTickCount64() - Time;
	cout << boolalpha << res << endl;
	cout << "计算时间:" << Time << "毫秒" << endl;
}
void Test()
{
	ios::sync_with_stdio(false);

	const vector<function<void()>>tests = 
		{ AddTest,SubTest,MulTest,DivTest,PowTest,SqrtTest,GCD_LCMTest,PrimeTest };
	while (1)
	{
		cout << "0.退出\n";
		cout << "1.加法测试\n";
		cout << "2.减法测试\n";
		cout << "3.乘法测试\n";
		cout << "4.除法测试\n";
		cout << "5.乘方测试\n";
		cout << "6.开方测试\n";
		cout << "7.GCD测试\n";
		cout << "8.质数测试\n";
		cout << "请选择:";
		int choose;
		cin >> choose;
		if (choose == 0)
			break;
		if (choose<0 || choose>tests.size())
		{
			cout << "输入无效!" << endl;
			system("pause & cls");
			continue;
		}
		try
		{
			tests[choose - 1]();
		}
		catch (const invalid_argument& err)
		{
			cout << "出现参数无效异常!异常信息:" << err.what() << endl;
		}
		catch (const exception& err)
		{
			cout << "出现其他类型异常!异常信息:" << err.what() << endl;
		}
		system("pause & cls");
	}
}
int main()
{
	Test();
	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,尾数正确。
由此可见,乘方功能满足需求。

评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值