数值精度:是否按比例缩放?

Numerical Accuracy: to scale or not?

我正在研究一个 n 体引力模拟器,它接受输入并以公制 MKS 单位产生输出。这涉及处理一些非常大的数字(例如以千克表示的太阳质量、以米表示的行星轨道的半长轴以及以秒表示的年的时间尺度),这些数字乘以一些非常小的数字(特别是引力常数,它是 6.67384e-11(以 MKS 为单位),而且偶尔会有非常小的数字被添加到非常大的数字中或从中减去(主要是在对成对加速度求和时),这让我担心舍入误差的影响。

我已经采取了将所有质量 m 替换为 Gm 的步骤(预乘引力常数),这显着降低了乘法总数,并使质量数小得多,这似乎对效率和准确性都有积极影响,正如模拟器节能程度所判断的那样。

不过,我想知道:是否值得尝试对不同的单位进行一些内部重新缩放以进一步减少浮点错误?如果是这样,我应该尝试让我的数字集中在什么样的范围内(对于双精度浮点数)以获得最大精度?

一般来说,如果你想在基于物理的渲染中得到精确的结果,你不想使用浮点数或双精度数,因为它们有 大量 舍入问题,因此会在你的模拟中引入错误。

如果您需要或想要坚持使用 floats/double,您可能应该重新调整为零。原因是通常浮点表示在该点附近具有较高的 "density" 值,而在 min/max 侧往往具有较少的值。 Image example from google

我建议您将所有值更改为基于整数的数字变量。这消除了舍入错误(over/underflow 仍然会发生!)并将计算过程加速一个数量级,因为普通 CPU 处理整数运算的速度更快。对于 GPU,其 基本上 相同,但那是另外一个故事了...

但在您努力进一步提高准确性之前,我强烈建议您使用任意精度数字库。这可能会带来性能损失,但应该比重新调整您的值更容易并产生更好的结果。

大多数数值数学家都遇到过这个问题。 首先让我提醒您,您不能为每次计算处理小于机器 epsilon 的数字(或物理值)。不幸的是,epsilon 取决于您正在分析的数字。就我记得 eps(1.0)~=2.3e-16 和 eps(0)~1e-298.

而言,你可以在 MATLAB 中对 a 的任何值尝试 eps(a)

这就是为什么在数值方法中要避免使用比例非常不同的数字进行计算。因为一个被另一个值忽略(小于它的 epsilon),舍入误差是不可避免的。

但是人们还会做些什么呢?如果他们遇到这样的物理问题,在编码之前,数学家会从理论上分析问题,他们会使用类似比例的数字进行简化。