[心得] - 大数的加减乘除运算

1. 大数相加

 相加比较简单, 以加法竖式的方式进行相加即可.

2. 大数相减

  在相减中遇到一个多次借位的问题, 如: 100, 000, 002 - 989 ; 由于0没有数, 要一直往上借位, 直到借到位为止. 该怎么解决?

  [心得] - 大数的加减乘除运算_第1张图片

  1). 当第一次借位时, 判断下一位是否为0; 

 [心得] - 大数的加减乘除运算_第2张图片

   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);
}

3. 大数相乘

  以乘法竖式方式计算,  使被乘数 乘以 乘数的每一位, 保留到一个链表当中, 再对链表进行求和.

4. 大数相除

  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;
        }
    }

  写在最后: 关于负数的四则运算, 前几天也写过, 但是在重构代码时遇到问题, 所以今天写的大数算法就没有写负数的运算, 单个写出来冗余度比较高. 

 

你可能感兴趣的:(Algorithm)