2012-05-29 11 views
10

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?

+0

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

+0

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

+3

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. –

Respuesta

25

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.

+1

El segundo ejemplo es excelente ya que no incluye Inf ni NaN. Muchas gracias. – updogliu

+1

Es posible que desee aclarar la constante '0x1p49', la última vez que miré los dígitos hexadecimales se ejecutó de 0 a F;) – MSalters

+8

@MSalters:" 0x1p49 "es punto flotante hexadecimal, como se define en el estándar C. El formato es "0x" "p" , donde es un número hexadecimal, que incluye opcionalmente un punto, y es un número decimal, que incluye opcionalmente un signo. La base para el exponente es dos, entonces 0x1p49 es 2 ** 49. 0x1p-4 sería 1/16, y 0x1.23p8 sería (1 + 2/16 + 3/256) * 2 ** 8 = 291. El punto flotante hexadecimal proporciona un formato que es fácil para los humanos y los compiladores para convertir hacia y desde codificaciones binarias en coma flotante sin problemas de redondeo. –

1

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.)

+1

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' ... –

+0

@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. –

-3

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.

+5

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. –

+8

Hay muchas cosas que se garantizan al usar flotadores IEEE-754. Esto pasa a no ser uno de ellos. –

+0

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/ –

Cuestiones relacionadas