高精度整数

高精度整数类

采用顺序存储结构, 用动态数组保存整数的每一数位, 根据整数的大小自动调整数组的尺寸, 实现动态内存管理。仿照C++的整数类型, 实现整数的全部运算。

话不多说,上代码:

/*BigInteger.h*/
#pragma once
#include<iostream>
#include<string>
#include<vector>
#define POSITIZE 1 //非负位
#define NEGATIVE -1 //负位
using namespace std;

class BigInteger
{
public:
	//构造函数
	BigInteger();//默认构造函数
	BigInteger(long long int);//int参数构造函数
	BigInteger(const BigInteger& a);//拷贝构造函数
	void zero_justify();//消除前导0
	friend ostream& operator<<(ostream& cout, BigInteger b);//重载输出
	friend istream& operator>>(istream& cin, BigInteger& b);//重载输入
	BigInteger operator << (int);//重载左移
	//比较
	friend int compare(const BigInteger& a, const BigInteger& b);//比较函数
	friend bool operator < (const BigInteger& a, const BigInteger& b);
	friend bool operator <= (const BigInteger& a, const BigInteger& b);
	friend bool operator > (const BigInteger& a, const BigInteger& b);
	friend bool operator >= (const BigInteger& a, const BigInteger& b);
	friend bool operator == (const BigInteger& a, const BigInteger& b);
	friend bool operator != (const BigInteger& a, const BigInteger& b);
	friend bool iszero(const BigInteger& a);//判断是否为0
	//重载 + - * / = ^运算符
	friend BigInteger operator + (BigInteger a, BigInteger b);
	BigInteger operator += (const BigInteger& b);
	friend BigInteger operator - (BigInteger a, BigInteger b);
	BigInteger operator -= (const BigInteger& b);
	friend BigInteger operator * (BigInteger a, BigInteger b);
	BigInteger operator *= (const BigInteger& b);
	friend BigInteger operator / (BigInteger a, BigInteger b);
	BigInteger operator /= (const BigInteger& b);
	friend BigInteger operator % (BigInteger a, BigInteger b);
	BigInteger operator %= (const BigInteger& b);
	BigInteger operator = (const BigInteger& b);
	BigInteger operator ^  (int n);

	//后置 递增 递减
	BigInteger operator++(int);
	BigInteger operator--(int);
	//前置 递增 递减
	BigInteger& operator++();
	BigInteger& operator--();
private:
	vector<int> value;//数位值 倒置存储 首位为个位
	int sign;//符号位 -1代表非负数 1代表非负数 采用int类型有利于后续符号位的计算 判断符号时将两个数的符号位相乘即为结果 但当2个数有一方为0时要注意判断
};

下面对几个关键函数做说明(最后有全部代码):

    一、BigInteger(long long int);//int参数构造函数

//整数参数构造
BigInteger::BigInteger(long long int a)
{
	sign = (a >= 0) ? POSITIZE : NEGATIVE;//判断符号
	long long int x;
	x = abs(a);
	do
	{
		this->value.push_back(x % 10);
		x /= 10;
	} while (x);
}

这个构造函数必须要有,如果没有就无法兼容 BigInteger类型和int类型的运算。比如 :

	friend BigInteger operator + (BigInteger a, BigInteger b);
BigInteger a, b;
a = b + 1000000;

因为 有构造函数:BigInteger(long long int); 上式中的1000000会自动类型转换为BigInteger类型。

二、比较函数friend int compare(const BigInteger& a, const BigInteger& b);//比较函数

其实这个函数的最大作用就是避免各种比较运算符的代码重复问题,就写一个函数,其他比较函数调用它就行,返回值为-1表示小于,0表示等于,1表示大于。

//比较函数 也是其他判断函数的内核 返回值 为 -1 0 1 分别代表 小于 等于 大于
int compare(const BigInteger& a, const BigInteger& b)
{
	if (a.sign < b.sign) //左值为负数 右值为正数时 直接返回小于(-1)
	{
		return -1;
	}
	else if(a.sign > b.sign)//左值为正数 右值为负数时 直接返回大于(1)
	{
		return 1;
	}
	//符号相同时:
	if (a.value.size() > b.value.size())//左值数位大于右值 由于符号相同 可以直接判断左值大于右值
	{
		return a.sign;
	}
	else if (a.value.size() < b.value.size())//与上同理
	{
		return a.sign * (-1);
	}
	for (int i = a.value.size() - 1; i >= 0; i--)//符号相同 数位相同 则从最高位开始比较
	{
		//此时比较有两方面要考虑 1:同位的数值大小比较 2:2个数的符号是同正 还是同负
		if (a.value[i] > b.value[i])//左值大于右值
		{
			return a.sign;//如果同为正 左值大于右值 反而左值小 所以直接返回左值的符号即可
		}
		if (a.value[i] < b.value[i])//左值小于右值
		{
			return a.sign * (-1);//与上同理
		}
	}
	return 0;
 }

三、重载乘法运算符 friend BigInteger operator * (BigInteger a, BigInteger b);

其实原理很简单,我们小学学的乘法时怎么算的我们就怎么算。比如:

123456 * 123

 

 注意:此函数中 用了重载的+运算符

//重载*
BigInteger operator * (BigInteger a, BigInteger b)
{
	BigInteger ret(0);//返回值 默认为0
	if (iszero(a) || iszero(b))//a b 任一为0 直接返回0
	{
		return ret;
	}
	else
	{
		//用ret保存结果 curr储存中间值 两数 从最低为开始相乘 将a依次与b的每一位相乘(从个位开始)得到curr 将curr累加得到ret即为结果
		int m = a.value.size(), n = b.value.size();
		for (int i = 0; i < n; i++)//i代表b的当前位数 从个位开始
		{
			BigInteger curr;
			for (int j = i; j > 0; j--)
			{//i每前进一位 curr都要左移一位 即乘10 如 b=123 则a要依次乘 3 20 100
				curr.value.push_back(0);
			}
			int add = 0;//进位数
			for (int j = 0; j < m; j++)//此处 j控制 a的位数
			{
				int p = a.value.at(j) * b.value.at(i) + add;//与加法相似 将个位存入 >=10的部分累加到进位数中
				curr.value.push_back(p % 10);
				add = p / 10;
			}
			while (add != 0)//进位数不为零 则直接将其顺位加入到高位中
			{
				curr.value.push_back(add % 10);
				add /= 10;
			}
			ret += curr;//累加到结果当中
		}
	}
	ret.zero_justify();
	ret.sign = a.sign * b.sign;//最后判断负号
	return ret;
}

完整代码:

三个构造函数:

//默认构造
BigInteger::BigInteger()
{
	sign = POSITIZE;//默认为非负
}

//整数参数构造
BigInteger::BigInteger(long long int a)
{
	sign = (a >= 0) ? POSITIZE : NEGATIVE;//判断符号
	long long int x;
	x = abs(a);
	do
	{
		this->value.push_back(x % 10);
		x /= 10;
	} while (x);
}

//拷贝构造
BigInteger::BigInteger(const BigInteger& a)
{
	this->value = a.value;
	this->sign = a.sign;
}

消除前导0:

//清除前导0
void BigInteger::zero_justify()
{
	for (int i = this->value.size() - 1; i >= 1;i--)//从最高位开始
	{
		if (this->value[i])//不为零就退出
		{
			break;
		}
		else
		{
			this->value.pop_back();//为零则清除此零
		}
	}
	if (this->value.size() == 1 && this->value[0] == 0)//值为0则不清除
	{
		this->sign = POSITIZE;
	}
}

重载输出、输入:

//重载输出
ostream& operator<<(ostream& out, const BigInteger b)
{
	if (b.sign < 0)//先判断符号 如果是负数 则先输出负号
	{
		out << '-';
	}
	for (int i = b.value.size() - 1; i >= 0; i--)//从最高位开始输出
	{
		out << b.value[i];
	}
	return out;//返回值为out 满足连续输出的需求
}

//重载输入
istream& operator>>(istream& in, BigInteger& b)
{
	string s;//以string方式输入
	in >> s;
	if (s.empty())//如果为空则直接退出
	{
		return in;//满足连续输入
	}
	if (isdigit(s[0]))//首位无符号 默认为正数
	{
		b.sign = POSITIZE;
	}
	else//有符号
	{
		b.sign = (s[0] == '+') ? POSITIZE : NEGATIVE;//判断符号位是否为'-'
		s.erase(s.begin());//符号判断完成后清除符号位 方便后续运算
	}
	b.value.clear();//输入前先清空
	for (int i = s.size() - 1; i >= 0; i--)
	{
		b.value.push_back(s[i] - '0');//从最高位开始入栈 并将每一位由char类型转换为int压入栈内 
	}
	b.zero_justify();//清除前导0
	return in;//满足连续输入
}

重载左移运算符 即*10操作:

//重载左移运算符 即*10操作
BigInteger BigInteger::operator << (int n)
{
	if (this->value.size() == 1 && this->value[0] == 0)//如果数值为0 则直接返回本身 即返回0
	{
		return *this;
	}
	this->value.insert(this->value.begin(), n, 0);//直接插入n个0
	return *this;
}

比较函数 也是其他判断函数的内核 返回值 为 -1 0 1 分别代表 小于 等于 大于:

//比较函数 也是其他判断函数的内核 返回值 为 -1 0 1 分别代表 小于 等于 大于
int compare(const BigInteger& a, const BigInteger& b)
{
	if (a.sign < b.sign) //左值为负数 右值为正数时 直接返回小于(-1)
	{
		return -1;
	}
	else if(a.sign > b.sign)//左值为正数 右值为负数时 直接返回大于(1)
	{
		return 1;
	}
	//符号相同时:
	if (a.value.size() > b.value.size())//左值数位大于右值 由于符号相同 可以直接判断左值大于右值
	{
		return a.sign;
	}
	else if (a.value.size() < b.value.size())//与上同理
	{
		return a.sign * (-1);
	}
	for (int i = a.value.size() - 1; i >= 0; i--)//符号相同 数位相同 则从最高位开始比较
	{
		//此时比较有两方面要考虑 1:同位的数值大小比较 2:2个数的符号是同正 还是同负
		if (a.value[i] > b.value[i])//左值大于右值
		{
			return a.sign;//如果同为正 左值大于右值 反而左值小 所以直接返回左值的符号即可
		}
		if (a.value[i] < b.value[i])//左值小于右值
		{
			return a.sign * (-1);//与上同理
		}
	}
	return 0;
 }

比较运算符重载:

//以下重载的比较函数 直接调用compare函数即可满足需求
//小于
bool operator < (const BigInteger& a, const BigInteger& b)
{
	return compare(a, b) < 0;
}

//小于等于
bool operator <= (const BigInteger& a, const BigInteger& b)
{
	return compare(a, b) <= 0;
}

//大于
bool operator > (const BigInteger& a, const BigInteger& b)
{
	return compare(a, b) > 0;
}

//大于等于
bool operator >= (const BigInteger& a, const BigInteger& b)
{
	return compare(a, b) >= 0;
}

//相等
bool operator == (const BigInteger& a, const BigInteger& b)
{
	return compare(a, b) == 0;
}

//不相等
bool operator != (const BigInteger& a, const BigInteger& b)
{
	return compare(a, b) != 0;
}

判断数值为0:

bool iszero(const BigInteger& a)
{
	bool ret = false;
	if (a.value.size() == 1 && a.value[0] == 0)
	{
		ret = true;
	}
	return ret;
}

重载加减乘除取余运算符+ - * / % ^:

注意:除法运算 被除数为零时 直接是报错

//重载+
BigInteger operator + (BigInteger a, BigInteger b)
{
	BigInteger c;//存放结果
	if (a.sign == b.sign)//两数符号相等 则结果的符号与两数符号相同
	{
		c.sign = a.sign;
	}
	else//两数符号不等 则转为减法运算再输出结果
	{
		if (a.sign == POSITIZE)//a为正 b为负 直接调用 a-b
		{
			b.sign = POSITIZE;
			c = a - b;
		}
		else
		{
			a.sign = POSITIZE;//a为负 b为正 直接调用 b-a
			c = b - a;
		}
		return c;
	}
	int i = 0, j = 0, add = 0;
	while (i < a.value.size() || j < b.value.size() || add != 0)//从个位开始计算 
	{
		//对应位的数值相加 存入c当中 当2数中的某个数算完时 则另一个数对应位的数值加0存入c中
		//三个步骤:1:对应位数值相乘 得到 ret ret可能>=10 2:ret大于10的部分为进位数 存入add当中 3:ret%10即为当前结果位的相应数值存入结果即可
		int x = i < a.value.size() ? a.value.at(i) : 0;
		int y = j < b.value.size() ? b.value.at(j) : 0;
		int ret = x + y + add;//用add储存进位数
		c.value.push_back(ret % 10);//将当前位数数值存入
		add = ret / 10;//保存进位数
		i++; j++;
	}
	c.zero_justify();//消除前置0
	return c;
}

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

//重载-
BigInteger operator - (BigInteger a, BigInteger b)
{
	BigInteger c;//保存结果
	if (a.sign < 0 || b.sign < 0)//当两数符号不同 转换为+法即可
	{
		b.sign *= -1;
		c = a + b;
		return c;
	}
	if (a < b)// a b 符号相同 a小于b 结果一定为负数 转换为 b-a 再将结果的符号改为负号即可 
	{
		c = b - a;
		c.sign = NEGATIVE;
		return c;
	}
	//a b负号相同 a >= b
	c.sign = POSITIZE;//结果一定非负
	int borrow = 0, i = 0, j = 0, ret; // 借位
	while (i < a.value.size() || j < b.value.size())//从最高位开始计算
	{
		int x = i < a.value.size() ? a.value.at(i) : 0;// 任一数位数不够 转为0即可 不做过多解释 与加法同理 
		int y = j < b.value.size() ? b.value.at(j) : 0;
		int ret = x - borrow - y;//borrow为借位
		if (ret < 0)//当x < y 即出现不够减的情况需要向高位借位
		{
			ret += 10;
			borrow = 1;
		}
		else
		{
			borrow = 0;
		}
		c.value.push_back(ret % 10);
		i++; j++;
	}
	c.zero_justify();
	return c;
}

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

//重载*
BigInteger operator * (BigInteger a, BigInteger b)
{
	BigInteger ret(0);//返回值 默认为0
	if (iszero(a) || iszero(b))//a b 任一为0 直接返回0
	{
		return ret;
	}
	else
	{
		//用ret保存结果 curr储存中间值 两数 从最低为开始相乘 将a依次与b的每一位相乘(从个位开始)得到curr 将curr累加得到ret即为结果
		int m = a.value.size(), n = b.value.size();
		for (int i = 0; i < n; i++)//i代表b的当前位数 从个位开始
		{
			BigInteger curr;
			for (int j = i; j > 0; j--)
			{//i每前进一位 curr都要左移一位 即乘10 如 b=123 则a要依次乘 3 20 100
				curr.value.push_back(0);
			}
			int add = 0;//进位数
			for (int j = 0; j < m; j++)//此处 j控制 a的位数
			{
				int p = a.value.at(j) * b.value.at(i) + add;//与加法相似 将个位存入 >=10的部分累加到进位数中
				curr.value.push_back(p % 10);
				add = p / 10;
			}
			while (add != 0)//进位数不为零 则直接将其顺位加入到高位中
			{
				curr.value.push_back(add % 10);
				add /= 10;
			}
			ret += curr;//累加到结果当中
		}
	}
	ret.zero_justify();
	ret.sign = a.sign * b.sign;//最后判断负号
	return ret;
}

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

//重载 /
BigInteger operator / (BigInteger a, BigInteger b)
{
	if (b == 0)
	{
		throw "Division by zero condition!";
	}//当除数为0时报错
	BigInteger ret, row;
	ret.sign = a.sign * b.sign;//先判断符号
	a.sign = 1;
	b.sign = 1;
	if(a == b)//两数相等 直接返回1即可
	{
		ret.value.push_back(1);
		return ret;
	}
	else
	{
		int i, t;
		for (int i = a.value.size() - 1; i >= 0; i--)//从a的最高位开始除
		{//如 5214/250 -> 判断 5/250 不够 -> 52/250 不够 -> 521 /250 够 521 / 250 = 2余21 将2加入ret的最低为 row=21 -> 214/250不够  ret左移 得到答案20
			row = row << 1;
			row.value[0] = a.value[i];
			t = 0;// 当除数小于被除数,减去除数,对应位的商增 1
			while (b <= row)
			{
				t++;
				row -= b;
			}
			ret = ret << 1;//在ret=0时 左移时无效的 只有当ret得到第一个不为0的值时才会开始左移
			ret.value[0] = t;
		}
		ret.zero_justify();
	}
	return ret;
}

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

//重载 =
BigInteger BigInteger::operator = (const BigInteger& b)
{
	this->value = b.value;
	this->sign = b.sign;
	return *this;
}

//重载 %
BigInteger operator % (BigInteger a, BigInteger b)
{//规定答案符号与a相同
	BigInteger ret;
	int s = a.sign;//此处保存a的符号 方便确定答案的符号
	a.sign = 1;
	b.sign = 1;
	if (a < b)//a<b 答案即为a
	{
		ret.value = a.value;
	}
	else if (a == b)//相等 答案为0
	{
		ret = 0;
	}
	else
	{
		BigInteger c;
		c = a / b;
		ret = a - b * c;
	}
	if (ret != 0)//如果a的符号为负 ret又为0 则ret的符号改为非负
	{
		ret.sign = s;
	}
	return ret;
}

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


//重载^幂运算
BigInteger BigInteger::operator ^  (int n)
{
	BigInteger x = *this;
	if (n == 0)
	{
		return BigInteger(1);
	}
	else if (n == 1)
	{
		return *this;
	}
	else if (n == 2)
	{
		return (*this) * (*this);
	}
	else
	{
		for (int i = 1; i < n; i++)
		{
			*this *= x;
		}
	}
	return *this;
}

递增递减:

//注意返回值的不同影响是否满足链式法则

//后置 递增
BigInteger BigInteger::operator++(int)
{
	BigInteger temp;
	temp = *this;
	*this += 1;
	return temp;
}
//后置 递减
BigInteger BigInteger::operator--(int)
{
	BigInteger temp;
	temp = *this;
	*this -= 1;
	return temp;
}
//前置 递增
BigInteger& BigInteger::operator++()
{
	*this += 1;
	return *this;
}

//前置 递减
BigInteger& BigInteger::operator--()
{
	*this -= 1;
	return *this;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值