如何比较两个数学库实现?

How to compare two Math library implementations?

如您所知,C 标准库定义了几个标准函数调用,这些函数调用应由任何兼容的实现实现,例如 Newlib、MUSL、GLIBC ...

例如,如果我的目标是 Linux,我必须在 glibc 和 MUSL 之间做出选择,我的标准是数学库的准确性 libm。我如何比较两种可能的实现方式,例如 sin()cos()

一种天真的方法是在一组随机生成的输入和参考输入(例如来自 Matlab)上测试两种实现的结果的输出质量,但是还有其他 reliable/formal/structured/guided 方法吗要compare/model两个?我试着看看是否有这方面的研究,但我找到了,所以任何指点都将受到赞赏。

一些想法:

  • 您可以使用 GNU Multiple Precision Arithmetic Library (GnuMP 生成良好的参考结果。
  • 可以详尽地测试大多数(如果不是全部)单参数单精度 (IEEE-754 binary32) 例程。 (对于一些 macOS 三角函数例程,例如 sinf,我们详尽地测试了一个实现,验证它返回 忠实舍入 结果,这意味着结果是数学值 [如果可表示] 或两个相邻值之一 [如果不是]。然后,在更改实现时,我们将一个与另一个进行比较。如果新实现结果与旧实现结果相同,则通过。否则,使用 GnuMP来测试它。由于新的实现与旧的实现在很大程度上是一致的,这导致 GnuMP 的调用很少,所以我们能够在大约三分钟内详尽地测试一个新的例程实现,如果我没记错的话。)
  • 详尽地测试多参数或双精度例程是不可行的。
  • 比较实现时,您必须选择一个或多个指标。具有良好的最坏情况错误的库有利于证明;可以断言它的界限对任何参数都成立,并且可以用来在后续计算中推导出进一步的界限。但是,具有良好平均误差的库可能会产生更好的结果,例如,使用大量数据的物理模拟。对于某些应用程序,只有“正常”域中的错误可能是相关的(大约 −2π 到 +2π 的角度),因此减少大参数(最多大约 10308)的错误可能无关紧要,因为从未使用过这些参数。
  • 各种套路都有一些共同点需要测试。例如,对于三角函数例程,测试 π 的不同分数。除了在数学上很有趣之外,这些往往是实现在内部近似值之间切换的地方。还要测试大量可表示但恰好非常接近 π 的简单分数的倍数。这些是参数缩减的最坏情况,如果处理不当,可能会产生巨大的相对错误。他们需要数论才能找到。在任何类型的分散方法中进行测试,甚至是未考虑此减少问题的有序方法,都将无法找到这些麻烦的参数,因此很容易将具有巨大错误的例程报告为准确。
  • 另一方面,如果不了解实施的内部知识,则无法知道要测试的要点。例如,在设计正弦例程时,我会使用 Remez 算法找到一个极小极大多项式,目标是从 –π/2 到 +π/2(对于这类事情来说相当大,但是仅举个例子)。然后我会看看在参数缩减过程中可能出现的算术和舍入错误。有时他们会产生稍微超出该间隔的结果。所以我会回到 minimax 多项式生成并推动稍大的间隔。而且我还会寻求参数减少方面的改进。最后,我最终会得到一个保证在一定区间内产生结果的缩减,以及一个已知在该区间内具有一定精度的多项式。要测试我的例程,您需要知道该区间的端点,并且您必须能够找到一些参数,参数缩减会在这些端点附近产生点,这意味着您必须了解我的参数缩减是如何进行的已实现——它使用了多少位,等等。就像上面提到的麻烦的论点一样,这些点不能用散点法找到。但与上述不同的是,它们不能从纯数学中找到;您需要有关实施的信息。这使得几乎不可能知道您已经比较了最糟糕的潜在实现参数。