我正在进行karatsuba实施,但我有这个错误:
java.lang.NumberFormatException: Zero length BigInteger
at java.math.BigInteger.<init>(BigInteger.java:296)
at java.math.BigInteger.<init>(BigInteger.java:476)
at com.Karatsuba.resolve(Karatsuba.java:20)
at com.Karatsuba.resolve(Karatsuba.java:26)
at com.KaratsubaTest.karatsubaShouldMultiply(KaratsubaTest.java:22)
这是我的方法:
BigInteger resolve(BigInteger left, BigInteger right) {
String leftS = left.toString();
String rightS = right.toString();
int digits = Math.max(leftS.length(), rightS.length());
digits = (digits / 2) + (digits % 2);
if (left.compareTo(new BigInteger("10", 10)) == -1 || right.compareTo(new BigInteger("10", 10)) == -1) {
return left.multiply(right);
}
BigInteger firstLeft = new BigInteger(leftS.substring(0, digits));
BigInteger secondLeft = new BigInteger(leftS.substring(firstLeft.toString().length(), leftS.length()));
BigInteger firstRight = new BigInteger(rightS.substring(0, digits));
BigInteger secondRight = new BigInteger(rightS.substring(firstRight.toString().length(), rightS.length()));
BigInteger z2 = resolve(firstLeft, firstRight);
BigInteger z0 = resolve(secondLeft, secondRight);
BigInteger z1 = resolve(firstLeft.add(secondLeft), firstRight.add(secondRight)).subtract(z2).subtract(z0);
return z2.multiply(BigInteger.valueOf((long) Math.pow(10, 2 * digits)))
.add(z1.multiply(BigInteger.valueOf((long) Math.pow(10, digits))))
.add(z0);
}
我认为这是因为我使用不同长度的参数,例如123和456789.有什么想法吗?
答案 0 :(得分:0)
NumberFormatException
引发了new BigInteger("")
,例如left = 10
和right = 100
,从那时起你会得到这样的结果:
digits = 2
firstLeft = new BigInteger("10".substring(0,2)) = new BigInteger("10")
secondLeft = new BigInteger("10".substring(2,2)) = new BigInteger("")
这很容易通过检查字符串是否为空来纠正,如果是,则将数字设置为零,例如像这样
BigInteger a = fromString(leftS.substring(0, digits));
BigInteger b = fromString(leftS.substring(a.toString().length(),digits));
BigInteger c = fromString(rightS.substring(0, digits));
BigInteger d = fromString(rightS.substring(c.toString().length(), rightS.length()));
...
private BigInteger fromString(String str) {
if (str.length() == 0)
return BigInteger.ZERO;
else
return new BigInteger(str);
}
我尝试运行算法,虽然它运行但是(算法实现)本身仍然存在问题。例如,100 * 100报告为1000000.我认为这与分裂的发生方式有关,但我无法完全修复它。以下是一些反思:
如果你在m = 3时分裂ab = 12345,那么在代码中它会得到a = 123和b = 45。但如果您正在阅读维基百科文章(我做过),那么您需要
ab = a*10^m+b
而你有ab = a*10^(ab.length-m)+b
前者可以通过更改代码来轻松完成:
int l = leftS.length();
int r = rightS.length();
int m0 = Math.max(l, r);
int r0 = m0%2;
int m = (m0 / 2) + r0;
...
BigInteger a = fromString(leftS.substring(0, m-r0));
BigInteger b = fromString(leftS.substring(a.toString().length(),l));
BigInteger c = fromString(rightS.substring(0, m-r0));
BigInteger d = fromString(rightS.substring(c.toString().length(), r));
现在100 * 100 = 10000,但是当位数不同时仍然存在问题。我找不到什么是错的,可能必须真正经历算法的每一步(而不是仅仅复制维基百科伪代码)才能找到错误。希望这仍然有一些帮助!
顺便说一下,我认为算法可能会更好地使用base 2,因为那时你可以为乘法做位移。分裂也可能更容易(也更快)。此外,递归应该可以更快地停止,因为算法仅对非常大的数字有效。这些当然是优化,但我认为它们值得一提。