tipos - sizeof long double y precisión no coincidente?
printf para long double (3)
Considere el siguiente código C:
#include <stdio.h>
int main(int argc, char* argv[])
{
const long double ld = 0.12345678901234567890123456789012345L;
printf("%lu %.36Lf/n", sizeof(ld), ld);
return 0;
}
Compilado con gcc 4.8.1
bajo Ubuntu x64 13.04
, imprime:
16 0.123456789012345678901321800735590983
Lo que me dice que un doble largo pesa 16 bytes, pero los decimales parecen estar bien solo en el 20º lugar. ¿Como es posible? 16 bytes corresponden a un quad, y un quad me daría entre 33 y 36 decimales.
El operador sizeof
devuelve el tamaño en bytes del tipo de datos. Los tipos de formato de punto flotante no son realmente comparables con el tamaño de bytes del tipo de datos, otros que un tamaño más grande generalmente significa una mejor precisión.
El formato long double
en su implementación C utiliza un formato Intel con un signo de un bit, un exponente de 15 bits y un significado de 64 bits (diez bytes en total). El compilador asigna 16 bytes para él, lo que es un desperdicio pero útil para algunos aspectos como la alineación. Sin embargo, los 64 bits solo proporcionan log 10 (2 64 ) dígitos de importancia, que son aproximadamente 20 dígitos.
Varias implementaciones de C del long double
pueden tener un rango y precisión variantes. El sizeof
sugerencias a la notación de punto flotante subyacente, pero no lo especifica. No se requiere un long double
para tener 33 a 36 decimales. Incluso podría tener exactamente la misma representación que un double
.
Sin codificar con precisión la precisión, pero usando toda la precisión disponible y no exagerar, recomiende:
const long double ld = 0.12345678901234567890123456789012345L;
printf("%.*Le/n", LDBL_DIG + 3, ld);
printf("%.*Le/n", LDBL_DIG + 3, nextafterl(ld, ld*2));
Esto se imprime (en mi eclipse intel de 64 bits), por supuesto, los tuyos pueden diferir.
1.234567890123456789013e-01
1.234567890123456789081e-01
[Editar]
En la revisión, un +2 es suficiente. Es mejor usar LDBL_DECIMAL_DIG
. vea el especificador de ancho de impresión para mantener la precisión del valor del punto flotante
printf("%.*Le/n", (LDBL_DIG + 3) - 1, ld);
printf("%.*Le/n", LDBL_DECIMAL_DIG - 1, ld);