如何在Java中正确实现二进制搜索算法来猜测随机的BigInteger?

如何在Java中正确实现二进制搜索算法来猜测随机的BigInteger?,java,search,biginteger,Java,Search,Biginteger,我正在编写一个程序,该程序可以从另一个程序中猜测随机生成的BigInteger。数字类给出了我的猜测是高于还是低于数字的反馈(如果答案正确,则为“正确”)。虽然我的程序运行良好,并且正确地猜测了BigInteger,但我实现的二进制搜索算法的效率低于我的预期。我一直在绞尽脑汁,弄不明白为什么(找到位后)猜测的次数超过了log(n)时间 我一直在计算猜测的次数,我的代码的第一部分(找到大整数的正确位)表现得非常好,通常只需要少量猜测 public static BigInteger guesser

我正在编写一个程序,该程序可以从另一个程序中猜测随机生成的BigInteger。数字类给出了我的猜测是高于还是低于数字的反馈(如果答案正确,则为“正确”)。虽然我的程序运行良好,并且正确地猜测了BigInteger,但我实现的二进制搜索算法的效率低于我的预期。我一直在绞尽脑汁,弄不明白为什么(找到位后)猜测的次数超过了log(n)时间

我一直在计算猜测的次数,我的代码的第一部分(找到大整数的正确位)表现得非常好,通常只需要少量猜测

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:

  • pow(2)
    -上限17次猜测-所有猜测65552次
  • 乘法(新的大整数(“25”))
    -上限8209次猜测-所有猜测46327次
  • 乘法(新的大整数(“100”)
    -上限5738次猜测-所有猜测43854次
  • 乘法(新的大整数(“1000”)
    -上限3826猜测-所有猜测41946
  • 乘法(新的大整数(“10000”)
    -上限2870次猜测-所有猜测40994次
  • 乘法(新的大整数(“50000”)
    -上限2443猜测-所有猜测40562
  • 乘法(新的大整数(“100000”)
    -上限2296次猜测-所有猜测40416

需要更多的猜测才能得出上限,但是我们离最终值更近了,所以它仍然是值得的。请注意,它在某一点上不再有价值。

这部分代码是不是在(!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个猜测的确切数字)。