Foros del Web » Programación para mayores de 30 ;) » Java »

Problema con números reales

Estas en el tema de Problema con números reales en el foro de Java en Foros del Web. Hola, tengo un problema con la siguiente operación -10/3 + 5*(2/3) . Debería dar 0 ya que -3.333333 + 3.333333 = 0 pero me da ...
  #1 (permalink)  
Antiguo 02/12/2008, 07:57
 
Fecha de Ingreso: noviembre-2008
Mensajes: 17
Antigüedad: 15 años, 5 meses
Puntos: 0
Problema con números reales

Hola, tengo un problema con la siguiente operación -10/3 + 5*(2/3) .

Debería dar 0 ya que -3.333333 + 3.333333 = 0 pero me da un número con exponente -16.

¿Cuál puede ser el problema?
  #2 (permalink)  
Antiguo 02/12/2008, 07:59
Avatar de masterojitos  
Fecha de Ingreso: julio-2008
Ubicación: Lima Callao Chucuito
Mensajes: 1.931
Antigüedad: 15 años, 9 meses
Puntos: 105
Respuesta: Problema con números reales

y por que no le das........

(-10/3) + (5*(2/3) )
__________________
Atte. MasterOjitos :ojotes:
Todo sobre Programación Web
Las ultimas tendencias en Efectos y Recursos Web: MasterOjitos Blog
  #3 (permalink)  
Antiguo 02/12/2008, 08:02
 
Fecha de Ingreso: noviembre-2008
Mensajes: 17
Antigüedad: 15 años, 5 meses
Puntos: 0
Respuesta: Problema con números reales

Bueno realmente el problema no si es ese, quizá me he explicado mal.
Es un programa que resuelve el algoritmo Simplex que no se si conoceréis pero tengo que hacer operaciones sobre filas en una matriz como si se tratara de un sistema de ecuaciones.
Entonces un caso me falla porque tengo una fila con -3.3333333 que es el resultado de dividir 10 entre 3 entonces al combinarlo con otra que es 5*(2/3) no da el resultado que debiera.

Muchas gracias por responder
  #4 (permalink)  
Antiguo 02/12/2008, 08:36
Avatar de nicolaspar  
Fecha de Ingreso: noviembre-2004
Ubicación: Villa Ballester Bs-As|Ar
Mensajes: 2.002
Antigüedad: 19 años, 5 meses
Puntos: 34
Respuesta: Problema con números reales

Hola Basmang_15, el tema no es simple, pero por lo que estas haciendo seguramente lo comprendes y verás que es fácil. Hasta donde sabrás los números se guardan en formato binario. Y aquí está el problema.
El 1 se almacena exactamente como es, pero algunos otros números en clave decimal como 0.1 no se pueden grabar de manera exacta en binario.
Lo mismo te esta pasando con 1/3 que en decimal se convierte en 0.33333..., el número 1/10 (10 en notación decimal, no 10 binario) se convierte en periodico al ser expresado en binario: 0.1 (decimal) = .0001100011000111000111... (binario).
Y acá está el tema, éste número se redondea por 2.79E-17 (o algo así) porque la pc lo recortará al número de bits máximos que va a usar.
Así que la manera es reducir los periodicos, algo así:
Código:
uno =  numberFormat( (-10 / 3 ),4); 
dos =  numberFormat( 5 * ( 2 / 3 ),4) ;
Claro que esto puede romper el exacto (puedes usar DecimalFormat), pero para tu caso me parece que lo solucionará.

Saludos, y espero no haberte mareado.
__________________
Mi punto de partida es Que Bueno Lo Nuevo
  #5 (permalink)  
Antiguo 02/12/2008, 08:41
 
Fecha de Ingreso: octubre-2003
Mensajes: 3.578
Antigüedad: 20 años, 6 meses
Puntos: 51
Respuesta: Problema con números reales

El problema es que los tipos primitivos de datos, float y double, son de precisión finita, por cuestiones de rendimiento, por lo que se producen perdidas significativas de precisión al operar con ellos.
La solución es usar los tipos de datos BigDecimal y BigInteger, que tienen precisión indefinida y no tienen estos problemas, a cambio, obviamente, de un menor rendimiento.

S!
__________________
Para obtener respuestas, pregunta de forma inteligente o si no, pregunta lo que quieras que yo contestaré lo que me dé la gana.
  #6 (permalink)  
Antiguo 04/12/2008, 02:11
 
Fecha de Ingreso: noviembre-2008
Mensajes: 17
Antigüedad: 15 años, 5 meses
Puntos: 0
Respuesta: Problema con números reales

Cierto el error era ese y gracias por las respuestas.
Por ejemplo en números que debe dar 5, claramente da algo así como 5.0000001 y luego hay problemas.

Pero lo que pasa que lo que me gustaría es tener un número x de decimales pero que se redondeara por ejemplo si tengo 4.9999999999 que se redondee a cinco pero si tengo 0.666666666667 que se redondee que se yo a 0.6667 o algo así porque entonces al restarlo menos 0.3333 no me daría 0.

Pero tampoco quiero utilizar un BigDecimal porque quedaría mal el programa y mas con lo "pijos" que son en mi universidad para corregir.

Entonces ¿como puedo operar con un doble y redondear el resultado a 4 o 5 decimales?, además he leido que al redondear por ejemplo 0.0000 es distinto que 0.0 y en esto me fallarían las sentencias if en alguna ocasión.

No sabía que java tuviera este problema...

No se si me explico
  #7 (permalink)  
Antiguo 04/12/2008, 03:33
 
Fecha de Ingreso: octubre-2003
Mensajes: 3.578
Antigüedad: 20 años, 6 meses
Puntos: 51
Respuesta: Problema con números reales

Cita:
Pero tampoco quiero utilizar un BigDecimal porque quedaría mal el programa y mas con lo "pijos" que son en mi universidad para corregir.
¿Quedar mal? Si que el resultado sea correcto sin perder precisión es quedar mal, mal vamos . Y no es que le pase a Java, le pasa a cualquier lenguaje que use una implementación de puntos flotantes con precisión finita por defecto, como por ejemplo le ocurre a C si no usas las librerias matemáticas especiales.

No queda muy claro exactamente como lo quieres redondear, pero para que lo haga un programa tendrás que expresarlo en lenguaje "formal y determinista".

De todas formas para un resultado preciso, hay que usar una precisión indefinida. Lo demás son aproximaciones.
S!
__________________
Para obtener respuestas, pregunta de forma inteligente o si no, pregunta lo que quieras que yo contestaré lo que me dé la gana.
  #8 (permalink)  
Antiguo 04/12/2008, 06:29
 
Fecha de Ingreso: noviembre-2008
Mensajes: 17
Antigüedad: 15 años, 5 meses
Puntos: 0
Respuesta: Problema con números reales

No se si consigo explicarme, yo tengo que hacer por decirlo de alguna manera como operaciones de un sistema de ecuaciones sobre filas.
Entonces en alguna ocasion como ya comente tengo que dividir 10/3 y dan decimales periódicos entonces lo que no se es como redondearlo de alguna manera que no pierda precisión ya que luego al restarlo cuando lo he hecho con redondeo no me da 0 como debería ser.
  #9 (permalink)  
Antiguo 05/12/2008, 02:54
 
Fecha de Ingreso: octubre-2003
Mensajes: 3.578
Antigüedad: 20 años, 6 meses
Puntos: 51
Respuesta: Problema con números reales

A ver, precisión vas a perder seguro, por que calculando numeros de coma flotante en una computadora acabas perdiendo precisión. Lo que ocurre es que con BigDecimal y BigInteger puedes controlar hasta donde controlas la precisión y con las primitivas no.

De todas formas, tambien tienes que tener en cuenta el orden de las operaciones. Por ejemplo, * y / son transitivos pero...
Cita:
float resultado = (-10f / 3f) + (5f * 2f / 3f); -> da 0
float resultado = (-10f / 3f) + (5f * (2f / 3f)); -> da 2.3841858E-7
Por que la division introduce perdida de precisión y si multiplicas despues, multiplicas esa perdida de precisión y la haces más grande.

Con BigDecimal, lo mismo:
Cita:
MathContext mc = new MathContext(6); // Precision para los calculos
BigDecimal first = new BigDecimal(-10).divide(new BigDecimal(3), mc);
BigDecimal second = new BigDecimal(5).multiply(new BigDecimal(2).divide(new BigDecimal(3), mc));
first = first.add(second); -> first es 0.000005
pero si usas
Cita:
BigDecimal second = new BigDecimal(5).multiply(new BigDecimal(2)).divide(new BigDecimal(3), mc);
entonces first te devolvera 0.000000

Con BigDecimal puedes decir que quieres precision hasta x digitos y luego redondeas si hace falta. Con las primitivas no sabes que precision tienes, asi que a la hora de redondear, pues no estas seguro cuanto has podido perder.

S!
__________________
Para obtener respuestas, pregunta de forma inteligente o si no, pregunta lo que quieras que yo contestaré lo que me dé la gana.
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta

SíEste tema le ha gustado a 1 personas




La zona horaria es GMT -6. Ahora son las 10:18.