C++ Exp 与 Log:哪个更快?
Posted
技术标签:
【中文标题】C++ Exp 与 Log:哪个更快?【英文标题】:C++ Exp vs. Log: Which is faster? 【发布时间】:2009-05-03 16:59:10 【问题描述】:我有一个 C++ 应用程序,我需要在其中比较两个值并确定哪个更大。唯一的复杂之处是一个数字在日志空间中表示,另一个则不是。例如:
double log_num_1 = log(1.23);
double num_2 = 1.24;
如果我想比较num_1
和num_2
,我必须使用log()
或exp()
,我想知道一个是否比另一个更容易计算(即运行时间更短,一般来说)。你可以假设我使用的是标准的cmath
库。
换句话说,以下在语义上是等价的,所以哪个更快:
if(exp(log_num_1) > num_2)) cout << "num_1 is greater";
或
if(log_num_1 > log(num_2)) cout << "num_1 is greater";
【问题讨论】:
你为什么不写一些测试并发布你的结果呢? :) 【参考方案1】:AFAIK 算法,复杂性是相同的,差异应该只是一个(希望可以忽略不计)常数。
因此,我会使用exp(a) > b
,只是因为它不会因无效输入而中断。
【讨论】:
关于 log() 更脆弱的观点非常好。特别是因为性能差异在现实中可能不是问题。 +1,同意。除非你在做一些非常非常需要性能的事情,否则你不应该担心像这样的微优化...... 感谢您的回答——非常有帮助。不过,我将使用 log(),因为我使用的是极小的正值(它们是概率),而且我认为在精确度方面,我会做得更好。 有趣的一点,redmoskito,结果是一个非常有趣的问题。【参考方案2】:你真的需要知道吗?这会占用你运行时间的很大一部分吗?你怎么知道的?
更糟糕的是,它可能取决于平台。然后呢?
当然,如果你在乎的话,可以测试一下,但是花很多时间在微优化上苦恼通常是个坏主意。
【讨论】:
更糟糕的是,它可能取决于您运行的处理器(您的应用几乎肯定会比当前一代的 CPU 寿命更长)。 我还没有分析过,但这很可能是我代码中的热点。不过,您可能是对的。我只是好奇,主要是,我认为这对后代来说可能是一个有用的问题。 好奇心永远不会变坏。今天太多的处理器周期被不够好奇的开发人员浪费了。 “只需投入更多硬件”是万恶之源。 @Svante:反对过早优化的论据不是我们可以“只是投入更多的硬件”,而是(1)只有优化成本高昂的部分才能获得更多收益首先很多,(2)优化的成本超出了程序员编写它们所需的时间,以及(3)总成本可以而且经常超过优化的总价值。所以你先测试。现在,redmoskito 已经表示这是一个紧密的循环,所以它是一个很好的候选者,但是...... @Svante:你没有抓住重点。好奇心很好,这就是为什么你应该在假设它是一个问题之前进行 PROFILE。太多的程序员时间被那些认为他们可以猜测 CPU 时间花在哪里的人浪费了,而那 是万恶之源,因为这需要开发时间远离它实际上会有所作为的地方。先配置文件,不要浪费时间进行优化,除非您确定要优化的内容实际上占用了足够的时间来需要优化。【参考方案3】:编辑:修改代码以避免 exp() 溢出。这导致两个函数之间的差距大大缩小。谢谢,弗雷德里克。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char **argv)
if (argc != 3)
return 0;
int type = atoi(argv[1]);
int count = atoi(argv[2]);
double (*func)(double) = type == 1 ? exp : log;
int i;
for (i = 0; i < count; i++)
func(i%100);
return 0;
(编译使用:)
emil@lanfear /home/emil/dev $ gcc -o test_log test_log.c -lm
结果似乎相当确凿:
emil@lanfear /home/emil/dev $ time ./test_log 0 10000000
real 0m2.307s
user 0m2.040s
sys 0m0.000s
emil@lanfear /home/emil/dev $ time ./test_log 1 10000000
real 0m2.639s
user 0m2.632s
sys 0m0.004s
有点令人惊讶的日志似乎是更快的。
纯属猜测:
也许底层数学taylor series 收敛得更快,对于 log 什么的?实际上,在我看来,natural logarithm 比 exponential function 更容易计算:
ln(1+x) = x - x^2/2 + x^3/3 ...
e^x = 1 + x + x^2/2! + x^3/3! + x^4/4! ...
但是,不确定 c 库函数是否会这样做。但这似乎并非完全不可能。
【讨论】:
+1:您的与我的不同,因为您正在评估一个不断变化的值,而我的却被编译器优化为一无所有。所以我认为错误是我的,而不是你的 啊,有趣。当你做同样的事情时,你会得到类似的结果吗? 不,指数函数的泰勒级数比自然对数收敛得更快。但这可能无关紧要,因为数学库很可能使用极小极大多项式而不是泰勒多项式。 exp 比登录测试慢得多的原因可能是它大部分时间都会溢出,这需要处理。请注意,exp(i) 在 i = 700 左右已经溢出。日志不会溢出。 我已经修改了我的测试来弥补这一点。谢谢(你的)信息。 :) 你的测试有点不公平...计算 1 到 100 之间的数字的对数相当简单(它是 0 到 ~4.6 之间的双精度数)。计算 N 介于 1 和 100 之间的 exp(N) 要困难得多。 (exp(100) 是 2.688x10^43。)【参考方案4】:由于您正在使用值 log(x) for x
【讨论】:
添加的测试可能会或可能不会更快,但它肯定是测试和分析的好方法。【参考方案5】:python 中的一些快速测试(使用 c 进行数学运算):
$ time python -c "from math import log, exp;[exp(100) for i in xrange(1000000)]"
real 0m0.590s
user 0m0.520s
sys 0m0.042s
$ time python -c "from math import log, exp;[log(100) for i in xrange(1000000)]"
real 0m0.685s
user 0m0.558s
sys 0m0.044s
表示日志稍慢
编辑:编译器似乎正在优化 C 函数,所以循环是占用时间的原因
有趣的是,在 C 语言中,它们的速度似乎相同(可能是因为 Mark 在评论中提到的原因)
#include <math.h>
void runExp(int n)
int i;
for (i=0; i<n; i++)
exp(100);
void runLog(int n)
int i;
for (i=0; i<n; i++)
log(100);
int main(int argc, char **argv)
if (argc <= 1)
return 0;
if (argv[1][0] == 'e')
runExp(1000000000);
else if (argv[1][0] == 'l')
runLog(1000000000);
return 0;
给予时间:
$ time ./exp l
real 0m2.987s
user 0m2.940s
sys 0m0.015s
$ time ./exp e
real 0m2.988s
user 0m2.942s
sys 0m0.012s
【讨论】:
好主意,但是 Python 可能会对日志执行额外的范围检查,并且它的实现方式可能与 OP 的库不同。此外,差异总是在 7% 左右吗?因为那可能只是实验性错误。【参考方案6】:它可能取决于您的 libm、平台和处理器。你最好写一些代码,多次调用exp
/log
,然后用time
调用几次,看看有没有明显的区别。
两者在我的计算机 (Windows) 上花费的时间基本相同,所以我会使用 exp
,因为它是为所有值定义的(假设您检查 ERANGE
)。但如果使用log
更自然,您应该使用它而不是无缘无故地尝试优化。
【讨论】:
【参考方案7】:log 更快是有道理的... Exp 必须执行多次乘法才能得出答案,而 log 只需要将尾数和指数从 base-2 转换为 base-e。
如果您使用日志,请务必进行边界检查(正如许多其他人所说)。
【讨论】:
【参考方案8】:如果你确定这是热点——编译器内在是你的朋友。虽然它依赖于平台(如果你在这样的地方追求性能——你不能与平台无关) 所以。真正的问题是——哪一个是目标架构上的 asm 指令——以及延迟+周期。没有这个纯属猜测。
【讨论】:
以上是关于C++ Exp 与 Log:哪个更快?的主要内容,如果未能解决你的问题,请参考以下文章