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



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

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

一种幼稚的方法是在一组随机生成的输入上测试两个实现的结果的输出质量,并带有参考输入(例如来自 Matlab(,但是有没有其他更可靠/正式/结构化/指导的方式来比较/建模两者?我试图看看是否有这方面的任何研究,但我找到了,所以任何指示都值得赞赏。

一些想法:

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

最新更新