如何在Java中正确实现二进制搜索算法来猜测随机的BigInteger?
我正在编写一个程序,该程序可以从另一个程序中猜测随机生成的BigInteger。数字类给出了我的猜测是高于还是低于数字的反馈(如果答案正确,则为“正确”)。虽然我的程序运行良好,并且正确地猜测了BigInteger,但我实现的二进制搜索算法的效率低于我的预期。我一直在绞尽脑汁,弄不明白为什么(找到位后)猜测的次数超过了log(n)时间 我一直在计算猜测的次数,我的代码的第一部分(找到大整数的正确位)表现得非常好,通常只需要少量猜测如何在Java中正确实现二进制搜索算法来猜测随机的BigInteger?,java,search,biginteger,Java,Search,Biginteger,我正在编写一个程序,该程序可以从另一个程序中猜测随机生成的BigInteger。数字类给出了我的猜测是高于还是低于数字的反馈(如果答案正确,则为“正确”)。虽然我的程序运行良好,并且正确地猜测了BigInteger,但我实现的二进制搜索算法的效率低于我的预期。我一直在绞尽脑汁,弄不明白为什么(找到位后)猜测的次数超过了log(n)时间 我一直在计算猜测的次数,我的代码的第一部分(找到大整数的正确位)表现得非常好,通常只需要少量猜测 public static BigInteger guesser
public static BigInteger guesser(Number n) {
int guesses=0;
String feedback = n.guess(BigInteger.ONE);
guesses++;
if (feedback.equals("correct")){
return BigInteger.ONE;
} else{
BigInteger two = new BigInteger("2");
BigInteger max = two;
BigInteger min = max;
BigInteger mid;
if(n.guess(max).equals("correct")) {
return max;
}
while (!feedback.equals("lower")) {
min = max;
max = max.pow(2);
feedback=n.guess(max);
guesses++;
}
mid = min.add(max).divide(two);
feedback = n.guess(mid);
guesses++;
while (!feedback.equals("correct")){
if (feedback.equals("higher")){
min=mid.add(BigInteger.ONE);
} else if (feedback.equals("lower")){
max=mid.subtract(BigInteger.ONE);
}
mid= min.add(max).divide(two);
feedback = n.guess(mid);
guesses++;
}
return mid;
}
代码中的二进制搜索算法部分引起了大量猜测,我不知道为什么。对于38119位BigInteger,程序的猜测次数大约是该数字的两倍。我是在做一些根本错误的事情,还是我忽略了一个简单的错误?猜测的次数不应该大约等于2log(n)吗?问题是,指数搜索的次数太多了。当这个数字足够大时,你发现的第一个数字比它需要的要高得多 假设您要猜的数字是
432632894129048128940218410982149128042804215324
,通过应用pow(2)
寻找上限范围,您要找到的第一个数字是1157920892373731619542357098500868790785326998465640564039457584007913129639936
,这要高得多,它需要如此多的尝试才能回到近距离
现在让我们假设您应用了乘法(新的大整数(“25”)
——您遇到的第一个数字是43368086899420177360298112034797668457031250
。是的,需要更多的尝试才能达到这个数字,但最终还是值得的,因为在如此巨大的数字上的最后一次pow(2)
造成了如此巨大的过度杀伤力,以至于很难恢复。我在这里用了一个小数字,但随着数字的增大,情况变得越来越糟
在我看来,你应该在求上限的同时,在应用pow和乘法之间找到平衡。也许如果一个数字足够大,那么停止指数运算,开始乘以某个值,并随着边界的增大使该值变高
我在上面的示例中使用了一个小值,但使用了38119
bit biginger:
-上限17次猜测-所有猜测65552次pow(2)
-上限8209次猜测-所有猜测46327次乘法(新的大整数(“25”))
-上限5738次猜测-所有猜测43854次乘法(新的大整数(“100”)
-上限3826猜测-所有猜测41946乘法(新的大整数(“1000”)
-上限2870次猜测-所有猜测40994次乘法(新的大整数(“10000”)
-上限2443猜测-所有猜测40562乘法(新的大整数(“50000”)
-上限2296次猜测-所有猜测40416乘法(新的大整数(“100000”)
需要更多的猜测才能得出上限,但是我们离最终值更近了,所以它仍然是值得的。请注意,它在某一点上不再有价值。这部分代码是不是在(!feedback.equals(“lower”){min=max;max=max.pow(2);feedback=n.guess(max);guesses++;}`累积额外的猜测?我习惯于看到一个以min=mininnum可能值,max=maximum可能值开头的min/mid/max,然后一直将列表一分为二。你还需要处理可能的负值吗?所以代码中这部分的原因是BigInteger没有上限,所以我以指数方式增加我的猜测,以便找到该值的位数。此部件以O(对数n)时间运行。这是实际的二进制搜索部分,正在累积猜测,我只是不知道我做错了什么。不,没有负值。假设这个大整数大于0.FWIW,
max:=max.pow(2)
可能比max:=max.multiply(max)慢一点代码>。与其乘以一个固定的数字,不如将ftleft()乘以一个固定的位数,例如16或32,性能可能会更好。当然,这个优势可能会被一个缓慢的guess()函数完全丧失+1.FWIW,对于38119位和32位的移位,上界可以在(38119+31)/32=1192个猜测中找到(加上~38119+31个猜测的确切数字)。