Mi problema esencial es cómo hacer que la aritmética con flotadores en x86 se comporte como un PowerPC, yendo de Classic MacOS (CodeWarrior) a Windows (VS 2008).Porte de código numérico powerpc a intel da diferentes resultados usando float
El código en cuestión, de los cuales hay muchos, tiene una pila de algoritmos que son altamente iterativos y numéricamente muy sensibles.
una línea compleja típica es:
Ims_sd = sqrt((4.0*Ams*sqr(nz)-8.0*(Ams+Dms)*nz+12.0*sqr(Ams))/
(4.0*sqr(Ams)*(sqr(nz)-1)) -
sqr(Ims_av))*sqrt(nz-1);
Está escrito usando un typedef'd float
como el tipo de base.
Cambiando a double
obtiene resultados muy similares en ambas plataformas, pero desafortunadamente los números no son aceptables por lo que no podemos tomar ese camino tan fácil.
El código de Mac se compila utilizando CodeWarrior y simplemente apagando la generación de las instrucciones FMADD & FMSUB tuvo un efecto drástico en los números creados. Por lo tanto, mi punto de partida fue buscar las opciones de Visual Studio (2008) que parecían más similares, asegurándome de que el fusionado add fuera en uso. Sospechamos que la clave está en el comportamiento del compilador al asignar almacenamiento intermedio en los cómputos
Actualmente, los mejores resultados se obtienen con una combinación de habilitar SSE2 y /fp:fast
. La habilitación de funciones intrínsecas hace que los valores se desvíen más de los valores de Mac.
La documentación del conmutador /fp dice que solo /fp:strict
desactiva el comportamiento de agregar fusionado.
MSDN habla de vincular FP10.OBJ "antes de LIBC.LIB, LIBCMT.LIB o MSVCRT.LIB". a garantizan una precisión de 64 bits. Al parecer, he logrado esto al especificar FP10.OBJ en el campo de entrada del enlazador (la salida del enlazador detallado lo muestra antes de MSVCRTD.lib).
también he ajustado precisión de 64 bits mediante la invocación de
_controlfp_s(&control_word, _PC_64, MCW_PC);
en DllMain.
Tenga en cuenta que el problema es no debido a diferencias en el manejo de excepciones de punto flotante entre plataformas, ni es debido a la forma (una delicia) que PowerPC permite la división por cero enteros (que acaban de volver a cero) ya que estas áreas ya han sido auditadas y dirigido, gracias enormemente al PC-Lint. El programa se ejecuta y produce resultados algo plausibles, pero no lo suficientemente buenos.
ACTUALIZACIÓN:
un interesante comentario de un amigo: Una posibilidad es que el PPC tiene un gran número de registros temporales que pueden almacenar valores intermedios de 64 bits mientras que el código x86 puede tener que descargar y volver a cargar el FPU (truncando a 4 bytes y perdiendo precisión).
Esta es la razón por la que SSE2 funciona mejor ya que (IIRC) tiene más registros y más posibilidades de preservar los valores intermedios.
Una posibilidad: ¿se puede compilar su código como de 64 bits? El modo x64 también tiene más registros para intermedios y mejores instrucciones de FP, por lo que puede estar más cerca del PPC en diseño y ejecución.
En realidad, las pruebas iniciales con una compilación de 64 bits se acercaron, como sugirió que podría ser (primero pensé que se sobrepasó, pero eso se debió a una configuración de modelado incorrecta).
Resolución Final
Estoy seguro de que cualquier persona interesada en este tema es lo suficientemente obsesivo que les gustaría saber cómo se resolvió todo en el final. El software está terminado y brinda resultados numéricos consistentes. Nunca pudimos obtener todos los algoritmos para entregar resultados idénticos a la Mac, pero estaban lo suficientemente cerca como para ser estadísticamente aceptable. Dado que el procesamiento es guiado por un usuario experto que selecciona las áreas de interés y que la contribución del usuario es en parte reactiva a la evolución del modelo, el director científico lo consideró aceptable (¡esta no fue una decisión de la noche a la mañana!). Las diferencias numéricas restantes están dentro de los límites de lo que determina los diferentes resultados clínicos, por lo que no se han observado diagnósticos diferentes con las pruebas.
+1 por una pregunta con una deliciosa cantidad de investigación y detalles, +1 nuevamente (si pudiera) para una pregunta tan nerd e interesante. . . pero desafortunadamente no puedo ayudar :( –
Tres días de sudor y un montón de "No lo creo" hasta ahora. –