对于接近统一的值,浮点数学是否更精确?

Is floating point math more precise for values close to unity?

问题

有人多次告诉我,如果运算的数字接近 1.0(有时 0.1),浮点运算的精度最高。这有什么道理吗?

澄清

“算术”是指 a + ba * ba / b,还有 sqrt(x) 和其他数学函数。

具体来说,假设所有变量都是IEEE 64 bit double precision浮点数。

例子

在物理模拟代码中,物理单位通常通过将它们映射到浮点值来合并。在这里我们有很多自由,但一个选择是使用 SI/metric system,比如

# Base units
m  = 1.0  # metre
s  = 1.0  # second
kg = 1.0  # kilogram
# Derived units
km = 1e+3*m             # kilometre
yr = 60*60*24*365.25*s  # year
m_sun = 1.98841e+30*kg  # mass of the sun
c = 299792458*m/s       # speed of light
...

此类代码中任何量纲变量的数值取决于单位系统的选择。如果我们得到一个值 x == 1.2e-9 并且 x 意味着被理解为例如长度,我们知道这意味着 x 是 1.2 纳米。如果我们选择设置 m = 1e-9x 将取而代之的是 1.2 的值,因为我们现在使用纳米是基本长度单位的单位系统。

根据模拟中研究的物理系统,可能会选择不同的“自然”单位系统。如果我们的重点是原子物理学,那么选择太阳质量作为基本质量单位可能并不理想。为什么不呢?那是我的问题。当然,所有感兴趣的质量都会有很小的数值,但那又怎样?使用极度 small/large 的数字是否会以某种方式放大浮点运算固有的不精确性?

我知道存在最小和最大浮点数(类似于 1e-3241e+308)。对于手头的任务使用如此古怪的单位系统,以至于我们的变量值超出这些限制当然是破坏性的。尽管将值保持在这些范围内,但代码中的典型值是否按 1.01e±101e±100?

顺序真的有什么区别吗

关于数学函数的注意事项

在非常 large/small 输入的情况下,各种数学函数实际上明显不精确。例如cos(1e-8) == 1,即cos()函数无法区分小于1e-8的正数。这与我的问题 相关,因为 cos() 的输入必须始终是无量纲的纯数字,即独立于代码中定义的单位系统。这同样适用于所有其他三角函数,还有 exp()log() 和其他函数。

Is floating point math more precise for values close to unity?

不是真的。

一般来说,浮点数学很好地保持了 真实 的精度 */sqrt() 覆盖了大部分的浮动点范围。 +- 由于减去附近的值而导致相对精度(对结果)的显着损失。

总体而言,相对 精度的正常数字几乎没有差异。它从 (0.5 到 1.0] * 2-53.

变化

绝对精度按 2 的幂变化。

浮点数 [0.5...1.0) 具有相同的绝对精度。对于double 2-54.
浮点数 [1.0...2.0) 具有相同的绝对精度。对于double 2-53.
浮点数 [2.0...4.0) 具有相同的绝对精度。对于double 2-52.
浮点数 [4.0...8.0) 具有相同的绝对精度。对于double 2-51.
等等

floating point arithmetic has the greatest precision if the numbers operated on are close to 1.0 (or sometimes 0.1). Is there any truth to this?

刚好低于 power-of-2 的值比刚好高于 2 的幂的值具有更高的绝对精度(大约 2 倍)。

使用微小的次正常 值,精度会丢失,每 2 次幂一位,直到达到 0.0。


高级:Trig 函数在其量级很大时特别值得关注。高质量 sin(1e10) 对主要 [-pi ... pi] 范围进行内部扩展高精度参数缩减。并非所有触发函数实现都能很好地处理此步骤。因此,对于弧度参数,从主要范围开始有助于保持精度。对于度参数,简单的 fmod(deg, 360.0) 是简单而精确的范围缩减。