Domanda

Ho un progetto software in cui a volte ottengo strani risultati da piccole e semplici operazioni in virgola mobile. Presumo che ci sia qualcosa che mi è sfuggito e vorrei alcuni consigli su come eseguire il debug dei seguenti problemi:

(il compilatore utilizzato è MS VC 6.0, ovvero la versione 12 del compilatore Microsoft C)

Prima anomalia:

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

Per qualche motivo, la valutazione del timer non è riuscita e il codice temporizzato non è mai stato eseguito. Nel debugger, non vi è stato alcun problema nel vedere che le condizioni di attivazione erano effettivamente vere, ma la FPU ha rifiutato di trovare un risultato positivo. Il seguente segmento di codice non ha avuto problemi sebbene abbia eseguito le stesse operazioni. Il problema è stato eluso inserendo una valutazione fasulla che poteva essere lasciata fallire.

Suppongo che lo stato della FPU sia in qualche modo contaminato da precedenti operazioni eseguite e che ci siano alcuni flag del compilatore che potrebbero aiutare?

Seconda anomalia:

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

Il risultato è #IND, anche se il debugger valuta l'equazione a circa 0,05. Il valore #IND appare nello stack FPU quando il valore 2.0F viene caricato nell'FPU dall'uso dell'istruzione fld. L'istruzione precedente carica il valore intero 2000 come doppio float usando l'istruzione fild. Una volta che lo stack FPU contiene il valore #IND, tutto viene perso, ma ancora una volta il debugger non ha problemi a valutare la formula. Successivamente, queste operazioni restituiscono i risultati previsti.

Inoltre, ancora una volta i problemi FPU si verificano direttamente dopo la chiamata di funzione. Devo inserire operazioni in virgola mobile che cancellano lo stato FPU dopo ogni nuova funzione? Esiste un flag di compilazione che potrebbe influire in qualche modo sulla FPU?

Sono grato a tutti i trucchi e suggerimenti a questo punto.

EDIT: sono riuscito a evitare il problema chiamando la funzione assembly EMMS come prima cosa nella funzione top. In questo modo la FPU viene cancellata da qualsiasi immondizia correlata a MMX che potrebbe essere stata o meno creata nell'ambiente da cui viene chiamato il mio codice. Sembra che lo stato della FPU non sia qualcosa da dare per scontato.

// Frank

È stato utile?

Soluzione

Se stai usando le funzioni Windows QueryPerformanceCounter e QueryPerformanceFrequency su un sistema che supporta MMX prova a inserire l'istruzione femms dopo aver interrogato la frequenza / contatore e prima del calcolo.

__asm femms

Ho riscontrato problemi con queste funzioni in precedenza quando eseguivano il calcolo a 64 bit utilizzando MMX e non cancellando i flag / stato in virgola mobile.

Questa situazione potrebbe verificarsi anche in presenza di aritmetica a 64 bit tra le operazioni in virgola mobile.

Altri suggerimenti

Non ho idea di quale possa essere il problema, ma su x86, le istruzioni FINIT cancellano la FPU. Per testare la tua teoria, puoi inserirla da qualche parte nel tuo codice:

__asm {
    finit
}

Non è proprio una risposta alla tua domanda, ma potresti voler esaminare due degli articoli di Raymond Chen riguardanti strani comportamenti FPU. Dopo aver letto la tua domanda e riletto gli articoli, non vedo immediatamente un link, ma se il codice che hai incollato non è completo o se gli articoli ti danno un'idea di alcuni comportamenti circostanti che hanno causato il problema. in particolare, se stai caricando una DLL ovunque nelle vicinanze.

Le variabili in virgola mobile non inizializzate possono essere mortali

Come è stata sollevata l'eccezione dell'operando in virgola mobile non valida quando L'ho disabilitato?

Anche se non ti sto fornendo una soluzione esatta, ti suggerisco di iniziare leggendo questo articolo che descrive le diverse ottimizzazioni che si possono usare.

re: timestamps

Da cosa stai ottenendo la tua fonte di timestamp? Qualcosa sembra sospetto. Prova a registrarli in un file.

Se il valore errato viene caricato da un fld che dovrebbe caricare 2.0, verificherei la memoria da cui viene caricato questo valore - potrebbe essere solo un problema di compilatore / linker.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top