大整数乘法,参照BigInteger中改写,直接上代码

对于java来说,每一个整数运算都是int型,为了能运用cpu本身的乘法且不溢出,所以选用int[]数组来存储结果,在BigInteger的源代码中,还有另外两个算法,有两个限值

private static final int KARATSUBA_THRESHOLD = 80;  //数据的Byte数=80*4

private static final int TOOM_COOK_THRESHOLD = 240;  //数据的Byte数=240*4

当任一乘数的表示需要的int数小于80时,选用multilplyToLen方法,当两个乘数的int数都小于240且大于80时,选用KARATSUBA,否则选用TOOM_COOK,这两种算法都是基于分治法来实现,然后利用多项式减少乘法的次数。

如果每次只取出一位十进制数做乘法运算,cpu执行的仍然是int型的乘法,很浪费,可以一次取出9位,然后做运算。

重新优化了一下循环中的代码

/*
       大整數乘法,@see BigInteger#multiplyToLen
     */
    public static String multiply(String x, String y) {
        int len1 = x.length();
        int len2 = y.length();

        int l1 = len1 / 9;
        int rem1 = len1 % 9;
        if (rem1 !=0) {
            l1++;
        }
        int[] xArr = extract(x, l1, rem1);

        int l2 = len2 / 9;
        int rem2 = len2 % 9;
        if (rem2 !=0) {
            l2++;
        }
        int[] yArr = extract(y, l2, rem2);

        int[] res = new int[l1+l2];
        int xstart=l1-1;
        int ystart=l2-1;

        long L_MASK = 1000000000L;
        long carry = 0;
        int k = l1 + l2 - 1;
        for (int j = ystart; j >=0; j--, k --) {
            long product = ((long) yArr[j]) * xArr[xstart] + carry;
            res[k] = (int) (product % L_MASK);
            carry = product / L_MASK;
        }
        res[k] = (int) carry;
        for (int i = xstart -1; i >=0; i--) {
            carry = 0;
            k = l2 + i;
            for (int j = ystart; j >=0; j --, k--) {
                long product = ((long) yArr[j]) * xArr[i] + res[k] + carry;
                res[k] = (int) (product % L_MASK);
                carry = product / L_MASK;
            }
            res[k] = (int) carry;
        }
        StringBuilder ans = new StringBuilder();
        boolean flag = false;
        for (int i = 0; i < res.length; i++) {
            if (flag==false) {
                if (res[i] != 0) {
                    flag = true;
                    ans.append(Integer.toString(res[i]));
                }
            }else {
                String s = Integer.toString(res[i]);
                for (int i1 = 0; i1 < 9 - s.length(); i1++) {
                    ans.append('0');
                }
                ans.append(s);
            }
        }
        return ans.toString();
    }

    private static int[] extract(String s, int len, int rem) {
        int[] arr = new int[len];
        for (int i = 0; i < len; i++) {
            int temp = i * 9;
            if (rem != 0) {
                if (i == 0) {
                    arr[i] = Integer.valueOf(s.substring(0, rem));
                } else {
                    arr[i] = Integer.valueOf(s.substring(rem + temp - 9, rem + temp));
                }
                continue;
            }
            arr[i] = Integer.valueOf(s.substring(temp, temp + 9));
        }
        return arr;
    }

2.性能测试结果

代码:

 public static void main(String[] args) {
        String s1 = "1325134651345642355434444462523452345632458888888888888888888888888888888888888888888888888888888888888888888888";
        String s2 = "13251346513456423554734564555555537388888888888888888888888888888888888888888888888888888888888888888888888888880000001";
        String multiply1 = null;
        String multiply2 = null;

        long t1 = System.nanoTime();
        for (int i = 0; i < 100000; i++) {
            multiply1 = new BigInteger(s1).multiply(new BigInteger(s2)).toString();
        }
        long t2 = System.nanoTime();
        for (int i = 0; i < 100000; i++) {
            multiply2 = multiply(s1, s2);
        }
        long t3 = System.nanoTime();
        System.out.println("" + (t2 - t1) / 100000.0 + "ns " + (t3 - t2) / 100000.0 + "ns");

        System.out.println(multiply1);
        System.out.println(multiply2);
    }

结果:

发布了26 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/luffy_1993/article/details/104719403