I'm working on an implementation of the Karatsuba algorithm of multiplying numbers, but unlike most implementations using Strings as the primary data structure instead of BigNumbers or longs. I've written a recursive solution to the problem that appears to work for all n < 6, but for some reason it fails to work for odd ns greater than 6, despite all of the base cases working. Here's the karatsuba part of the program, with a few prints left behind from debugging. All of the methods used in this should work as intended, I tested them thoroughly. For a value factor1 = "180" and factor2 = "109", the correct result is outputted. For a value factor1 = "1111" and factor2 = "1111" the correct result is outputted. For a factor1 = "2348711" and factor2 = "8579294" the program outputs "20358060808034" when it should output "20150282190034". I've tried backtracing the logic, and I can't find where exactly it goes wrong. If anyone has any insight as to where something may not work, any help is appreciated.
public static String multiply(String factor1, String factor2) {
// base case of length = 1
System.out.println("Factor1 " + factor1 + " factor2 " + factor2);
if (factor1.length() == 1 && factor2.length() == 1) {
return smallNumberMultiplication(factor1, factor2);
} else if (factor1.length() == 1 && factor2.length() == 2) { //these conditions needed for odd-size #s
return smallNumberMultiplication(factor1, factor2); // max iteration = 10
} else if (factor1.length() == 2 && factor2.length() == 1) {
return smallNumberMultiplication(factor2, factor1); // max iteration = 10
}
// check which factor is smaller, find the index at which the value is split
int numberLength = factor1.length();
int middleIndex = numberLength / 2;
// Find the power to which 10 is raised such that it follows Karatsuba's algorithm for ac
int powerValue = numberLength + numberLength % 2;
// divide both numbers into two parts bounded by middleIndex place
String[] tempSplitString = splitString(factor1, middleIndex);
String f1Large = tempSplitString[0], f1Small = tempSplitString[1];
tempSplitString = splitString(factor2, middleIndex);
String f2Large = tempSplitString[0], f2Small = tempSplitString[1];
String multiplyHighestNumbers, multiplySmallestNumbers, multiplyMiddleNumbers;
// large factor1 * large factor2
multiplyHighestNumbers = multiply(f1Large, f2Large);
// Multiply (f1Large + f1Small)*(f2Large + f2Small)
multiplyMiddleNumbers = multiply(addTwoValues(f1Large, f1Small), addTwoValues(f2Large, f2Small));
// small factor1 * small factor2
multiplySmallestNumbers = multiply(f1Small, f2Small);
// add trailing zeros to values (multiply by 10^powerValue)
String finalHighestNumber = addTrailingZeros(multiplyHighestNumbers, powerValue);
String finalMiddleNumber = addTrailingZeros(
subtractTwoValues(subtractTwoValues(multiplyMiddleNumbers, multiplyHighestNumbers),
multiplySmallestNumbers),
powerValue / 2);
String finalSmallestNumber = multiplySmallestNumbers;
// add each part together
return removeLeadingZeros(addTwoValues(addTwoValues(finalHighestNumber, finalMiddleNumber), finalSmallestNumber));
}
I noticed two problems:
middleIndex
) and shifting (powerValue
) (needlessly implemented by tacking on zeroes).productHighParts
("multiplyHighestNumbers
") to be closer in length to the other products, use (factor1.length() + factor2.length()) / 4
(half the average length of both factors).splitString()
, not the leading part.(Note that the first two controlled statements can be combined:
if (factor1.length() <= 1 && factor2.length() <= 2)
.)