Suponga que t
, a
, b
son todos (IEEE Std 754) las variables dobles, y ambos valores de a
, b
NO son NaN
(pero puede ser Inf
). Después de t = a - b
, ¿tengo necesariamente a == b + t
?IEEE Std 754 Floating-Point: let t: = a - b, ¿el estándar garantiza que a == b + t?
Respuesta
Absolutamente no. Un caso obvio es a=DBL_MAX
, b=-DBL_MAX
. Luego t=INFINITY
, entonces b+t
es también INFINITY
.
Lo que puede ser más sorprendente es que hay casos en que esto sucede sin ningún desbordamiento. Básicamente, son todos del formulario donde a-b
es inexacto. Por ejemplo, si a
es DBL_EPSILON/4
y b
es -1
, a-b
es 1 (suponiendo que el modo de redondeo por defecto), y a-b+b
es luego 0.
La razón que menciono este segundo ejemplo es que esta es la canónica forma de forzar redondeando a una precisión particular en aritmética IEEE. Por ejemplo, si tiene un número en el rango [0,1) y desea forzar el redondeo a 4 bits de precisión, debe sumar y luego restar 0x1p49
.
El segundo ejemplo es excelente ya que no incluye Inf ni NaN. Muchas gracias. – updogliu
Es posible que desee aclarar la constante '0x1p49', la última vez que miré los dígitos hexadecimales se ejecutó de 0 a F;) – MSalters
@MSalters:" 0x1p49 "es punto flotante hexadecimal, como se define en el estándar C. El formato es "0x"
En el proceso de hacer la primera operación, los bits podrían haberse perdido del extremo inferior del resultado. Entonces una pregunta es, ¿la segunda operación reproducirá exactamente esas pérdidas? No lo he pensado del todo.
Pero, por supuesto, la primera operación podría haberse desbordado a +/- infinito, lo que hace que la segunda comparación no sea igual.
(Y, por supuesto, en el caso general usando ==
para los valores de punto flotante es casi siempre un error.)
Solo con un argumento de conteo, la segunda operación no puede devolver lo que se perdió. Si pudiera, estaría almacenando más bits de información en 't' que la cantidad de bits en' t' ... –
@R - Sí. Intuitivamente uno sabe que no funcionará, por lo que dices, pero encontrar ejemplos es una mejor "prueba" que apelar a una regla esotérica, no importa cuán válida sea. –
no le garantiza nada al utilizar flotadores. Si el exponente es diferente para ambos números, el resultado de una operación aritmética puede no ser completamente representable en un flotante.
consideran este código:
float a = 0.003f;
float b = 10000000.0f;
float t = a - b;
float x = b + t;
se ejecuta en Visual Studio 2010, se obtiene t==-10000000.0f
, y por lo tanto x==0
.
Nunca debe usar igualdad al comparar flotadores. En su lugar, compare el valor absoluto de la diferencia entre ambos valores y un valor epsilon lo suficientemente pequeño para sus necesidades de precisión.
Se vuelve aún más extraño ya que las diferentes implementaciones de punto flotante pueden devolver resultados diferentes para la misma operación.
Nunca me gustó el consejo de "comparar el valor absoluto de la diferencia". Es posible obtener límites en los errores ([Lo que todo científico informático debería saber sobre la aritmética de coma flotante] (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) es una buena comienzo) y uno debería pensar en lo que se está tratando de lograr con la comparación antes de pasar ciegamente a un límite arbitrario. –
Hay muchas cosas que se garantizan al usar flotadores IEEE-754. Esto pasa a no ser uno de ellos. –
Hay muchas garantías cuando se usan flotantes IEEE, y hay momentos en que la comparación por igualdad no solo es razonable, sino esencial. Las matemáticas de punto flotante definitivamente son difíciles, pero no son aleatorias ni maliciosas. Aquí hay un ejemplo de mi blog de cuando probar la igualdad de coma flotante es fundamental: https://randomascii.wordpress.com/2014/01/27/theres-only-four-billion-floatsso-test-them-all/ –
- 1. Implementación de zipE :: Evento t a -> Evento t b -> Evento t (a, b)
- 2. Tipo parámetro de minBy [B] (f: ((A, B)) ⇒ B) (cmp implícita: Orden [B]): (A, B)
- 3. Nombre del tipo de patrón: R a b = Q (a -> (R a b, b))
- 4. ¿Cómo [b] [b = a, 0] intercambia entre a y b?
- 5. Lógica: is (A &&! (B || C)) || (B || C) lo mismo que (A || B || C)?
- 6. La manera más fácil de convertir "a/b/c" a ["a/b/c", "a/b", "a"]
- 7. Cómo convertir A [B [C]] a B [A [C]] si A y B son mónadas?
- 8. ¿Por qué (a | b) es equivalente a a - (a & b) + b?
- 9. ¿Por qué el estándar IEEE 754 usa un sesgo 127?
- 10. Rangos A a B donde A> B en F #
- 11. Diferencia entre un +++++ b y A ++ + ++ b
- 12. Cómo restar números IEEE 754?
- 13. División de enteros: ¿es a // b == int (a/b) verdadero para todos los enteros a, b?
- 14. dobles - IEEE 754 alternativas
- 15. ¿Math.max (a, b) o (a> b)? A: b son más rápidos en Java?
- 16. ¿Por qué funciona "a + + b", pero "a ++ b" no?
- 17. ¿Cuál es la diferencia entre a [:] = b y a = b [:]
- 18. Rubí pregunta sintaxis: racional (a, b) y Rational.new (a, b)
- 19. Diferencia entre a [:] = b y a = b [:]? (Python)
- 20. Cálculo (a^b)% MOD
- 21. diferencia entre (A '(símbolo de la función' defalias B)) y ('A 'defalias B)
- 22. ¿Debo definir el índice (A) y el índice (B), o el índice (A, B) o ambos?
- 23. Unificación de tipo genérico: parámetros múltiples (T, T) frente a listas de parámetros múltiples (T) (T)?
- 24. Shell: ¿"a -lt b" no significa verdadero si a es menor que b?
- 25. ¿Por qué std :: sub_match <T> hereda públicamente de std :: pair <T, T>?
- 26. Rieles 3: ¿Cómo validar que A <B donde A y B son atributos del modelo?
- 27. ¿Por qué "SELECT DISTINCT a, b FROM ..." devuelve menos registros que "SELECT DISTINCT A + '|' + B DE ... "?
- 28. Asignaciones múltiples var a = b = b || {} En código javascript
- 29. ¿Cuándo puede a == b ser falso y a.Equals (b) verdadero?
- 30. Functor es para (a -> b) -> (f a -> f b), ¿qué es para (Categoría c) => c a b -> c (f a) (f b)?
Creo que el resultado de un subdesbordamiento no estaría definido, al igual que el de un desbordamiento en la segunda expresión, por lo que no. Si alguien pudiera confirmar eso, estaría bien. – chris
Ah, supongo que esto confirma que el desbordamiento tampoco está definido para el punto flotante: 'Como con cualquier otro flujo aritmético, si el resultado no encaja en el espacio provisto, el comportamiento está indefinido. – chris
En una implementación C conforme a IEEE 754, no hay UB para ninguna aritmética de coma flotante. Todos los resultados están estrictamente definidos. –