$\Huge\color{orchid}{点击此处获取更多干货}$
高精度
依旧是回忆一下,小学的时候学的减法:
减法同样是将被减数(minuend)和减数(subtrahend)的最低位对齐,每次只计算一位,如果计算结果小于0,就说明当前位不够减,需要向高一位的数字借1,被借位的数字在轮到它计算时需要视作事先减了1,同样,缺少的位数视作0,结果中需要去掉前导0(这里是真的有可能出现)
在需求描述中,并不能保证被减数一定大于减数,如果被减数小,需要暂时交换被减数和减数,最后添上负号。和加法同样,这里得到的结果也是倒序的,需要反转
还有一点需要注意,比较两个字符串表示的数字,需要自己写函数,而不能在全局区重载比较运算符,这样做虽然在本地(我的IDE是支持C++20的Visual Studio 17.3)可能不出问题,但是网站上不让你这么干。原因是C++20中string类封装的比较运算符重载函数已被禁用,但是在线编译器没有支持全部C++20的更新内容(就包括string类的比较运算符重载成员函数禁用),所以运行期就优先把比较运算绑定在了string类还未被弃用的比较运算符重载成员函数,这里特意给用惯了MSVC19.29和GCC13(这两个编译器能完美支持C++20)及以上版本的玩家们提个醒
C++ 代码
字符串比较函数:
bool isLess(string& s1, string& s2) {
if (s1.size() != s2.size()) return s1.size() < s2.size();
else return s1 < s2;
}
运算函数:
class SubtractCalculator : public LargeNumCalculator {
public:
string& calculate(string minuend, string subtrahend) {
ans.clear();//原因同样之后解释
bool less = false;
//默认被减数大,小了的话先交换相减后添负号
if (isLess(minuend, subtrahend)) {
less = true;
minuend.swap(subtrahend);
}
//依旧是反转两字符串,对齐最低位
reverse(minuend.begin(), minuend.end());
reverse(subtrahend.begin(), subtrahend.end());
int len1 = minuend.size(), len2 = subtrahend.size(), minus = 0;
//被减数的长度一定不小于减数长度,只有减数才会出现位数不够的情况
for (int i = 0; i < len1; i++) {
minus += minuend[i] - '0';
if (i < len2) {
minus -= subtrahend[i] - '0';
}
ans += '0' + ((minus + 10) % 10);//先加后模不影响取模结果,还可以避免讨论正负数
minus = (minus < 0) ? -1 : 0;//如果不够减,需要向高位借1
}
while (ans.size() > 1 && ans.back() == '0') {
ans.pop_back();
}
//到最后再加负号,反转ans的时候不用讨论
if (less) {
ans += '-';
}
reverse(ans.begin(), ans.end());
return ans;
}
};