算法-大数相乘

解决算法;
*  1. 模拟小学乘法:最简单的乘法竖式手算的累加型;
*  2. 分治乘法:最简单的是Karatsuba乘法,一般化以后有Toom-Cook乘法;
*  3. 快速傅里叶变换FFT:(为了避免精度问题,可以改用快速数论变换FNTT),时间复杂度O(N lgN lglgN)。具体可参照Schönhage–Strassen algorithm;
*  4. 中国剩余定理:把每个数分解到一些互素的模上,然后每个同余方程对应乘起来就行;
*  5. Furer’s algorithm:在渐进意义上FNTT还快的算法。不过好像不太实用,本文就不作介绍了。大家可以参考维基百科Fürer’s algorithm

参考地址:https://blog.csdn.net/u010983881/article/details/77503519

1. 小学乘法代码如下:

/**
     * 模拟小学乘法
     */
    public static String primaryMul(String str1, String str2){
        System.out.println("start primaryMul param=" + str1 + "," + str2 + ";time=" + System.currentTimeMillis());
        int[] int1 = string2IntArray(str1);
        int[] int2 = string2IntArray(str2);
        List result = new ArrayList<>();
        for (int i = int1.length-1; i >=0 ; i--) {
            List tempList = new ArrayList<>();
            int ten = 0;
            for (int j = int2.length-1; j >=0 ; j--) {
                int a = int1[i] * int2[j] + ten;
                ten = a / 10;
                tempList.add(a % 10);
            }
            if (ten > 0){
                tempList.add(ten);
            }
            //两行相加
            int carry = 0;
            for (int j = 0; j < tempList.size(); j++) {
                int r1 = 0;
                int index = j + (int1.length-1-i);
                if (index < 0 | result.size() > index){
                    r1 = result.get(index);
                }
                int a = tempList.get(j) + r1 + carry;
                carry = a / 10;
                if (index < 0 | result.size() > index){
                    result.set(index, a % 10);
                }else{
                    result.add(a % 10);
                }
            }
            if (carry > 0){
                result.add(carry);
            }
        }
        //方向旋转
        int copy;
        for (int i = 0; i < result.size(); i++) {
            if (i < result.size() / 2){
                copy = result.get(i);
                int index = result.size() -1 -i;
                result.set(i, result.get(index));
                result.set(index, copy);
            }
        }
        StringBuilder sb = new StringBuilder();
        for (Integer integer : result) {
            sb.append(integer);
        }
        System.out.println("end primaryMul result=" + sb + ";time=" + System.currentTimeMillis());
        return sb.toString();
    }

    public static int[] string2IntArray(String str){
        String[] strs = str.split("");
        int[] ret = new int[strs.length];
        for (int i = 0; i < strs.length; i++) {
            ret[i] = Integer.parseInt(strs[i]);
        }
        return ret;
    }

2. 小学算法-累加算法

 

/**
     * 模拟小学乘法 - 累加算法
     */
    private static String accumul(String str1, String str2){
        System.out.println("start accumul param=" + str1 + "," + str2 + ";time=" + System.currentTimeMillis());
        int[] int1 = string2IntArray(str1);
        int[] int2 = string2IntArray(str2);
        int[] result = new int[int1.length + int2.length];
        for (int i = 0; i < int1.length; i++) {
            for (int j = 0; j < int2.length; j++) {
                result[i + j + 1] += int1[i] * int2[j];
            }
        }
        for (int i = result.length - 1; i >= 0; i--) {
            if (result[i] >= 10){
                result[i-1] += result[i] / 10;
                result[i] = result[i] % 10;
            }
        }
        StringBuilder sb = new StringBuilder();
        for (Integer integer : result) {
            sb.append(integer);
        }
        System.out.println("end accumul result=" + sb + ";time=" + System.currentTimeMillis());
        return sb.toString();
    }

3. 分治算法-Karatsuba

/**
 * Karatsuba乘法
 */
public static long karatsuba(long num1, long num2){
    //递归终止条件
    if(num1 < 10 || num2 < 10) return num1 * num2;

    // 计算拆分长度
    int size1 = String.valueOf(num1).length();
    int size2 = String.valueOf(num2).length();
    int halfN = Math.max(size1, size2) / 2;

    /* 拆分为a, b, c, d */
    long a = Long.valueOf(String.valueOf(num1).substring(0, size1 - halfN));
    long b = Long.valueOf(String.valueOf(num1).substring(size1 - halfN));
    long c = Long.valueOf(String.valueOf(num2).substring(0, size2 - halfN));
    long d = Long.valueOf(String.valueOf(num2).substring(size2 - halfN));

    // 计算z2, z0, z1, 此处的乘法使用递归
    long z2 = karatsuba(a, c);
    long z0 = karatsuba(b, d);
    long z1 = karatsuba((a + b), (c + d)) - z0 - z2;

    return (long)(z2 * Math.pow(10, (2*halfN)) + z1 * Math.pow(10, halfN) + z0);
}

你可能感兴趣的:(java,算法,java)