2010-05-03 11 views
6

Odważyłbym się powiedzieć, że wartości numeryczne obliczone przez Fortran i C++ będą bardziej podobne. Jednak z tego, czego doświadczam, okazuje się, że obliczone liczby zaczynają się rozchodzić po zbyt małej liczbie cyfr dziesiętnych. Natknąłem się na ten problem podczas przenoszenia starego kodu z poprzedniego do drugiego. Oryginalny kod Fortran 77 ...Rozbieżności między wartościami obliczonymi przez Fortran i C++

INTEGER M, ROUND 
    DOUBLE PRECISION NUMERATOR, DENOMINATOR 

    M = 2 
    ROUND = 1 
    NUMERATOR=5./((M-1+(1.3**M))**1.8) 
    DENOMINATOR = 0.7714+0.2286*(ROUND**3.82) 
    WRITE (*, '(F20.15)') NUMERATOR/DENOMINATOR 
    STOP 

... wyjścia ,842201471328735, podczas gdy jego odpowiednik C++ ...

int m = 2; 
int round = 1; 
long double numerator = 5.0/pow((m-1)+pow(1.3, m), 1.8); 
long double denominator = 0.7714 + 0.2286 * pow(round, 3.82); 
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(15) 
      << numerator/denominator << std::endl; 
exit(1); 

... zwraca 0.842201286195064. Oznacza to, że obliczone wartości są równe tylko do szóstej cyfry dziesiętnej. Chociaż nie jestem szczególnie zwolennikiem Fortranu, czuję się skłonny do uznania jego wyników za "prawidłowe", biorąc pod uwagę jego wiarygodną reputację "cruncher liczby". Intryguje mnie jednak przyczyna tej różnicy między wyliczonymi wartościami. Czy ktoś wie, jaka może być przyczyna tej rozbieżności?

+1

http://docs.sun.com/source/806-3568/ncg_goldberg.html –

+0

C++ wynik jest bardziej poprawne '0.8422012861950640318689334181' – jfs

+0

Może wydrukować niektóre wartości pośrednie w obu zestawach kodu. –

Odpowiedz

11

W języku Fortran domyślnie literały zmiennopozycyjne są pojedynczą precyzją, natomiast w języku C/C++ są podwójną precyzją.

Tak więc w kodzie Fortrana wyrażenie do obliczania NUMERATORA jest wykonywane z pojedynczą precyzją; jest ona przekształcana tylko w podwójną precyzję, gdy przypisujemy końcowy wynik do zmiennej NUMERATOR.

To samo dotyczy wyrażenia obliczającego wartość przypisaną do zmiennej DENOMINATOR.

+1

Dokładnie. Jest to częsty błąd - wyrażenie po prawej stronie nie "wie", że zmienna po lewej to podwójna precyzja. Metoda FORTRAN 77 określająca, że ​​stała zmiennoprzecinkowa jest podwójną precyzją, to dodanie sufiksu "D0" - spróbuj dodać to do starego kodu FORTRAN. –

+0

Dziękuję wam obojgu. Również, dla celów porównawczych, i jak wskazał J.F. Sebastian, -fdefault-real-8 może być użyty podczas kompilacji z gfortran w celu użycia literówek zmiennoprzecinkowych podwójnej precyzji. – plok

+0

Wiem, że to stary wątek, ale nauczyłem się dzisiaj czegoś bardzo cennego, co naprawia rozbieżności, które mamy w naszym kodzie. Dzięki @ M.S.B. dla końcówki "D0". – jitihsk

Powiązane problemy