Почему std::sin() и std:: cos() медленнее, чем sin() и cos()?
тестовый код:
#include <cmath>
#include <cstdio>
const int N = 4096;
const float PI = 3.1415926535897932384626;
float cosine[N][N];
float sine[N][N];
int main() {
printf("an");
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("bn");
}
вот этот момент:
$ g++ main.cc -o main
$ time ./main
a
b
real 0m1.406s
user 0m1.370s
sys 0m0.030s
после добавления using namespace std;
время:
$ g++ main.cc -o main
$ time ./main
a
b
real 0m8.743s
user 0m8.680s
sys 0m0.030s
компилятор:
$ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
сборка:
Dump of assembler code for function sin@plt:
0x0000000000400500 <+0>: jmpq *0x200b12(%rip) # 0x601018 <_GLOBAL_OFFSET_TABLE_+48>
0x0000000000400506 <+6>: pushq x3
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 x10,%rsp
0x000000000040070a <+8>: movss %xmm0,-0x4(%rbp)
0x000000000040070f <+13>: movss -0x4(%rbp),%xmm0
0x0000000000400714 <+18>: callq 0x400500 <sinf@plt>
0x0000000000400719 <+23>: leaveq
0x000000000040071a <+24>: retq
End of assembler dump.
Dump of assembler code for function sinf@plt:
0x0000000000400500 <+0>: jmpq *0x200b12(%rip) # 0x601018 <_GLOBAL_OFFSET_TABLE_+48>
0x0000000000400506 <+6>: pushq x3
0x000000000040050b <+11>: jmpq 0x4004c0
End of assembler dump.
4 ответов
вы используете другую перегрузку:
попробовать
double angle = i*j*2*PI/N;
cosine[i][j] = cos(angle);
sine[i][j] = sin(angle);
он должен выполнять то же самое с или без using namespace std;
Я Угадай разница в том, что есть перегрузки для std::sin() для float и для double, в то время как sin() принимает только double. Внутри std::sin() для поплавков может быть преобразование в double, затем вызов std:: sin() для двойников, а затем преобразование результата обратно в float, что делает его медленнее.
используйте флаг-S в командной строке компилятора и проверьте разницу между выводом ассемблера. Может быть!--0--> дает много неиспользуемого материала в исполняемом файле.
я сделал некоторые измерения, используя clang с -O3
оптимизация, работает на Intel Core i7
. Я обнаружил, что:
-
std::sin
onfloat
имеет такую же стоимость какsinf
-
std::sin
ondouble
имеет такую же стоимость какsin
- грех функционирует на
double
2,5 x медленнее, чем наfloat
(опять же, работает наIntel Core i7
).
вот полный код для его воспроизведения:
#include <chrono>
#include <cmath>
#include <iostream>
template<typename Clock>
struct Timer
{
using rep = typename Clock::rep;
using time_point = typename Clock::time_point;
using resolution = typename Clock::duration;
Timer(rep& duration) :
duration(&duration) {
startTime = Clock::now();
}
~Timer() {
using namespace std::chrono;
*duration = duration_cast<resolution>(Clock::now() - startTime).count();
}
private:
time_point startTime;
rep* duration;
};
template<typename T, typename F>
void testSin(F sin_func) {
using namespace std;
using namespace std::chrono;
high_resolution_clock::rep duration = 0;
T sum {};
{
Timer<high_resolution_clock> t(duration);
for(int i=0; i<100000000; ++i) {
sum += sin_func(static_cast<T>(i));
}
}
cout << duration << endl;
cout << " " << sum << endl;
}
int main() {
testSin<float> ([] (float v) { return std::sin(v); });
testSin<float> ([] (float v) { return sinf(v); });
testSin<double>([] (double v) { return std::sin(v); });
testSin<double>([] (double v) { return sin(v); });
return 0;
}
мне было бы интересно, если люди могут сообщать в комментариях к результатам о своих архитектурах, особенно в отношении float
и double
времени.