Sto lavorando a un calcolo scientifico & progetto di visualizzazione in C# /. NET, e usiamo double
s per rappresentare tutte le quantità fisiche. Dal momento che i numeri in virgola mobile sono sempre un po 'di arrotondamento, abbiamo metodi semplici per fare confronti di uguaglianza, come ad esempio:Gestione degli errori in virgola mobile in .NET
static double EPSILON = 1e-6;
bool ApproxEquals(double d1, double d2) {
return Math.Abs(d1 - d2) < EPSILON;
}
Piuttosto standard.
Tuttavia, ci troviamo costantemente a dover regolare la grandezza di EPSILON
quando incontriamo situazioni in cui l'errore di quantità "uguali" è maggiore di quanto avevamo previsto. Ad esempio, se si moltiplicano 5 grandi double
s e poi si dividono 5 volte, si perde molta precisione. È arrivato al punto in cui non siamo in grado di rendere EPSILON troppo più grande o ci darà falsi positivi, ma otteniamo anche falsi negativi.
In generale, il nostro approccio è stato quello di cercare altri algoritmi numericamente stabili con cui lavorare, ma il programma è molto computazionale e c'è solo così tanto che siamo stati in grado di fare.
Qualcuno ha qualche buona strategia per affrontare questo problema? Ho esaminato un po 'il tipo Decimal
, ma sono preoccupato per le prestazioni e in realtà non ne so abbastanza per sapere se risolverebbe il problema o lo oscurasse solo. Sarei disposto ad accettare un hit moderato (ad esempio 2x) andando a Decimal
se risolverà questi problemi, ma le prestazioni sono sicuramente una preoccupazione e poiché il codice è per lo più limitato dall'aritmetica in virgola mobile, non credo è una preoccupazione irragionevole. Ho visto persone citando una differenza di 100x, che sarebbe sicuramente inaccettabile.
Inoltre, il passaggio a Decimal
ha altre complicazioni, come la mancanza generale di supporto nella libreria Math
, quindi dovremmo scrivere la nostra funzione radice quadrata, ad esempio.
Qualche consiglio?
EDIT: a proposito, il fatto che io stia utilizzando un epsilon costante (invece di un confronto relativo) non è il punto della mia domanda. L'ho appena messo lì come esempio, non è in realtà uno snippit del mio codice. Passare a un confronto relativo non farebbe la differenza per la domanda, perché il problema deriva dalla perdita di precisione quando i numeri diventano molto grandi e poi di nuovo piccoli. Ad esempio, potrei avere un valore 1000 e quindi eseguo una serie di calcoli su di esso che dovrebbe risultare esattamente nello stesso numero, ma a causa della perdita di precisione ho effettivamente 1001. Se poi vado a confrontare quei numeri, non lo fa Non importa se uso un confronto relativo o assoluto (a patto che abbia definito i confronti in modo significativo per il problema e la scala).
In ogni caso, come suggerito da Mitch Wheat, il riordino degli algoritmi ha aiutato i problemi.
@nobugz: se la senti forte, ripristina la tua risposta e rimuoverò il downvote. –
@ Mark ad alte prestazioni: questo commento era destinato all'OP? –
Beh, ho esaminato i nostri algoritmi e ho fatto un po 'di riordinamento come suggerito, e sembra aver aiutato. Ho iniziato a lavorare su quell'articolo, anche se non è esattamente una lettura leggera! Grazie per l'aiuto. –