c - ¿Por qué gdb evalúa sqrt(3) a 0?
eclipse math (5)
La raíz cuadrada de 3, según lo estimado por Wolfram Alpha:
1.7320508075688772935274463415058723669428052538103806280558...
Cuando hago sqrt(3)
en C, se evalúa a 0. ¿Por qué?
EDIT4 : aquí es cómo puede reproducir este problema en GDB. Crea test.c
siguiente manera:
#include <stdio.h>
#include <math.h>
int main()
{
printf("sqrt(3): %f/n", sqrt(3));
return 0;
}
Compilar:
gcc -O0 -g -Wall -pedantic -ansi -lm -o test test.c
Ejecutar depurador:
gdb test
Introduce esto en la consola:
(gdb) break test.c:6
Breakpoint 1 at 0x400578: file test.c, line 6.
(gdb) r
Starting program: /home/pdedecker/Desktop/test
Breakpoint 1, main () at test.c:6
6 printf("sqrt(3): %f/n", sqrt(3));
(gdb) print sqrt(3)
$1 = 0
(gdb) s
sqrt(3): 1.732051
Mi versión GDB es GNU gdb (GDB) SUSE (7.1-3.12)
.
El problema no es la falta de declaración de la función (que no falta, ya que <math.h>
).
Al problema le falta información de depuración para el sqrt
que realmente está utilizando. Sin esa información de depuración, GDB no tiene ni idea de qué tipo de parámetro pasar a sqrt()
y qué devuelve.
Puede obtener la información de depuración requerida en muchas distribuciones de Linux instalando el paquete libc-debuginfo. Aquí está lo que veo en tal sistema:
gdb -q ./a.out
Reading symbols from /tmp/a.out...done.
(gdb) b main
Breakpoint 1 at 0x400558: file t.c, line 6.
(gdb) r
Breakpoint 1, main () at t.c:6
6 printf("sqrt(3): %f/n", sqrt(3));
(gdb) p sqrt
$1 = {<text variable, no debug info>} 0x7ffff7b7fb50 <__sqrt>
Nota: "no hay información de depuración"
(gdb) p sqrt(3)
$2 = 0
(gdb) p sqrt(3.0)
$3 = 0
Nota: coincide con su comportamiento. ¿Qué funciones sqrt
tienen información de depuración?
(gdb) info func sqrt
All functions matching regular expression "sqrt":
File ../sysdeps/x86_64/fpu/e_sqrt.c:
double __ieee754_sqrt(double);
File s_csqrt.c:
complex double __csqrt(complex double);
File ../sysdeps/x86_64/fpu/e_sqrtf.c:
float __ieee754_sqrtf(float);
File w_sqrtf.c:
float __sqrtf(float);
File s_csqrtf.c:
complex float __csqrtf(complex float);
File ../sysdeps/i386/fpu/e_sqrtl.c:
long double __ieee754_sqrtl(long double);
File w_sqrtl.c:
long double __sqrtl(long double);
File s_csqrtl.c:
complex long double __csqrtl(complex long double);
File ../sysdeps/ieee754/dbl-64/mpsqrt.c:
void __mpsqrt(mp_no *, mp_no *, int);
File w_sqrt.c:
double __sqrt(double);
(gdb) p __sqrt
$4 = {double (double)} 0x7ffff7b7fb50 <__sqrt>
Nota: __sqrt
está en la misma dirección que sqrt
, ¡pero GDB conoce su tipo!
(gdb) p __sqrt(3)
$5 = 1.7320508075688772
(gdb) p __sqrt(3.0)
$6 = 1.7320508075688772
Uno puede razonablemente argumentar que esto es un error en GDB. Siéntase libre de crear uno en GDB bugzilla .
Para llamar a una función sin información de depuración, debe indicar explícitamente a gdb el tipo para la devolución y los argumentos, utilizando un puntero a función. Por lo tanto, para su ejemplo:
(gdb) print ((double (*) (double)) sqrt) (3)
$1 = 1.7320508075688772
Predigo que no hiciste #include <math.h>
Sin una declaración de función, C ajustará por defecto el valor de retorno de una función a int
. Un número de punto flotante podría regresar como 0 dependiendo del tamaño de su int. C tampoco sabrá cómo convertir el argumento de la función. Por defecto pasará el argumento como el tipo que sea. Si pasa un entero a sqrt()
, no se convertirá a doble, pero la función sqrt()
interpretará el patrón de bits como double
.
Tal vez llamando a sqrt no es compatible! Tal vez porque es una función libc. No sé por qué, pero la siguiente prueba muestra un comportamiento interesante:
double mysqrt(double x) { return sqrt(x) };
Luego en una sesión de gdb:
(gdb) p mysqrt(3)
$1 = 1.7320508075688772
(gdb) p sqrt(3)
$2 = -1209775368
#include <stdio.h>
#include <math.h>
int main()
{
printf("sqrt(3): %f/n", sqrt(3));
return 0;
}
Salida:
josh@josh-ubuntu:~/scratch$ ./a.out
sqrt(3): 1.732051