Java大数加减乘法

加减法就是模拟笔算的过程,包括进位和借位。乘法若用笔算过程,时间复杂度为O(n2)。现有Karatsuba算法,时间复杂度为O(nlog23)

原理如下:

比如1234*5678,先把数字拆为12, 34和 56, 78
令z=34*78
r1=12*56*10000
r2=(12*78+34*56)*100
=((12+34)*(56+78)-34*78)*100
//这样算可以少算一次乘法,因为34*78已经在上一步算过
最后结果=r1+r2+z
如果第一次拆分之后数还是比较大,可以递归调用接着拆分,直到拆分后的数足够小。

代码如下:

package test;

import java.math.BigInteger;

public class BigNumberCalculater {

    public static void main(String[] args) {
        String num1 = "987654321";
        String num2 = "123456789";

        System.out.println("加=" + AddString(num1, num2));
        System.out.println("减=" + MinusString(num1, num2));
        System.out.println("乘=" + KaratsubaMultiply(num1, num2));

        BigInteger a = new BigInteger(num1);
        BigInteger b = new BigInteger(num2);

        System.out.println("加=" + a.add(b));
        System.out.println("减=" + a.subtract(b));
        System.out.println("乘=" + a.multiply(b));
        System.out.println("除=" + a.divide(b));
        System.out.println("取余=" + a.mod(b));
    }

    // 大数减法
    public static String MinusString(String num1, String num2) {
        int len1 = num1.length();
        int len2 = num2.length();
        if (num1.equals(num2)) {
            return "0";
        }
        boolean positive = true;
        if (len1 < len2 || (len1 == len2 && num1.compareTo(num2) < 0)) {
            positive = false;
            String tmp = num1;
            num1 = num2;
            num2 = tmp;
            int temp = len1;
            len1 = len2;
            len2 = temp;
        }
        String result = "";
        int i = len1 - 1, j = len2 - 1;
        int a, b, sum, carray = 0;

        while (i >= 0 || j >= 0) {// 从低位到高位对位做减法
            a = (i >= 0 ? num1.charAt(i) - '0' : 0);
            b = (j >= 0 ? num2.charAt(j) - '0' : 0);
            sum = a - b + carray;
            carray = 0;

            if (sum < 0) {// 借位
                sum += 10;
                carray = -1;
            }
            result = (sum) + result;
            --i;
            --j;
        }
        result = result.replaceAll("^[0]+", "");// 删除前导0
        return positive ? result : "-" + result;
    }

    // 大数加法
    public static String AddString(String num1, String num2) {
        int len1 = num1.length();
        int len2 = num2.length();
        if (len1 <= 0) {
            return num2;
        }
        if (len2 <= 0) {
            return num1;
        }
        String result = "";
        int i = len1 - 1, j = len2 - 1;
        int a, b, sum, carry = 0;
        while (i >= 0 || j >= 0 || carry > 0) {// 从末位开始相加
            a = i >= 0 ? num1.charAt(i) - '0' : 0;
            b = j >= 0 ? num2.charAt(j) - '0' : 0;
            sum = a + b + carry; // 按位相加并加上进位
            carry = sum / 10;// 进位
            result = (sum % 10) + result;
            --i;
            --j;
        }
        return result;
    }

    // Karatsuba大数乘法
    public static String KaratsubaMultiply(String num1, String num2) {
        int len1 = num1.length();
        int len2 = num2.length();
        int len = len1;
        if (len1 < len2) {
            for (int i = 0; i < len2 - len1; ++i) {
                num1 = "0" + num1;
            }
            len = len2;
        } else {
            for (int i = 0; i < len1 - len2; ++i) {
                num2 = "0" + num2;
            }
            len = len1;
        }
        if (len == 0) {
            return "0";
        }
        if (len == 1) {
            return String.valueOf(((num1.charAt(0) - '0') * (num2.charAt(0) - '0')));
        }
        int mid = len / 2;

        String x1 = num1.substring(0, mid);
        String x0 = num1.substring(mid, len);
        String y1 = num2.substring(0, mid);
        String y0 = num2.substring(mid, len);

        String z0 = KaratsubaMultiply(x0, y0);
        String z1 = KaratsubaMultiply(AddString(x1, x0), AddString(y1, y0));
        String z2 = KaratsubaMultiply(x1, y1);

        String r1 = ShiftString(z2, 2 * (len - mid));
        String r2 = ShiftString(MinusString(MinusString(z1, z2), z0), len - mid);

        return AddString(AddString(r1, r2), z0);
    }

    // 在右边添加len个0
    public static String ShiftString(String num, int len) {
        if (num.equals("0")) {
            return num;
        }
        for (int i = 0; i < len; ++i) {
            num += "0";
        }
        return num;
    }
}

java自带的BigInteger可以满足任意大整数的各种运算,实数的话可以用BigDecimal,于是我顺便用BigInteger验证了一下此算法的结果。结果为:

加=1111111110
减=864197532
乘=121932631112635269
加=1111111110
减=864197532
乘=121932631112635269
除=8
取余=9

你可能感兴趣的:(Java)