GCC源代码中的数学算法在哪里可以找到?数学函数是如何工作的?

5
晚上好。我是一名数学学士,正在研究log() 和 series。我想看看GCC如何计算这些东西,这将对我很有帮助。我已经阅读了math.h文件,但里面没有任何信息。我正在尝试找到GCC使用最快方法来计算对数和平方根的方法。我已经下载了源代码,但无法找到数学程序在哪里。 https://github.com/gcc-mirror/gcc 我只想看看它,我并不是一个好的程序员,我的专业是数学。

它在C库中 - 请参见此处 https://dev59.com/Ymgu5IYBdhLWcg3wJDyb - Hellmar Becker
GCC编译器本身使用GMP、MPFR、MPC等库进行计算(还有其他库)。由编译器生成的代码使用您机器上的C库(库)-通常使用“-lm”链接数学库,但有时不需要(例如在Mac上)。 - Jonathan Leffler
3个回答

5

数学函数是 C 标准库的一部分,GCC 只是使用这些函数。如果你想查看源代码,你可以从官方 glibc 网站 下载源代码(针对 GNU C Library 版本,这是其中最常用的之一),或使用在线代码浏览器。例如,这是用于 log() 的代码

由于你说你不是很懂编程,我怀疑你可能无法理解 GNU C 标准库。它是数十年优化和兼容性调整的结果,代码非常复杂。因此,我建议您看看 musl C 库 其源代码更简洁,也更有注释。这里有 log() 函数,以及关于数学函数的所有文件

最后,无论是 GCC 还是 C 库都没有 "有史以来最快的方法" 来计算这些函数。C 库的目标不是提供每个数学函数的最快实现,而是在保持足够快的同时,仍然具备跨多个架构使用的可移植性,因此这些函数仍然非常快,但很可能并不是 "有史以来最快的"。在最好的情况下,一些数学函数甚至可以缩减为单个 CPU 指令,如果 CPU 支持快速内置硬件数学运算,则可以像 Intel x86 的 fsqrt 一样


2
请看这个对数实现
这是来自fdlibm的实现(遵循IEEE-754),用于在C语言中实现许多数学函数。
从实现中可以看到:

方法

  1. 参数缩减:找到kf,使得
    x = 2^k * (1+f),
    where sqrt(2)/2 < 1+f < sqrt(2) .
  1. 对log(1+f)的近似计算。
Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
     = 2s + 2/3 s**3 + 2/5 s**5 + .....,
         = 2s + s*R
  • 我们在区间[0,0.1716]上使用特殊的Reme算法,生成14次多项式来近似R。这个多项式近似的最大误差受到2**-58.45的限制。换句话说,
                 2      4      6      8      10      12      14
    R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s  +Lg6*s  +Lg7*s
    (the values of Lg1 to Lg7 are listed in the program)

并且

    |      2          14          |     -58.45
    | Lg1*s +...+Lg7*s    -  R(z) | <= 2 
    |                             |

请注意,2s = f - s*f = f - hfsq + s*hfsq,其中hfsq = f*f/2。为了保证对数的误差在1ulp以下,我们通过以下方式计算对数:
    log(1+f) = f - s*(f - R)    (if f is not too large)
    log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
  1. Finally,
     log(x) = k*ln2 + log(1+f).  
            = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
  • 这里的ln2被分成了两个浮点数:
        ln2_hi + ln2_lo,

|n| < 2000 时,n*ln2_hi 总是精确的。

有关实现细节和特殊情况,请参考此链接:link


1

log这样的函数是数学库的一部分,通常被称为“libm”。标准C库的实现通常带有libm的实现,因此您要查找的内容很可能在glibc中。您可以在glibc中找到log的实现,链接如下:https://code.woboq.org/userspace/glibc/sysdeps/ieee754/dbl-64/e_log.c.html

源代码中有一些注释,可以给您提供有关使用的算法的提示,但没有详细的解释。

当然,还有不同的libm实现-例如,有openlibmnetlib fdlibm。两者的文档都解释了所使用的算法。以下是openlibm中实现log的方法:https://github.com/JuliaMath/openlibm/blob/master/src/e_log.c

有趣 - 看起来 openlibm 和 fdlibm 中的 log 来自同一源代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接