эрф (х) и математика - PullRequest
       13

эрф (х) и математика

5 голосов
/ 10 марта 2009

Согласно этому сайту функция ошибки 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. Откуда это?

Ответы [ 4 ]

7 голосов
/ 27 ноября 2011

У меня была похожая проблема, и мне нужно было найти точное определение erf, поэтому позвольте мне остановиться на этом подробнее. Как сказал Крис Додд, функция объявлена ​​в 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.a или libm.so (gcc -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     
 ...
4 голосов
/ 10 марта 2009

'erf' фактически объявлен в битах / mathcalls.h, который # включается в math.h. Фактическое объявление сильно скрыто макромагией, чтобы заставить его делать правильные вещи как для C, так и для C ++

3 голосов
/ 10 марта 2009

Вам необходимо также связать математическую библиотеку (libm):

$ gcc mathHTest.c -lm

Все обычные функции математической библиотеки на самом деле есть, а не в стандартной библиотеке C (libc).

Согласно моим тестам, g++ автоматически включает libm, а gcc - нет.

1 голос
/ 30 сентября 2009

У меня была такая же проблема при использовании gcc из cygwin на процессоре x86. Включенный параметр библиотеки «-lm» (после списка файлов!) Работал отлично.

...