我看见奇怪的东西储存双在字典,而且我困惑为什么。

这里的代码:

            Dictionary<string, double> a = new Dictionary<string, double>();
            a.Add("a", 1e-3);

            if (1.0 < a["a"] * 1e3)
                Console.WriteLine("Wrong");

            if (1.0 < 1e-3 * 1e3)
                Console.WriteLine("Wrong");

第二,如果声明的工作;1.0是不小于1.0.现在,第一,如果声明的计算结果为正确的。非常奇怪的是,当我悬停在如果智能感知告诉我假,但愉快地代码移至控制台。有.

这是为C#3.5在Visual Studio2008年。

这是一个浮点的准确度的问题?那为什么第二,如果声明的工作?我觉得我失去了一些东西非常重要的在这里。

任何见解表示赞赏。

Edit2 (重新设计问题一点):

我可以接受的精确的数学问题,但是我现在的问题是:为什么悬停在评估是否正确?这也是真实的中间窗口。我粘贴从第一,如果声明的中间窗口,它计算错误的。

更新

首先,非常感谢所有伟大的答案。

我也有问题,重建这另一个项目,在同一台机器上。看在项目设置,我看不出有任何差异。看IL项目之间,我看不出有任何差异。看拆卸,我看到没有明显的差异(除了存储地址)。然而,当我"调试"原始项目中,我看到:screenshot of problem

立即窗口告诉我如果是虚假的,但该代码落入条件。

无论如何,最好的答案,我认为,准备浮点运算在这些情况。原因我不能让这一切更多的是调试器的计算不同的运行时间。所以非常感谢布莱恩*吉迪恩和stephentyrone对于一些非常有见地的评论。

有帮助吗?

解决方案

这是浮动精度问题。

第二个语句有效,因为编译器在发出.exe之前计算表达式1e-3 * 1e3。

在ILDasm / Reflector中查找,它会发出类似

的内容
 if (1.0 < 1.0)
                Console.WriteLine("Wrong");

其他提示

这里的问题是相当微妙的。C#编译器不(总是)发射代码不计算在双人,甚至当这种类型,你已经指定。特别是,它发出的代码不计算在"扩展"精度使用x87说明,而不舍的中间结果增加一倍。

这取决于是否1e-3进行评估作为一种双重或长期的双重,以及是否将乘积计算在双重或长期的双重,有可能获得任何的以下三个结果:

  • (只要双)1e-3*1e3计算在长双为1.0-epsilon
  • (double)1e-3*1e3计算在双是正1.0
  • (double)1e-3*1e3计算在长双为1.0+epsilon

显然,第比较,一个不符合你的期望是正在进行评估的方式描述的三种方案中,我列出。1e-3是被四舍五入到双重或者是因为你储存和装载它再次,其部队的四舍五入,或者因为C#认识到1e-3,为双精确的文字和治疗这种方式。乘法是正在评估在长期双因为 C#有一个脑死亡数字模型 就是这样编译器产生的代码。

乘法在第二个比较是无论正在进行评估使用一种其他两个方法,(你可以找出哪些试图通过"1>1e-3*1e3"),或者编译器是四舍五入的结果乘之前,比较它与1.0时,它评估表在编制时间。

很可能你可以告诉编译器,不使用扩展的精确度没有你告诉它通过一些建立定;启用代码,以SSE2也可以工作。

查看答案此处

嗯...奇怪。我无法重现您的问题。我也在使用C#3.5和Visual Studio 2008。我在您的示例中输入完全,因为它已发布,我没有看到 Console.WriteLine 语句执行。

此外,第二个if语句正在由编译器进行优化。当我在ILDASM / Reflector中检查调试和发布版本时,我没有看到它的证据。这是因为我得到一个编译器警告,说它上面检测到无法访问的代码。

最后,我不知道这可能是一个浮点精度问题。为什么C#编译器会在运行时以静态方式评估两个双精度值?如果确实如此,那么可以说C#编译器存在错误。

编辑:在更多地考虑之后,我更加确信这是浮点精度问题。您必须偶然发现编译器或调试器中的错误,或者您发布的代码并不完全代表您正在运行的实际代码。我对编译器中的错误持高度怀疑态度,但调试器中的错误似乎更有可能。尝试重建项目并再次运行它。也许与exe一起编译的调试信息也不同步。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top