Scegliere un epsilon quando si confrontano numeri in virgola mobile su sistemi diversi

0

Sto trascrivendo migliaia di righe di codice computazionale da MATLAB a C ++. Non capisco perfettamente la matematica da solo, ma posso eseguirlo con MATLAB, suppongo sia corretto e confrontare i risultati con il mio codice C ++.

Il problema è che la precisione che ottengo è molto incoerente. A volte MATLAB mi dà quattro cifre significative per un numero dell'ordine di 1e6, quindi devo usare un epsilon di 100. Altre volte, userò un epsilon di 1e-3, ma poi improvvisamente ci sarà un valore che solo abbastanza diversi da richiedermi di farlo risalire fino a 1e-2.

Ci sono potenziali problemi con la regolazione dell' epsilon dei miei test su un valore che passa? C'è un approccio più affidabile?

    
posta JETM 30.06.2016 - 14:02
fonte

3 risposte

5

Dai commenti che ci siamo scambiati, sembra che tu non sia poco familiare con la matematica, ma anche con la disciplina di calcolo numerico di base.

Innanzitutto, per l'amor di dio, non selezionare automaticamente un epsilon per far "passare" i test. Se elimini gli epsiloni fino a quando l'errore non è sotto epsilon, i tuoi test non testano nulla e potresti ignorare problemi di precisione davvero pessimi (forse anche un algoritmo sbagliato se si verificano risultati simili in i tuoi casi di test).

Scegli invece epsiloni ragionevoli a priori e rispettali . Se ottieni errori più gravi di quanto ti aspetti o ti aspetti, ciò significa che devi correggere il tuo codice, non abbassare le tue aspettative . Purtroppo, quali aspettative sono "ragionevoli" dipende dall'applicazione e dall'algoritmo, ma per impostazione predefinita mi aspetterei, per esempio, un errore relativo inferiore a 1e-12 se i float sono a 64 bit.

In secondo luogo, la parola chiave è un errore relativo . L'errore assoluto è, come hai visto, molto sensibile alla grandezza dei valori, e quindi spesso inutile. Inoltre, a causa di come funziona il floating point, c'è un errore relativo fisso che non si può battere a meno che non si produca lo stesso esatto pattern di bit (per i float a 64 bit, si tratta di 1e-17 ). Quindi, se i numeri sono abbastanza grandi, scoprirai che il tuo errore assoluto è zero (improbabile) o piuttosto grande, anche se il calcolo potrebbe essere solo di un'unità nell'ultimo posto (ULP).

Per questo, dovresti anche forzare MATLAB a generare più cifre (17 è il numero massimo che ha senso per i float a 64 bit). Oh, e i calcoli relativi all'errore relativo possono essere piuttosto complicati, come sottolinea anche @CodeInChaos, quindi potresti voler fare affidamento su algoritmi esistenti che gestiscono casi limite meglio degli approcci ingenui, come link

    
risposta data 30.06.2016 - 15:06
fonte
2

Usando doppia precisione punti fluttuanti in entrambi i programmi (che è lo standard in MATLAB) sullo stesso l'hardware per un algoritmo deterministico è un requisito minimo per ottenere risultati simili in entrambi i programmi, presupponendo che tu sia molto convinto nell'implementare ogni operazione di calcolo dal tuo programma MATLAB in modo 1: 1 nel tuo programma C ++.

Tuttavia, devi capire la matematica che stai facendo almeno al punto in cui sei sicuro che i tuoi algoritmi non mostrino alcuni aspetti instabili o caotico comportamento, altrimenti la minima differenza in alcuni valori di input o implementazione interna può comportare una differenza molto più grande per i risultati di quanto ci si potrebbe aspettare. Ho visto questo tipo di effetti, ad esempio, anche nello stesso programma , con un algoritmo deterministico , semplicemente compilandolo ed eseguendolo in modalità "debug" vs. rilascia "mode.

La migliore raccomandazione che posso darti per una tale situazione è l'ampia registrazione dei valori intermedi in entrambi i programmi e confrontare i risultati per scoprire quali operazioni si comportano diversamente, in modo da poter adattare l'implementazione del C ++ e renderla più simile al Codice MATLAB.

    
risposta data 30.06.2016 - 14:49
fonte
1

Potresti usare un errore relativo.

abs(actual / correct - 1) < epsilon

Ma questo non funziona bene se correct è molto piccolo. Quindi potresti avere sia un epsilon assoluto che relativo, accettando il risultato se è più piccolo di almeno uno di essi.

    
risposta data 30.06.2016 - 15:05
fonte

Leggi altre domande sui tag