Lo que es probable que, con las máquinas actualmente populares y software, son:
El compilador 0,7 codificado como 0x1.6666666666666p-1 (este es el número hexadecimal 1.6666666666666 multiplicado por 2 a la potencia de -1), .2 como 0x1.999999999999ap-3 y .1 como 0x1.999999999999ap-4. Cada uno de estos es el número representable en punto flotante más cercano al número decimal que usted escribió.
Observe que cada una de estas constantes de coma flotante hexadecimales tiene exactamente 53 bits en su significado (la parte de "fracción", a menudo llamada inexactamente mantisa). El número hexadecimal para el significando tiene un "1" y trece dígitos hexadecimales más (cuatro bits cada uno, 52 en total, 53 incluyendo el "1"), que es lo que establece el estándar IEEE-754, para flotación binaria de 64 bits. números de puntos.
Agreguemos los números para .7 y .2: 0x1.6666666666666p-1 y 0x1.999999999999ap-3. Primero, escala el exponente del segundo número para que coincida con el primero. Para hacer esto, multiplicaremos el exponente por 4 (cambiando "p-3" por "p-1") y multiplicaremos el significado por 1/4, dando 0x0.66666666666668p-1. A continuación, agregue 0x1.6666666666666p-1 y 0x0.66666666666668p-1, dando 0x1.ccccccccccccc8p-1. Tenga en cuenta que este número tiene más de 53 bits en el significado: el "8" es el 14º dígito después del período. El punto flotante no puede devolver un resultado con tantos bits, por lo que debe redondearse al número representable más cercano. En este caso, hay dos números que están igualmente cerca, 0x1.cccccccccccccp-1 y 0x1.ccccccccccccdp-1. Cuando hay un empate, se usa el número con un cero en el bit más bajo del significado. "c" es par y "d" es impar, entonces se usa "c". El resultado final de la adición es 0x1.cccccccccccccp-1.
A continuación, agregue el número de .1 (0x1.999999999999ap-4) a eso. De nuevo, escalamos para que los exponentes coincidan, por lo que 0x1,9999999999999ap-4 pasa a ser 0x.33333333333334p-1. A continuación, agregue eso a 0x1.cccccccccccccp-1, dando 0x1.fffffffffffff4p-1. Redondear eso a 53 bits da 0x1.fffffffffffffp-1, y ese es el resultado final de ".7 + .2 + .1".
Considere ahora ".7 + .1 + .2". Para ".7 + .1", agregue 0x1.6666666666666p-1 y 0x1.999999999999ap-4. Recuerde que este último tiene una escala de 0x.33333333333334p-1. Entonces, la suma exacta es 0x1.99999999999994p-1. Redondeando eso a 53 bits da 0x1.9999999999999p-1.
A continuación, agregue el número de .2 (0x1.999999999999ap-3), que se escala a 0x0.66666666666668p-1. La suma exacta es 0x2.00000000000008p-1. Los significados de coma flotante siempre se escalan para comenzar con 1 (excepto en casos especiales: cero, infinito y números muy pequeños en la parte inferior del rango representable), por lo que ajustamos esto a 0x1.00000000000004p0.Finalmente, redondeamos a 53 bits, dando 0x1.0000000000000p0.
Por lo tanto, debido a los errores que se producen al redondear, ".7 + .2 + .1" devuelve 0x1.fffffffffffffp-1 (muy poco menos de 1), y ".7 + .1 + .2" regresa 0x1.0000000000000p0 (exactamente 1).
Su código de ejemplo difiere en * conmutatividad *, no * asociatividad *. Una versión que demuestre asociatividad sería '(0.7 + (0.1 + 0.2))' –
@MattMcNabb: + es una operación binaria. Con operandos de coma flotante, es conmutativo pero no asociativo. Por lo tanto, si tiene dos expresiones que producen resultados diferentes, no puede formar una de la otra aplicando solo conmutatividad. – tmyklebu
@tmyklebu OK, entonces esto comprueba la asociatividad si y solo si se sabe que la conmutatividad se cumple. (El estándar de C++ no parece garantizar la conmutatividad). –