¿Coaccionar el punto flotante para ser determinista en .NET?

He estado leyendo mucho sobre el determinismo de punto flotante en .NET, es decir, asegurándome de que el mismo código con las mismas entradas dará los mismos resultados en diferentes máquinas. Como .NET carece de opciones como fpstrict de Java y fp de MSVC: estricto,el consenso parece ser que no hay forma de evitar este problema utilizando código administrado puro. El juego de C # AI Wars se ha decidido a usarMatemáticas de punto fijo en cambio, pero esta es una solución engorrosa.

El problema principal parece ser que el CLR permite que los resultados intermedios vivan en registros de FPU que tienen una precisión mayor que la precisión nativa del tipo, lo que lleva a resultados de precisión impredeciblemente más altos. UnArtículo de MSDN por el ingeniero CLR David Notario explica lo siguiente:

Tenga en cuenta que con la especificación actual, sigue siendo una opción de idioma para dar "previsibilidad".El lenguaje puede insertar instrucciones conv.r4 o conv.r8 después de cada operación de PF para obtener un comportamiento "predecible". Obviamente, esto es realmente costoso, y diferentes idiomas tienen diferentes compromisos. C #, por ejemplo, no hace nada, si desea reducir, tendrá que insertar (flotar) y (doble) moldes a mano.

Esto sugiere que se puede lograr un determinismo de punto flotante simplemente insertando conversiones explícitas para cada expresión y subexpresión que se evalúa para flotar. Uno podría escribir un tipo de envoltorio alrededor de float para automatizar esta tarea. ¡Esta sería una solución simple e ideal!

Sin embargo, otros comentarios sugieren que no es tan simple.Eric Lippert declaró recientemente (énfasis mío):

en alguna versión del tiempo de ejecución, la conversión a flotar da explícitamente un resultado diferente al no hacerlo. Cuando explícitamente lanzas para flotar, el compilador de C #da una pista al tiempo de ejecución para decir "saque esta cosa del modo de precisión extra alta si está utilizando esta optimización".

¿Qué es esta "pista" para el tiempo de ejecución? ¿La especificación de C # estipula que una conversión explícita a flotar provoca la inserción de un conv.r4 en el IL? ¿La especificación CLR estipula que una instrucción conv.r4 hace que un valor se reduzca a su tamaño nativo? Solo si ambos son verdaderos, podemos confiar en los lanzamientos explícitos para proporcionar una "previsibilidad" de punto flotante, como lo explicó David Notario.

Finalmente, incluso si podemos forzar todos los resultados intermedios al tamaño nativo del tipo, ¿es esto suficiente para garantizar la reproducibilidad en las máquinas, o existen otros factores como la configuración en tiempo de ejecución de la FPU / SSE?

Respuestas a la pregunta(2)

Su respuesta a la pregunta