Al menos en Java, si escribo este código:
float a = 1000.0F;
float b = 0.00004F;
float c = a + b + b;
float d = b + b + a;
boolean e = c == d;
El valor de sería . Creo que esto se debe al hecho de que los flotadores son muy limitados en la forma de representar con precisión los números. Pero no entiendo por qué solo cambiar la posición de podría causar esta desigualdad.
Reduje la s a uno en las líneas 3 y 4 como se muestra a continuación, sin embargo , el valor de vuelve :
float a = 1000.0F;
float b = 0.00004F;
float c = a + b;
float d = b + a;
boolean e = c == d;
¿Qué sucedió exactamente en las líneas 3 y 4? ¿Por qué las operaciones de suma con flotadores no son asociativas?
Gracias por adelantado.
arithmetic
floating-point
numerical-algorithms
Zeta conocido
fuente
fuente
X
un número muy grande yY
un número muy pequeño, de tal maneraX + Y = X
. Aquí,X + Y + -X
será cero. PeroX + -X + Y
lo seráY
.Respuestas:
En implementaciones típicas de coma flotante, el resultado de una sola operación se produce como si la operación se realizara con precisión infinita y luego se redondeara al número de coma flotante más cercano.
Compare y b + a : el resultado de cada operación realizada con precisión infinita es el mismo, por lo tanto, estos resultados idénticos de precisión infinita se redondean de manera idéntica. En otras palabras, la suma de punto flotante es conmutativa.a + b b + a
Tome : b es un número de coma flotante. Con números binarios de coma flotante, 2 b también es un número de coma flotante (el exponente es mayor en uno), por lo que b + b se agrega sin ningún error de redondeo. Entonces una se añade a la exacta valor b + b . El resultado es el valor exacto 2 b + a , redondeado al número de punto flotante más cercano.b + b + a si 2 b b + b un b + b 2 b + a
Tome : un + b se añade, y habrá un error de redondeo r , por lo que obtener el resultado de un + b + r . Agregue b , y el resultado es el valor exacto 2 b + a + r , redondeado al número de punto flotante más cercano.a + b + b a + b r a + b + r si 2 b + a + r
Entonces, en un caso, , redondeado. En el otro caso, 2 b + a + r , redondeado.2 b + a 2 b + a + r
PD. Si para dos números particulares y b ambos cálculos dan el mismo resultado o no, depende de los números y del error de redondeo en el cálculo a + b , y generalmente es difícil de predecir. El uso de precisión simple o doble no hace ninguna diferencia al problema en principio, pero dado que los errores de redondeo son diferentes, habrá valores de a y b donde en precisión simple los resultados son iguales y en precisión doble no lo son, o viceversa. La precisión será mucho mayor, pero el problema de que dos expresiones son matemáticamente iguales pero no iguales en aritmética de coma flotante sigue siendo el mismo.un si a + b
PPS En algunos idiomas, la aritmética de coma flotante se puede realizar con mayor precisión o un rango de números mayor que el que dan las declaraciones reales. En ese caso, sería mucho más probable (pero aún no está garantizado) que ambas sumas den el mismo resultado.
PPPS Un comentario preguntó si deberíamos preguntar si los números de coma flotante son iguales o no. Absolutamente si sabes lo que estás haciendo. Por ejemplo, si ordena una matriz o implementa un conjunto, se mete en problemas si desea utilizar alguna noción de "aproximadamente igual". En una interfaz gráfica de usuario, es posible que deba volver a calcular los tamaños de los objetos si el tamaño de un objeto ha cambiado: compara oldSize == newSize para evitar ese recálculo, sabiendo que en la práctica casi nunca tiene tamaños casi idénticos, y su programa es correcto incluso si hay un recálculo innecesario.
fuente
b
en esta respuesta no es 0.00004, es lo que obtienes después de la conversión y redondeo.El formato de punto flotante binario admitido por las computadoras es esencialmente similar a la notación científica decimal utilizada por los humanos.
Un número de coma flotante consiste en un signo, mantisa (ancho fijo) y exponente (ancho fijo), como este:
La notación científica regular tiene un formato similar:
Si hacemos aritmética en notación científica con precisión finita, redondeando después de cada operación, obtendremos los mismos efectos negativos que el punto flotante binario.
Ejemplo
Para ilustrar, supongamos que usamos exactamente 3 dígitos después del punto decimal.
(a + b) + b
Ahora calculamos:
En el siguiente paso, por supuesto:
Por lo tanto (a + b) + b = 9.999 × 10 4 .
(b + b) + a
Pero si hicimos las operaciones en un orden diferente:
A continuación calculamos:
Por lo tanto (b + b) + a = 1.000 × 10 5 , que es diferente a nuestra otra respuesta.
fuente
Java utiliza la representación de punto flotante binario IEEE 754, que dedica 23 dígitos binarios a la mantisa, que se normaliza para comenzar con el primer dígito significativo (omitido, para ahorrar espacio).
Las partes en rojo son las mantisas, ya que en realidad están representadas (antes del redondeo).
fuente
Recientemente nos encontramos con un problema de redondeo similar. Las respuestas mencionadas anteriormente son correctas, aunque bastante técnicas.
Encontré lo siguiente como una buena explicación de por qué existen errores de redondeo. http://csharpindepth.com/Articles/General/FloatingPoint.aspx
TLDR: los puntos flotantes binarios no se pueden asignar con precisión a los puntos flotantes decimales. Esto provoca imprecisiones que pueden agravarse durante las operaciones matemáticas.
Un ejemplo que usa números flotantes decimales: 1/3 + 1/3 + 1/3 normalmente sería igual a 1. Sin embargo, en decimales: 0.333333 + 0.333333 + 0.333333 nunca es exactamente igual a 1.000000
Lo mismo sucede cuando se realizan operaciones matemáticas en decimales binarios.
fuente