1

用二分查找很容易找到一个整数,即使它可以是任意大的:首先猜测数量级,然后继续划分区间。 该答案描述了如何找到任意有理数。

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

(这不是家庭作业。不过,我可能会做一个,如果结果证明这是一个有趣的答案,而不仅仅是“通过大量特殊情况处理将浮点数值困难打死。”)

编辑:如果我在搜索方面做得更好,我可以找到答案--- 但只有当你已经知道重新解释是int有效的(有某些警告)时才有效。所以留下这个。感谢哈罗德的精彩回答!

4

2 回答 2

4

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 次猜测用完之前很久发生。

于 2017-07-09T05:09:52.947 回答
0

相同的方法可以应用于浮点数。更坏的情况下运行时间是 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);
    }
}
于 2017-07-08T23:23:29.707 回答