- 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/
我有两个数据框列“vibration_X”和“vibration_Y”。此外,我在某些列中几乎没有零值。我想创建新列“theta”,它是vibration_Y 和vibration_X 的tan 倒数
我知道我可以做到: //With A = tax(x); return tan(arctan(A)/2); 但我想要更高效的东西。 最佳答案 当 x 介于 -π/2 和 π/2 之间时,您可以使用此公
我正在尝试编写以弧度为单位计算角度 tan 的函数。我必须使用泰勒级数使用迭代来完成此操作,但仅限于前 13 个提名者和分母。公式如下: http://upload.wikimedia.org/mat
我正在尝试计算三点之间的角度,我需要使用 Tangent 函数 tan() .奇怪的是 VBA 返回错误的值。 例如: tan(209) = 0.554309051 但在 VBA 中: tan(209
这个问题已经有答案了: 已关闭 10 年前。 Possible Duplicate: tan 45 gives me 0.9999 当我使用tan时我得到了一个很长的答案: double degree
我遇到了一些代码问题,但找不到错误。我正在尝试计算下图中用红色标记的距离。 我的代码返回值:-41.63 正确值为:3.75 我的代码: return round(6.5 * tan(30),2);
我试着算出三角形的角。 如果三角形的一边是100,另一边是100。 我如何使它达到 45 度。 如果我在我的计算器上运行 tan-1(100/100),我得到 45。我如何在 PHP 中执行此操作?
如何在C++编程语言中从0度到360度打印sin,cos和tan的值? #include #include using namespace std; #define PI 3.14159265 i
好吧,我在我的一个游戏中为僵尸制作了一个人工智能,但是当我尝试旋转僵尸以便他面对玩家时,一切都变得一团糟。他们以错误的方式旋转,当我靠近时旋转,即使角度不应该改变。这是我的一些代码:ps 忽略 z,这
我想在 JS 中获取三 Angular 形的 Angular 。 计算对边/邻边后如何得到与正切的 Angular ? 最佳答案 degrees = Math.atan(a/b) * 180 / Ma
我目前正在为 Windows Phone 编写一个计算程序。计算之一是找到用户输入的数字乘以用户输入的另一个数字的正切值。 问题是,当我输入 1*tan(45)(即 1)时,它返回 1.6...。我通
我试图在 python 中计算 tan 的倒数,但它没有给我正确的值,例如,如果我要做 1.18 的倒数,math.atan(1.18) >>>math.atan(1.18) 0.8677 但是,正确
Tan 函数 返回某个角的正切值。 Tan(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Tan 取某个角并返回直角三角形两个直角边的比值。此比值
如何在 iOS SDK 中计算 cos、sin、tan 等三角函数? 我尝试了 tan(45) 但它返回了错误的输出。有什么帮助吗? 最佳答案 大多数数学库使用 radians ,而不是度数。 关于i
import java.util.Scanner; public class a { /** * @param args */ public static void m
我正在测试一个程序,该程序读取数学输入,并根据运算顺序计算答案。我遇到了一个问题。计算 Math.PI/2 的正切时,返回值 1.633123935319537E16。 但是,在我的程序中的某个位置,
我正在使用此链接上的公式制作计算器: http://cereference.com/book/surveying-and-transportation-engineering/simple-curve
我一直在使用 Decimal.js 来提高我的函数的精度,该函数通过反复试验计算 a = tan(a) 的第 m 个正根。它可以工作,但是对于 nTan(504)(将返回 4.4934... 到 50
已关闭。这个问题是 off-topic 。目前不接受答案。 想要改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 已关闭10 年前。 Improve th
我想返回一个值的棕褐色,该值是 35,但我得到的是 0.473815。但是这个值应该是 0.70020753...?为什么它给我 0.473815?我正在使用 tan(35)?我不明白为什么会这样说。
我是一名优秀的程序员,十分优秀!