浮点运算是否稳定?

Ste*_*eve 37 c# floating-point

我知道浮点数具有精度,精度后的数字不可靠.

但是如果用于计算数字的等式是相同的呢?我可以假设结果也一样吗?

例如,我们有两个浮点数xy.我们可以假设x/y机器1的结果与机器2的结果完全相同吗?IE ==比较将返回true

Jon*_*eet 46

但是如果用于计算数字的等式是相同的呢?我可以假设结果也一样吗?

不,不一定.

特别是,在某些情况下,允许JIT使用更准确的中间表示 - 例如,当您的原始数据是64位时为80位 - 而在其他情况下则不会.当满足以下任何条件时,这可能会导致看到不同的结果:

  • 您的代码略有不同,例如使用局部变量而不是字段,这可以改变值是否存储在寄存器中.(这是一个相对明显的例子;还有其他更微妙的例子可以影响事物,比如方法中存在一个try块......)
  • 您正在不同的处理器上执行(我曾经观察过AMD和Intel之间的差异;同一制造商的不同CPU之间也可能存在差异)
  • 您正在使用不同的优化级别执行(例如,在调试器下或不在调试器下)

从C#5规范部分4.1.6:

可以以比操作的结果类型更高的精度执行浮点运算.例如,某些硬件体系结构支持"扩展"或"长双"浮点类型,其范围和精度比double类型更大,并使用此更高精度类型隐式执行所有浮点运算.只有在性能成本过高的情况下,才能使这种硬件架构以较低的精度执行浮点运算,而不是要求实现放弃性能和精度,C#允许更高精度的类型用于所有浮点运算.除了提供更精确的结果外,这几乎没有任何可衡量的影响.但是,在表单的表达式中x * y / z,乘法产生的结果超出双范围,但随后的除法将临时结果带回双范围,表达式以更高范围格式计算的事实可能导致产生有限结果而不是无穷大.

  • "不,不是必然的"你太善良了.我打开了"没有!" =) (4认同)
  • 我将补充说,根据经验,处理器的差异不仅与制造商有关.intel核心2计算的值不同于I5/i7,xeon E5 v3和E7 v3也不同. (3认同)

Eri*_*ert 20

乔恩的回答当然是正确的.然而,没有一个答案说过如何确保浮点运算以规范保证的精度完成,而不是更多.

在以下情况下,C#会自动将任何浮点数截断回其规范的32位或64位表示:

  • 你输入了一个冗余的显式转换:x + y可能有x和y作为更高精度的数字然后被添加.但是(double)((double)x+(double)y)确保在数学发生之前和之后所有内容都被截断为64位精度.
  • 对类,静态字段,数组元素或解除引用指针的实例字段任何存储始终都会截断.(本地商店,参数和临时商店的商店不能保证截断;它们可以被注册.结构的字段可能位于短期池中,也可以注册.)

这些保证不是由语言规范做出的,但实现应该遵守这些规则.C#和CLR的Microsoft实现.

编写代码以确保浮点运算在C#中是可预测的但是可以完成是一件痛苦的事.请注意,这样做可能会减慢算术速度.

关于这种可怕情况的投诉应该针对英特尔,而不是微软; 他们是设计芯片的人,这使得可预测的算法变得更慢.

另请注意,这是一个经常被问到的问题.您可以考虑将其作为以下内容的副本:

为什么在由parantheses分隔和由语句分隔时,C#中的浮点精度会有所不同?

为什么这个浮点计算在不同的机器上给出不同的结果?

将结果转换为float方法返回float更改结果

(.1f + .2f ==.3f)!=(.1f + .2f).Equals(.3f)为什么?

在.NET中强制浮点是确定性的吗?

C#XNA Visual Studio:"发布"和"调试"模式之间的区别?

C# - 32位和64位的数学运算结果不一致

C#中的舍入错误:不同PC上的结果不同

浮点文字与浮点变量的奇怪编译器行为

  • @ThomasWeller:我从未使用过R#,但据我所知,它在很多静态分析中都具有相当高的误报率.也许提到它们,看看他们是否可以修复警告. (2认同)
  • @PaŭloEbermann:我可以继续.有许多地方C#语言略显不足,而且很多地方的实现都以微妙的方式违反了规范,以避免向后兼并破坏更改.请参阅Roslyn源代码,注释表示DELIBERATE SPEC VIOLATION.在许多这些场景中,我留下了大量的注释. (2认同)
  • @Deduplicator:欢迎来到C#团队七年来我生命中的每一天.我们不断努力为开发人员找到最佳平衡,以保持向后兼容,规格准确性,规格优雅,实施性能以及其他十几个因素.*实施数百万人依赖的语言时,没有简单的选择.* (2认同)

Pat*_*man 9

不,不是的.每个CPU的计算结果可能不同,因为浮点运算的实现可能因CPU制造商或CPU设计而异.我甚至还记得一些英特尔处理器中的浮点运算中的一个错误,这搞砸了我们的计算.

然后,在JIT编译器中如何评估代码存在差异.

  • 啊,好的'奔腾天; 这几天英特尔不发布破损的处理器是一件好事,是吗?#太快了 (12认同)

Mar*_*ell 8

坦白说,我不希望在同一代码库两个地返回同样的事情x/y在同xy-在同一台机器上相同的过程; 它可以取决于编译器/ JIT的准确性xy优化程度 - 如果它们以不同的方式注册,它们可以具有不同的中间精度.使用比预期更多的位(寄存器大小)完成了许多操作; 并且它被强制降低到64位时可能会影响结果."确切时间"的选择取决于周围代码中发生的其他事情.


归档时间:

查看次数:

3157 次

最近记录:

8 年 前