Autor Tema: Concepto y definición de clase en Java. Objetos del mundo real y abstractos.  (Leído 4098 veces)

micaelasol

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 33
    • Ver Perfil
Hola. He intentado hacer el ejercicio de la clase(CU00644B), lo he corregido en el foro pero me da un error que, aunque comprendo que quiere decir, no se como sacarlo ya que sino no se como resolverlo al ejercicio.

Actividad:
Citar
Define una clase denominada multiplicadorDieces con un constructor vacío y que contenga un método denominado multiplicarPorDieces que reciba dos parámetros: el primero un número de tipo double y el segundo un número de tipo entero. El método debe devolver el resultado de multiplicar por 10 elevado al segundo número el primer número. Ejemplo: multiplicarPorDieces (2.55, 2) devuelve 2.55*100 = 255. multiplicarPorDieces (3, 5) devuelve 3*100000 = 300000. MultiplicarPorDieces (-0.0563, 3) devuelve -0.563 * 1000 = -56.3. Crea un objeto y comprueba que el método opera correctamente.

Código: [Seleccionar]
public class multiplicadorDieces{
   
    public multiplicadorDieces(){}
   
    public int multiplicarPorDieces(double a, int b){
        int resultado =1;
        for(int i=1;i<=b; i++){
            resultado=resultado*10;
        }
        resultado = a [color=red]* resultado[/color];
        return  resultado;
    }
       
}

Donde marqué un error me aparece un error "incompatible types: possible lossy conversion from double to int".

Muchas gracias

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
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:

Citar
   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):
Código: [Seleccionar]
    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:
Código: [Seleccionar]
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 casting

El 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:

Citar
   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!! :o
Código: [Seleccionar]
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."

Citar
   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:
Código: [Seleccionar]
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"
Citar
   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:
Código: [Seleccionar]
   
    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:
Código: [Seleccionar]
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í:
Código: [Seleccionar]
    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:
Código: [Seleccionar]
    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.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".