2009-12-25 9 views
7

HI,diferente comportamiento de matemáticas de redondeo entre Linux, Mac OS X y Windows

he desarrollado un código mixto C/C++, con algunos cálculos numéricos intensivos. Cuando estoy compilado en Linux y Mac OS X obtengo resultados muy similares después de que finaliza la simulación. En Windows, el programa compila también, pero obtengo resultados muy diferentes y, a veces, el programa no parece funcionar.

Utilicé compiladores de GNU en todos los sistemas. Un amigo me recomendó que agregue -frounding-math y ahora la versión de Windows parece funcionar más estable, pero Linux y Os X, sus resultados, no cambian para nada.

¿Podría recomendar otras opciones para obtener más concordancia entre las versiones de Win y Linux/OSX?

Gracias

P.D. También intenté -O0 (sin optimizaciones) y especificó -m32

+0

Linux y OS X ambos usan GCC, por lo que esperaría exactamente los mismos resultados, siempre que ambos se ejecutaran en la misma arquitectura de procesador. ¿Acabas de obtener resultados "similares" allí? Si es así, parece que algo de azar se inyecta en tus cálculos. ¿Alguna variable no inicializada? –

Respuesta

9

Hay cuatro tipos diferentes de redondeo para números de coma flotante: redondear hacia cero, redondear hacia arriba, redondear hacia abajo y redondear al número más cercano. Dependiendo del compilador/sistema operativo, el predeterminado puede ser diferente en diferentes sistemas. Para cambiar mediante programación el método de redondeo, consulte fesetround. Está especificado por el estándar C99, pero puede estar disponible para usted.

También puedes probar -ffloat-store gcc option. Esto intentará evitar que gcc use valores de coma flotante de 80 bits en los registros.

Además, si los resultados cambian según el método de redondeo, y las diferencias son significativas, significa que sus cálculos pueden no ser estables. Considere realizar análisis de intervalos o usar algún otro método para encontrar el problema. Para obtener más información, consulte How Futile are Mindless Assessments of Roundoff in Floating-Point Computation? (pdf) y The pitfalls of verifying floating-point computations (enlace de ACM, pero puede obtener PDF de muchos lugares si eso no funciona para usted).

+0

+1 para estabilidad numérica: si los resultados varían sustancialmente en función del redondeo, hay algún problema con los cálculos. Y solo para descartar lo obvio: ¿Usó 'doble' y no solo 'flote' para sus variables? –

9

No puedo hablar de la implementación en Windows, pero los chips Intel contienen registros de coma flotante de 80 bits y pueden dar una mayor precisión que la especificada en el estándar de coma flotante IEEE-754. Puede intentar llamar a esta rutina en el principal() de su aplicación (en plataformas de chips Intel):

inline void fpu_round_to_IEEE_double() 
{ 
    unsigned short cw = 0; 
    _FPU_GETCW(cw);  // Get the FPU control word 
    cw &= ~_FPU_EXTENDED; // mask out '80-bit' register precision 
    cw |= _FPU_DOUBLE;  // Mask in '64-bit' register precision 
    _FPU_SETCW(cw);  // Set the FPU control word 
} 

I que esto es distinto de los modos de redondeo discutidos por @Alok.

+2

+1 por mencionar registros de 80 bits. No sabía sobre '_FPU_ *'. –

+0

y eso está en x87, que ya no debería usarse. La matemática SSE es mucho más rápida –

1

Además de la configuración de redondeo en tiempo de ejecución que las personas mencionaron, puede controlar la configuración del compilador de Visual Studio en Propiedades> C++> Generación de código> Modelo de punto flotante. He visto casos en los que establecer esto en "Rápido" puede causar un comportamiento numérico incorrecto (por ejemplo, los métodos iterativos no logran converger).

Los ajustes se explican aquí: http://msdn.microsoft.com/en-us/library/e7s85ffb%28VS.80%29.aspx

+0

gracias uso eclipse – asdf

+0

Sin embargo, esto tiene el mismo problema. La configuración del modelo de coma flotante de VC++ se puede configurar para forzar las representaciones internas de 80 bits para redondearlas a sus equivalentes de 64 bits en momentos bien definidos, y eso debería hacer que los resultados sean consistentes con otras implementaciones que usan 64 bits hasta el final. mediante. –

0

El IEEE/C++ y C normas dejan algunos aspectos de matemáticas de punto flotante no especificado. Sí, se determina el resultado preciso de agregar flotadores, pero ningún cálculo más complicado lo es. Por ejemplo, si agrega tres flotantes, el compilador puede realizar la evaluación con precisión flotante, precisión doble o superior. Del mismo modo, si agrega tres dobles, el compilador puede hacer la evaluación con una precisión doble o superior.

VC++ se establece de manera predeterminada en establecer la precisión de las FPU x87 en el doble. Creo que gcc lo deja con una precisión de 80 bits.Ninguno de los dos es claramente mejor, pero pueden dar resultados fácilmente, especialmente si hay alguna inestabilidad en sus cálculos. En particular, "pequeño + grande - grande" puede dar resultados muy diferentes si tiene bits de precisión adicionales (o si el orden de evaluación cambia). Las implicaciones de diversa precisión intermedia se discuten aquí: se discuten aquí

http://randomascii.wordpress.com/2012/03/21/intermediate-floating-point-precision/

los desafíos de la determinista de punto flotante:

http://randomascii.wordpress.com/2013/07/16/floating-point-determinism/

Aritmética en coma flotante es complicado. Debe averiguar cuándo difieren sus cálculos y examinar el código generado para comprender por qué. Solo entonces puedes decidir qué acciones tomar.

Cuestiones relacionadas