2011-08-07 16 views
17

Test:Dlaczego std :: sin() i std :: cos() są wolniejsze niż sin() i cos()? Kod

#include <cmath> 
#include <cstdio> 

const int N = 4096; 
const float PI = 3.1415926535897932384626; 

float cosine[N][N]; 
float sine[N][N]; 

int main() { 
    printf("a\n"); 
    for (int i = 0; i < N; i++) { 
     for (int j = 0; j < N; j++) { 
      cosine[i][j] = cos(i*j*2*PI/N); 
      sine[i][j] = sin(-i*j*2*PI/N); 
     } 
    } 
    printf("b\n"); 
} 

Oto czas:

$ g++ main.cc -o main 
$ time ./main 
a 
b 

real 0m1.406s 
user 0m1.370s 
sys  0m0.030s 

Po dodaniu using namespace std;, czas jest:

$ g++ main.cc -o main 
$ time ./main 
a 
b 

real 0m8.743s 
user 0m8.680s 
sys  0m0.030s 

Compiler:

$ g++ --version 
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 

Montaż:

Dump of assembler code for function [email protected]:          
0x0000000000400500 <+0>:  jmpq *0x200b12(%rip)  # 0x601018 <_GLOBAL_OFFSET_TABLE_+48> 
0x0000000000400506 <+6>:  pushq $0x3          
0x000000000040050b <+11>: jmpq 0x4004c0         
End of assembler dump. 

Dump of assembler code for function std::sin(float):        
0x0000000000400702 <+0>:  push %rbp          
0x0000000000400703 <+1>:  mov %rsp,%rbp         
0x0000000000400706 <+4>:  sub $0x10,%rsp        
0x000000000040070a <+8>:  movss %xmm0,-0x4(%rbp)       
0x000000000040070f <+13>: movss -0x4(%rbp),%xmm0       
0x0000000000400714 <+18>: callq 0x400500 <[email protected]>      
0x0000000000400719 <+23>: leaveq           
0x000000000040071a <+24>: retq            
End of assembler dump. 

Dump of assembler code for function [email protected]:         
0x0000000000400500 <+0>:  jmpq *0x200b12(%rip)  # 0x601018 <_GLOBAL_OFFSET_TABLE_+48> 
0x0000000000400506 <+6>:  pushq $0x3          
0x000000000040050b <+11>: jmpq 0x4004c0         
End of assembler dump. 
+11

@Nawaz: Może. Jest to szczegół implementacji, czy '' zapewnia 'double sin (double)' i 'double cos (double)' w globalnej przestrzeni nazw. Ditto dla '' i 'printf'. –

+0

@Nawaz To kompiluje. To moje prawdziwe kodowanie. – rynlbrwn

+0

Najprostszym sposobem odpowiedzi na takie problemy jest porównywanie danych wyjściowych zespołu kompilatora. –

Odpowiedz

19

Używasz inny przeciążeniem:

Spróbuj

 double angle = i*j*2*PI/N; 
     cosine[i][j] = cos(angle); 
     sine[i][j] = sin(angle); 

powinien wykonać to samo z lub bez using namespace std;

+0

Twój kod działa, ale działa szybko z lub bez zmiany przestrzeni nazw. Dlaczego podany kod działa znacznie wolniej? – rynlbrwn

+11

@Ryan: Ponieważ mój kod zawsze wywołuje 'podwójne grzechy (podwójne)'. Twój pierwotny kod wywołuje 'double sin (double)' z globalnego zasięgu lub 'float sin (float)' z 'namespace std'. Nowoczesne jednostki FPU są zoptymalizowane pod kątem operacji w grze podwójnej. –

+0

Dodano pewne złożenie, czy twoje wnioski nadal trwają? (Nie jestem ninja z montażem) – rynlbrwn

3

I odgadnąć z różnica polega na tym, że istnieją stany przeciążeniowe dla std :: sin() dla float i fo r podwójne, podczas gdy sin() zajmuje tylko podwójne. Wewnątrz std :: sin() dla floats, może wystąpić konwersja do double, a następnie wywołanie std :: sin() dla double, a następnie konwersja wyniku z powrotem do float, co powoduje spowolnienie.

+0

Konwersje pomiędzy 'float' i' double' nie uwzględniają tego. Przeprowadziłem dzisiaj kilka testów z g ++ i odkryłem, że przy użyciu '-O2' kod' float' był znacznie wolniejszy.Jednakże, gdy testowałem z ręcznymi konwersjami, takimi jak to: '(float) sin ((double) input)' Stwierdziłem, że zoptymalizowany kod 'float' działał _faster_ niż zoptymalizowany kod' double', mimo że wymuszałem '. float' code do użycia funkcji 'double'' sin'. –

+0

@KyleA: To był 2011. Teraz jest 2017. Kod środowiska wykonawczego mógł się zmienić. –

1

Użyj flagi -S w wierszu komend kompilatora i sprawdź różnicę między wyjściami asemblera. Może using namespace std; daje dużo nieużywanych rzeczy w pliku wykonywalnym.

+0

Dlatego właśnie miałem instrukcje drukowania, więc jeśli uruchomiłeś kod, zobaczyłeś, że większość czasu spędzasz w pętli, a nie inicjalizacji. – rynlbrwn