2011-05-25 13 views

Respuesta

8

Mi otra respuesta estaba equivocada.

#include <stdio.h> 

int 
main(int argc, char *argv[]) 
{ 
    unsigned long long n = 1ULL << 53; 
    unsigned long long a = 2*(n-1); 
    unsigned long long b = 2*(n-2); 
    printf("%llu\n%llu\n%d\n", a, b, (double)a == (double)b); 
    return 0; 
} 

compilar y ejecutar para ver:

18014398509481982 
18014398509481980 
0 

a y b son sólo 2 * (2^53-1) y 2 * (2^53-2).

Esos son los números de base 10 de 17 dígitos. Cuando se redondean a 16 dígitos, son lo mismo. Sin embargo, ayb claramente solo necesitan 53 bits de precisión para representar en base-2. Entonces, si tomas a y b y los echas al doble, obtienes tu contraejemplo.

+0

He editado un poco tu programa. Ahora imprime los dos números de doble precisión diferentes: 1.8014398509481982e + 16 1.8014398509481980e + 16 ¡Muchas gracias, esta es la respuesta correcta! –

+0

También publiqué un programa Fortran simple a continuación, que muestra que de hecho se necesitan 17 dígitos. –

+4

Por cierto, aquí hay una manera simple de probar por qué necesitamos 17 dígitos: Si el doble más pequeño que se puede agregar a 1 es épsilon ~ 2e-16, entonces 1 + epsilon = 1.0000000000000002, que obviamente requiere 17 dígitos para representar. –

1

Creo que el hombre en ese hilo está equivocado, y 16 dígitos de base 10 son siempre suficientes para representar un doble IEEE.

Mi intento de una prueba sería algo como esto:

Supongamos lo contrario. Entonces, necesariamente, dos números distintos de precisión doble deben estar representados por el mismo número de base 16 de 16 dígitos significativos.

Pero dos números distintos de precisión doble deben diferir en al menos una parte en 2^53, que es mayor que una parte en 10^16. Y no hay dos números que difieran en más de una parte en 10^16, posiblemente podrían redondear al mismo número de base-10 de 16 dígitos significativos.

Esto no es completamente riguroso y podría ser incorrecto. :-)

+0

Buen argumento. Estoy poniendo esto como la respuesta correcta, a menos que alguien realmente proporcione un argumento contrario (un número que no funciona). Aquí está el código en Python (el formateo no es excelente): 'En [1]: 2 ** (- 53) Fuera [1]: 1.1102230246251565e-16 En [2]: 10 ** (- 16) Fuera [2]: 9.9999999999999998e-17 ' –

+0

Desafortunadamente, ahora creo que estoy equivocado ... Supongamos que solo tenemos tres partes de mantisa. Según mi argumento, eso debería corresponder a un dígito de base 10. Pero ahora considere 2, 4, 6, 8, 10, 12 y 14 (es decir, 2 veces 1,2,3, ... 7). Esos son claramente mantisas de tres bits, pero 10, 12 y 14 son todos iguales cuando se redondean a un dígito significativo. Trataré de construir un contraejemplo "doble" más tarde hoy. (Gran pregunta, por cierto) – Nemo

+0

De hecho, su otra respuesta lo definió. Así que puse esa como la respuesta correcta. Muchas gracias por esto, realmente aprecio tu esfuerzo. Así que ahora está claro, que si quiero imprimir dobles, necesito usar '% .16e' en C, o' (es23.16) 'en Fortran. –

1

La respuesta correcta es la de Nemo anterior. Aquí solo estoy pegando un simple programa Fortran que muestra un ejemplo de los dos números, que necesitan 17 dígitos de precisión para imprimir, mostrando que uno necesita el formato (es23.16) para imprimir números de doble precisión, si uno no quiere perder precisión :

program test 
implicit none 
integer, parameter :: dp = kind(0.d0) 
real(dp) :: a, b 
a = 1.8014398509481982e+16_dp 
b = 1.8014398509481980e+16_dp 
print *, "First we show, that we have two different 'a' and 'b':" 
print *, "a == b:", a == b, "a-b:", a-b 
print *, "using (es22.15)" 
print "(es22.15)", a 
print "(es22.15)", b 
print *, "using (es23.16)" 
print "(es23.16)", a 
print "(es23.16)", b 
end program 

imprime:

First we show, that we have two different 'a' and 'b': 
a == b: F a-b: 2.0000000000000000  
using (es22.15) 
1.801439850948198E+16 
1.801439850948198E+16 
using (es23.16) 
1.8014398509481982E+16 
1.8014398509481980E+16 
0

Adéntrate en los conceptos básicos de precisión simple y doble y dejar de depender de la noción de tal o cual (16-17) muchos dígitos decimales y empezar a pensar en (53) Dígitos binarios. Los ejemplos necesarios se pueden encontrar aquí en stackoverflow si pasas algún tiempo escarbando.

Y no veo cómo se puede otorgar la mejor respuesta a cualquiera dando una respuesta DECIMAL sin explicaciones BINARIAS calificadas. Esto es sencillo pero no es trivial.

+0

Hola Olof, gracias por tu respuesta. He buscado a través del stackoverflow con mucho cuidado, pero no he podido encontrar la respuesta a mi pregunta. ¿Podría indicarme algunos ejemplos de eso? –

+0

[Esta publicación] (http://stackoverflow.com/questions/4738768/printing-double-without-losing-precision/4851671#4851671) debería proporcionarle una idea de por qué los valores de punto flotante (parecen) "se comportan de manera extraña" "(no lo hacen). Trataré de buscar más. –

+0

[Aquí hay otro] (http://stackoverflow.com/questions/4827176/how-to-distinguish-between-1-and-zero-floating-point-values/4844572#4844572) y [otro] (http://stackoverflow.com/questions/327020/why-are-floating-point-values-so-prolific/4164252#4164252) –

0

El rango continuo más grande de números enteros que pueden ser exactamente representados por una doble (8 byte IEEE) es -2^53 a 2^53 (-9007199254740992. A 9007199254740992.). Los números -2^53-1 y 2^53 + 1 no se pueden representar exactamente con un doble.

Por lo tanto, no más de 16 dígitos decimales significativos a la izquierda del punto decimal representarán exactamente un doble en el rango continuo.

Cuestiones relacionadas