Pregunta

Según este sitio viene la función de error erf (x) de math.h. Pero en realidad, buscando en math.h, no está allí, y gcc no puede compilar el siguiente programa de prueba, mientras que g ++ puede:

#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

¿Qué hace g ++ para que gcc no lo haga? Buscando en / usr / include, el único lugar donde pude encontrar erf (x) fue en tgmath.h, que no incluyo. Entonces, g ++ debe estar tomando diferentes encabezados que gcc, pero ¿cuáles?

EDITAR: no estaba enlazando en libm con gcc, de ahí el error de enlace. Sin embargo, todavía no entiendo por qué erf () no está en matemáticas. ¿De dónde viene?

¿Fue útil?

Solución

'erf' en realidad se declara en bits / mathcalls.h, que está #incluido por math.h. La declaración real está muy oscurecida por la magia mágica para que haga lo correcto tanto para C como para C ++

Otros consejos

Tuve un problema similar y necesitaba encontrar la definición exacta de erf , así que permítanme ampliar esto. Como dijo Chris Dodd, la función se declara en bits / mathcalls.h que se incluye en 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
...

Macro magic expande __MATHCALL (erf ,, (_Mdouble_)); a

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

El código real está en libm.a o 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
...

La fuente se puede obtener de gnu libc página web. Para una idea aproximada sobre la implementación real, aquí hay algunas líneas de la fuente:

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     
 ...

También debe vincular la biblioteca matemática ( libm ):

$ gcc mathHTest.c -lm

Todas las funciones normales de la biblioteca matemática están realmente allí, y no en la biblioteca C estándar ( libc ).

Según mis pruebas, g ++ incluye libm automáticamente, pero gcc no lo hace.

Tuve el mismo problema al usar gcc de cygwin en un procesador x86. El " -lm " El parámetro de incluir biblioteca (¡después de la lista de archivos!) funcionó perfectamente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top