Jog*_*rge 61 c# floating-point
如果我们在控制台应用程序上执行以下C#代码,我们将收到一条消息The sums are Not equal
.
如果我们在取消注释该行后执行它System.Console.WriteLine()
,我们将收到一条消息The sums are equal
.
static void Main(string[] args)
{
float f = Sum(0.1f, 0.2f);
float g = Sum(0.1f, 0.2f);
//System.Console.WriteLine("f = " + f + " and g = " + g);
if (f == g)
{
System.Console.WriteLine("The sums are equal");
}
else
{
System.Console.WriteLine("The sums are Not equal");
}
}
static float Sum(float a, float b)
{
System.Console.WriteLine(a + b);
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
这种行为的实际原因是什么?
Mis*_*hax 46
它与范围无关.它是堆栈动态和浮点处理的组合.编译器的一些知识将有助于使这种违反直觉的行为变得清晰.
当Console.WriteLine
评论时,值f
和值g
在评估堆栈上并保持在那里,直到您在Main方法中通过相等测试.
当Console.Writeline
没有被注释掉,价值观f
以及g
在调用的瞬间从计算堆栈调用堆栈移动,恢复到计算堆栈时Console.WriteLine
返回.然后你的比较if (f == g)
就完成了.在将值存储到调用堆栈期间可能发生一些舍入,并且一些信息可能丢失.
在你调用的场景Console.WriteLine
中,f
并g
在对比测试是不一样的价值观.它们已被复制并恢复为虚拟机具有不同精度和舍入规则的格式.
在您的特定代码中,当Console.WriteLine
注释的调用时,评估堆栈永远不会存储到调用堆栈中,也不会发生舍入.因为允许平台的实现在评估堆栈上提供改进的精度,所以可能出现这种差异.
编辑 CLI规范允许我们在这种情况下遇到的问题.在第I.12.1.3节中,它的内容如下:
浮点数(静态,数组元素和类的字段)的存储位置具有固定大小.支持的存储大小为float32和float64.其他地方(在评估堆栈上,作为参数,作为返回类型和作为局部变量)浮点数使用内部浮点类型表示.在每个这样的实例中,变量或表达式的标称类型是float32或float64,但其值可以在内部用额外的范围和/或精度表示.内部浮点表示的大小取决于实现,可以变化,并且其精度至少与表示的变量或表达式的精度一样大.
此引用中的关键字是"依赖于实现"和"可以变化".在OP的案例中,我们看到他的实施确实有所不同.
Java平台中的非严格浮点运算也存在相关问题,对于更多信息检查,我对JVM上的Will浮点运算的回答在所有平台上都给出了相同的结果吗?
Jon*_*eet 24
这种行为的实际原因是什么?
我无法详细说明这个特定情况下究竟发生了什么,但我理解一般问题,以及为什么使用Console.WriteLine
可以改变一些事情.
正如我们在上一篇文章中看到的,有时候操作是以浮点类型执行的,其精度高于变量类型中指定的精度.对于局部变量,可以包括在执行方法期间值如何存储在内存中.
我怀疑你的情况:
Sum
方法正在内联(但稍后会看到)f
说)被存储在一个高精度寄存器
g
)的值作为32位值存储在堆栈中
当您取消注释该Console.WriteLine
语句时,我猜测(无论出于何种原因)强制将两个变量存储在它们的"正确"32位精度中,因此它们都以相同的方式处理.
这个假设在某种程度上被加入的事实搞砸了
[MethodImpl(MethodImplOptions.NoInlining)]
Run Code Online (Sandbox Code Playgroud)
......就我所见,并没有改变结果.我可能会在这些方面做错其他的事情.
真的,我们应该看看正在执行的汇编代码 - 遗憾的是,我现在没有时间这么做.
Bas*_*Bas 14
(不是一个真正的答案,但希望一些支持文档)
配置:Core i7,Windows 8.1,Visual Studio 2013
平台x86:
Version Optimized Code? Debugger Enabled? Outcome
4.5.1 Yes No Not equal
4.5.1 Yes Yes Equal
4.5.1 No No Equal
4.5.1 No Yes Equal
2.0 Yes No Not Equal
2.0 Yes Yes Equal
2.0 No No Equal
2.0 No Yes Equal
Run Code Online (Sandbox Code Playgroud)
平台x64:
Version Optimized Code? Debugger Enabled? Outcome
4.5.1 Yes No Equal
4.5.1 Yes Yes Equal
4.5.1 No No Equal
4.5.1 No Yes Equal
2.0 Yes No Equal
2.0 Yes Yes Equal
2.0 No No Equal
2.0 No Yes Equal
Run Code Online (Sandbox Code Playgroud)
只有x86配置上的优化代码才会出现这种情况.
归档时间: |
|
查看次数: |
2517 次 |
最近记录: |