C#如何在悬停和即时窗口与编译窗口中计算浮点?
我发现在字典里储存双倍数字有些奇怪,我不明白为什么 代码如下:C#如何在悬停和即时窗口与编译窗口中计算浮点?,c#,math,floating-point,C#,Math,Floating Point,我发现在字典里储存双倍数字有些奇怪,我不明白为什么 代码如下: Dictionary<string, double> a = new Dictionary<string, double>(); a.Add("a", 1e-3); if (1.0 < a["a"] * 1e3) Console.WriteLine("Wrong"); if
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");
字典a=新字典();
a、 添加(“a”,1e-3);
如果(1.0
第二个if语句按预期工作;1.0不小于1.0。现在,第一个if语句的计算结果为true。非常奇怪的是,当我将鼠标悬停在if上时,intellisense告诉我false,但代码却很高兴地移动到Console.WriteLine
这是针对VisualStudio2008中的C#3.5
这是浮点精度问题吗?那么为什么第二个if语句有效呢?我觉得我在这里遗漏了一些非常基本的东西
任何见解都值得赞赏
Edit2(稍微改变一下问题的目的):
我可以接受数学精度的问题,但我现在的问题是:为什么悬停在正确的评估?即时窗口也是如此。我将第一个if语句中的代码粘贴到即时窗口中,它的计算结果为false
更新
首先,非常感谢所有伟大的答案
我在同一台机器上的另一个项目中重新创建它时也遇到问题。看看项目设置,我看不出有什么不同。看看项目之间的IL,我看不出有什么不同。查看反汇编,我没有看到明显的差异(除了内存地址)。然而,当我调试原始项目时,我看到:
immediate窗口告诉我if为false,但代码属于条件类型
无论如何,我认为最好的答案是在这种情况下为浮点运算做准备。我不能放弃这一点的原因更多地与调试器的计算不同于运行时有关。因此,非常感谢Brian Gideon和stephentyrone的一些非常有见解的评论。这是浮点精度问题 第二条语句之所以有效,是因为编译器在发出.exe之前对表达式1e-3*1e3进行计数 在ILDasm/反射器中查找,它会发出类似
if (1.0 < 1.0)
Console.WriteLine("Wrong");
if(1.0<1.0)
控制台。写入线(“错误”);
查看答案嗯……奇怪。我无法重现你的问题。我也在使用C#3.5和VisualStudio2008。我输入的示例与发布的示例完全相同,我没有看到执行Console.WriteLine
语句
另外,编译器正在优化第二个if语句。当我检查ILDASM/Reflector中的调试版本和发布版本时,我没有看到任何证据。这是因为我收到一条编译器警告,说在上面检测到了无法访问的代码
最后,我不明白这怎么会是一个浮点精度问题。为什么C#编译器静态计算两个double的方式与CLR在运行时的方式不同?如果真的是这样的话,那么我们可以说C#编译器有一个bug
编辑:在仔细考虑之后,我更加确信这不是一个浮点精度问题。您一定是在编译器或调试器中偶然发现了错误,或者您发布的代码并不完全代表您正在运行的实际代码。我对编译器中的错误表示高度怀疑,但调试器中的错误似乎更有可能出现。尝试重新生成项目并再次运行它。可能是与exe一起编译的调试信息不同步或其他什么。这里的问题相当微妙。C#编译器不会(总是)发出以双精度进行计算的代码,即使这是您指定的类型。特别是,它发出的代码使用x87指令以“扩展”精度进行计算,而不会将中间结果四舍五入到两倍 根据1e-3是按双精度还是长双精度计算,以及乘法是按双精度还是长双精度计算,可以得到以下三个结果中的任意一个:
- (长双精度)在长双精度中计算的1e-3*1e3为1.0-ε
- (双精度)双精度计算的1e-3*1e3正好是1.0
- (双精度)长双精度计算的1e-3*1e3为1.0+ε
在没有通过某些构建设置告诉编译器不要使用扩展精度的情况下,您可能会告诉编译器不要使用扩展精度;将codegen启用到SSE2也可能起作用。1e3是浮点常量还是双常量?如果你能接受数学精度问题,为什么还要问?问题是1e-3无法准确表示,因此1e3*1e-3不是1.0,它很接近,但不完全,这意味着它失败。“1e3”被编译为双精度,因为我在IL输出中看到ldc.r8指令。@Lasse:我接受在运行时发生这种情况的原因;我想知道为什么我的调试器(鼠标悬停在