2012-12-08 12 views
10

Quindi ero in un concorso di informatica e ho notato un bug strano. pow (26,2) restituirebbe sempre 675 e talvolta 674? anche se la risposta corretta è 676. Questi errori si verificano anche con pow (26,3), pow (26,4), ecc. Dopo aver effettuato il debug dopo il concorso, credo che la risposta abbia a che fare con il fatto che int annota. È interessante notare che questo tipo di errore non mi è mai accaduto prima. Il computer che avevo era in esecuzione mingw su Windows 8. La versione GCC era abbastanza nuova, come credo di 2-3 mesi. Ma quello che ho trovato è che se avessi girato la bandiera di ottimizzazione o1/o2/o3 su questo tipo di errore sarebbe miracolosamente scomparso. pow (26,2) otterrebbe sempre 676, ovvero la risposta corretta. Qualcuno può spiegare perché?GCC C++ precisione Pow

#include <cmath> 
#include <iostream> 

using namespace std; 
int main() { 
    cout<<pow(26,2)<<endl; 
    cout<<int(pow(26,2))<<endl; 
} 

I risultati con i doppi sono strani.

double a=26; 
double b=2; 
cout<<int(pow(a,b))<<endl; #outputs 675 
cout<<int(pow(26.0,2.0))<<endl; # outputs 676 
cout<<int(pow(26*1.00,2*1.00))<<endl; # outputs 676 
+2

'pow (26,2)' come in 26 * 26 = 676? –

+0

sì, pow come nella funzione di potenza standard. –

+0

Puoi pubblicare il tuo codice? Non sono sicuro di come otterresti questi valori. –

risposta

10

La funzione pow opera su due valori in virgola mobile e può sollevarsi l'uno con l'altro. Ciò avviene tramite algoritmo di approssimazione, in quanto è necessario essere in grado di gestire i valori dal più piccolo al più grande.

Poiché si tratta di un algoritmo approssimativo, a volte ottiene il valore un po 'errato. Nella maggior parte dei casi, questo è OK. Tuttavia, se sei interessato a ottenere un risultato esatto, non usarlo.

Vorrei fortemente evitare di usarlo per interi. E se il secondo operando è noto (2, in questo caso) è banale sostituirlo con codice che lo fa molto più velocemente e che restituisce il valore corretto. Ad esempio:

int square(int x) 
{ 
    return x * x; 
} 

Per rispondere alla domanda attuale: Alcuni compilatori possono sostituire le chiamate a pow con altro codice, o eliminare tutti insieme, quando uno o entrambi gli argomenti sono noti. Questo spiega perché ottieni risultati diversi.

+1

Un motivo particolare per cui si consiglia di utilizzare una macro e non una funzione? – NPE

+1

Inoltre, vorrei sostituire * è noto * con * è un numero intero piccolo noto *. Non è molto utile se è conosciuto o è grande o frazionario. – NPE

+0

@NPE, ho scelto una macro poichè è di tipo neutro, ed è stato facile digitare :). Naturalmente, se si conosce il tipo è possibile definire una funzione, in alternativa una serie di funzioni sovraccariche o anche una funzione di modello. – Lindydancer