问题描述
背景
所以我用C#做了一个不公平的绞刑的简单游戏(有一个单词列表,这些单词是基于我给玩家的信息(例如,单词长度),这些单词是有效的解决方案,随着时间的推移逐渐缩小,只有当只有一个可能的解决方案并且他们猜到了所有字母时,玩家才会赢)。
无论如何,重要的是要知道我有一行代码,如下所示:
availableWords.RemoveAll(word => AmountInCommon(word) != lowestInCommon);
(我从AvailableWord中删除与用户猜测的字母相同的字母多于AvailableWords中共有字母最少的单词的所有单词)
问题是,此代码仅在关闭编译器优化时才起作用。
演示问题的代码
class Program {
static void Main() {
float randomPowerOf2 = (float)Math.Pow(2, new Random().Next(-4, 5));
float foo1 = Foo(3f); // some non power of 2
float foo2 = Foo(randomPowerOf2);
float baz = Baz();
// prints false with compiler optimizations; true without compiler optimizations
Console.WriteLine(Math.Round(Foo(3f), 2) == Math.Round(foo1, 2));
// prints true with and without compiler optimizations
Console.WriteLine(Math.Round(Foo(3f), 2) == Math.Round(foo1, 2));
// prints true with and without compiler optimizations
Console.WriteLine(Foo(randomPowerOf2) == foo2);
// prints true with and without compiler optimizations
Console.WriteLine(Baz() == baz);
Console.ReadLine();
}
static float Foo(float divisor) {
return 1 / divisor;
}
static float Baz() {
return 1 / 3f;
}
}
我认为这与浮点数的工作方式有关,但让我困惑的是,为什么打开和关闭编译器优化会影响它。我猜我应该做的就是将浮点数舍入到精度的3位小数,因为这就是我真正需要的。为什么会发生这种情况?我的解决方案是最佳实践吗?
编辑:
我意识到,在这种情况下,由于单词长度不变,我可以让AmountInCommon
返回表示共有多少个字母的整数,而不是表示共有字母与单词长度之比的浮点数。不过,您的回答仍然很有帮助。
推荐答案
短篇小说
请勿比较浮点值是否相等。
程序员在说完这句话后通常做的第一件事是推荐使用Epsilon。然而,这是错误的。float.Epsilon
是大于零的最小浮点数,但是(更重要的是)它并不意味着它是任意两个浮点数之间的最小差。比较浮点数时,更好的做法是选择一个合理的值来确定两个浮点数是否足够接近以相等。
代码的问题是您先对数字进行舍入,这可能包括以某种方式舍入舍入的显著差异。
说来话长
来自ECMA规格
9.3.7浮点类型
C#支持两种浮点类型:FLOAT和DOUBLE。浮点数和 双精度类型使用32位单精度和 64位双精度IEC 60559格式......
浮点运算的执行精度可能高于 操作的结果类型。[示例:一些硬件 体系结构支持"扩展"或"长双精度"浮点 类型比Double类型具有更大的范围和精度,并且 隐式执行所有浮点运算。 精度类型。...
进一步
IEC 60559标准没有为扩展浮点格式的参数指定确切值。它只指定最小值。Intel处理器从8087开始使用的扩展格式是80位长,指数为15位,有效数为64位。与其他格式不同,扩展格式确实为有效位的前导位留出了空间,从而实现了某些处理器优化等功能。示例
编译器
现在出现在编译器中。在CPU上执行代码之前,编译器和抖动将尝试在不同的点对代码进行优化,具体取决于它的优化设置(以及其他内容)。
这些优化将影响存储在内存中的内容、如何以及在寄存器和重组中设置了什么,以及许多其他可能或可能不会发生的微妙指令(取决于一系列因素)。这些优化中的每一个都有可能不确定地更改浮点计算的结果。这正是你的问题所在。摘要中
对于浮点算术,千万不要依赖浮点相等。此外,不要尝试和确定地依赖编译器、抖动、CPU、体系结构、平台、版本或应用程序的位的结果。
(对您)比较预期范围内的浮点类型。
这篇关于JIT优化浮点问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!