2014-06-30 9 views
5

Próbuję porównać czasy obliczeń prostego kodu do obliczenia sumy kostek liczb całkowitych przy użyciu zarówno Fortran 90 i C++, ponieważ słyszałem, że są one szybkie na podobnych poziomach. Używam gfortran i g ++ (na Mac OSX), aby skompilować te kody.Jak mogę przyspieszyć ten prosty 90-bitowy kod?

Czy ktoś może wskazać, dlaczego kod Fortran 90 zajmuje o wiele więcej czasu (49 sekund) niż odpowiadający mu kod C++ (12 sekund)? Jedyne, co wiem, że C++ jest wierszem głównym, a Fortran jest kolumną główną, ale nie sądzę, że jest to istotne dla tych kodów. Jak mogę przyspieszyć ten kod fortran90? Wszelkie wskazówki zostaną docenione. Dzięki.

Fortran kod i kompilacji z gfortran -o bb1 code15.f90

program code15 
implicit none 

double precision, dimension(:), allocatable :: a 
integer (kind=8) :: n,i 
real (kind=16) :: ssum 
real :: ts1, ts2 

call cpu_time(ts1) 
n = 1600000000 
allocate(a(n)) 
ssum=0.0 

do i=1,n 
    a(i)=i 
    ssum=ssum+a(i)*a(i)*a(i) 
end do 

print *, 'final sum ', ssum 
deallocate(a) 
call cpu_time(ts2) 
print *,'the time taken is ',ts2-ts1 

end program 

wyjście jest

final sum 1.63840000204800000399876515667619840E+0036 
the time taken is 48.6228256 

C++ kod i kompilacji z g++ -o bb1 code10.cpp

#include <iostream> 
#include <time.h> 
using namespace std; 

main() 
{ 
    long int n,i; 
    long double ssum; 

    clock_t starttime = clock(); 
    n=1600000000; 
    double *a = new double[n]; 
    ssum=0; 

    for(i=0; i<n; i++) 
    { 
     a[i]=i+1; 
     ssum=ssum+a[i]*a[i]*a[i]; 
    } 

    cout << "final sum " << ssum << endl; 
    delete [ ]a; 
    cout << "the time taken is " 
     << (double)(clock() - starttime)/(double)CLOCKS_PER_SEC 
     << endl; 
} 

wyjściem jest

final sum 1.6384e+36 
the time taken is 12.0104 
+0

Jakiś konkretny powód, aby utworzyć tablicę do przechowywania 'n -> n + 1'? Mogę się mylić, ale czy FORTRAN nie przechodzi przez wszystkie zmienne, aby znaleźć to, czego chcesz? Czy oznacza to, że liczba iteracji przekroczyłaby 1,6 miliarda zmiennych, zanim znajdzie to, czego szukasz? –

+0

to dlatego, że w indeksowaniu tablic fortranowych zaczyna się od 1, więc jest 1,2,3 .. ale w C++ indeksowanie tablicy zaczyna się od 0, więc jest to 0,1,2,3 – Guddu

+3

Nie ma sensu porównywanie wydajności bez włączania optymalizacja (np. 'g ++ -O2 ...'). –

Odpowiedz

6

Nie jestem Fortran ekspertem, ale wydaje się, że

real (kind=16) :: ssum 

deklaruje poczwórnej precyzji (16 bajtów) liczbę zmiennoprzecinkową, która jest prawdopodobnie emulowane programowo na swoim sprzęcie. Twój kod C++ używa long double, który odpowiada rozszerzonej precyzji (10 bajtów) liczbie zmiennoprzecinkowej, która może być wykonana przez twój sprzęt (i jest znacznie szybsza). Należy pamiętać, że long double nie jest 10-bajtowym numerem zmiennoprzecinkowym na wszystkich platformach, na przykład na niektórych platformach może to być to samo co double. Myślę, że tak jest w przypadku Windows i MSVC. Aby uzyskać liczbę zmiennoprzecinkową o zwiększonej dokładności w sieci fortran, należy użyć:

real (kind=10) :: ssum 
+0

, ale 'sizeof (ssum)' w moim C++ zwraca kod "16", a nie "10". więc czy jest to nadal 10-bajtowa precyzja i po prostu zajmowanie 16 bajtów w pamięci? – Guddu

+0

@Guddu: Uruchamianie 'gcc -dM -E -

+0

dziękuję, strona wiki na "długim podwójnym" też była pomocna, to było moje nieporozumienie, że 'długi podwójny' daje podwójną precyzję' podwójnego' – Guddu