【问题标题】:erf(x) and math.herf(x) 和 math.h
【发布时间】:2010-10-12 12:15:16
【问题描述】:

根据this site,误差函数 erf(x) 来自 math.h。但实际上在 math.h 中查找,它不存在,gcc 无法编译以下测试程序,而 g++ 可以:

#include <math.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
  double x;
  double erfX;
  x = 1.0;
  erfX = erf(x);

  printf("erf(%f) = %f", x, erfX);
}

$ gcc mathHTest.c
/tmp/ccWfNox5.o: In function `main':
mathHTest.c:(.text+0x28): undefined reference to `erf'
collect2: ld returned 1 exit status
$ g++ mathHTest.c

g++ 引入了哪些 gcc 没有引入的功能?在 /usr/include 中查找,我唯一能找到 erf(x) 的地方是 tgmath.h,我不包括在内。所以 g++ 必须抓取与 gcc 不同的标头,但哪些标头?

编辑:我没有在 libm 中使用 gcc 链接,因此出现链接错误。但是,我仍然不明白为什么 erf() 不在 math.h 中。它来自哪里?

【问题讨论】:

    标签: math.h


    【解决方案1】:

    我遇到了类似的问题,需要找到erf 的确切定义,所以让我对此进行扩展。正如 Chris Dodd 所说,该函数在 bits/mathcalls.h 中声明,maths.h 包含该函数。

    bits/mathcalls.h:

    ...
    #if defined __USE_MISC || defined __USE_XOPEN || defined __USE_ISOC99
    __BEGIN_NAMESPACE_C99
    /* Error and gamma functions.  */
    __MATHCALL (erf,, (_Mdouble_));
    __MATHCALL (erfc,, (_Mdouble_));
    __MATHCALL (lgamma,, (_Mdouble_));
    __END_NAMESPACE_C99
    #endif
    ...
    

    宏魔法将__MATHCALL (erf,, (_Mdouble_)); 扩展为

    extern double erf (double) throw (); extern double __erf (double) throw ();
    

    实际代码在libm.alibm.sogcc -lm)中:

    $ nm /usr/lib/libm.a
    ...
    s_erf.o:
    00000400 T __erf
    00000000 T __erfc
             U __ieee754_exp
    00000400 W erf
    00000000 W erfc
    ...
    

    来源可从gnu libc网页获取。对于实际实现的粗略想法,这里有几行源代码:

    sysdeps/ieee754/dbl-64/s_erf.c:

    /* double erf(double x)
     * double erfc(double x)
     *                           x
     *                    2      |\
     *     erf(x)  =  ---------  | exp(-t*t)dt
     *                 sqrt(pi) \|
     *                           0
     *
     *     erfc(x) =  1-erf(x)
     *  Note that
     *              erf(-x) = -erf(x)
     *              erfc(-x) = 2 - erfc(x)
     *
     * Method:
     *      1. For |x| in [0, 0.84375]
     *          erf(x)  = x + x*R(x^2)
     *          erfc(x) = 1 - erf(x)           if x in [-.84375,0.25]
     *                  = 0.5 + ((0.5-x)-x*R)  if x in [0.25,0.84375]
     *         where R = P/Q where P is an odd poly of degree 8 and
     *         Q is an odd poly of degree 10.
     *                                               -57.90
     *                      | R - (erf(x)-x)/x | <= 2
     *
     *
     *         Remark. The formula is derived by noting
     *          erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
     *         and that
     *          2/sqrt(pi) = 1.128379167095512573896158903121545171688
     *         is close to one. The interval is chosen because the fix
     *         point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
     *         near 0.6174), and by some experiment, 0.84375 is chosen to
     *         guarantee the error is less than one ulp for erf.
     *
     *      2. For |x| in [0.84375,1.25], let s = |x| - 1, and     
     ...
    

    【讨论】:

      【解决方案2】:

      'erf' 实际上是在 bits/mathcalls.h 中声明的,它是由 math.h #included 的。实际的声明被宏魔法严重掩盖,使其对 C 和 C++ 都做正确的事情

      【讨论】:

        【解决方案3】:

        您还需要链接数学库 (libm):

        $ gcc mathHTest.c -lm
        

        所有普通的数学库函数实际上都在那里,而不是标准 C 库 (libc)。

        根据我的测试,g++ 确实自动包含libm,但gcc 没有。

        【讨论】:

          【解决方案4】:

          我在 x86 处理器上使用来自 cygwin 的 gcc 时遇到了同样的问题。 “-lm”库包含参数(在文件列表之后!)完美运行。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-01-19
            • 1970-01-01
            • 1970-01-01
            • 2012-05-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多