Pregunta

Tengo un proyecto de software en el que a veces obtengo resultados extraños de operaciones pequeñas y simples de coma flotante. Supongo que hay algo que me he perdido, y me gustaría obtener algunos consejos sobre cómo depurar los siguientes problemas:

(el compilador utilizado es MS VC 6.0, es decir, la versión 12 del compilador de Microsoft C)

Primera anomalía:

extern double Time, TimeStamp, TimeStep;  // History terms, updated elsewhere
void timer_evaluation_function( ) {
    if ( ( Time - TimeStamp ) >= TimeStep ) {  
        TimeStamp += TimeStep;  
        timer_controlled_code( );  
    }
{....}

Por alguna razón, la evaluación del temporizador falló y el código temporizado nunca se ejecutó. En el depurador, no hubo ningún problema para ver que la condición trigonométrica era de hecho cierta, pero la FPU se negó a encontrar un resultado positivo. El siguiente segmento de código no tuvo problemas, aunque realizó las mismas operaciones. El problema se evitó insertando una evaluación falsa que podría fallar.

Supongo que el estado de la FPU está de alguna manera contaminado por operaciones anteriores realizadas, y que hay algunos indicadores del compilador que ayudarían.

Segunda anomalía:

double K, Kp = 1.0, Ti = 0.02;
void timed_code( ){
    K = ( Kp * ( float ) 2000 ) / ( ( float ) 2000 - 2.0F * Ti * 1e6 )
{....}

El resultado es #IND, aunque el depurador evalúa la ecuación a aproximadamente 0.05. El valor #IND aparece en la pila de FPU cuando el valor 2.0F se carga en la FPU al usar la instrucción fld. La instrucción anterior carga el valor entero 2000 como un flotante doble utilizando la instrucción fild. Una vez que la pila FPU contiene el valor #IND, todo se pierde, pero una vez más, el depurador no tiene problemas para evaluar la fórmula. Más tarde, estas operaciones devuelven los resultados esperados.

Además, una vez más, los problemas de FPU ocurren directamente después de la llamada a la función. ¿Debo insertar operaciones de punto flotante que borren el estado de FPU después de cada nueva función? ¿Hay un indicador del compilador que podría afectar a la FPU de alguna manera?

Estoy agradecido de todos y cada uno de los consejos y trucos en este momento.

EDITAR: He logrado evitar el problema llamando a la función de ensamblaje EMMS en primer lugar en la función superior. De esa manera, la FPU se limpia de cualquier basura relacionada con MMX que se haya creado o no en el entorno desde el que se llama mi código. Parece que el estado de la FPU no es algo que se dé por sentado.

// Frank

¿Fue útil?

Solución

Si está utilizando las funciones Windows QueryPerformanceCounter y QueryPerformanceFrequency en un sistema que admite MMX, intente insertar la instrucción femms después de consultar la frecuencia / contador y antes del cálculo.

__asm femms

He encontrado problemas con estas funciones antes, donde estaban haciendo cómputos de 64 bits usando MMX y no borrando los indicadores / estado de coma flotante.

Esta situación también podría ocurrir si hay alguna aritmética de 64 bits entre las operaciones de coma flotante.

Otros consejos

No tengo idea de cuál podría ser el problema, pero en x86, las instrucciones FINIT borran la FPU. Para probar su teoría, puede insertar esto en algún lugar de su código:

__asm {
    finit
}

No es realmente una respuesta a su pregunta, pero es posible que desee ver dos de los artículos de Raymond Chen sobre el extraño comportamiento de la FPU. Después de leer su pregunta y volver a leer los artículos, no veo un enlace de inmediato, pero si el código que ha pegado no está completo o si los artículos le dan una idea sobre el comportamiento circundante que causó el problema ... específicamente, si está cargando una DLL en cualquier lugar cercano.

Las variables de punto flotante no inicializadas pueden ser mortales

¿Cómo surgió la excepción de operando de coma flotante no válida cuando ¿Lo deshabilité?

Si bien no le estoy brindando una solución exacta, le sugiero que comience leyendo esto artículo que describe las diferentes optimizaciones que uno puede usar.

re: marcas de tiempo--

¿De dónde obtiene su fuente de marcas de tiempo? Algo suena sospechoso. Intente iniciar sesión en un archivo.

Si el valor incorrecto es cargado por un fld que debería cargar 2.0, comprobaría la memoria desde donde se carga este valor, podría ser un problema de compilador / enlazador.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top