El problema está en que intentas guardar un valor que originalmente es un double, en una variable int.
Esto supone perder información, ya que un double es un número real, es decir, tiene una parte entera y otra decimal.
Pero un int solo es un entero y no puede albergar parte decimal.
Es decir, si yo el valor double 5.25 lo guardo en un int, se me quedaría en 5.
El 0.25 restante desaparece, o sea, que he perdido información.
¿Entonces es imposible guardar un double en un int?
No, no es imposible. Lo que pasa es que Java, por seguridad, no nos lo va a permitir, a no ser que hagamos lo que se llama un
casting.
Un
casting es una forma de decirle a Java que somos conscientes de la perdida de información que puede suponer este cambio de tipo, y que nos da igual.
Esto es muy fácil de hacer, basta con envolver con paréntesis el valor o expresión que origina el valor double y anteponer también entre paréntesis, el tipo de dato al que queremos transformar:
public MultiplicadorDieces(){}
public int multiplicarPorDieces(double a, int b){
int resultado = 1;
for(int i=1;i<=b; i++){
resultado=resultado*10;
}
resultado = (int) (a * resultado);
return resultado;
}
Y ya está, con esto Java ya no se quejará.
Sin embargo, en este ejercicio, ¿realmente queremos que el resultado sea un entero?
Habrá ocasiones en las que si nos convenga, o no nos importe, que un double acabe siendo un int.
Pero no en este caso, porque esa pérdida de información nos va a dar resultados matemáticos incorrectos.
Si probamos a multiplicar 2.55 por 2 dieces (o sea, por 100):
public static void main(String[] args) {
MultiplicadorDieces mult = new MultiplicadorDieces();
System.out.println("Resultado:" + mult.multiplicarPorDieces(2.55, 2));
}
El resultado debería ser 255. Pero nuestro método nos va a dar un resultado erróneo:
Resultado:254
He aquí el problema de convertir doubles a enteros. Como dijimos, en el proceso se pierde información y por eso Java no lo permite hacer a no ser que el programador lo pida expresamente con un
castingEl caso es, que para nuestro ejercicio, resultado no puede ser un int.
Si estamos operando con un double, lo ideal es que el resultado final también sea un double (salvo en casos especiales como dije antes)
Así que el tipo de resultado, y el tipo que retorna el método, ha de cambiar a double:
public MultiplicadorDieces(){}
public double multiplicarPorDieces(double a, int b){
double resultado = 1;
for(int i=1;i<=b; i++){
resultado=resultado*10;
}
resultado = a * resultado;
return resultado;
}
Si lo probamos ahora, el resultado se acerca un poco más al correcto.
¡¡Pero sigue sin ser correcto del todo!!
Resultado:254.99999999999997
¡¡Aaghh!! Por algún sitio se han esfumado 0.00000000000003 décimas.
No es mucho, pero no deja de ser un resultado incorrecto.
Sinceramente, no se a que es debido. Pero desde luego no es por un error de programación por nuestra parte.
Será por alguna peculiaridad a nivel interno, ya sea de Java o de la propia CPU, cuando tratan con números de tan alta precisión.
¿Qué podemos hacer entonces?
Aunque no es un error nuestro, podemos probar a simplificar un poco el código.
Tu código no está mal, pero primero acumulas una multiplicación de varios "dieces" y luego lo multiplicas por el valor inicial.
Insisto, no está mal. Pero es un paso que podemos ahorrarnos.
Podemos inicializar la variable resultado directamente con el valor inicial.
Y en el bucle, por cada repetición, le aplicamos directamente una multiplicación por 10.
Así operamos directamente sobre el valor inicial, en lugar de acumular previamente unos "dieces multiplicados."
public MultiplicadorDieces(){}
public double multiplicarPorDieces(double a, int b){
double resultado = a;
for(int i=1;i<=b; i++){
resultado=resultado*10;
}
return resultado;
}
Esto ahora, sí nos da un resultado correcto:
Resultado:255.0
Insisto en que tu lógica estaba bien y seguramente si solo trabajásemos con int habría funcionado.
Pero por algún motivo, al aplicarla con doubles, ocurre un pequeño baile de décimas y no se por qué....
Cambiando de tema, este es un buen ejercicio para aplicar "Recursividad" en la solución.
La Recursividad es una forma bastante óptima de resolver determinados cálculos, pero puede ser algo difícil de comprender su proceso lógico.
Una función recursiva (o método recursivo) lo que hace es que los cómputos de sus valores se van realizando en sucesivas llamadas a sí misma.
Es decir, un método "normal" hace él todos los cómputos y retorna el valor computado.
Un método "recursivo" lo que hace es computar solo una parte y a continuación se llama a sí mismo para pasarse de nuevo esos valores y continuar con los cómputos.
Este proceso de llamarse a sí mismo una y otra vez (recursividad) finaliza cuando se ha cumplido una determinada condición y es entonces cuando se obtiene el resultado final.
Sí, no es fácil de explicar, y aún menos de entender.
Así que no te preocupes si ahora todo esto te suena a chino.
Pero aún así te voy a mostrar como podría resolverse de forma recursiva. Aunque no lo entiendas(que quizás sí lo entiendas, en realidad no hace falta ser un genio), guarda este ejemplo como referencia para el futuro.
En algún momento se te pedirá aplicar recursividad y tener algún ejemplo a mano viene bien.
En tu clase he puesto los dos métodos, el "tradicional" y el "recursivo"
public MultiplicadorDieces(){}
public double multiplicarPorDieces(double a, int b){
double resultado = a;
for(int i=1;i<=b; i++){
resultado=resultado*10;
}
return resultado;
}
public double multiplicarPorDiecesRecursivo(double a, int b) {
if (b == 0) //Si el multiplicador de dieces ya llegó a 0
return a; //Retornamos el valor y termina el proceso recursivo
else { //Si el multiplicador de dieces aún no es 0
a = a * 10; // Multiplicamos un 10
b = b - 1; //Decrementamos el multiplicador
return multiplicarPorDiecesRecursivo(a, b); //Llamada recursiva con los valores actuales
}
}
Lo que hace es comprobar el valor del "multiplicador de dieces"
Si no es 0, significa que hay que multiplicar al menos un 10 al valor original.
Pues se multiplica ese 10, se reduce el valor del "multiplicador de dieces" y se pasan estos valores a una llamada recursiva a ese mismo método.
Tras una o varias llamadas recursivas, el "multiplicador de dieces" alcanzará el valor 0.
Eso significa que se han multiplicado todos los "dieces" necesarios, así que ya podemos retornar el resultado final y poner fin a las llamadas recursivas.
Si probamos ambos métodos en un programa:
public static void main(String[] args) {
MultiplicadorDieces mult = new MultiplicadorDieces();
System.out.println("Resultado:" + mult.multiplicarPorDieces(2.55, 2));
System.out.println("Resultado Recursivo:" + mult.multiplicarPorDiecesRecursivo(2.55, 2));
}
Ambos darán el mismo resultado en pantalla:
Resultado:255.0
Resultado Recursivo:255.0
La ventaja de la recursividad es que permite simplificar el código y reducir las operaciones necesarias.
Quizás en este ejercicio no se perciba tanta diferencia entre un método y otro, pero en ejercicios más complejos la diferencia si puede ser mayor.
Además lo he escrito de forma un poco más extensa para que se entienda mejor la lógica que se está siguiendo y poder comentar cada línea para explicarlo.
Si aplicásemos los distintos operadores que ofrece Java para comprimir el código, el método recursivo podría quedar así:
public double multiplicarPorDiecesRecursivo(double a, int b) {
if (b == 0)
return a;
else
return multiplicarPorDiecesRecursivo(a*=10, --b);
}
Y si usamos el "
condicional ternario", todo queda resuelto en una sola línea:
public double multiplicarPorDiecesRecursivo(double a, int b) {
return (b == 0)? a: multiplicarPorDiecesRecursivo(a*=10, --b);
}
Pero insisto en que ahora no es necesario, ni prudente, que te calientes el cerebro intentando asimilar todo esto.
Tan solo guarda este ejercicio a mano para poder revisitarlo en el futuro.
Un saludo.