2009-03-10 2 views
5

В соответствии с this site функция ошибки erf (x) исходит из math.h. Но на самом деле, глядя в math.h, не существует, и GCC не может скомпилировать следующий тестовую программу, в то время как г ++ может:erf (x) и math.h

#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 

Что г ++ тянуть в этом НКУ не? Если посмотреть в/usr/include, единственное место, где я мог бы найти erf (x), было в tgmath.h, которого я не включаю. Так что g ++ должен захватывать разные заголовки, чем gcc, но какие?

EDIT: Я не связывался в libm с gcc, поэтому ошибка ссылки. Тем не менее, я до сих пор не понимаю, почему erf() не находится в математике. Откуда он?

ответ

4

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

3

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

$ gcc mathHTest.c -lm 

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

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

1

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

7

У меня была аналогичная проблема, и мне нужно было найти точное определение 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  
...