C++之运算符的重载实现大数的运算

  前段时间,刚刚看完了刘汝佳的算法入门经典的重载运算符,刚开始不是很懂那是什么鬼,不过,现在学完了C++的运算符重载之后,就感觉So easy!~

  实现大数的运算,主要还是字符串的模拟。程序实现大数的运算,说白了,就是我们笔算的过程,而我们需要做的是如何控制程序以我们笔算的过程来运算。

  

class Operator
{
public:
	Operator(){}                                                //构造函数
	~Operator(){}                                               //析构函数
	friend istream& operator >> (istream &, Operator &);        //重载流提取运算符
	friend ostream& operator << (ostream &, Operator &);        //重载流插入运算符
	friend Operator operator + (Operator, Operator);            //重载 + 
	friend Operator operator - (Operator, Operator);            //重载 -
	friend Operator operator * (Operator, Operator);            //重载 *
	friend Operator operator / (Operator, int);                 //重载 /
private:
	char str[1000];
};
这是我定义的类,相信大家应该看到了,除法的那个友元函数,目前的我,还不会大数除以大数,所以只能用大数除以一个小的数来实现了。而大数除以大数,也是我们笔算的过程来实现,有机会再尝试一下,再来给大家分享。

重载 + 号实现大数加法,相对比较简单,不多说

Operator operator + (Operator s1, Operator s2)
{
	Operator s;
	int length1, length2, i, j, k;
	int a[1000];
	length1 = strlen(s1.str);
	length2 = strlen(s2.str);
	k = 0;
	i = length1 - 1;
	j = length2 - 1;
	for ( ; i >= 0 && j >= 0; )
	{
		a[k++] = (s1.str[i--] - '0') + (s2.str[j--] - '0');
	}
	while (i >= 0)                              //s1中没有加完
	{
		a[k++] = s1.str[i--] - '0';
	}
	while (j >= 0)                              //s2中没有加完
	{
		a[k++] = s2.str[j--] - '0';
	}
	for (i = 0; i < k; i++)                     //进位
	{
		if (a[i] >= 10 && i != k - 1)
		{
			a[i + 1] += a[i] / 10;
			a[i] %= 10;
		}
	}
	if (a[k - 1] >= 10)
	{
		a[k] = a[k - 1] / 10;
		a[k - 1] = a[k - 1] % 10;
		k++;
	}
	j = 0;
	for (i = k - 1; i >= 0; i--)                //因为我是逆序存放的结果,所以这里要反过来,才能得到结果
	{
		s.str[j++] = a[i] + '0';
	}
	s.str[j] = '\0';
	return s;
}
重载 - 号,相对比较麻烦,需要考虑减数和被减数的大小。主要是考虑两个数的大小,是否需要加上“-”号,我的函数中,比较长,因为有很多地方是重复的。
Operator operator - (Operator s1, Operator s2)
{
	Operator s;
	int length1, length2;
	length1 = strlen(s1.str);
	length2 = strlen(s2.str);
	if (strcmp(s1.str, s2.str) == 0)              //两个数相等的情况
	{
		s.str[0] = '0';
		s.str[1] = '\0';
		return s;
	}
	else
	{
		int a[1000], i, j, k = 0;            
		i = length1 - 1;
		j = length2 - 1;
		if (length1 > length2)                //减数大的情况
		{
			for (; j >= 0;)
			{
				if (s1.str[i] < s2.str[j])          //向下一位借1
				{
					s1.str[i - 1] -= 1;
					s1.str[i] += 10;
				}
				a[k++] = (s1.str[i--] - '0') - (s2.str[j--] - '0');
			}
			while (i >= 0)                             //减完了,剩余的位数补上
			{
				if (s1.str[i] < '0')                //0被借1之后的情况,需要再向前借
				{
					s1.str[i - 1] -= 1;
					s1.str[i] += 10;
				}
				a[k++] = (s1.str[i--] - '0');
			}
		}
		else if (length1 < length2)                        //被减数大的情况
		{
			for (; i >= 0;)
			{
				if (s2.str[j] < s1.str[i])          //借位
				{
					s2.str[j - 1] -= 1;
					s2.str[j] += 10;
				}
				a[k++] = (s2.str[j--] - '0') - (s1.str[i--] - '0');
			}
			while (j >= 0)                            //减完,补位
			{
				if (s2.str[j] < '0')              //0被借位的情况,同上
				{
					s2.str[j - 1] -= 1;
					s2.str[j] += 10;
				}
				a[k++] = (s2.str[j--] - '0');
			}
			a[k++] = '-';                        //最后补上负号
		}
		else                                          //两个数长度相同但不相等的情况,不需考虑借位遗留的问题
		{
			int flag = 0, b = 0;
			while (1)                               //判断哪个数比较大
			{
				if (s1.str[b] > s2.str[b])
				{
					break;
				}
				else if (s1.str[b] < s2.str[b])
				{
					flag = 1;
					break;
				}
				else
					b++;
			}
			if (flag == 0)                      //减数大的情况
			{
				for (; j >= 0;)
				{
					if (s1.str[i] < s2.str[j])
					{
						s1.str[i - 1] -= 1;
						s1.str[i] += 10;
					}
					a[k++] = (s1.str[i] - '0') - (s2.str[j] - '0');
				}
			}
			else                                  //被减数大的情况
			{
				for (; i >= 0;)
				{
					if (s2.str[j] < s1.str[i])
					{
						s2.str[j - 1] -= 1;
						s2.str[j] += 10;
					}
					a[k++] = (s2.str[j--] - '0') - (s1.str[i--] - '0');
				}
				a[k++] = '-';                //添加负号
			}
		}
		j = 0;
		if (a[k - 1] == '-')            //有负号,先添加
		{
			s.str[j++] = '-';
			k--;
		}
		while (a[k - 1] == 0)             //去掉因为借位和相减结果为0的前置的0
		{
			k--;
		}
		for (i = k - 1; i >= 0; i--)            //逆序返回结果。
		{
			s.str[j++] = a[i] + '0';
		}
		s.str[j] = '\0';
	}
	return s;
}
重载 * 号,比较简单,不多说

Operator operator * (Operator s1, Operator s2)
{
	Operator s;
	int a[2000], length1, length2;
	length1 = strlen(s1.str);
	length2 = strlen(s2.str);
	for (int i = 0; i < 2000; i++)
		a[i] = 0;
	for (int i = 0; i < length1; i++)                   //乘法运算
	{
		for (int j = 0; j < length2; j++)
		{
			a[i + j + 1] += (s1.str[i] - '0') * (s2.str[j] - '0');
		}
	}
	for (int i = length1 + length2 - 1; i >= 0; i--)        //进位
	{
		if (a[i] >= 10)
		{
			a[i - 1] += a[i] / 10;
			a[i] %= 10;
		}
	}
	int i = 0, j;
	while (!a[i])                                    //去掉前置的0
		i++;
	for (j = 0; i < length1 + length2; j++, i++)     //返回结果
		s.str[j] = a[i] + '0';
	s.str[j] = '\0';
	return s;
}

重载 / 号,这个也很简单,而这里的是整除,余数没有输出的。

Operator operator / (Operator s1, int s2)
{
	Operator s;
	int div = 0, length, i, j, k = 0;
	int a[1000];
	length = strlen(s1.str);
	for (i = 0; i < length; i++)
	{
		div = div * 10 + (s1.str[i] - '0');
		a[k++] = div / s2;
		div = div % s2;
	}
	j = i = 0;
	while (!a[j])    //去掉前置的0
		j++;
	for (; j < k; j++)
		s.str[i++] = a[j] + '0';
	s.str[i] = '\0';
	return s;
}

大数的运算,实际就是我们笔算的过程,只要想好我们笔算如何去算的,算法的实现就很简单了!~~

下面是整的代码:

 
# include <iostream>
# include <string>
using namespace std;
class Operator
{
public:
	Operator(){}                                                //构造函数
	~Operator(){}                                               //析构函数
	friend istream& operator >> (istream &, Operator &);        //重载流提取运算符
	friend ostream& operator << (ostream &, Operator &);        //重载流插入运算符
	friend Operator operator + (Operator, Operator);            //重载 + 
	friend Operator operator - (Operator, Operator);            //重载 -
	friend Operator operator * (Operator, Operator);            //重载 *
	friend Operator operator / (Operator, int);                 //重载 /
private:
	char str[1000];
};
istream& operator >> (istream &input, Operator &s)
{
	input >> s.str;
	return input;
}
ostream& operator << (ostream &output, Operator &s)
{
	output << s.str;
	return output;
}
Operator operator + (Operator s1, Operator s2)
{
	Operator s;
	int length1, length2, i, j, k;
	int a[1000];
	length1 = strlen(s1.str);
	length2 = strlen(s2.str);
	k = 0;
	i = length1 - 1;
	j = length2 - 1;
	for (; i >= 0 && j >= 0;)
	{
		a[k++] = (s1.str[i--] - '0') + (s2.str[j--] - '0');
	}
	while (i >= 0)                              //s1中没有加完
	{
		a[k++] = s1.str[i--] - '0';
	}
	while (j >= 0)                              //s2中没有加完
	{
		a[k++] = s2.str[j--] - '0';
	}
	for (i = 0; i < k; i++)                     //进位
	{
		if (a[i] >= 10 && i != k - 1)
		{
			a[i + 1] += a[i] / 10;
			a[i] %= 10;
		}
	}
	if (a[k - 1] >= 10)
	{
		a[k] = a[k - 1] / 10;
		a[k - 1] = a[k - 1] % 10;
		k++;
	}
	j = 0;
	for (i = k - 1; i >= 0; i--)                //因为我是逆序存放的结果,所以这里要反过来,才能得到结果
	{
		s.str[j++] = a[i] + '0';
	}
	s.str[j] = '\0';
	return s;
}
Operator operator - (Operator s1, Operator s2)
{
	Operator s;
	int length1, length2;
	length1 = strlen(s1.str);
	length2 = strlen(s2.str);
	if (strcmp(s1.str, s2.str) == 0)              //两个数相等的情况
	{
		s.str[0] = '0';
		s.str[1] = '\0';
		return s;
	}
	else
	{
		int a[1000], i, j, k = 0;
		i = length1 - 1;
		j = length2 - 1;
		if (length1 > length2)                //减数大的情况
		{
			for (; j >= 0;)
			{
				if (s1.str[i] < s2.str[j])          //向下一位借1
				{
					s1.str[i - 1] -= 1;
					s1.str[i] += 10;
				}
				a[k++] = (s1.str[i--] - '0') - (s2.str[j--] - '0');
			}
			while (i >= 0)                             //减完了,剩余的位数补上
			{
				if (s1.str[i] < '0')                //0被借1之后的情况,需要再向前借
				{
					s1.str[i - 1] -= 1;
					s1.str[i] += 10;
				}
				a[k++] = (s1.str[i--] - '0');
			}
		}
		else if (length1 < length2)                        //被减数大的情况
		{
			for (; i >= 0;)
			{
				if (s2.str[j] < s1.str[i])          //借位
				{
					s2.str[j - 1] -= 1;
					s2.str[j] += 10;
				}
				a[k++] = (s2.str[j--] - '0') - (s1.str[i--] - '0');
			}
			while (j >= 0)                            //减完,补位
			{
				if (s2.str[j] < '0')              //0被借位的情况,同上
				{
					s2.str[j - 1] -= 1;
					s2.str[j] += 10;
				}
				a[k++] = (s2.str[j--] - '0');
			}
			a[k++] = '-';                        //最后补上负号
		}
		else                                          //两个数长度相同但不相等的情况,不需考虑借位遗留的问题
		{
			int flag = 0, b = 0;
			while (1)                               //判断哪个数比较大
			{
				if (s1.str[b] > s2.str[b])
				{
					break;
				}
				else if (s1.str[b] < s2.str[b])
				{
					flag = 1;
					break;
				}
				else
					b++;
			}
			if (flag == 0)                      //减数大的情况
			{
				for (; j >= 0;)
				{
					if (s1.str[i] < s2.str[j])
					{
						s1.str[i - 1] -= 1;
						s1.str[i] += 10;
					}
					a[k++] = (s1.str[i] - '0') - (s2.str[j] - '0');
				}
			}
			else                                  //被减数大的情况
			{
				for (; i >= 0;)
				{
					if (s2.str[j] < s1.str[i])
					{
						s2.str[j - 1] -= 1;
						s2.str[j] += 10;
					}
					a[k++] = (s2.str[j--] - '0') - (s1.str[i--] - '0');
				}
				a[k++] = '-';                //添加负号
			}
		}
		j = 0;
		if (a[k - 1] == '-')            //有负号,先添加
		{
			s.str[j++] = '-';
			k--;
		}
		while (a[k - 1] == 0)             //去掉因为借位和相减结果为0的前置的0
		{
			k--;
		}
		for (i = k - 1; i >= 0; i--)            //逆序返回结果。
		{
			s.str[j++] = a[i] + '0';
		}
		s.str[j] = '\0';
	}
	return s;
}
Operator operator * (Operator s1, Operator s2)
{
	Operator s;
	int a[2000], length1, length2;
	length1 = strlen(s1.str);
	length2 = strlen(s2.str);
	for (int i = 0; i < 2000; i++)
		a[i] = 0;
	for (int i = 0; i < length1; i++)                   //乘法运算
	{
		for (int j = 0; j < length2; j++)
		{
			a[i + j + 1] += (s1.str[i] - '0') * (s2.str[j] - '0');
		}
	}
	for (int i = length1 + length2 - 1; i >= 0; i--)        //进位
	{
		if (a[i] >= 10)
		{
			a[i - 1] += a[i] / 10;
			a[i] %= 10;
		}
	}
	int i = 0, j;
	while (!a[i])                                    //去掉前置的0
		i++;
	for (j = 0; i < length1 + length2; j++, i++)     //返回结果
		s.str[j] = a[i] + '0';
	s.str[j] = '\0';
	return s;
}
Operator operator / (Operator s1, int s2)
{
	Operator s;
	int div = 0, length, i, j, k = 0;
	int a[1000];
	length = strlen(s1.str);
	for (i = 0; i < length; i++)
	{
		div = div * 10 + (s1.str[i] - '0');
		a[k++] = div / s2;
		div = div % s2;
	}
	j = i = 0;
	while (!a[j])                                      //去掉前置的0
		j++;
	for (; j < k; j++)
		s.str[i++] = a[j] + '0';
	s.str[i] = '\0';
	return s;
}
int main()
{
	Operator a, b, c;
	cin >> a >> b;
	c = a + b;
	cout << a << '+' << b << '=' << c << endl;
	c = a - b;
	cout << a << '-' << b << '=' << c << endl;
	c = a * b;
	cout << a << '*' << b << '=' << c << endl;
	c = a / 111;
	cout << a << '/' << "111" << '=' << c << endl;
	return 0;
}


下面是样例的结果:


如果大家发现有什么错误的话,欢迎跟我说,我会纠正的!~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值