【算法学习】大数乘法

要求:

计算两个大数X,Y的乘法,要求时间小于n^2.

方法:

 

分治法,将两个数分解为等长的两段。

X(n)= (a*10^m + b) , Y(n) = (c *10^m + d);(其中m = n/2)

X*Y = a*c*S(2m) + b*d  + (ad + bc)*S(m);

这里需要4次乘法(a*c, b*d, a*d, b*c),*S(m)不为乘法,通过位置/位移来控制。

其中ad + bc = (a +b)*(c +d) - ac -bd。

X*Y = a*c*S(2m) + b*d  + ((a +b)*(c +d) - ac -bd)*S(m);

因此只需要3次乘法,若干次加法和位置拷贝操作。

O(F(n)) = O( X(n)*Y(n)) = O(3F(n/2)  + n) = n^(log3)

代码

    //******************************************************************************************

    private static BigData praseString2BigData(String str) {
        BigData result = new BigData();
        result.len = str.length();
        result.data = new int[result.len];
        int loop = 0;
        byte[] byteNum = str.getBytes();
        for (int index = byteNum.length - 1; index >= 0; index--) {
            result.data[loop] = byteNum[index] - '0';
            loop++;
        }
        return result;
    }

    private static String praseBigData2Str(BigData bigData) {
        StringBuilder builder = new StringBuilder();
        for (int index = bigData.len - 1; index >= 0; index--) {
            builder.append(bigData.data[index]);
        }
        return builder.toString();
    }

    public static class BigData {
        public int[] data;

        public int len;

        public BigData(int len) {
            data = new int[len];
            this.len = 0;
        }

        public BigData() {
            len = 0;
        }
    }

    private static BigData add(BigData input1, BigData input2) {
        int bigLen = Math.max(input1.len, input2.len) + 1;
        BigData result = new BigData(bigLen);
        int shift = 0;
        int num1;
        int num2;
        int countNum;
        for (int loop = 0; loop < bigLen; loop++) {
            num1 = loop < input1.len ? input1.data[loop] : 0;
            num2 = loop < input2.len ? input2.data[loop] : 0;
            countNum = num1 + num2 + shift;
            shift = countNum / 10;
            result.data[loop] = countNum % 10;
        }
        result.len = result.data[bigLen - 1] == 0 ? bigLen - 1 : bigLen;
        return result;
    }

    private static BigData shiftLeft(BigData input, int len) {
        int bigLen = input.len + len;
        BigData result = new BigData(bigLen);
        System.arraycopy(input.data, 0, result.data, len, input.len);
        result.len = bigLen;
        return result;
    }

    private static BigData singleMultiply(final int input1, BigData input2) {
        BigData result = new BigData();
        result.len = input2.len + 1;
        result.data = new int[result.len];

        int num2;
        int shift = 0;
        int out;
        int outLen = 0;
        for (int loop = 0; loop < result.len; loop++) {
            num2 = loop < input2.len ? input2.data[loop] : 0;
            out = input1 * num2 + shift;
            result.data[loop] = out % 10;
            shift = out < 10 ? 0 : out / 10;
            if (out != 0) {
                outLen = loop;
            }
        }
        result.len = outLen + 1;
        return result;
    }

    private static void seperate(BigData input, int lowLen, BigData outputHigh, BigData outputLow) {
        outputHigh.len = input.len - lowLen;
        outputLow.len = lowLen;
        outputHigh.data = new int[outputHigh.len];
        outputLow.data = new int[outputLow.len];

        System.arraycopy(input.data, 0, outputLow.data, 0, outputLow.len);
        System.arraycopy(input.data, outputLow.len, outputHigh.data, 0, outputHigh.len);
        return;
    }

    private static BigData delete(BigData input1, BigData input2) {
        int bigLen = Math.max(input1.len, input2.len);
        BigData result = new BigData(bigLen);
        int shift = 0;
        int num1;
        int num2;
        int countNum;
        for (int loop = 0; loop < input1.len; loop++) {
            num2 = loop < input2.len ? input2.data[loop] : 0;
            countNum = input1.data[loop] - num2 - shift;
            if (countNum < 0) {
                shift = 1;
                countNum = 10 + countNum;
            } else {
                shift = 0;
            }
            result.data[loop] = countNum;
            if (countNum != 0) {
                result.len = loop;
            }
        }
        result.len += 1;
        return result;
    }

    /**
     *
     *  X = 10^s *a + b
     *  Y = 10^s *c + d
     *  X * Y = 10^(2s)ac + bd + 10^s( ad + bc)
     *       =10^(2s)ac + bd + 10^s( (a + b) * (c + d) - ac - bd)
     * @param input1
     * @param input2
     * @return
     */
    private static BigData multiply(BigData input1, BigData input2) {
        if (input1.len == 1) {
            return singleMultiply(input1.data[0], input2);
        }
        if (input2.len == 1) {
            return singleMultiply(input2.data[0], input1);
        }
        int inputLowLen = Math.min(input1.len / 2, input2.len / 2);
        BigData a = new BigData();
        BigData b = new BigData();
        BigData c = new BigData();
        BigData d = new BigData();
        seperate(input1, inputLowLen, a, b);
        seperate(input2, inputLowLen, c, d);
        BigData ac = multiply(a, c);
        BigData bd = multiply(b, d);
        BigData a_b = add(a, b);
        BigData c_d = add(c, d);
        BigData a_bc_d = multiply(a_b, c_d);
        BigData thrd = delete(delete(a_bc_d, ac), bd);
        BigData result = shiftLeft(ac, 2 * inputLowLen);
        result = add(result, bd);
        result = add(result, shiftLeft(thrd, inputLowLen));
        return result;

    }

    public static void main(String[] arg) {
        String strX = "3141592653589793238462643383279502884197169399375105820974944592";
        String strY = "2718281828459045235360287471352662497757247093699959574966967627";

        BigData x = praseString2BigData(strX);
        BigData y = praseString2BigData(strY);

        BigData result = multiply(x, y);
        String aa = praseBigData2Str(result);

    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值