Pergunta
De acordo com a neste site a função de erro ERF (x) vem de math.h. Mas, na verdade, olhando em math.h, não está lá, e gcc não pode compilar o seguinte programa de teste enquanto g ++ pode:
#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
O que g puxar ++ em que gcc não? Olhando em / usr / include, o único lugar que eu poderia encontrar erf (x) estava em tgmath.h, que eu não incluem. Então, g ++ deve ser agarrando cabeçalhos diferentes do gcc, mas quais?
EDIT: Eu não estava ligando em libm com gcc, daí o erro link. No entanto, eu ainda não entendo por que erf () não está na math.h. Onde é que vem?
Solução
'ERF' é realmente declarado em bits / mathcalls.h, que é #included por math.h. A declaração real é fortemente obscurecido por mágica macro para que ele faça a coisa certa para C e C ++
Outras dicas
Eu tive um problema semelhante e precisava encontrar a definição exata de erf
então deixe-me expandir sobre este assunto. Como disse Chris Dodd a função é declarada em bits/mathcalls.h
que está incluído por 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
...
mágica macro expande __MATHCALL (erf,, (_Mdouble_));
para
extern double erf (double) throw (); extern double __erf (double) throw ();
O código real está em libm.a
ou 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
...
A fonte pode ser obtido a partir da GNU libc página da web. Para uma idéia aproximada sobre a aplicação efectiva aqui algumas linhas da fonte:
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
...
Você precisa vincular a biblioteca matemática (libm
) demasiado:
$ gcc mathHTest.c -lm
Todas as funções da biblioteca de matemática normais estão realmente lá, e não na biblioteca C standard (libc
).
De acordo com meus testes, g++
não inclui libm
automaticamente, mas gcc
não.
Eu tive o mesmo problema usando gcc a partir cygwin em um processador x86. A biblioteca "lm" incluem parâmetros (após a lista de arquivos!) Funcionou perfeitamente.