$\Huge\color{orchid}{点击此处获取更多干货}$
高精度
除法运算是最特别的,其他三种运算都是对齐低位,除法需要对齐高位,因此被除数和除数都不需要反转。还是老规矩,结合下图回忆一下小学的时候除法是怎么算的:
由此可见,除法运算过程中,需要从高位开始依次取出被除数(dividend)的每一位,并将组成的新数与除数(divisor)相除,当前位的商需要对齐,取得余数(remainder)后再取出原被除数下一位,让它作为新的被除数继续和除数做除法,直到原被除数的所有数位都被取出并取得商(quotient)。
这其中有两个注意点:
1. 除了最后一位产生的余数之外,中间每一位的余数如果是0,需要将其省略
2. 在1的条件下,如果最后余数是空串,需要将0还给它
由于每一位的商只能是0到9之间这10个数,因此可以将余数依次减去除数(高精度的减)并让商递增的“笨办法”,这里需要用到减法计算器,虽然改为了在除法计算器类的私有成员中添加减法计算器实例的方式来减少耦合,但还是无法避免减法计算器中ans串的清空,原因和加法中一样(T_T)
C++ 代码
class DivideCalculator : public LargeNumCalculator {
public:
string& calculate(string dividend, string divisor) {
for (int i = 0; i < dividend.size(); i++) {
remainder += dividend[i];
int quo = 0;
//由于余数一定小于除数,当前位得出的商一定不会大于9
while (!isLess(remainder, divisor)) {
remainder = subtractCalculator.calculate(remainder, divisor);
quo++;
}
//如果上一位得出的余数是0,需要把这个0去掉,要不然下一次比较的时候会出问题
if (remainder == "0") remainder = "";
ans += '0' + quo;
}
//除法运算全程都是正序进行,按照正序方法去掉前导0
int nz = ans.find_first_not_of('0');
ans = (nz == -1) ? "0" : ans.substr(nz);
//这儿如果发现余数是空串就说明余数为0,需要把0还给它
if (remainder == "") remainder = "0";
ans += '\n' + remainder;
return ans;
}
private:
//将减法计算器和除法计算器的关系从泛化改为聚合
//虽然能降低一定耦合,但无法避免减法计算器中ans.clear()的调用
SubtractCalculator subtractCalculator;
string remainder;
};