繁体   English   中英

二进制搜索/二等分浮点数

[英]Binary search / bisection for floating point numbers

即使二进制数可以任意大 ,也很容易通过二进制搜索找到 :首先猜测数量级,然后继续划分区间。 该答案描述了如何找到任意有理数。

设置好场景后,我的问题是类似的:我们如何猜测IEEE 754浮点数? 假设它不是NaN,但其他一切都是公平的游戏。 对于每个猜测,系统都会告知您的程序所讨论的数字是更高,等于还是更低。 最小化最坏情况下所需的猜测次数。

(这不是一项家庭作业。但是,如果可以得出一个有趣的答案,那不只是“用大量特殊情况处理来克服浮点数的数字死亡的危险”,我可能会做一个。)

编辑:如果我比较擅长搜索,我可能会找到答案 ---但只有在您已经知道将重新解释为int有效的情况下(某些警告),该方法才有效。 因此,离开这个。 感谢Harold的出色回答!

IEEE-754 64位浮点数实际上是64位表示形式。 此外,除了NaN值外,浮点比较与正值的整数比较之间没有区别。 (也就是说,无论将符号位设置为int64_t还是double ,两个未设置符号位的位模式都会产生相同的比较结果,除非其中一个位模式是浮点NaN-。)

这意味着即使数字为±∞,也可以一次猜测一位,从而在64个猜测中找到一个数字。 首先将数字与0进行比较; 如果目标是“较少”,则以与下面相同的方式产生猜测,但是在猜测之前将其取反。 (由于IEEE-754浮点数是符号/幅度,因此可以通过将符号位设置为1来取反数字。或者可以执行正位模式重新解释,然后浮点取反结果。)

之后,从最高位开始,一次猜测一位。 如果数字大于或等于猜测值,则将该位置1。 如果数量较少,则将该位置0; 并继续进行下一点,直到没有更多为止。 要构造猜测,请将位模式重新解释为double

有两个警告:

  1. 您无法通过比较测试来区分±0。 这意味着,如果您的对手希望您区分他们,他们将不得不向您提供一种询问是否等于-0的方式,并且在您明确确定数字为0之后,您将必须使用该机制。 (将在第64个猜测上发生)。 这将增加一个猜测,总共65个。

  2. 如果您确定目标不是NaN,则没有其他问题。 如果它可能是NaN,则需要谨慎进行比较:如果您总是问“ X是否于此猜测?”, 那么一切都会顺利进行,因为NaN比较将始终返回false。 这意味着,在连续11个“否”答案(不计算建立符号的答案)之后,您会发现自己猜测∞,并假设如果该数量不少于∞,则它必须相等。 但是, 仅在这种情况下,您还需要明确测试是否相等,因为如果目标是NaN,那也将是错误的。 这不会增加计数的额外猜测,因为它总是会在64个猜测用完之前很久发生。

可以将相同的方法应用于浮点数。 更糟糕的情况是运行时间为O(log n)。

public class GuessComparer
{
    private float random;
    public GuessComparer() // generate a random float and keep it private
    {
        Random rnd = new Random();
        var buffer = new byte[4];
        rnd.NextBytes(buffer);
        random = BitConverter.ToSingle(buffer, 0);
    }
    public int CheckGuess(float quess) // answer whether number is high, lower or the same.
    {
        return random.CompareTo(quess);
    }
}
public class FloatFinder
{

    public static int Find(GuessComparer checker)
    {
        float guess = 0;
        int result = checker.CheckGuess(guess);
        int guesscount = 1;
        var high = float.MaxValue;
        var low = float.MinValue;
        while (result != 0)
        {
            if (result > 0) //random is higher than guess
                low = guess;
            else// random is lower than guess

                high = guess;

            guess = (high + low) / 2;
            guesscount++;
            result = checker.CheckGuess(guess);
        }
        Console.WriteLine("Found answer in {0}", guesscount);
        return guesscount;
    }

    public static void Find()
    {
        var checker = new GuessComparer();
        int guesses = Find(checker);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM