Floating point 信任浮点算法

Floating point 信任浮点算法,floating-point,Floating Point,我知道像0.3这样的数字有问题,不能用浮点数来表示,所以它们会产生浮点数错误。 那么可以表示的数字呢?比如0.5,0.75等等。。。如果我处理的是二的负幂的数字以及由二的负幂组成的数字,我能相信浮点运算是无错误的吗?有些加法和减法在浮点运算中是精确的,但在一般情况下,乘法在浮点运算中不能不舍入,因为你需要两倍的数字表示产品的位数。假设您有一个IEEE754体系结构,并且如果您只执行加法、减法和乘法,并且结果合适,那么它应该是正确的。只有当结果分母是二的幂时,才能使用除法。任何其他内置的数学函数,

我知道像0.3这样的数字有问题,不能用浮点数来表示,所以它们会产生浮点数错误。

那么可以表示的数字呢?比如0.5,0.75等等。。。如果我处理的是二的负幂的数字以及由二的负幂组成的数字,我能相信浮点运算是无错误的吗?

有些加法和减法在浮点运算中是精确的,但在一般情况下,乘法在浮点运算中不能不舍入,因为你需要两倍的数字表示产品的位数。

假设您有一个IEEE754体系结构,并且如果您只执行加法、减法和乘法,并且结果合适,那么它应该是正确的。只有当结果分母是二的幂时,才能使用除法。任何其他内置的数学函数,如exp和log,都不可能是正确的(由于Lindemann Weierstrass);非自然幂也是如此(尽管在大多数CPU中甚至没有内置幂函数)。

还有另一个明显的限制:正常的浮点数将有(例如)53位有效位,因此(在缩放后)所涉及的每个数字的二进制表示必须适合53个二进制数字,以避免丢失精度。

当您使用符合IEEE-754的浮点实现时,您可以保证基本运算(加法、减法、乘法、除法、余数、平方根)的计算尽可能精确。因此,您可以安全地执行以下所有操作:

  • 1.0+1.0
  • 1.0-0.5
  • 0.0--0.0
  • 0.16845703125*0.16845703125
  • sqrt(4.0)
  • sqrt(20.25)
  • 15.5/0.5
与其他基本运算不同,余数运算对于任何两个操作数都是精确的


您只需确保所需的精度永远不会超过浮点类型提供的精度。

您需要获得IEEE浮点规范的副本并研究它。现在几乎所有的编译器和CPU都严格遵循这一点,所以如果你严格遵循规范,你可以得到“精确”的结果

有一件事你并不总是(取决于语言)有控制权,那就是计算结果是保留在寄存器中还是存储回“home”。这可能会影响下一次计算的精度


但几乎每种通用计算语言都实现(或作为附加组件提供)某种“长十进制”或“长整数”支持,可用于生成任意长度/精度的精确结果,只要您坚持以这些形式表示的值。

首先在x86体系结构上实施IEEE规范,尝试处理所有异常情况。除零,下溢和溢出是明显的例外。另一个不太明显的问题是“不精确”,即操作的结果无法准确表示。在任何情况下——据我所知——许多开发环境只是掩盖了导致此类情况不被注意的异常。即使在没有训练轮的环境中,不精确异常也会被屏蔽,但当然可以启用

至于二的负幂的问题,答案是你应该确保不安全的价值不会在没有任何商业价值的地方结束。0作为除数,将负值转换为sqrt或log/ln等。这意味着实现对输入的控制,以便算法在使用它们时不会异常。因为您的异常可能会被屏蔽,所以在您面对结果之前,您的算法可能已经在错误值上做了相当多的工作:+NAN,-NAN或“咒骂删除”-从printf中查看格式

浮点运算带来了一些问题,这些问题可能会导致(而且经常会导致)一系列蠕虫。因此,我的建议是,您在引擎盖下多看一些,然后用插入不同fp操作的值进行实验


如今,成为浮点大师不需要太多时间。

请定义“处理”。如果除法的结果可以准确表示,那么它与加法和减法一样安全。阅读IEEE 754-1985第5节,该节保证“每项操作的执行应如同其首先产生一个中间结果,该中间结果具有无限的精度和无限的范围,然后强制该中间结果符合目的地的格式”。不完全如此。12.5除以1.25保证为10.0;分母不一定是2的幂。@RolandIllig:10的分母是1,这是2的幂,不是吗?啊,现在我明白你的意思了。我只是不知道你说的分母是什么意思。这对保证来说有点狭隘。至少在IEEE754中,你可以期待更多的精确计算。四舍五入必然发生在乘法之后。产品生产至全长,并根据需要磨圆,以适合结果位置。当然,你不能总是控制的是结果是保留在寄存器中还是存储回去,这会影响舍入是否/如何发生。啊,好吧。乘法时,在许多情况下,最终结果必须四舍五入。在加法或减法时,至少有更多的情况。对于“你需要”来说,读“你可能需要”。问题是有效位(尾数)中有多少有效位。例如,将3.0乘以3.0涉及有效位中的两个隐式位和两个显式位。结果用一个隐式位和三个显式位表示。只要看一下有效位,运算就是(1)1*(1)1=(1)001,其中括号括住了相应的隐式位。