很容易找到一个带二分搜索even if it can be arbitrarily large的整数:首先猜测数量级,然后继续划分间隔。 This answer描述了如何找到任意有理数。
设置场景后,我的问题是类似的:我们如何猜测IEEE 754浮点数?假设它不是NaN,但其他一切都是公平的游戏。对于每个猜测,您的程序将被告知相关数字是高,等或更低。最大限度地减少最坏情况下所需的猜测次数。
(这不是一个家庭作业。虽然,我可能会把它作为一个,如果事实证明有一个有趣的答案,不仅仅是“通过大量的特殊案件处理来击败浮动数字难以致死”。 )
编辑:如果我更擅长搜索,我可以找到answer ---但只有当你已经知道重新解释为int
时才会有效(有一些警告)。所以留下这个。感谢哈罗德给出了一个很好的答案!
答案 0 :(得分:4)
IEEE-754 64位浮点数实际上是64位表示。此外,除NaN值外,浮点比较和正值的整数比较之间没有差异。 (也就是说,符号位未设置的两位模式将产生相同的比较结果,无论您将它们比较为int64_t
还是double
,除非其中一个位模式是浮点NaN-。 )
这意味着您可以通过一次猜测一个位来找到64个猜测中的数字,即使该数字是±∞。首先将数字与0进行比较;如果目标是“较少”,则以与下面相同的方式产生猜测,但在猜测之前否定它们。 (由于IEEE-754浮点数是符号/幅度,您可以通过将符号位设置为1来否定数字。或者您可以执行正位模式重新解释,然后浮点否定结果。)
之后,一次猜一位,从最高位值开始。如果数字大于或等于猜测,则将该位设置为1;如果数字较小,则将该位设置为0;并继续下一个位,直到没有更多。要构造猜测,请将位模式重新解释为double
。
有两点需要注意:
您无法通过比较测试来区分±0。这意味着如果你的对手希望你区分它们,他们将不得不向你提供一种询问与-0相等的方法,并且在你明显确定数字为0之后你将不得不使用这种机制。 (这将发生在第64次猜测)。这将增加一个猜测,总共65个。
如果您确信目标不是NaN,则没有其他问题。如果它可能是一个NaN,你需要小心你的比较:如果你总是问“这个X 这个猜测吗?”事情将会很好,因为NaN比较总会返回false 。这意味着在连续11次“否”回答(不计算建立符号的那个)之后,你会发现自己猜测∞,假设如果数不小于∞,它必须相等。但是,在这种情况下单独你也需要明确地测试相等性,因为如果目标是NaN,那也将是假的。这不会给计数增加额外的猜测,因为它总会在64次猜测用完之前很久就会发生。
答案 1 :(得分: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);
}
}