在this question中,讨论的是在处理浮点运算时Debug模式和Release模式之间的可能差异。特别是在this answer中,我们看到了一个看似无辜的操作,
Single f1 = 0.00000000002f;
Single f2 = 1 / f1;
Double d = f2;
Console.WriteLine(d);
可能在x86调试和发布模式(分别打印49999998976和50000000199,7901)中产生不同的结果。从组件的角度来看,发生这种情况是因为存储-然后-加载对
fstp dword ptr [ebp-44h]
fld dword ptr [ebp-44h]
在Release模式下进行了优化,在Debug模式下,从80位x87寄存器中获取值,将其移至dword并再次返回,足以降低精度。
现在,我想知道的是,这是否实际上符合规范。 C# specification声明
与操作的结果类型相比,可以更高的精度执行浮点运算。例如,某些硬件体系结构支持比双精度类型具有更大范围和精度的“扩展”或“长双精度”浮点类型,并使用此更高精度类型隐式执行所有浮点运算。只有付出过高的性能代价,才能使此类硬件体系结构以较低的精度执行浮点运算,而不是要求实现同时牺牲性能和精度,而C#允许将高精度类型用于所有浮点运算。
但是,据我所读,这仅适用于单个操作,由于在我们的情况下,我们非常清楚除法结果应如何存储在Single
中,然后才转换为{{ 1}},仅鉴于此规范,我希望得到的Double
始终可以表示为单精度浮点。另一方面,正如the accepted answer中对另一个问题的详细说明,runtime specification继续指出
浮点数(静态,数组元素和类的字段)的存储位置大小固定。支持的存储大小为float32和float64。使用内部浮点类型表示浮点数(在评估堆栈上,作为参数,返回类型和局部变量)的其他任何地方。在每个这样的实例中,变量或表达式的标称类型为float32或float64,但其值可以在内部以附加范围和/或精度表示。内部浮点表示的大小取决于实现,可以变化,并且精度至少应与所表示的变量或表达式的精度一样。
所以我的问题是我是否正在正确阅读和理解这一点:
是否由于在调试和发布模式之间存在上述差异,因为我们正在处理局部变量,因此Double
实际上应始终读为“ Single
或更精确”?尤其是,如果我们在整个过程中仅使用Single
,我们将得到不同的结果,那么允许编译器进行优化,就好像所有本地变量都是double一样。
我意识到可以用简单的“是”或“否”来回答这个问题,但任何其他见解也将不胜感激。
值得注意的是,如果我们将Double
,f1
和f2
的全部更改为一个类的字段,则Debug和Release模式的结果会一致,这将支持上述解释。 / p>