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_1num_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) &gt; 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:哪个更快?的主要内容,如果未能解决你的问题,请参考以下文章

Win32 消息泵与 MFC 消息映射,哪个更快? C++

zookeeper支持c++吗

在以下情况下哪个更快? [关闭]

C# 中的哈希表比 C++ 更快?

如何在 C++ 上执行 FreeConsole() 但更快

哪个更快? ++、+= 还是 x + 1?