- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在研究使用大量数学函数的算法,最近我们从 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
的时间(和相对性能)不同。有些处理器有 sin
、cos
和 tan
的机器指令,但它们可能不会被使用(因为编译器或 libm
知道它们比例程慢)。 GCC 有 builtins对于这些。
关于c++ - 使用 g++ 4.8.2 时,tan() 计算比 sin()/cos() 长两倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27799096/
我刚开始研究 C#,冗长的数学函数让我很烦。是否有标准的方法来编写 Cos(或任何其他 Math 函数)而不是 Math.Cos 而无需定义您自己的 Cos 函数? 最佳答案 切换到新的 Roslyn
我通过 R 运行 WolframAlpha Wolfram Alpha API from R 我的问题是,我需要将 wolfram 输出转换为 R 表达式。我在需要的地方添加了“*”,还有另一个问题
我遇到了一些应该很容易回答的问题,但我不能 Handlebars 指放在上面。自从我做了一些三角函数以来已经有一段时间了。 double cosValue = -2.7105054312E-20; /
如何重现此行为? https://isocpp.org/wiki/faq/newbie#floating-point-arith2 准确的说,在下面的代码中,参数x和y是相等的;它们可以等于 1.0
JavaScript 中的所有数学函数都使用弧度代替度数。然而,它们要么不相等,要么我离题太远。 从度数到弧度的转换是: var rad = angle * Math.PI / 180 90 度 An
这个问题已经有答案了: How can I get sin, cos, and tan to use degrees instead of radians? (6 个回答) 已关闭 9 年前。 cos
这是怎么回事?? 测试 sin 和 cos 函数以找出为什么在将我的坐标输出到 SVG 文件时我在错误的位置得到如此漂亮的定位。所以我做了这个测试代码,我可以预测答案是什么来找出原因。奇怪的是,没有任
这个问题在这里已经有了答案: 关闭10 年前。 Possible Duplicate: C Build error when getting the value of sin() 我试图在这段时间内
在 Javascript 中使用 a.b(c) 或 [a.b][0](c) 是不同的,原因是 this 的绑定(bind)> 在 a.b 的代码执行期间是否发送给对象 a。 使用相同的推理 var z
这是一个很简单的问题,让我很困惑。 我收到一个源文件的以下错误,但另一个没有: 4 src/Source2.cpp:1466: error: no matching function for cal
如何只使用 sin 或 cos 而不是 Math.sin 或 Math.cos?我尝试导入 Math.* 但我想我可能需要对命名空间做一些事情? 最佳答案 import static java.lan
测试代码: #include #include const int N = 4096; const float PI = 3.1415926535897932384626; float cosin
代码片段1: from sympy import symbols, integrate, cos, pi from numpy import sqrt n = symbols('n', integer
我正在使用 Taylors series 来计算一个数字的 cos,对于小数字,该函数返回准确的结果,例如 cos(5) 给出 0.28366218546322663 。但是对于较大的数字,它会返回不
我是一个完全的编程初学者,我被分配了以下任务: 编写一个 C++ 程序,使用一系列内接和外接正多边形计算一对 π 的估计值。在不超过 30 步后停止,或者当外接多边形和内切多边形的周长之差小于 ε=1
我正在尝试使用余弦和正弦,但它们没有返回我期望的值。 #include #include #include int main() { float magnitudeForce;
我有一个作业要编写一个程序来通过 Maclaurin approximation 计算 cos(x) .但是,我必须为 cos(x) 使用一个函数,并使用另一个函数来计算 cos(x) 函数内的分母上
我正在尝试使用 Python2.7 对方程式进行数值求解。这是整个代码: from sympy import * from sympy import Symbol from sympy.solvers
因此,我正在尝试创建一个使用泰勒近似计算 cos(x) 的程序。 程序非常简单:用户输入一个参数 x(x 是以弧度为单位的角度)和一个 float ε,它是 cos(x) 值的精度。 基本上,程序唯一
我正在尝试将内部 cos() 函数调用插入 LLVM 传递。我在 FunctionPass 中的代码: std::vector arg_type; arg_type.push_back(Type::g
我是一名优秀的程序员,十分优秀!