Imprimir decimales en c++ – c++

Pregunta:


La pregunta es básica.

Tengo el siguiente código:

#include <iostream>
#include <iomanip>

int main()
{
    double resp = 0.8912637126836812;
    resp = 5/2;
    std::cout << std::fixed << std::setprecision(4) << 5/2+20%6 << " || resp:" << resp;
    return 0;
}

Como salida obtengo.

4 || resp:2.0000

¿Por qué no me imprime en la primera operación el 4.5 y en la segunda el 2.5 que corresponde?

Si imprimo el valor original con el que inicialicé la variable, me la imprime sin problema.

¿Por qué?

Preguntado por: Dilakv

eferion

¿Por qué no me imprime en la primera operación el 4.5 y en la segunda el 2.5 que corresponde?

Porque setprecision solo funciona con tipos decimales, es decir, con float y double.

En tu caso, todos los números involucrados en la operación son de tipo int, luego el resultado va a ser, sí o sí, de tipo int y, por tanto, no va a tener decimales.

Como te ha dicho @GusZL la solución pasa por conseguir que el resultado sea decimal. Sin embargo, en C++ no soy partidario de usar una conversión a pelo. Esto no es C y en C++ hay 4 funciones especiales para realizar conversiones que son mucho más potentes y seguras que las usadas en C. Puedes obtener más información sobre el tema en esta otra pregunta.

Para este caso valdría con static_cast:

static_cast<double>(5)/2+20%6

Fíjate que solo fuerzo la conversión de un número en vez del resultado de la operación… si hiciese esto:

static_cast<double>(5/2+20%6)

La operación 5/2 se realizaría sobre tipos enteros y devolvería 2 en vez de 2.5. En cambio, en cuanto uno de los dos números es double, el compilador realizará una conversión de tipo int a double antes de ejecutar la operación:

numerador decimal:   5.0/2 => 5.0/2.0 = 2.5
denominador decimal: 5/2.0 => 5.0/2.0 = 2.5
ambos tipos enteros: 5/2   =  2             -> se descartan los decimales

Otra posibilidad es escribir los números que interesen directamente en notación decimal para que su tipo nativo sea double:

opción 1: 5.0/2.0
           ~~
opción 2: 5/2.0
             ~~
opción 3: 5.0/2.0
           ~~  ~~

Tienes que castear el resultado a double

#include <iostream>
#include <iomanip>

int main()
{
    double resp = 0.8912637126836812;
    resp = (double) 5/2;
    std::cout << std::fixed << std::setprecision(4) << (double) 5/2+20%6 << " || resp:" << resp;
    return 0;
}

Hazme saber si te funciona

Estoy de acuerdo con algunas de las respuestas (el resultado debe forzar el tipo a double), pero en mi humilde opinión la solución debe pasar por cambiar esto:

resp = 5/2;

por esto:

resp = 5.0 / 2.0;

o bien por esto:

resp = ((double) 5) / 2;

¿Porqué??? Pues porque en la solución anterior no queda claro si primero se está haciendo la conversión de 5 a double y después la división por 2 o bien es al revés: hacemos 5/2 como enteros (resultado 2, porque se trunca a entero) y luego convertimos ese 2 a double.

Los puristas dirán que mirando la precedencia de operadores queda el tema resuelto, pero creo que es mejor dejar a los lectores novatos la cosa clara.

C++ no realiza operaciones con tipos distintos, antes de operar transforma los operandos a un tipo común siguiendo las normas del estándar C++ en el apartado §5.9.10 (la traducción y resaltado mío):

Varios operadores binarios que esperan operadores de tipo aritmético o enumerado causan conversiones y devuelven tipos de una manera similar. El propósito es devolver un tipo común, que es también el tipo del resultado. Este patrón es llamado conversiones aritméticas usuales, que se define así:

  • 10.2 Si alguno de los operandos es de tipo long double, el otro debe ser convertido a long double.
  • 10.3 En caso contrario, si alguno de los operandos es double, el otro debe ser convertido a double.
  • 10.4 En caso contrario, si alguno de los operandos es float, el otro debe ser convertido a float.
  • 10.5 En caso contrario las promociones integrales deben ser aplicadas a ambos operandos. Entonces las siguientes reglas serán aplicadas a los operandos promocionados:
    • 10.5.1 Si ambos operandos tienen el mismo tipo, no se requiere ninguna conversión adicional.
    • 10.5.2 En caso contrario, si ambos operandos tienen tipos con signo o ambos tipos tienen tipos sin signo, el operando con el tipo con menor rango será convertido al tipo con mayor rango.
    • 10.5.3 En caso contrario, si el operando que tiene tipo entero sin signo tiene un rango mayor o igual al rango del tipo del otro operando, el operando con tipo entero con signo debe ser convertido al tipo del operando con tipo entero sin signo.
    • 10.5.4 En caso contrario, si el tipo del operando con tipo entero con signo puede representar todos los valores del tipo del operando entero sin signo, el poerando con tipo entero sin signo debe ser convertido al tipo con el operando con tipo entero con signo.
    • 10.5.5 En caso contrario, ambos operandos deben ser convertidos a tipo entero sin signo correspondiendo al tipo del operando entero sin signo.

En todas tus operaciones estás usando literales son de tipo int así que el resultado de la operación será también de tipo int:

5/2 <-- 2 es int   5/2+20%6
^                  ^ ^ ^  ^
|                  | | |  |
_ 5 es int        | | |  _ 6 es int
                   | | _ 20 es int
                   | _ 2 es int
                   _ 5 es int

¿Por qué no me imprime en la primera operación el 4.5 y en la segunda el 2.5 que corresponde?

Como ya hemos visto la operación 5/2 es de tipo int, por lo que realiza una división entera cuyo resultado es 2, que al guardar en un double se queda en 2.0000.

También hemos visto que la operación 5/2+20%6, que por preferencia de operadores es equivalente a (5 / 2) + (20 % 6) es de tipo int, siendo 2 el primer resultado y 2 el segundo, por lo tanto la operación 2 + 2 también es de tipo entero y resulta en 4.

Solución.

Como hemos visto en el apartado §5.9.10 del estándar, si al menos uno de los operandos es de tipo double, todos los operandos se transformarán automáticamente a double y la operación devolverá un double; lo más sencillo para esto es usar un literal double añadiendo un punto (.) al número:

int main()
{
    double resp = 0.8912637126836812;
    resp = 5./2.;
//          ~  ~ <-- ahora 5 y 2 son de tipo double
    std::cout << std::fixed << std::setprecision(4) << 5./2.+20%6 << " || resp:" << resp;
//                   ahora 5 y 2 son de tipo double --> ~  ~
    return 0;
}

Este cambio provoca que toda la expresión sea de tipo double y resulta en:

4.5000 || resp:2.5000

Fuente

Related Posts:

Declarar un array de structs de tamaño dinamico – c++
Pregunta: buenas, lo que quiero conseguir es declarar un struct con array que tenga su tamaño dinamico, pero cuando lo hago el programa se me ...
Problemas con el registro de un archivo .tlb – c# windows vb6
Pregunta: La situación es la siguiente: He creado un pequeño proyecto de librería de clases en C# que me permita realizar ciertas operaciones. El nombre del ...
Uso de js y c# en unity. ¿Igual rendimiento? – javascript c# unity3d
Pregunta: Estoy comenzando con unity . Y veo que se pueden usar c# y js para programar. Mi pregunta es si tanto c# como js ...
Cómo puedo incluir librería beecrypt en un proyecto en C – c
Pregunta: Tengo un archivo .lib (librería) y quiero usarla en un proyecto de C. Para ser más especifica estoy intentando instalar beecrypt que es una librería ...
Ocultar y Mostrar con Mapa de Google – javascript c# asp.net
Pregunta: Tengo un div en mi página ASP.NET que contiene un Mapa de Google, y necesito mostrarlo y ocultarlo pero no me funciona. Este es el ...
para que sirve #ifdef_MSDOS_ en c++? – c++
Pregunta: He tenido problemas porque donde trabajo usan una versión de dev c++ 4.9 y yo uso en mi hogar la 5.1, ...
¿Como instalar C# en SublimeText? – c# sublimetext3 sublimetext
Pregunta: El problema es que actualmente quiero programar sobre esta tecnologia, pero no quiero descargar aun el visual studio porque consume recursos y es bastante ...
Thread en c++ error compilacion – c++
Pregunta: Estoy empezando con threads y he estado siguien varios tutos y creo que esta todo bien, pero a la hora de ejecutarlo me da ...
¿Es posible capturar un segfault con try/catch? – c++ try-catch
Pregunta: Para comprobar si es posible hice lo siguiente: try { int *x = 0; *x = 1234; } catch(...) { ...
Conexion C# con PostgreSQL mediante proveedor Npgsql – c# postgresql
Pregunta: Hola el problema es que la conexión esta bien solo cuando estoy utilizando el ODBC, pero cuando lo cambio al proveedor de PostgreSQL Npgsql, ...
Construcción extraña: objeto = funcion1() && funcion2() ¿Posible? – c#
Pregunta: acabo de encontrarme en una documentación una construcción como esta: var pose = Body.LeftHand.Near(Body.Head) && Body.LeftArm.Bended(90); posees una objeto que debe crearse a partir de la ...
Cómo importar datos de un Excel a DataGrid pero iniciarlo en la segunda fila? – c# sql-server postgresql
Pregunta: Disculpen una duda, como cargar de excel un formato iniciando en la segunda fila? tengo este código solamente que el excel esta justificado en ...
No completa el ciclo foreach – c#
Pregunta: Estoy haciendo un método para invertir palabras que contengan 5 o mas letras. El problema que tengo es que si mi cadena tiene mas ...
Obtener elementos específicos de un array – c array optimización
Pregunta: Buenas, si yo por ejemplo hago: char buf; fgets(buf, 1024, stdin); ¿Puedo coger los caracteres que escribí del array sin coger los elementos que no utilicé? ¿O ...
Averiguar número de elementos en un array de LUA – c++ array lua
Pregunta: ¿Cómo puedo averiguar el número de elementos que contiene un array en un fichero LUA? me gustaría poder volcarlo a un entero desde C++. -- ...
Tags:

Add a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *