0

I am trying to multiply two numbers using karatsuba multiplication. My java code is not working. I have used string as parameters and arguments so that we can multiply two n digit numbers (n is even). Also, I don't want to use long or BigInteger. Please help me to figure out my code mistake.

class karat{

public static String karatsuba(String first, String second){

    if(first.length() <= 1 || second.length() <= 1)
        return String.valueOf(Long.parseLong(first)*Long.parseLong(second));

    String a = karatsuba(first.substring(0, first.length()/2), second.substring(0, second.length()/2));

    String b = karatsuba(first.substring(first.length() - first.length()/2, first.length()), second.substring(second.length() - second.length()/2, second.length()));

    String c = karatsuba(String.valueOf(Long.parseLong(first.substring(0, first.length()/2)) + Long.parseLong(first.substring(first.length() - first.length()/2, first.length()))), String.valueOf(Long.parseLong(second.substring(0, second.length()/2)) + Long.parseLong(second.substring(second.length() - second.length()/2, second.length()))));

    String d = String.valueOf(Long.parseLong(c) - Long.parseLong(b) - Long.parseLong(a));

    return String.valueOf(((int)Math.pow(10, first.length()))*(Long.parseLong(a)) + (((int)Math.pow(10, first.length()/2))*Long.parseLong(d)) + (Long.parseLong(c)));
}

public static void main(String[] args){
        String result = karatsuba("1234", "5678");
        System.out.println(result); }
}

Can you also please refine my code.

Numbers passed for multiplication - 1234 and 5678

Output is - 6655870 (Incorrect)

Output should be - 7006652 (Correct)

Thank you

Sid
  • 29
  • 7
  • Try to write down what multiplying with `Math.pow(10, length/2)` (and `Math.pow(10, 2*(length/2))`) *means*. Do a few examples *by hand* (esp with different/non-power-of-2 lengths). – greybeard Aug 20 '17 at 12:37
  • On paper everything is fine. For example, I passed 22 and 22. Output is 496, it should be 484. I don't know what is wrong. – Sid Aug 20 '17 at 12:41
  • You (needlessly) use `String.valueOf(s.substring())`, repeatedly determine identical parts of the inputs (e.g. `first.substring(0, first.length()/2)`) and don't give those parts names: makes your code hard to grasp and to argue about. Choose a readily accessible presentation of the Karatsuba algorithm for reference and name variables for the parts accordingly. Most come with a (tiny) example; use a debugger to trace the steps of your code. Adapt the code presented here & identify the reference. If you still can't spot "the" bug (there are more), describe exactly where you find yourself stuck. – greybeard Aug 20 '17 at 15:32
  • Your problem is very similar to this: https://stackoverflow.com/questions/28233748/recursive-karatsuba-multiplication-not-working – biziclop Aug 20 '17 at 18:11

2 Answers2

1

First of all I tried look at your code, it gets a programmer to get lost, few things before we go into solution.

General advice. It is not good practice to convert string to value and back and forward like you do, it does not work like this. I tried as well to debug your code, it is just devil circle.

So I would start with check if value length and the maximum one.

Than if one of the values is less than 2 of length mean every thing less than 10 do multiplication otherwise do karatsuba recursion algorithm.

Here is the solution:

public static long karatsuba(long num1, long num2) {

    int m = Math.max(
            String.valueOf(num1).length(),
            String.valueOf(num2).length()
    );

    if (m < 2)
        return num1 * num2;

    m = (m / 2) + (m % 2);

    long b = num1 >> m;
    long a = num1 - (b << m);
    long d = num2 >> m;
    long c = num2 - (d << m);

    long ac = karatsuba(a, c);
    long bd = karatsuba(b, d);
    long abcd = karatsuba(a + b, c + d);

    return ac + (abcd - ac - bd << m) + (bd << 2 * m);
}

Some test;

public static void main(String[] args) {
    System.out.println(karatsuba(1, 9));
    System.out.println(karatsuba(1234, 5678));
    System.out.println(karatsuba(12345, 6789));
}

The output would be

9
7006652
83810205

It is less pain than your Stringish code. Btw, the solution is inspired from the pesudo in wiki and this class.

Maytham Fahmi
  • 31,138
  • 14
  • 118
  • 137
  • Thank you. From next time, I will always take care about writing code that is easy to read for others also. If I will not use strings, how am I going to multiply numbers greater than numbers in long range . I convert string to long and vice versa for calculations on string because I can't multiply two strings stray away. My main aim is to multiply n digit numbers which may be greater than numbers present in long range. – Sid Aug 21 '17 at 01:44
  • It is called Big numbers look at the class I put link to in my answer, it is exactly what you are looking for, if you think the answer was helpful please check as answer – Maytham Fahmi Aug 21 '17 at 05:41
  • Thank you maytham. Isn't there any way I can use strings ? – Sid Aug 21 '17 at 09:59
  • It is posible as you did before, then you need to convert back and forward, and remember you can not use string to force max value of any type, for example integer max value is 2147483647 you can not use string bigger than this number and convert it to int the same is valid for any type, that you need to check which number size specification you want to work with. – Maytham Fahmi Aug 21 '17 at 10:04
0

Interesting algorithm. One mistake is in

return String.valueOf(((int)Math.pow(10, first.length()))*(Long.parseLong(a)) + (((int)Math.pow(10, first.length()/2))*Long.parseLong(d)) + (Long.parseLong(c)));

At the end, it should be Long.parseLong(b) instead of Long.parseLong(c).

And in intermediate calculations, it can happen that the two strings are of different lengths. That also doesn't work correctly.

Please, allow some comments to improve the implementation. The idea to use strings seems to allow for big numbers, but then you introduce things like Long.parseLong() or (int)Math.pow(10, first.length()), limiting you to the long or int range.

If you really want to do big numbers, write your own String-based addition and power-of-ten multiplication (that one being trivial by appending some zeroes).

And, try to avoid names like a, b, c, or d - it's too easy to forget what they mean, as was your original mistake. E.g. the names from Wikipedia are a little bit better (using z0, z1 and z2), but still not perfect...

Ralf Kleberhoff
  • 6,990
  • 1
  • 13
  • 7
  • Thank you for your help. After making the changes as per your suggestions program is working but output is still wrong on 1234*5678. What is wrong ? – Sid Aug 20 '17 at 16:11
  • As I said, "And in intermediate calculations, it can happen that the two strings are of different lengths. That also doesn't work correctly." Follow the flow of your program (either by debugger or by inserting System.out.println() calls), and then you'll see the case where your `karatsuba` method returns the wrong result. Analyze that case carefully step-by-step, and you'll see what's going wrong. One more hint: don't do so much in one line of code - introduce intermediate variables, that makes debugging easier. – Ralf Kleberhoff Aug 20 '17 at 18:57