了解CLR浮点优化

时间:2019-03-28 13:15:40

标签: c# .net floating-point clr

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一样。

我意识到可以用简单的“是”或“否”来回答这个问题,但任何其他见解也将不胜感激。

值得注意的是,如果我们将Doublef1f2的全部更改为一个类的字段,则Debug和Release模式的结果会一致,这将支持上述解释。 / p>

0 个答案:

没有答案