log (10.0) puede compilar pero log (0.0) no puede con una referencia indefinida?

7 minutos de lectura

avatar de usuario
xuhdev

Para el siguiente C código fuente:

#include <math.h>

int main(void)
{
    double          x;

    x = log(0.0);

    return 0;
}

Cuando compilo con gcc -lmTengo:

/tmp/ccxxANVH.o: In function `main':
a.c:(.text+0xd): undefined reference to `log'
collect2: error: ld returned 1 exit status

Pero, si reemplazo log(0.0) con log(10.0)entonces puede compilar con éxito.

No entiendo muy bien esto, ya que no importa si tienen sentido matemático o no, deben compilarse, no hay error de sintaxis. ¿Alguien podría explicar esto?

Por si acaso, mi gcc -v producción:

Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.2-19ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)

Tenga en cuenta que esta pregunta es sobre el plegado constante, pero la pregunta duplicada sugerida es sobre una biblioteca de enlaces faltante.

  • Esto probablemente tiene que ver con la propagación constante y no especificar -lm.

    – Místico

    18 de junio de 2014 a las 20:38

  • @Cornstalks De hecho, uno debería especificar -lm después del archivo fuente.

    – xuhdev

    19 de junio de 2014 a las 4:00

  • No estoy de acuerdo con su premisa de que debe compilarse una expresión matemática indefinida. Dado que log(0) no está definido/singular, su presencia en un programa solo puede ser el resultado de un error de programación. No hubiera esperado que el compilador captara esto, pero considere el hecho de que hace un rasgoNo un defecto.

    – Gdalya

    25 de junio de 2014 a las 18:56

  • @gdalya debería devolver -Inf, no indefinido. Ver aquí

    – xuhdev

    25/06/2014 a las 19:35

  • @LưuVĩnhPhúc Son dos preguntas diferentes. Ver mi edición en la última línea.

    – xuhdev

    20 ago 2016 a las 17:30

avatar de usuario
Shafik Yaghmour

gcc puedo usar funciones integradas en muchos casos, su documentación dice:

Muchas de estas funciones solo se optimizan en determinados casos; si no están optimizados en un caso particular, se emite una llamada a la función de biblioteca.

asi que, por lo tanto gcc no necesitará vincularse con la biblioteca matemática cuando use la función incorporada, pero dado que log(0) es no definida probablemente obligagcc para evaluarlo en tiempo de ejecución ya que tiene un efecto secundario.

Si nos fijamos en el borrador del estándar C99 sección 7.12.1 Tratamiento de las condiciones de error en el párrafo 4 dice (énfasis mío):

Un resultado flotante se desborda si la magnitud del resultado matemático es finita pero tan grande que el resultado matemático no se puede representar sin un error de redondeo extraordinario en un objeto del tipo especificado. Si un resultado flotante se desborda y el redondeo predeterminado está en vigor, o si el resultado matemático es un infinito exacto a partir de argumentos finitos (por ejemplo, log(0.0)), la función devuelve el valor de la macro HUGE_VAL, HUGE_VALF o HUGE_VALL según el tipo de devolucióncon el mismo signo que el valor correcto de la función;
si la expresión entera math_errhandling & MATH_ERRNO es distinta de cero, la expresión entera errno adquiere el valor ERANGE; si la expresión entera math_errhandling & MATH_ERREXCEPT es distinta de cero, se genera la excepción de coma flotante “dividir por cero” si el resultado matemático es un infinito exacto y, de lo contrario, se genera la excepción de coma flotante “desbordamiento”.

Podemos ver en un ejemplo en vivo usando -S bandera para generar ensamblado y grep log para filtrar las llamadas a log.

En el caso de log(0.0) se genera la siguiente instrucción (verlo en vivo):

call    log

pero en el caso de log(10.0) no call log se genera la instrucción, (verlo en vivo).

Por lo general, podemos prevenir gcc de usar la función incorporada usando el -bandera incorporada de fno que es probablemente una forma más rápida de probar si se está utilizando una función integrada.

Tenga en cuenta que -lm necesita ir después del archivo fuente, por ejemplo (tomado de la respuesta vinculada) si main.c requiere la biblioteca de matemáticas, entonces usaría:

 gcc main.c -lm 

  • ¡Esa es una excelente respuesta! Sí, ahí es exactamente donde está el problema.

    – xuhdev

    18/06/2014 a las 20:40

  • La razón por la que gcc no puede evaluar log(0) en tiempo de ejecución es complicado. El estándar especifica que devuelve -HUGE_VALpero también provoca un error de rango como efecto secundario (visible en errno por ejemplo) para que no pueda eliminar la llamada.

    –Tavian Barnes

    18/06/2014 a las 20:45

  • @TavianBarnes, de hecho, también iba a agregar eso.

    – Shafik Yaghmour

    18 de junio de 2014 a las 20:46

  • @TavianBarnes: Bueno, un compilador pudo reemplazar log(0.0) con código que produce HUGE_VAL y conjuntos errnopero probablemente sea más simple generar la llamada (ya que de todos modos tiene que poder hacerlo para argumentos no constantes).

    –Keith Thompson

    18 de junio de 2014 a las 20:56

  • @KeithThompson Me imagino que quieren mantener el código de evaluación incorporado simple y evitar el manejo de excepciones y otras cosas que hacen que el código de tiempo de ejecución sea más complicado.

    – Shafik Yaghmour

    18 de junio de 2014 a las 21:15

avatar de usuario
axel

La compilación está bien, es solo el interruptor del enlazador. -lm eso falta

La segunda versión probablemente compila y vincula porque gcc reemplaza log(10.0) con una constante, por lo que no se necesita llamar a la biblioteca matemática. En el segundo caso, el resultado no está definido matemáticamente y la evaluación da como resultado un error de dominio. En ese caso, la expresión no se puede reemplazar por una constante, ya que el manejo de los errores de dominio puede ser diferente en tiempo de ejecución.

Cita del estándar C (sequía):

En un error de dominio, la función devuelve un valor definido por la implementación; si la expresión entera math_errhandling & MATH_ERRNO es distinta de cero, la expresión entera errno adquiere el valor EDOM; si la expresión entera math_errhandling & MATH_ERREXCEPT es distinta de cero, se genera la excepción de coma flotante ”no válida”.

Así que evaluación de log(0.0) cualquiera da como resultado la devolución del valor HUGE_VAL (no NAN como dije antes) o una excepción de coma flotante.

EDITAR: corregí mi respuesta en función de los comentarios recibidos y agregué un enlace a la descripción en el estándar C.

  • Gracias por su respuesta, lamento que @Shafik esté un paso antes que usted, por lo que no puedo aceptar su respuesta como la respuesta aceptada.

    – xuhdev

    18 de junio de 2014 a las 20:42

  • No hay problema. Para eso es SO… 🙂

    – Axel

    18 de junio de 2014 a las 20:43

  • El resultado es -Inf, no NaN.

    –Tavian Barnes

    18 de junio de 2014 a las 20:47

  • @TavianBarnes: Creo que eso está definido por la implementación. El estándar simplemente dice esto: “Las funciones de registro calculan el logaritmo base-e (natural) de x. Se produce un error de dominio si el argumento es negativo. Puede ocurrir un error de rango si el argumento es cero”.

    – Axel

    19 de junio de 2014 a las 7:02

  • @Axel “… si el resultado matemático es un infinito exacto (por ejemplo, log (0.0)), entonces la función devuelve el valor de la macro HUGE_VAL, HUGE_VALF o HUGE_VALL según el tipo de retorno, con el mismo signo que el valor correcto de la función”

    –Tavian Barnes

    19 de junio de 2014 a las 12:50

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad