使用BigInteger进行Karatsuba乘法

时间:2016-10-19 06:59:45

标签: java algorithm biginteger

我首先使用long编写了Karatsuba算法的代码。我觉得它完美无缺。使用相同的逻辑我将代码转换为BigInteger但由于某些原因它给出了StackOverflowError。

我无法弄清楚原因。请帮忙。

EDIT1:long的代码也有逻辑缺陷。我不确定是什么。

EDIT2:现在长期的代码。我换了一个"%"运算符" /"错误的。

EDIT3:现在好了。我将.xor更改为.pow和==更改为.equals并在return语句中修复了一些括号问题。谢谢大家的帮助!

这是正确的代码:

public static BigInteger karatsuba3(BigInteger i, BigInteger j){
    if (i.compareTo(Ten) == -1 || j.compareTo(Ten) == -1)
        return i.multiply(j);
    String length = getLength(i.max(j));
    BigInteger n = new BigInteger(length);
    if (n.mod(Two).equals(One))
        n = n.add(One);

    BigInteger a = i.divide(Ten.pow(n.divide(Two).intValue()));
    BigInteger b = i.mod(Ten.pow(n.divide(Two).intValue()));
    BigInteger c = j.divide(Ten.pow(n.divide(Two).intValue()));
    BigInteger d = j.mod(Ten.pow(n.divide(Two).intValue()));

    BigInteger first = karatsuba3(a,c);
    BigInteger second = karatsuba3(b,d);
    BigInteger third = karatsuba3(a.add(b),c.add(d));

    return ((first.multiply(Ten.pow(n.intValue()))).add ((((third.subtract(first)).subtract( second))).multiply(Ten.pow(n.divide((new BigInteger("2"))).intValue()))).add(second));
}

长码的Karatsuba:

public static long karatsuba1(long i, long j){
    if (i < 10 || j < 10) 
        return i*j;
    double n = getLength(Math.max(i,j));
    if (n%2 == 1)
        n++;
    long a = (long) (i/Math.pow(10,(n/2)));
    long b = (long) (i%Math.pow(10,(n/2)));
    long c = (long) (j/Math.pow(10,(n/2)));
    long d = (long) (j%Math.pow(10,(n/2)));

    long first = karatsuba1(a, c);
    long second = karatsuba1(b, d);
    long third = karatsuba1(a + b, c + d);

    return ((long) ((first * Math.pow(10, n)) + ((third - first - second) * Math.pow(10, (n/2))) + second));
}

public static int getLength( long a){
    String b = Long.toString(a);
    return b.length();
}

带有BigInteger代码的Karatsuba:

public static BigInteger karatsuba3(BigInteger i, BigInteger j){
    BigInteger Ten = new BigInteger("10");
    if (i.compareTo(Ten) == -1 || j.compareTo(Ten) == -1)
        return i.multiply(j);
    String length = getLength(i.max(j));
    BigInteger n = new BigInteger(length);
    if (n.mod(new BigInteger("2")) == new BigInteger("1"))
        n.add(new BigInteger ("1"));

    BigInteger a = i.divide(Ten.xor(n.divide((new BigInteger("2")))));
    BigInteger b = i.mod(Ten.xor(n.divide((new BigInteger("2")))));
    BigInteger c = j.divide(Ten.xor(n.divide((new BigInteger("2")))));
    BigInteger d = j.mod(Ten.xor(n.divide((new BigInteger("2")))));

    BigInteger first = karatsuba3(a,c);
    BigInteger second = karatsuba3(b,d);
    BigInteger third = karatsuba3(a.add(b),c.add(d));

    return ((first.multiply(Ten.xor(n))).add (((third.subtract(first).subtract( second)))).multiply(Ten.xor(n.divide((new BigInteger("2"))))).add(second));
}

public static String getLength( BigInteger a){
    String b = a.toString();
    return Integer.toString(b.length());
}

4 个答案:

答案 0 :(得分:4)

在第一个片段中,这条线对我来说不对:

long d = (long) (j/Math.pow(10,(n/2)));

所以现在你有c = d 可能你想要:

long d = (long) (j%Math.pow(10,(n/2)));

答案 1 :(得分:1)

在比较和分配bigint时你犯了一些错误,所以它是无限递归调用的原因。

if (n.mod(new BigInteger("2")) == new BigInteger("1"))
        n.add(new BigInteger ("1"));

应该纠正为;

if (n.mod(new BigInteger("2")).equals(new BigInteger("1")))
      n = n.add(new BigInteger ("1"));

但是还有其他问题你应该修复它以产生与&#34; long&#34;相同的结果。版。希望你能够纠正它们。

答案 2 :(得分:0)

使用 Ten.pow(x.intValue())而不是 Ten.xor(x)

答案 3 :(得分:-1)

现在可以使用

public static BigInteger karatsuba3(BigInteger x, BigInteger y) {

    // cutoff to brute force
    int N = Math.max(x.bitLength(), y.bitLength());
    if (N <= 2000) return x.multiply(y);                // optimize this parameter

    // number of bits divided by 2, rounded up
    N = (N / 2) + (N % 2);

    // x = a + 2^N b,   y = c + 2^N d
    BigInteger b = x.shiftRight(N);
    BigInteger a = x.subtract(b.shiftLeft(N));
    BigInteger d = y.shiftRight(N);
    BigInteger c = y.subtract(d.shiftLeft(N));

    // compute sub-expressions
    BigInteger ac    = karatsuba3(a, c);
    BigInteger bd    = karatsuba3(b, d);
    BigInteger abcd  = karatsuba3(a.add(b), c.add(d));

    return ac.add(abcd.subtract(ac).subtract(bd).shiftLeft(N)).add(bd.shiftLeft(2*N));
}

public static void main(String[] args){
    System.out.println(karatsuba3(BigInteger.valueOf(12347634456346L), BigInteger.valueOf(23346345643565L)));
}

在此处找到解决方案:Karatsuba Java

现在您可以比较并查看出现了什么问题