为什么 tanh 在我的机器上比 exp 快?
Why tanh is faster than exp on my machine?
这个问题源于一个单独的问题,结果证明它有一些明显的机器特定的怪癖。当我运行下面列出的C++代码来记录tanh
和exp
之间的时序差异时,我看到以下结果:
tanh: 5.22203
exp: 14.9393
tanh
运行速度是exp
的 ~3 倍。考虑到tanh
的数学定义(并且对实现的算法定义一无所知),这有点令人惊讶。
更重要的是,这发生在我的笔记本电脑上(Ubuntu 16.04,英特尔酷睿 i7-3517U CPU @ 1.90GHz × 4),但不会发生在我的桌面上(相同的操作系统,现在不确定 CPU 规格)。
我用g++
编译了下面的代码。上述时间没有编译器优化,尽管如果我对每个n
都使用-On
,趋势仍然存在。我还摆弄了a
和b
值,以查看正在评估的值范围是否产生影响。这似乎并不重要。
是什么导致tanh
比不同机器上的exp
更快?
#include <iostream>
#include <cmath>
#include <ctime>
using namespace std;
int main() {
double a = -5;
double b = 5;
int N = 10001;
double x[10001];
double y[10001];
double h = (b-a) / (N-1);
clock_t begin, end;
for(int i=0; i < N; i++)
x[i] = a + i*h;
begin = clock();
for(int i=0; i < N; i++)
for(int j=0; j < N; j++)
y[i] = tanh(x[i]);
end = clock();
cout << "tanh: " << double(end - begin) / CLOCKS_PER_SEC << "n";
begin = clock();
for(int i=0; i < N; i++)
for(int j=0; j < N; j++)
y[i] = exp(x[i]);
end = clock();
cout << "exp: " << double(end - begin) / CLOCKS_PER_SEC << "n";
return 0;
}
编辑:一些程序集输出
当我使用g++ -g -O -Wa,-aslh nothing2.cpp > stuff.txt
编译以下简化代码时,这是输出的。
#include <cmath>
int main() {
double x = 0.0;
double y,z;
y = tanh(x);
z = exp(x);
return 0;
}
编辑:另一个更新
假设nothing2.cpp
包含上一次编辑中的简化代码。我跑:
g++ -o nothing2.so -shared -fPIC nothing2.cpp
objdump -d nothing2.so > stuff.txt
以下是stuff.txt
的内容
有各种可能的解释,适用于您的解释取决于您正在使用的平台或确切正在使用的数学库。但一种可能的解释是:
首先,tanh
的计算不依赖于tanh
的标准定义,而是用exp(-2*x)
或expm1(2*x)
来表示,这意味着只需要计算一个指数,这可能是繁重的操作(此外还有一个除法和一些补充)。
其次,这可能是诀窍,对于x
的较大值,这将减少到(exp(2*x)-1)/(exp(2*x)+1) = 1 - 2/(expm1(2*x)+2)
。这里的优点是,由于第二项很小,因此不必以相同的相对精度计算即可获得相同的最终精度。这意味着人们通常不需要这里的expm1
。
同样对于x
的 smalish 值,将其重写为(1-exp(-2*x))/(1+exp(-2*x)) = - 1/ (1 + 2/(expm1(-2*x)+2)
也有类似的技巧,这再次意味着我们可以利用该因子exp(-2*x)
很大而不必以相同的精度计算它。但是,您不必以这种方式实际计算它,而是使用表达式expm1(-2*x)/(2+expm1(-2*x))
,对expm1
具有相同的精度要求。
此外,对于较大的x
值,还有其他优化,这对于基本相同来源的exp
是不可能的。对于较大的x
因子expm1(2*x)
将变得如此之大,以至于我们可以简单地完全丢弃它,而对于exp
,我们仍然必须计算它(即使是大负x
也是如此)。对于这些值tanh
将立即决定1
,同时必须计算exp
。
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何在本地机器上运行c++和javascript客户端代码(hackerbank风格)
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 64位机器上的C++内存对齐
- 使用不同的链接器会产生不同的机器代码吗
- 我写了一个C++程序来模拟Enigma机器.我没有得到输出
- 如何将经过训练的机器学习模型保存在python中并将其加载到C++中进行预测?
- C++ 两台不同机器之间通过wifi进行套接字通信
- 使用 ssh 重新连接到远程 Ubuntu 机器后,如何继续使用 gdb 调试 c++ 代码?
- 代码厨师 2019 年 12 月午餐时间愚蠢的机器
- CMake:尝试在 Jenkins 构建机器上运行时出现"Linked Library"错误 (0xc0000135)
- objdump 不显示机器代码,但显示 ASM
- 不同机器之间的标准时钟性能差异显著
- 如何使用Messenger示例连接两台机器
- 提升多精度浮点数128:标准::exp错误:'no matching function for call'
- 在 c++ 中计算对数和 exp 函数
- 单词exp和带空格的字符串
- C++ exp 在 i7-3770 和 i7-4790 上的 x64 下函数不同的结果
- 如何在拆分为多个文件的分层 SM 中退出子机器?(使用boost::MSM)
- 为什么 tanh 在我的机器上比 exp 快?