百练 大整数的加减乘除(C++高精度)

题目来源:http://cxsjsxmooc.openjudge.cn/test/D/

D:大整数的加减乘除

总时间限制: 1000ms   内存限制: 65536kB

描述

给出两个正整数以及四则运算操作符(+ - * /),求运算结果。

输入

第一行:正整数a,长度不超过100
第二行:四则运算符oo“+”“-”“*”“/”中的某一个
第三行:正整数b,长度不超过100

保证输入不含多余的空格或其它字符

输出

一行:表达式“a o b”的值。

补充说明:
1. 减法结果有可能为负数
2. 除法结果向下取整
3. 输出符合日常书写习惯,不能有多余的0、空格或其它字符

样例输入

9876543210

+

9876543210

样例输出

19753086420

------------------------------------------------------------

题意

C++高精度,限定输入为正整数(只有减法结果可能产生负数)

------------------------------------------------------------

思路

【数据结构】

用字符串表示大整数。

【减法】

由于“小数 – 大数”会产生负数,为避免直接处理“小数 – 大数”的情况,首先写一个大整数的比较函数,然后根据减数和被减数的大小比较结果将“小数 – 大数”化为“大数 – 小数”,并在结果之前添上一个负号。

【乘法/除法】

记被乘/除数和乘/除数分别为a/b. 如果直接将乘法化为加法(乘数个被乘数相加)、将除法化为减法(被除数减除数的次数),则乘法复杂度为O(b(log(a)+log(b))),除法复杂度为O((a/b)log(a)),对于大整数来说,b和a/b都可能是极大的数(可达10^100),这样肯定会超时。

正确的算法是模仿竖式乘/除法。竖式乘法的复杂度为O(log(a)log(b)(log(a)+log(b))),竖式除法的复杂度为O((log(a)-log(b))log(a)).

------------------------------------------------------------

代码

/*
	正整数大数类的加减乘除
	http://cxsjsxmooc.openjudge.cn/test/D/
*/

#include<string>
#include<iostream>
#include<algorithm>

void reverse_string(std::string &ans)
{
	int n = ans.length(), i;
	char tmp;
	for (i=0; i<n/2; i++)
	{
		tmp = ans.at(i);
		ans.at(i) = ans.at(n-i-1);
		ans.at(n-i-1) = tmp;
	}
}

void remove_zeros(std::string &ans)
{
	if (ans == "0")
	{
		return;
	}
	int i = 0;
	for (i=0; i<ans.length(); i++)
	{
		if (ans.at(i) != '0')
		{
			break;
		}
	}
	ans = ans.substr(i);
}

class BigInt {
public:
	std::string num;	// unsigned number

	BigInt(void) {}
	BigInt(std::string Num): num(Num) {}

	BigInt Add(const BigInt & b)
	{
		std::string ans;
		int i, n1 = std::min(num.length(), b.num.length()), n2 = std::max(num.length(), b.num.length()), a1, a2, s = 0, si = 0;
		for (i=0; i<n1; i++)
		{
			a1 = num.at(num.length()-i-1) - '0';
			a2 = b.num.at(b.num.length()-i-1) - '0';
			if (a1 + a2 + si< 10)
			{
				s = a1 + a2 + si;
				si = 0;
			}
			else
			{
				s = (a1 + a2 + si) - 10;
				si = 1;
			}
			ans.push_back((char)(s + '0'));
		}
		for (i=n1; i<n2; i++)
		{
			if (n2 == num.length())
			{
				a1 = num.at(n2-i-1) - '0';
			}
			else
			{
				a1 = b.num.at(n2-i-1) - '0';
			}
			if (a1 + si < 10)
			{
				s = a1 + si;
				si = 0;
			}
			else
			{
				s = (a1 + si) - 10;
				si = 1;
			}
			ans.push_back((char)(s + '0'));
		}
		if (si == 1)
		{
			ans.push_back('1');
		}
		reverse_string(ans);
		return BigInt(ans);
	}

	int Compare(const BigInt & b)	// -1: <   0: ==   1: >
	{
		int n1 = num.length(), n2 = b.num.length(), i = 0;
		if (n1 > n2)
		{
			return 1;
		}
		else if (n1 < n2)
		{
			return -1;
		}
		else
		{
			for (i=0; i<n1; i++)
			{
				if (num.at(i) > b.num.at(i))
				{
					return 1;
				}
				else if (num.at(i) < b.num.at(i))
				{
					return -1;
				}
			}
			return 0;
		}
	}

	BigInt Subtract(const BigInt & b)
	{
		std::string ans;
		int oper = Compare(b), i, n1 = num.length(), n2 = b.num.length(), a1, a2, s = 0, si = 0;
		if (oper == 0)
		{
			return BigInt("0");
		}
		else if (oper == -1)
		{
			n1 = b.num.length();
			n2 = num.length();
			for (i=0; i<n2; i++)
			{
				a1 = b.num.at(n1-i-1) - '0';
				a2 = num.at(n2-i-1) - '0';
				if (a1 - a2 - si >= 0)
				{
					s = a1 - a2 - si;
					si = 0;
				}
				else
				{
					s = (a1 - a2 - si) + 10;
					si = 1;
				}
				ans.push_back((char)(s + '0'));
			}
			for (i=n2; i<n1; i++)
			{
				a1 = b.num.at(n1-i-1) - '0';
				if (a1 - si >= 0)
				{
					s = a1 - si;
					si = 0;
				}
				else
				{
					s = (a1 - si) + 10;
					si = 1;
				}
				ans.push_back((char)(s + '0'));
			}
			reverse_string(ans);
			remove_zeros(ans);
			std::string ans1 = "-";
			ans = ans1.append(ans);
		}
		else
		{
			for (i=0; i<n2; i++)
			{
				a1 = num.at(n1-i-1) - '0';
				a2 = b.num.at(n2-i-1) - '0';
				if (a1 - a2 - si >= 0)
				{
					s = a1 - a2 - si;
					si = 0;
				}
				else
				{
					s = (a1 - a2 - si) + 10;
					si = 1;
				}
				ans.push_back((char)(s + '0'));
			}
			for (i=n2; i<n1; i++)
			{
				a1 = num.at(n1-i-1) - '0';
				if (a1 - si >= 0)
				{
					s = a1 - si;
					si = 0;
				}
				else
				{
					s = (a1 - si) + 10;
					si = 1;
				}
				ans.push_back((char)(s + '0'));
			}
			reverse_string(ans);
			remove_zeros(ans);
		}
		return BigInt(ans);
	}

	BigInt Multiply(const BigInt & b)
	{
		BigInt ans("0");
		std::string tmp;
		int i, j, k, n1 = num.length(), n2 = b.num.length(), a1, a2, s = 0, si = 0;
		for (j=n2-1; j>=0; j--)
		{
			a2 = b.num.at(j) - '0';
			if (a2 == 0)
			{
				continue;
			}
			tmp.clear();
			s = 0;
			si = 0;
			for (k=0; k<n2-1-j; k++)
			{
				tmp.push_back('0');
			}
			for (i=n1-1; i>=0; i--)
			{
				a1 = num.at(i) - '0';
				s = (a1 * a2 + si) % 10;
				si = (a1 * a2 + si) / 10;
				tmp.push_back((char)(s + '0'));
			}
			if (si != 0)
			{
				tmp.push_back((char) (si + '0'));
			}
			reverse_string(tmp);
			ans = ans.Add(BigInt(tmp));
		}
		return ans;
	}

	BigInt Divide(const BigInt & b)
	{
		std::string ans;
		BigInt div;
		int n1 = num.length(), n2 = b.num.length(), i, tmp = 0;
		if (n1 < n2)
		{
			return BigInt("0");
		}
		div.num = num.substr(0, n2-1);
		for (i = 0; i <= n1 - n2; i++)
		{
			div.num.push_back(num.at(i+n2-1));
			tmp = 0;
			while (div.Compare(b) >= 0)
			{
				tmp++;
				div = div.Subtract(b);
			}
			ans.push_back((char) (tmp + '0'));
		}
		remove_zeros(ans);
		return BigInt(ans);
	}
};

int main()
{
	BigInt a,b;
	char oper;
	std::cin >> a.num >> oper >> b.num;
	switch (oper)
	{
	case '+':
		std::cout << a.Add(b).num;
		break;
	case '-':
		std::cout << a.Subtract(b).num;
		break;
	case '*':
		std::cout << a.Multiply(b).num;
		break;
	case '/':
		std::cout << a.Divide(b).num;
		break;
	default: break;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/82287011
今日推荐