4

I first wrote a code for Karatsuba algorithm using long. It works perfectly I think. Using the same logic I converted the code to BigInteger but for some reasons its giving StackOverflowError.

I cant figure out why. Please help.


EDIT1: The code for long also has a logical flaw. I am not sure what.

EDIT2: The code for long works now. I switched a "%" operator with "/" by mistake.

EDIT3: All good now. I changed .xor to .pow and == to .equals and fixed some bracket issues in the return statement. Thank you everyone for the help!


Here is the correct code:

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 with long code:

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();
}

Karatsuba with BigInteger code:

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());
}
jww
  • 97,681
  • 90
  • 411
  • 885
hsnsd
  • 1,728
  • 12
  • 30
  • On another look you are using the new without delete often. Are you absolutely sure it is properly deleted after return? – Spektre Oct 19 '16 at 07:30
  • @Spektre: `I do not see where BigInteger Ten = new BigInteger("10"); is deleted` - wouldn't be the cause due to JRE/JVM garbage collection (on top of no delete to begin with). Not using `java.math.BigInteger.TEN/TWO` is weird - for values that fit `long` (and are not predefined), `BigInteger.valueOf(long val)` would be appropriate. Using 10 (or a power thereof) for divmod is questionable. One _can_ have a peek at most `BigInteger` implementation, sporting Toom-Cook on top of Karatsuba more often than not. – greybeard Oct 19 '16 at 08:05
  • @greybeard as I mention I do not code in JAVA so I do not know the behavior. Anyway the whole implementation apart learning purposes has no validity as for bigint `*` is used bigint `/,%` and the `pow` is also questionable as it is limiting the input values. Instead halving of used base `WORD`s count is used in the real implementations. The base is never `10` but either a power of `2` or the biggest power of `10` fitting into **ALU** `WORD` used. This converts the whole stuff to just pointer conversion or mem copy. – Spektre Oct 19 '16 at 08:50
  • I didn't even notice the use of a bit-wise operation where `BigInteger.pow(int power)` would have been appropriate (limits the exponent to int - no deal with bases in the range @Spektre suggests, but one cannot (easily) define `BigInteger.pow(long power)` (outside a JRE implementation). – greybeard Oct 19 '16 at 09:33
  • Refactor `Ten.pow(n.divide(BigInteger.TWO))` (and `Math.pow(10, n/2)`, at that) into BASE. Use `BigInteger.divideAndRemainder()` in spite of its appalling name. – greybeard Oct 19 '16 at 09:53
  • (Note that you have `first.multiply()` produce a product about as big as `i.multiply(j)`.) – greybeard Oct 19 '16 at 13:48
  • You should post each revision of the code along with the edit, otherwise it's confusing as it stands. The edits are supposed to be meaningful updates to the post, not a history of what happened; the latter is captured by the SO site and is available by clicking on the `edit` link below your post. In other words, please do better than making your edits look like `git log`. – Abhijit Sarkar Nov 04 '18 at 20:27

4 Answers4

4

In the first snippet, this line looks wrong to me:

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

so right now you have c = d probably you want:

long d = (long) (j%Math.pow(10,(n/2)));
pkacprzak
  • 5,537
  • 1
  • 17
  • 37
1

you have done some mistake when comparing and assigning bigint,so it is the cause for infinite recursive call.

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

should be rectified as;

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

but there are other issues that you should fix it to produce the same result as the "long" version. hope you will be able to rectify them.

hunter
  • 3,963
  • 1
  • 16
  • 19
  • It wasnt working because I was using == instead of .equals at other places. Thank you! – hsnsd Oct 19 '16 at 09:50
  • (Worse, using `==` _might or might not give the intended behaviour_ using `BigInteger.valueOf(4711)`, at least between different JREs (just as with `String` (`intern()`) and primitive type wrappers).) – greybeard Oct 19 '16 at 13:28
0

Use Ten.pow(x.intValue()) instead of Ten.xor(x)

rustot
  • 331
  • 1
  • 11
-1

This works now

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)));
}

Found the solution here: Karatsuba Java

Now you can compare and see what's going wrong

  • what did you use from @rustot answer? – hunter Oct 19 '16 at 09:03
  • 1
    It compiles but its giving the wrong answer I tried 12*12 and got 111 – hsnsd Oct 19 '16 at 09:05
  • @hunter he changed .xor to .pow from rustot's answer idk if that makes any difference – hsnsd Oct 19 '16 at 09:06
  • i cant see it,he is still using xor – hunter Oct 19 '16 at 09:07
  • @hunter I changed everything to .pow from .xor and now I am getting 1044 for 12*12. Previously i was getting 111 Still not sure where is the error – hsnsd Oct 19 '16 at 09:14
  • 1
    Did you check with numbers above 2000 bits ? otherwise your Karatsuba multiplication is not used ... (since you have an `if` for that there) – Spektre Oct 19 '16 at 12:31
  • 1
    I can see the Karatsuba multiplication code in `karatsuba3()` _not_ getting executed from any call where no number is longer than 2000 bits. I can see `karatsuba3()` _not_ making directly recursive calls to `karatsuba3()`. – greybeard Oct 19 '16 at 12:32
  • This happens to be a copy-paste from somewhere else with no explanation. The only thing it shows is that the author has an internet connection. – Abhijit Sarkar Nov 04 '18 at 20:53