gpt4 book ai didi

c++ - 使用 g++ 4.8.2 时,tan() 计算比 sin()/cos() 长两倍

转载 作者:太空狗 更新时间:2023-10-29 19:52:19 24 4
gpt4 key购买 nike

我正在研究使用大量数学函数的算法,最近我们从 Solaris 平台在 Ubuntu 系统上移植了 g++ 4.8.2 下的代码。

令人惊讶的是,一些算法比以前花费了很多时间。背后的原因是 std::tan() 函数比 std::sin()/std::cos() 长两倍。

用 sin/cos 代替 tan 大大减少了相同结果的计算时间。我想知道为什么会有这样的差异。是因为标准库的实现吗? tan 函数不应该更有效吗?

我写了一个程序来检查函数的时间:

#include <cmath>
#include <iostream>
#include <chrono>

int main(int argc, char * argv[])
{
using namespace std::chrono;

auto start_tan = system_clock::now();

for (int i = 0; i < 50000; ++i)
{
const double & a = static_cast<double>(i);
const double & b = std::tan(a);
}

auto end_tan = system_clock::now();
auto elapsed_time_tan = end_tan - start_tan;
std::cout << "tan : ";
std::cout << elapsed_time_tan.count() << std::endl;

auto start_sincos = system_clock::now();

for (int i = 0; i < 50000; ++i)
{
const double & a = static_cast<double>(i);
const double & b = std::sin(a) / std::cos(a);
}

auto end_sincos = system_clock::now();
auto elapsed_time_sincos = end_sincos - start_sincos;
std::cout << "sincos : " << elapsed_time_sincos.count() << std::endl;

}

事实上,在输出中我有以下未优化的时间:

tan : 8319960
sincos : 4736988

以及优化 (-O2) :

tan : 294
sincos : 120

如果有人对此行为有任何想法。

编辑

我根据@Basile Starynkevitch 的回复修改了程序:

#include <cmath>
#include <iostream>
#include <chrono>

int main(int argc, char * argv[])
{
using namespace std::chrono;

if (argc != 2)
{
std::cout << "Need one and only argument : the number of iteration." << std::endl;
return 1;
}

int nb_iter = std::atoi(argv[1]);
std::cout << "Number of iteration programmed : " << nb_iter << std::endl;


double tan_sum = 0.0;
auto start_tan = system_clock::now();
for (int i = 0; i < nb_iter; ++i)
{
const double & a = static_cast<double>(i);
const double b = std::tan(a);
tan_sum += b;
}

auto end_tan = system_clock::now();
auto elapsed_time_tan = end_tan - start_tan;
std::cout << "tan : " << elapsed_time_tan.count() << std::endl;
std::cout << "tan sum : " << tan_sum << std::endl;

double sincos_sum = 0.0;
auto start_sincos = system_clock::now();
for (int i = 0; i < nb_iter; ++i)
{
const double & a = static_cast<double>(i);
const double b = std::sin(a) / std::cos(a);
sincos_sum += b;
}

auto end_sincos = system_clock::now();
auto elapsed_time_sincos = end_sincos - start_sincos;
std::cout << "sincos : " << elapsed_time_sincos.count() << std::endl;
std::cout << "sincos sum : " << sincos_sum << std::endl;

}

现在结果是我得到了类似的时间 -O2 only :

tan : 8345021
sincos : 7838740

但仍然与 -O2 -mtune=native 不同,但确实更快:

tan : 5426201
sincos : 3721938

我不会使用 -ffast-math,因为我需要保持 IEEE 合规性。

最佳答案

您不应该关心未优化的代码。

关于优化,GCC 编译器可能会抛出循环,因为您没有对结果做任何事情。顺便说一句,b 不应是 const double& 引用,而应是 const double

如果您想要一个有意义的基准,请尝试存储 b(或对其求和)。并将迭代次数 (50000) 作为运行时参数(例如 int nbiter = (argc>1)?atoi(argv[1]):1000;)

您可能希望将 -O2 -ffast-math -mtune=native 作为优化标志传递给 g++(注意 -ffast-math 在优化细节上不符合标准)

用那些标志和我的改变:

double sumtan=0.0, sumsincos=0.0;
int nbiter = argc>1?atoi(argv[1]):10000;

for (int i = 0; i < nbiter; ++i)
{
const double & a = static_cast<double>(i);
const double b = std::tan(a);
sumtan += b;
}

for (int i =  0; i < nbiter; ++i)
{
const double & a = static_cast<double>(i);
const double b = std::sin(a) / std::cos(a);
sumsincos += b;
}

std::cout << "tan : "  << elapsed_time_tan.count() 
<< " sumtan=" << sumtan << std::endl;

std::cout << "sincos : " << elapsed_time_sincos.count() 
<< " sumsincos=" << sumsincos << std::endl;

使用 GCC 4.9.2 编译

 g++ -std=c++11 -O2 -Wall -ffast-math -mtune=native b.cc -o b.bin

我得到的时间非常相似:

  % ./b.bin 1000000
tan : 77158579 sumtan=-3.42432e+06
sincos : 70219657 sumsincos=-3.42432e+06

这是在 4 年前的台式机上(Intel(R) Xeon(R) CPU X3430 @ 2.40GHz)

如果使用 clang++ 3.5.0 编译

tan : 78098229 sumtan=-3.42432e+06
sincos : 106817614 sumsincos=-3.42432e+06

附言。 -O3 的时间(和相对性能)不同。有些处理器有 sincostan 的机器指令,但它们可能不会被使用(因为编译器或 libm 知道它们比例程慢)。 GCC 有 builtins对于这些。

关于c++ - 使用 g++ 4.8.2 时,tan() 计算比 sin()/cos() 长两倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27799096/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com