大数相减(Big Number Subtraction)

大数相减

思路相比大数相加要复杂一些,因为涉及了是小减大还是大减小的问题,在计算机编程中,我们的实现与现实中我们手算的思路是一致的:借位相减。我们来举一个例子:

通过这个计算,我们知道,当我们用大减小时,从低位开始减,当减出负数是,我们就需要向高一位的位数借一位,再相减,此时高位就比原来少一,在编程语言中我们就需要记录这个行为,在下一位相减时提前计算出大数正确的大小再去与小数相同的位相减,而后重复上述操作。

当我们需要小减大的时候我们是怎么做的呢?

其实我们只是将其转换为大减小,只不过在计算出结果后加一个负数就可以了,在计算机编程中,我们就需要预先判断。

最后我们处理数据输入的问题,我们可以将输入的数字以字符串的格式来接收,而后通过其对应的Unicode(或ASICC码)来一个一个取出每个位对应的数字,然后将其保存在数组中,这样我们就可以模拟我们手算时从低位到高位计算的操作了。

这里我们需要明确另外两个问题,当我们将数字存在数组中时我们究竟是从高位到低位存还是低位到高位存呢?

我们选择从低位到高位存,也就是说1234这个数字,我们存在数组中的顺序是4321,这样做的目的是为了方便做计算时位数变化的操作,比如说1000-999=1 ,如果我们是从高位到低位存,那么我们就会存出{0, 0, 0, 1}这样的数组,一个是浪费了空间,另一个是如果是加法要增添空间时就会变得很麻烦(位数增加时就需要将数组整体向后平移,导致效率变低)

第二个问题是,当我们以1000-999以后我们会计算出{1, 0, 0, 0}这样得数组,我们需要将多余的0去掉,这可以避免浪费空间以及更方便地输出。

最后,我们就可以将我们的代码贴出来啦!(注意这里使用了类去封装,因为这么做可以方便我们在之后做功能的扩展)

class LargeDiscount {
public:
	std::string operator()(std::string& a, std::string& b)
	{

		auto CMP=[](std::string& a, std::string& b) {
            if (a.size() == b.size()) 
            {
			for (int i = 0; i < a.size(); ++i)
				if (a[i] != b[i])
					return a[i] > b[i];
		    }
		    else
			    return a.size() > b.size();
		return true; };
		bool right = CMP(a, b);

		std::vector<int> A, B;
		if (right)
		{
			for (int i = a.size() - 1; i >= 0; --i) A.push_back(a[i] - '0');
			for (int i = b.size() - 1; i >= 0; --i) B.push_back(b[i] - '0');
		}
		else
		{
			for (int i = a.size() - 1; i >= 0; --i) B.push_back(a[i] - '0');
			for (int i = b.size() - 1; i >= 0; --i) A.push_back(b[i] - '0');
		}

		int count = 0;
		std::vector<int> result;
		for (int i = 0; i < A.size(); ++i)
		{
			count = A[i] - count;
			if (i < B.size())
				count -= B[i];
			result.push_back((count + 10) % 10);
			if (count >= 0) count = 0;
			else count = 1;
		}

		while (result.size() > 1 && result.back() == 0)
			result.pop_back();
		std::string r;
		if (!right)
			r.push_back('-');
		for (int i = result.size() - 1; i >= 0; --i)
		{
			r.push_back(result[i] + '0');
		}
		return r;
	}
};