He encontrado un problema molesto al generar un número de coma flotante. Cuando formato 11.545 con una precisión de 2 decimales en Windows, da salida a "11.55", como era de esperar. Sin embargo, cuando hago lo mismo en Linux, la salida es "11.54".Emular el comportamiento de conversión de cadena de punto flotante de Linux en Windows
Originalmente encontré el problema en Python, pero la investigación posterior mostró que la diferencia está en la biblioteca C en tiempo de ejecución subyacente. (La arquitectura es x86-x64 en ambos casos). La ejecución de la siguiente línea de C produce los diferentes resultados en Windows y Linux, al igual que en Python.
printf("%.2f", 11.545);
de arrojar más luz sobre este Imprimí el número de 20 cifras decimales ("%.20f"
):
Windows: 11.54500000000000000000
Linux: 11.54499999999999992895
Sé que 11.545 no se puede almacenar, precisamente, como un número binario. Entonces, lo que parece estar sucediendo es que Linux genera el número que realmente está almacenado con la mejor precisión posible, mientras que Windows emite la representación decimal más simple de él, es decir. trata de adivinar lo que el usuario probablemente haya querido decir.
Mi pregunta es: ¿hay alguna forma (razonable) de emular el comportamiento de Linux en Windows?
(Aunque el comportamiento de Windows es ciertamente el intuitivo, en mi caso, realmente necesito comparar el resultado de un programa de Windows con el de un programa de Linux y el de Windows es el único que puedo cambiar. así, traté de mirar a la fuente de Windows de printf
, pero la función real que hace el Float-> conversión de cadenas es _cfltcvt_l
y su fuente no parece estar disponible)
EDIT:. la trama se complica ! La teoría sobre este ser causada por una representación imprecisa que podría estar equivocado, porque 0,125 tiene una representación binaria exacta y sigue siendo diferente cuando la salida con '%.2f' % 0.125
:
Windows: 0.13
Linux: 0.12
Sin embargo, round(0.125, 2)
rendimientos 0.13 en Windows y Linux .
Comparar flotantes mediante la conversión a cadenas y la comparación de las cadenas es una idea fundamentalmente no portátil. Además, si está haciendo matemática para llegar a estos valores, normalmente podría terminar obteniendo resultados diferentes (por ejemplo, precisión FPU interna de 32, 64 u 80 bits, diferente precisión de las funciones de la libma), incluso antes de que llegue a formateo –
Una doble tiene aproximadamente 15 dígitos decimales de precisión, al menos para MSVC. Hubiera supuesto que sería similar para una versión de Linux x86, pero tal vez tengan algunas técnicas para proporcionar más (¿es un 'doble' en la versión de Linux de 8 bytes? Es' DBL_DIG' en 'float.h' algo más grande de 15?) Lo que está sucediendo en su compilación de Windows es correcto, ya que con los 15 dígitos de precisión, el valor representa 11.545. Bienvenido al mundo extraño y no siempre tan maravilloso de punto flotante ... –