Question

J'ai un projet de logiciel dans lequel il m'arrive parfois d'obtenir d'étranges résultats avec de petites opérations en virgule flottante. Je suppose que quelque chose m'a échappé et j'aimerais quelques astuces sur la façon de déboguer les problèmes suivants:

(le compilateur utilisé est MS VC 6.0, c'est-à-dire la version 12 du compilateur Microsoft C)

Première anomalie:

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

Pour une raison quelconque, l'évaluation du minuteur a échoué et le code temporisé n'a jamais été exécuté. Dans le débogueur, il n’y avait aucun problème à voir que la condition de déclenchement était en réalité vraie, mais la FPU a refusé de trouver un résultat positif. Le segment de code suivant n'a eu aucun problème bien qu'il ait effectué les mêmes opérations. Le problème a été évité en insérant une évaluation fictive qui pourrait échouer.

Je suppose que l'état de la FPU est quelque peu altéré par les opérations précédentes, et qu'il existe des indicateurs de compilateur qui pourraient vous aider?

Deuxième anomalie:

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

Le résultat est #IND, même si le débogueur évalue l'équation à environ 0,05. La valeur #IND apparaît dans la pile FPU lorsque la valeur 2.0F est chargée dans le FPU après avoir utilisé l'instruction fld. L'instruction précédente charge la valeur entière 2000 sous forme de double float à l'aide de l'instruction fild. Une fois que la pile FPU contient la valeur #IND, tout est perdu, mais une fois encore, le débogueur n'a aucun problème à évaluer la formule. Ces opérations renvoient ensuite les résultats escomptés.

En outre, encore une fois, les problèmes de FPU se produisent directement après l’appel de la fonction. Devrais-je insérer des opérations en virgule flottante qui effacent l'état de la FPU après chaque nouvelle fonction? Existe-t-il un indicateur de compilation susceptible d’affecter la FPU d’une certaine manière?

Je suis reconnaissant de tous les conseils et astuces à ce stade.

EDIT: J'ai réussi à éviter le problème en appelant la fonction d'assemblage EMMS en premier dans la fonction supérieure. De cette façon, la FPU est débarrassée de tout déchet lié à MMX qui peut avoir été créé ou non dans l'environnement à partir duquel mon code est appelé. Il semble que l’état de la FPU n’est pas à prendre pour acquis.

// Frank

Était-ce utile?

La solution

Si vous utilisez les fonctions Windows QueryPerformanceCounter et QueryPerformanceFrequency sur un système prenant en charge MMX, essayez d'insérer l'instruction femms après avoir interrogé la fréquence / le compteur et avant le calcul.

__asm femms

J'ai déjà rencontré des problèmes avec ces fonctions auparavant, où ils effectuaient un calcul 64 bits à l'aide de MMX sans effacer les indicateurs / états en virgule flottante.

Cette situation peut également se produire s'il existe une arithmétique de 64 bits entre les opérations en virgule flottante.

Autres conseils

Aucune idée du problème, mais sur x86, les instructions FINIT effacent la FPU. Pour tester votre théorie, vous pouvez l'insérer quelque part dans votre code:

__asm {
    finit
}

Ce n'est pas vraiment une réponse à votre question, mais vous voudrez peut-être consulter deux articles de Raymond Chen concernant le comportement étrange de la FPU. Après avoir lu votre question et relu les articles, je ne vois pas immédiatement de lien - mais si le code que vous avez collé n'est pas complet ou si les articles vous donnent une idée du comportement entourant l'origine du problème. . spécifiquement, si vous chargez une DLL n'importe où à proximité.

Les variables à virgule flottante non initialisées peuvent être mortelles

Comment l'exception d'opérande à virgule flottante non valide a-t-elle été déclenchée lorsque Je l'ai désactivé?

Bien que je ne vous fournisse pas de solution exacte, je vous suggère de commencer par lire ce article qui décrit les différentes optimisations que vous pouvez utiliser.

re: timestamps -

De quoi obtenez-vous votre source d'horodatages? Quelque chose semble suspect. Essayez de les enregistrer dans un fichier.

Si la valeur incorrecte est chargée par un fichier qui devrait charger la version 2.0, je vérifierai la mémoire à partir de laquelle cette valeur est chargée. Il pourrait s'agir simplement d'un problème de compilateur / éditeur de liens.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top