美文网首页
大数相乘之Karatsuba算法

大数相乘之Karatsuba算法

作者: Stroman | 来源:发表于2018-03-22 19:17 被阅读112次

问题大数相乘

计算123×456,其实12345和6789就是大数。

思路

这是分治算法思想的典型体现。计算机只会加减不会乘除的,乘法都是通过设计的算法实现的。用的是Karatsuba乘法,它是把每个大数分成2个部分,比如说大数A前面的n位分出来变成了数字a,后面的m位分出来变成了b,其实A=a×10m+b,同理B也被拆分成了c和d。则可以推出A×B=(a×10m+b)(c×10n+d)=a×c×10(m+n)+a×d×10m+b×c×10n+b×d。可以看到中间那两项因为乘方幂次不同所以不能合并,于是再分解大数的时候拆分一定要保持幂次部分相同。现在假设幂次部分都是n,则有A×B=ac×102n+(ad+bc)×10n+bd。因为计算ad+bc的话总共需要4个乘法运算,消耗有点多。因为(a+b)(c+d)=ac+ad+bc+db==>(a+b)(c+d)-ac-bd=ad+bc。又因为ac和bd已经计算出来了所以乘法步骤被降为3步。那么现在要做的就是把ac×102n、(ad+bc)×10n、bd这三部分,更确切地说是把ac、bd、(a+b)(c+d)-ac-bd相加了,于是大问题就被分解为小问题了。那么如何获取每个数字的长度呢?没办法只能除以10了,不过为了增加运算速度可以把长度作为参数传递给递归体的,这样以后就不用运算了。

使用

package com.company;

public class Main {

    public static void main(String[] args) {
    // write your code here
        Solution.bigNumberMultiplication(12345,6789);
    }
}

输出

乘积是:83810205

Process finished with exit code 0

实现

package com.company;

public class Solution {
    /**
     * 两个大数相乘,这是分治算法的体现。
     * @param A
     * @param B
     */
    static public void bigNumberMultiplication(int A,int B) {
        if (A < 0 || B < 0) {
            System.out.println("输入错误!");
            return;
        }
        //首先计算A和B的长度
        int aLength = Solution.getNumberLength(A);
        int bLength = Solution.getNumberLength(B);
        if (aLength == -1 || bLength == -1) {
            System.out.println("输入错误!");
            return;
        }
        System.out.println("乘积是:" + Solution.karatsuba(A,aLength,B,bLength));
    }

    /**
     * karatsuba算法
     * @param A
     * @param ALength
     * @param B
     * @param BLength
     * @return
     */
    static private int karatsuba(int A,int ALength,int B,int BLength) {
        if (ALength < 2 || BLength < 2)return A*B;
        //应该选取较大的长度除以2,因为这样可以首先把较大的数变成较小的数。
        int middleLength = 0;
        if (ALength > BLength)middleLength = ALength / 2;
        else middleLength = BLength / 2;
        int tenPower = Solution.getTenPower(middleLength);
        int a = 0,b = 0;
        int aLength = 0,bLength = 0;
        if (ALength > middleLength) {
            a = A / tenPower;
            aLength = ALength - middleLength;
            b = A % tenPower;
            bLength = middleLength;
        } else {
            a = 0;
            aLength = 0;
            b = A;
            bLength = ALength;
        }
        int c = 0,d = 0;
        int cLength = 0,dLength = 0;
        if (BLength > middleLength) {
            c = B / tenPower;
            cLength = BLength - middleLength;
            d = B % tenPower;
            dLength = middleLength;
        } else {
            c = 0;
            cLength = 0;
            d = B;
            dLength = BLength;
        }
        int aMultiplyC = Solution.karatsuba(a,aLength,c,cLength);
        int bMultiplyd = Solution.karatsuba(b,bLength,d,dLength);
        int aPlusB = a + b;
        int cPlusD = c + d;
        int aPlusBLength = Solution.getNumberLength(aPlusB);
        int cPlusDLength = Solution.getNumberLength(cPlusD);
        int aPlusBMulitiplyCPlusD = Solution.karatsuba(aPlusB,aPlusBLength,cPlusD,cPlusDLength);
        int result = aMultiplyC * tenPower * tenPower + bMultiplyd + (aPlusBMulitiplyCPlusD - aMultiplyC - bMultiplyd) * tenPower;
        return result;
    }

    /**
     * 获取10的幂次结果
     * @param length
     * @return
     */
    static private int getTenPower(int length) {
        if (length <= 0)return 1;
        else {
            int lengthCopy = length;
            int zeroCounter = 1;
            while (lengthCopy > 0) {
                lengthCopy--;
                zeroCounter *= 10;
            }
            return zeroCounter;
        }
    }

    /**
     * 获取一个数字的长度
     * @param number
     * @return
     */
    static private int getNumberLength(int number) {
        if (number < 0)return -1;
        else {
            int numberCopy = number;
            int bitCounter = 0;
            while (numberCopy > 0) {
                numberCopy /= 10;
                bitCounter++;
            }
            return bitCounter;
        }
    }
}

相关文章

  • 大数相乘之Karatsuba算法

    问题大数相乘 计算123×456,其实12345和6789就是大数。 思路 这是分治算法思想的典型体现。计算机只会...

  • 大数相乘算法

    1、计算两个大数相乘的结果。2、算法流程:(1)大数可能超出任何一种整数类型,会引发溢出问题,所以用字符串的格式存...

  • 大数相乘-算法

    参考文章 题目 思路 例如:计算98×21,步骤如下 Objective-C 版 swift 版 待更新

  • 大数相乘--golang简单实现

    大数乘法之golang实现所谓大数相乘(Multiplication algorithm),就是指数字比较大,相乘...

  • 算法之俩个大数相乘

    具体实现如下: 运行结果:

  • OC大数相加相乘算法

    前些天做了份笔试题,最后一道题是写一个大数相乘的算法,太久没做题了,也没有草稿纸,脑子没动起来,笔就开始天马行空了...

  • 分治法 Divide and Conquer

    解决的最轻,最重,矩阵乘法,大整数乘法以及排序(快速排序,归并算法)。快速傅立叶变换,Karatsuba乘法算法 ...

  • Strassen算法

    【嵌牛导读】矩阵乘法之strassen算法 【嵌牛鼻子】分治算法 矩阵相乘strassen算法 【嵌牛提问】str...

  • 大数相乘

    所谓大数相乘(Multiplication algorithm),就是指数字比较大,相乘的结果超出了基本类型的表示...

  • 大数相乘

网友评论

      本文标题:大数相乘之Karatsuba算法

      本文链接:https://www.haomeiwen.com/subject/yfkzqftx.html