相加比较简单, 以加法竖式的方式进行相加即可.
在相减中遇到一个多次借位的问题, 如: 100, 000, 002 - 989 ; 由于0没有数, 要一直往上借位, 直到借到位为止. 该怎么解决?
1). 当第一次借位时, 判断下一位是否为0;
2). 因为借位每一位最多借1, 那么被减数直接设置为9(已知被借位的数是0, 10 - 1 = 9), 设置完继续判断下一位是否还为0, 如果是0就继续设置.
3). 上面还有个lastIsZero, 意为上一个数是否为0, 设置完被减数后, 继续判断下一位是否为0, 如果不是, 那么它肯定是被0借位的数.
4). 如果上一个数是否为0, 那么被减数自减1, 然后设置为false.
while (!linkFirst.empty()) {
// first > second 被减数 > 减数
int subtracted = linkFirst.pop() - borrow; // 被减数
int subtraction; // 减数
try {
subtraction = linkSecond.pop();
} catch (NullPointerException e) {
subtraction = 0;
}
borrow = 0;
if (lastIsZero) {
subtracted--;
lastIsZero = false;
}
if (isZero) {
subtracted = 9;
if (linkFirst.peek() == 0) {
isZero = true;
} else {
isZero = false;
lastIsZero = true;
}
}
if (subtracted - subtraction < 0) {
borrow = 1;
}
if (borrow == 1) {
subtracted = subtracted + 10;
if (linkFirst.peek() == 0) {
isZero = true;
}
}
linkResult.add(subtracted - subtraction);
}
以乘法竖式方式计算, 使被乘数 乘以 乘数的每一位, 保留到一个链表当中, 再对链表进行求和.
1). 例如: 989 / 120 = ?
2). 120 * 2 = 240; 240 * 2 = 480; 480 * 2 = 960; 960 * 2 = 1920;
3). 2 是可调整的, 可以是3,4,5.... 也可以是10及更大的数.
4). 再用 1920 - 120 = 1800 .....
5). 这样可以得出商, 以及余数, 返回余数, 再用余数 / 120, 这样可以精确到小数点位.
[2, 4 可以调整, 我试过100位数除以10位数, 如果是 * 2, 和减去 120, 非常慢; 在这里可以适当的优化调整. ]
private String division(String divided, String divisor) {
boolean isFirst = true;
// LessThan 是前一个数比后一个数小, 返回true, 同理MoreThan
// 当被除数小于除数时, 被除数添加一个0, 代表 * 10
// 有时, * 10 还不够, 所以如果还需要乘10, 则需要在结果也添加0.(除法竖式原则)
while (comparison(divided, divisor).equals(Utils.ComparisionEnum.LessThan)) {
divided += "0";
if (isFirst) {
hasDecimalPoint();
isFirst = false;
} else {
result += "0";
}
}
String quotient = "1";
String original = divisor;
while (comparison(divided, divisor).equals(Utils.ComparisionEnum.MoreThan)) {
divisor = new Multiplication().calculation(divisor, "2"); // 乘法
quotient = new Multiplication().calculation(quotient, "2");
divisor = getNoComma(divisor); // 因为结果是格式化(以逗号分隔, 去逗号的方法)
quotient = getNoComma(quotient);
}
while (comparison(divided, divisor).equals(Utils.ComparisionEnum.LessThan)) {
divisor = new Subtraction().calculation(divisor, original); // 减法
quotient = new Subtraction().calculation(quotient, "1");
divisor = getNoComma(divisor);
quotient = getNoComma(quotient);
}
String remainder = new Subtraction().calculation(divided, divisor);
remainder = getNoComma(remainder);
remainder = checkZero(remainder); // 去掉开头的0
System.out.println();
System.out.println("+==================================+");
System.out.println("divided: " + divided);
System.out.println("divisor: " + divisor);
System.out.println("remainder: " + remainder);
System.out.println("quotient: " + quotient);
System.out.println("+==================================+");
result += quotient;
return remainder;
}
// 判断结果中是否又小数点
private boolean hasPoint = false;
private void hasDecimalPoint() {
if (!hasPoint) {
if (result.equals("")) result = "0";
result += ".";
hasPoint = true;
}
}
写在最后: 关于负数的四则运算, 前几天也写过, 但是在重构代码时遇到问题, 所以今天写的大数算法就没有写负数的运算, 单个写出来冗余度比较高.