c++ - mostrar - scanf
¿Por qué el doble en C imprime menos dígitos decimales que C++? (2)
Con MinGW g ++ (y gcc) 7.3.0 sus resultados se reproducen exactamente.
Este es un caso bastante extraño de comportamiento indefinido.
El comportamiento indefinido se debe al uso de
printf
sin incluir un encabezado apropiado, lo que viola el "debe" en
" Una unidad de traducción debe incluir un encabezado solo fuera de cualquier declaración o definición, y debe incluir el encabezado léxicamente antes de la primera referencia en esa unidad de traducción a cualquiera de las entidades declaradas en ese encabezado. No se requiere ningún diagnóstico.
En el código C ++, cambie
<iostream>
a
<stdio.h>
, para obtener
un código C ++ válido
, y obtendrá el mismo resultado que con el programa C.
¿Por qué el código de C ++ incluso compila?
Bueno, a diferencia de C, en C ++ se permite arrastrar un encabezado de biblioteca estándar en cualquier otro encabezado.
Y evidentemente con g ++ el encabezado
<iostream>
arrastra en alguna declaración de
printf
.
Simplemente no es del todo correcto.
Detalles: Con MinGW g ++ 7.3.0, la declaración / definición de
printf
depende del símbolo de macro
__USE_MINGW_ANSI_STDIO
.
El valor predeterminado es que
<stdio.h>
declara
printf
.
Pero cuando
__USE_MINGW_ANSI_STDIO
se define como lógica verdadera,
<stdio.h>
proporciona una definición de
printf
que
__mingw_vprintf
, que llama a
__mingw_vprintf
.
Y a medida que sucede, el encabezado
<cstdio>
define (a través de una inclusión indirecta)
__USE_MINGW_ANSI_STDIO
antes de incluir
<stdio.h>
.
Hay un comentario en
<_mingw.h>
, "Tenga en cuenta que también lo habilitamos para _GNU_SOURCE en C ++, pero no para el caso C.".
En C ++, con las versiones relevantes de este compilador, hay efectivamente una diferencia entre incluir
<stdio.h>
y usar
printf
, o incluir
<cstdio>
, diciendo que
using std::printf;
, y utilizando
printf
.
Respecto a
” Además, ¿cómo puede ir hasta 55 decimales? El punto flotante IEEE 754 tiene solo 52 bits para el número fraccional con el que podemos obtener 15 dígitos decimales de precisión. Se almacena en binario. ¿Cómo es que su interpretación decimal almacena más?
... es solo la presentación decimal que es más larga. Los dígitos más allá de la precisión de la representación interna, unos 15 dígitos para IEEE 754 de 64 bits, son esencialmente basura, pero se pueden usar para reconstituir los bits originales exactamente. En algún momento se convertirán en todos los ceros, y ese punto se alcanza para el último dígito en la salida del programa C ++.
1 Gracias a Dietrich Epp por encontrar esa cita de estándares.
Tengo este código en C, donde he declarado 0.1 como doble.
#include <stdio.h>
int main() {
double a = 0.1;
printf("a is %0.56f/n", a);
return 0;
}
Esto es lo que imprime,
a is 0.10000000000000001000000000000000000000000000000000000000
Mismo código en C ++,
#include <iostream>
using namespace std;
int main() {
double a = 0.1;
printf("a is %0.56f/n", a);
return 0;
}
Esto es lo que imprime,
a is 0.1000000000000000055511151231257827021181583404541015625
¿Cuál es la diferencia? Cuando leo ambos se asignan 8 bytes? ¿Cómo C ++ imprime más números en los lugares decimales?
Además, ¿cómo puede ir hasta 55 decimales? El punto flotante IEEE 754 tiene solo 52 bits para el número fraccional con el que podemos obtener 15 dígitos decimales de precisión. Se almacena en binario. ¿Cómo es que su interpretación decimal almacena más?
Me parece que ambos casos imprimen 56 dígitos decimales, por lo que la pregunta se basa técnicamente en una premisa errónea.
También veo que ambos números son iguales a
0.1
dentro de 52 bits de precisión, por lo que ambos son correctos.
Eso lleva a tu pregunta final, "¿Por qué su interpretación decimal almacena más?".
No
almacena
más decimales.
double
no almacena decimales.
Almacena bits.
Los decimales se generan.