problema tipo de datos en java

D@C

Lanero Regular
27 Ene 2004
25
Un saludo para todos...

Tengo un problema con la siguiente clase

public class angulo {

public static void main(String args[]) {
final double angulo = 4.09;
double grado = 0, minuto = 0, segundo = 0;

grado = Math.floor(angulo);
minuto = Math.floor((angulo - grado) * 100);
segundo = (((angulo - grado) * 100) - minuto) * 100;

System.out.println("Grados: " + grado);
System.out.println("Minutos: " + minuto);
System.out.println("Segundos: " + segundo);
}

}

en la cual, al realizar la operacion (angulo - grado) * 100 obtengo 8.999999999999986 y no 9.0 que es lo que deseo por lo cual la variable minuto realmente se le asigna 8.0. Trate de cambiar la variable angulo por float pero al final obtengo 9.000015258789062, no entiendo realmente que es lo que sucede, por favor si ustedes me pueden colaborar e indicarme que estoy haciendo mal.
 
Yo tuvé un problema similar, y terminé usando la clase BigDecimal, parece ser un problema de precisión bien extraño en Java.
 
Este problema es innerente a que los computadores son máquinas binarias, es decir, representan los números fraccionarios utilizando esquemas de almacenamiento que pierden precisión. El problema no es solo de Java sino de cualquier lenguaje de programación que utilices.

La solución para este "problema" es utilizar, como ya lo dijeron BigDecimal, que es bastante engorroso. Un "machetazo" es que al imprimir los resultados redondees los valores.
 
Puede ke exista algun método en java ke le redondee, si es pues del caso ke necesite un redondeo, ud sabe ke java tiene muchos métodos ke sirven y son desconocidos, puede mirar la documentacion en http://java.sun.com/
 
swoko, gracias por el articulo, realmente no entendia por que se obtienen esos resultados.

Al final he utilizado la funcion Math.round() para redondear el resultado.
 
Si hice el laboratorio, en sistema operativo Linux, los resultados fueron:

Código Java:

Código:
/*
 * Created on Mar 3, 2005
 *
 */
package rulas.pruebas;

/**
 * Prueba de precisión decimal en plataforma Java.
 *
 * @author Rulas
 * @version 1.0
 * 
 */
public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println("Prueba precisión decimal; By Rulas (c) 2005");
        double angulo =  4.09;
        double grado = 4;
        double minuto = (angulo - grado) * 100;
        System.out.println("Minutos: " + minuto);
    }
}

Arrojó: 8.999999999999986

Código C++:

Código:
/**
* decimal.c++
*
* Prueba de precisión decimal en plataforma C++
* Programado por: Rulas    
*/

#include <iostream>
#include <string>
#include <cstdio>
                                                                                
using namespace std;
                                                                                
int main (int count, char** args) {
        cout << "Prueba precisión decimal; By Rulas (c) 2005\n";
        double angulo =  4.09;
        double grado = 4;
        double minuto = (angulo - grado) * 100;
                                                                                
        cout << minuto << "\n";
                                                                                
        return 0;
}

La versión C++ arrojó 9

CONCLUSIONES: Aún no se puede determinar si es un problema del lenguaje o realmente es del procesador, puede que el tipo de dato double en java no sea equivalente al de C++.
 
CONCLUSIONES: Aún no se puede determinar si es un problema del lenguaje o realmente es del procesador, puede que el tipo de dato double en java no sea equivalente al de C++.

Que curioso. ¿Qué compilador de c++ y qué procesador tenes? Sería interesante averiguar cómo se almacenan los números de punto flotante en esa combinación compilador/plataforma respecto a Java/JVM.
 
El procesador es un PIV, el compilador:
Código:
> g++ -v
Reading specs from /usr/lib/gcc-lib/i586-suse-linux/3.3.3/specs
Configured with: ../configure --enable-threads=posix --prefix=/usr --with-local- prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --enable-lan guages=c,c++,f77,objc,java,ada --disable-checking --libdir=/usr/lib --enable-lib gcj --with-gxx-include-dir=/usr/include/g++ --with-slibdir=/lib --with-system-zl ib --enable-shared --enable-__cxa_atexit i586-suse-linux

Thread model: posix

gcc version 3.3.3 (SuSE Linux)
 
Bueno, me tiene cabezón el por qué C++ no falla con lo mismo. Me huele a optimización del compilador.

Lastima que no tenga tiempo para consultar más sobre C++. Sin embargo, dos buenas fuentes donde explican el problema son este comparativo http://developers.sun.com/tools/cc/articles/fp_errors.html y esta presentación http://servlet.java.sun.com/javaone/resources/content/sf2002/conf/sessions/pdfs/1079.pdf.

En resumen dicen que los lenguajes implementan el estándar IEEE754 (Floating-Point) y que al almacenar números fraccionarios, inevitablemente se pierde precisión.

El primer link compara los errores acumulativos entre IA32 (Intel) y otras arquitecturas RISC (SPARC, etc) y además sobre diferentes sistemas operativos.

El segundo link, habla específicamente de JAVA y en conclusión, se debe utilizar BigDecimal si no se quiere perder precisión alguna.

Si alguien descubre por qué C++ no falla que por favor nos ilumine.
 
Hermano la solucion la tiene en sus manos la multifuncionalidd de java le permite que programe la clase para redondear. hagalo y no pierda mas tiempo.
 
Es que el tipo de dato en C++ depende de la plataforma donde esté montado. En java un double siempre es de 8 bytes y funciona con el estándar IEEE que se mencionó antes.
 

Los últimos temas