2012-12-08 22 views
10

Więc byłem w konkursie komputerowym i zauważyłem dziwny błąd. pow (26,2) zawsze zwróci 675, a czasami 674? mimo że poprawna odpowiedź to 676. Tego rodzaju błędy występują również przy pow (26,3), pow (26,4) itd. Po pewnym debugowaniu po zawodach sądzę, że odpowiedź ma związek z faktem, że rundy są mniejsze. Co ciekawe, tego rodzaju błąd nigdy wcześniej mi się nie zdarzył. Komputer, który miałem uruchomił mingw na Windows 8. Wersja GCC była całkiem nowa, jak sądzę, 2-3 miesiące. Ale odkryłem, że jeśli zmienię flagę optymalizacji o1/o2/o3 na tego rodzaju błąd, to cudem zniknę. pow (26,2) zawsze dostanie 676 aka poprawnej odpowiedzi Czy ktokolwiek może wyjaśnić dlaczego?GCC C++ pow dokładność

#include <cmath> 
#include <iostream> 

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

Wyniki z gry podwójnej są dziwne.

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)' jak w 26 * 26 = 676? –

+0

tak, pow jak w standardowej funkcji zasilania. –

+0

Czy możesz opublikować swój kod? Nie jestem pewien, w jaki sposób zdobędziesz te wartości. –

Odpowiedz

10

Funkcja pow działa na dwóch wartościach zmiennoprzecinkowych i może podnosić jeden do drugiego. Odbywa się to za pomocą algorytmu przybliżania, ponieważ jest on wymagany do obsługi wartości od najmniejszej do największej.

Ponieważ jest to algorytm aproksymujący, czasami jego wartość jest trochę zła. W większości przypadków jest to OK. Jeśli jednak jesteś zainteresowany uzyskaniem dokładnego wyniku, nie używaj go.

Zdecydowanie radzę unikać używania go w liczbach całkowitych. A jeśli drugi operand jest znany (w tym przypadku 2), zastąpienie go kodem znacznie szybszym i zwracającym prawidłową wartość jest trywialne. Na przykład:

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

Aby odpowiedzieć na rzeczywiste pytanie: Niektóre kompilatory może zastąpić wywołań pow z innym kodem lub wyeliminować je wszystkie razem, gdy znane są jeden lub oba argumenty. To wyjaśnia, dlaczego otrzymujesz różne wyniki.

+1

Jakiś konkretny powód, dla którego zalecamy używanie makra, a nie funkcji? – NPE

+1

Ponadto, chciałbym wymienić * jest znany * z * jest znaną małą liczbą całkowitą *. Nie jest to zbyt użyteczne, jeśli wiadomo, że jest duże lub ułamkowe. – NPE

+0

@NPE, wybrałem makro, ponieważ jest ono neutralne i łatwo było wpisać :). Oczywiście, jeśli znasz typ, możesz zdefiniować funkcję, alternatywnie zestaw przeciążonych funkcji, a nawet funkcję szablonu. – Lindydancer