¿Por qué el mismo código produciría diferentes resultados numéricos en máquinas de 32 y 64 bits?

5 minutos de lectura

¿Por que el mismo codigo produciria diferentes resultados numericos en
lindelof

Estamos trabajando en una biblioteca de rutinas numéricas en C. Aún no estamos seguros de si trabajaremos con precisión simple (float) o doble (double), por lo que hemos definido un tipo SP como un alias hasta que decidamos:

typedef float SP;

Cuando ejecutamos nuestras pruebas unitarias, todas pasan en mi máquina (un Ubuntu de 64 bits) pero fallan en la de mi colega (un Ubuntu de 32 bits que se instaló por error en una máquina de 64 bits).

Usando Git bisect comando, encontramos la diferencia exacta que comenzó a producir resultados diferentes entre su máquina y la mía:

-typedef double SP;
+typedef float SP;

En otras palabras, pasar de precisión doble a precisión simple produce resultados numéricamente diferentes en nuestras máquinas (alrededor de 1e-3 de diferencia relativa en el peor de los casos).

Estamos bastante seguros de que nunca estamos comparando entradas sin firmar con entradas con signo negativo en ninguna parte.

¿Por qué una biblioteca de rutinas numéricas daría resultados diferentes en un sistema operativo de 32 bits y en un sistema de 64 bits?

ACLARACIÓN

Me temo que no he sido lo suficientemente claro: tenemos Git commit 2f3f671 que usa doble precisión, y donde las pruebas unitarias pasan igualmente bien en ambas máquinas. Luego tenemos Git commit 46f2badonde cambiamos a precisión simple, y aquí las pruebas todavía pasar la máquina de 64 bits pero no en la máquina de 32 bits.

  • ¿Estás seguro de que es el bittage del sistema operativo y no las diferencias de hardware?

    – rotafolio

    21 de octubre de 2011 a las 9:13

  • Probablemente debido a esto: stackoverflow.com/questions/1076190/… , (el código de 32 bits usa el coprocesador 387, el código de 64 bits podría usar sse)

    – nos

    21 de octubre de 2011 a las 9:29


  • nos es el único que acertó en esto. Las respuestas dadas son incorrectas.

    – R.. GitHub DEJA DE AYUDAR A ICE

    21 de octubre de 2011 a las 9:52

  • En vista del comentario de nos, probablemente debería analizar el efecto que tienen las opciones de optimización para la corrección de su código. Gcc tiene algunos que manejan el comportamiento de las operaciones de coma flotante. Intente leer el ensamblador que se produce y vea si difiere significativamente entre las dos arquitecturas.

    – Jens Gusted

    21 de octubre de 2011 a las 10:05

Se está encontrando con lo que a menudo se denomina el “error” de exceso de precisión x87.

En resumen: históricamente, (casi) todos los cálculos de punto flotante en los procesadores x86 se realizaban utilizando el conjunto de instrucciones x87, que de forma predeterminada opera en un tipo de punto flotante de 80 bits, pero se puede configurar para operar en uno o dos. -precisión (casi) por algunos bits en un registro de control.

Si se realizan operaciones de precisión simple mientras la precisión del registro de control x87 está establecida en precisión doble o extendida, los resultados diferirán de los que se producirían si se realizaran las mismas operaciones en precisión simple (a menos que el compilador esté extraordinariamente cuidadoso y almacena el resultado de cada cálculo y lo vuelve a cargar para forzar el redondeo en el lugar correcto).

Su código que se ejecuta en 32 bits está utilizando la unidad x87 para el cálculo de coma flotante (aparentemente con el registro de control configurado para doble precisión) y, por lo tanto, se encuentra con el problema descrito anteriormente. Su código que se ejecuta en 64 bits está usando el SSE[2,3,…] instrucciones para el cálculo de punto flotante, que proporcionan operaciones nativas de precisión simple y doble y, por lo tanto, no tienen exceso de precisión. Es por eso que sus resultados difieren.

Puede evitar esto (hasta cierto punto) diciéndole a su compilador que use SSE para el cálculo de punto flotante incluso en 32 bits (-mfpmath=sse con CCG). Incluso entonces, los resultados con precisión de bit no están garantizados porque las diversas bibliotecas con las que se vincula pueden usar x87, o simplemente usar diferentes algoritmos según la arquitectura.

  • Dios mío, tienes razón. agregando -mfpmath=sse (pero junto con -msse, según la página de manual de gcc) lo hace pasar a la máquina de 32 bits. Gracias, gracias, gracias

    – Lindelof

    21 de octubre de 2011 a las 10:26


  • ¿Tiene enlaces a artículos sobre por qué se mudaron de FPU a SSE?

    – Skizz

    21 de octubre de 2011 a las 12:08

  • @Skizz: Sin enlaces, pero “porque es mejor en casi todos los sentidos”. SSE no sufre de exceso de precisión, puede redondear a tipos más pequeños sin necesidad de almacenar, tiene un mejor soporte para el manejo de NaN, es más rápido, no tiene tantas paradas ocultas, admite conversiones entre punto flotante y entero, requiere menos tráfico de memoria, …

    – Esteban Canon

    21 de octubre de 2011 a las 12:17


IIRC, la precisión de ‘doble’ es solo requerido ser >= la precisión de ‘float’. Entonces, en una implementación, el número real de bits en ‘flotante’ y ‘doble’ puede ser el mismo, mientras que en el otro difieren. Esto probablemente esté relacionado con la diferencia de 32 bits/64 bits en las plataformas, pero puede que no sea así.

  • ¡¿Qué pasa con la votación negativa?! Me refiero a la definición del LENGUAJE C de tipos flotantes y dobles. Estos no TIENEN QUE asignarse a los tipos de precisión simple y doble precisión IEEE 754. Siempre que la precisión de double sea mejor o IGUAL A la precisión de float, la implementación se ajusta a la especificación C

    – Máx.

    21 de octubre de 2011 a las 10:11

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad