2016-04-19 27 views
5

Sto per sviluppare un calcolatore scientifico. La mia domanda è: Come posso distinguere zero risultato da numeri molto piccoli usando il numero float?Come distinguere lo zero da un numero molto piccolo in forma fluttuante

Ad esempio, per 0.3 - 0.2 - 0.1, il risultato è qualcosa come 1E-19, che non è puro zero (problema di precisione, ovviamente). Voglio stampare il risultato (0.0). Quindi uso EPSILON per fare il confronto con zero.

Il problema è, per il calcolo: 3E-19 - 2E-19 il risultato dovrebbe essere 1E-19. Dovrei stampare il risultato esatto (anche se piccolo) 1E-19. Ma se utilizzo ancora il confronto EPSILON, il risultato è forzato a zero.

Quindi, ancora una volta, la mia domanda è: come posso fare il controllo per numeri zero e molto piccoli?

+0

L'utilizzo dell'aritmetica a virgola mobile è un requisito rigoroso nel progetto o sarebbe disposto a considerare implementazioni aritmetiche alternative? – ApproachingDarknessFish

+0

Prenderò in considerazione la manipolazione delle stringhe o l'utilizzo di una libreria come GMP. – Chirality

risposta

5

Questo non è possibile se si utilizza il tipo di dati in virgola mobile binario.

Invece, se si desidera un controllo preciso su precisione numerica e arrotondamento, è necessario utilizzare una libreria decimale, ad esempio GNU Multiprecision (GMP) o Boost.Multiprecision.

+0

Sì, grazie. Penso che dovrei provare a utilizzare GMP. Non l'ho mai usato prima. Grazie. –

0

Nel caso in cui non lo si trovi, this page è in pratica l'ultima parola nel confronto in virgola mobile.

Tuttavia, penso che il tuo problema si limiti a sapere quale precisione è necessaria in base agli operandi e alle operazioni che sono state eseguite. Potresti essere in grado di giudicarlo dal più grande ULP tra operandi. Se tra gli operandi è presente un ULP di grandi dimensioni, potrebbe essere necessario visualizzare una risposta più precisa (fino al limite di precisione disponibile in floating per le rappresentazioni). Può valere la pena sperimentare qualcosa in questo senso.

2

Hai detto che 0.3-0.2-0.1 non è 0 ma piuttosto 1E-19. In realtà è già float (0.3) -float (0.2) -float (0.1) che non è più 0. A meno che tu non controlli esplicitamente se 0.3 possa essere codificato in float o double losslessly allora non c'è modo di verificare se il tuo piccolo numero ottenere dopo il calcolo è dovuto a errore di operando o davvero un piccolo numero.

0

Certamente la calcolatrice scientifica verrà eseguito in questo problema con le equazioni come 1.0 - 7*(1.0/7.0)indipendentemente se il codice utilizza double (binari FP) o ad alta precisione librerie di base 2, 10.

Utilizzare un decimale biblioteca punto floating a minimizzare l'occorrenza di problemi di errore di arrotondamento con input decimali come 0.1, 0.2, 0.3.

"Voglio stampare il risultato (0.0), quindi utilizzo EPSILON per fare il confronto con zero." fallisce in quanto i numeri FP hanno una distribuzione logaritmica.

Considerazione: Consente all'utente per controllare il formato del visualizzata uscita. In sostanza ciò consente all'utente di impostare EPSILON. Per esempio. "%.17f" e 0.3 - 0.2 - 0.1 verranno visualizzati zero.

+0

"Consenti all'utente di controllare il formato" comporta che l'utente possa ancora scoprire che la calcolatrice è "scarsa precisione". T.T –

+0

@guan boshen L'accuratezza "scarsa" deriva dall'utilizzo di virgola mobile (in qualsiasi base) per nascondere un numero (testo "0,1") in un numero interno non esattamente rappresentabile come 'double'. Questa è la fonte del problema. A seconda degli obiettivi di codifica, ci sono varie soluzioni - alcune certamente più facili/più portatili di altre. Anche se il codice utilizza un virgola mobile in base 10, lo stesso problema si verifica dato che 1) la precisione dell'ingresso del testo può superare la rappresentazione interna e 2) alcuni risultati non sono rappresentabili finiti '1.0/7.0'. L'utente può __still__ scoprire che la calcolatrice è "scarsa precisione" – chux

+0

Sì, conosci molto di GMP? Con GMP, posso specificare il numero esatto di "cifre significative"? Ad esempio, 1.23456789E-19 ha 9 cifre significative. –

Problemi correlati