浮点运算总是偏离零吗?

时间:2018-04-05 08:36:49

标签: floating-point language-agnostic rounding precision

在C#/ .NET中,表达式String.Format("{0:R}", 0.1 * 199)产生19.900000000000002

因为它是一个浮点数,我显然不会期望获得精确的“19.9”结果。然而,从我的测试来看,似乎错误似乎总是积极的,从不消极。也就是说,我的结果总是比它应该的大一点点,而不是一点点。

我可以一直依靠这种行为吗?或者我只是做错了测试?

(我认为这是一种与语言无关的原则,不是C#/ .NET独有的)

3 个答案:

答案 0 :(得分:2)

浮点运算具有多个舍入行为。最常见的默认行为是将精确的数学结果舍入到最接近的可表示值,如果是平局,则舍入到具有偶数低位的值。

IEEE-754浮点标准定义的其他舍入行为是:

  • 回归零。
  • 向上舍入(朝向+∞)。
  • 向下舍入(朝向-infinity)。
  • 舍入到最接近的可表示值,但是,如果是平局,则从0开圆。

正如您所看到的,这些都不是“远离零”,因此它不是标准化的舍入行为,您不太可能在通用硬件或软件中找到它。但是,the Wikipedia page on rounding讨论了它和其他行为。

虽然常见的默认值是圆到最近的连接,但这不是语言无关的。每种编程语言和/或每个计算平台可以选择它可用的舍入行为以及哪一个是默认值。

答案 1 :(得分:1)

任何单个操作都会将最接近的浮点表示用于实际结果;尝试0.1 + 0.7。

答案 2 :(得分:1)

它不是绝对语言不可知的,但仍然是一种实用的解释。在C#中,运行时支持的唯一舍入是roundToNearestTiesEven(IEEE754 term)。任何其他模式都需要丑陋的黑客作为处理器模式或专用库的不安全切换。它并不孤单; Java,Python和许多其他人也是如此。 (对于具有自己特定内容的Decimal来说,这不是真的。)实际上,有更少的语言明确定义舍入控制支持(如C,C ++)而不是" unaware"的。

对于其他细节,我会得到@Ry和@EricPostpischil的第二个答案。 0.1 + 0.7的示例适用于舍入double值,这些值是相同的roundToNearestTiesToEven实际上向零舍入。

谈到C#,人们还会注意到32位x86 C#有自己的特性与内部FPU处理相关联,可以对中间值使用更宽的精度。 Here是将0.1+0.2转换为单个isn&t; t等于FPU中剩余的相同值Double的示例,here是其在C中的再现。