C++;Exp vs.Log:哪个更快? 我有一个C++应用程序,在这里我需要比较两个值,决定哪个更大。唯一复杂的是,一个数字在日志空间中表示,另一个则不表示。例如: double log_num_1 = log(1.23); double num_2 = 1.24;

C++;Exp vs.Log:哪个更快? 我有一个C++应用程序,在这里我需要比较两个值,决定哪个更大。唯一复杂的是,一个数字在日志空间中表示,另一个则不表示。例如: double log_num_1 = log(1.23); double num_2 = 1.24;,c++,math,performance,C++,Math,Performance,如果我想比较num_1和num_2,我必须使用log()或exp(),我想知道其中一个是否比另一个更容易计算(即,通常运行时间更短)。您可以假设我使用的是标准cmath库 换言之,以下内容在语义上是等价的,因此哪个更快: if(exp(log_num_1) > num_2)) cout << "num_1 is greater"; if(exp(log_num_1)>num_2))cout log(num_2))coutpython中的一些快速测试(使用c表示数学): 表示日

如果我想比较
num_1
num_2
,我必须使用
log()
exp()
,我想知道其中一个是否比另一个更容易计算(即,通常运行时间更短)。您可以假设我使用的是标准
cmath

换言之,以下内容在语义上是等价的,因此哪个更快:

if(exp(log_num_1) > num_2)) cout << "num_1 is greater";

if(exp(log_num_1)>num_2))cout log(num_2))coutpython中的一些快速测试(使用c表示数学):

表示日志稍微慢一点

编辑:编译器似乎正在优化C函数,因此循环占用了大量时间

有趣的是,在C语言中,它们似乎是相同的速度(可能是因为马克在评论中提到的原因)

你真的需要知道吗?这会占用你大部分的跑步时间吗?你怎么知道的

更糟糕的是,它可能依赖于平台。然后呢


当然,如果你在意的话,可以测试一下,但是花很多时间在微观优化上是个坏主意。

这取决于你的libm、平台和处理器。最好编写一些多次调用
exp
/
log
的代码,然后使用
time
调用几次,看看是否有明显的差异


两者在我的计算机(Windows)上占用的时间基本相同,因此我会使用
exp
,因为它是为所有值定义的(假设您检查
ERANGE
)。但是,如果使用
log
更自然,那么应该使用它,而不是毫无理由地尝试优化。

编辑:修改代码以避免exp()溢出。这导致这两个函数之间的余量大幅缩小。谢谢你,fredrikj。

代码:

结果似乎相当确凿:

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
有点令人惊讶的是,log似乎是最快的

纯投机:

也许,对于log之类的东西,潜在的数学收敛速度更快?事实上,在我看来,计算比计算更容易:


然而,我不确定c库函数是否会这样做。但这似乎并非完全不可能。

对算法来说,复杂度是相同的,差异应该只是一个常数(希望可以忽略不计)。
因此,我会使用
exp(a)>b
,因为它不会在无效输入时中断。

如果您确定这是热点,编译器instrinsic是您的朋友。尽管它依赖于平台(如果你在这样的地方追求性能,你不能不依赖平台)
所以问题是——哪一个是目标体系结构上的asm指令——以及延迟+周期。如果没有这一点,这纯粹是猜测。

因为您使用的是x的值log(x),所以日志速度更快是有道理的。。。Exp必须执行多次乘法才能得到答案,而log只需将尾数和指数从base-2转换为base-e


如果您使用的是log,请确保进行边界检查(正如许多其他人所说)。

更糟糕的是,这可能取决于您运行的处理器(您的应用程序几乎肯定会比当前一代CPU寿命长)。我还没有分析过,但这可能是我代码中的一个热点。不过,你可能是对的。大部分时候我只是好奇,我想这对后代来说可能是一个有用的问题。好奇从来都不是坏事。今天,由于开发人员不够好奇,浪费了太多处理器周期。“向它扔更多的硬件”是万恶之源。@Svante:反对过早优化的理由不是我们可以“向它扔更多的硬件”,而是(1)如果你首先优化成本高昂的部分,你只能获得很多,(2)优化的成本超出了程序员编写它们所需的时间,(3)总成本可以而且经常超过优化的总价值。所以你先测试一下。现在,redmoskito已经指出这是一个紧密的循环,所以它是一个很好的候选人,但是…@Svante:你没有抓住重点。好奇心是好的,这就是为什么你应该在假设它是一个问题之前先分析它。太多的程序员时间被那些认为他们能猜到CPU时间花在哪里的人浪费了,这是所有问题的根源,因为这会把开发时间从实际会产生影响的地方拿走。首先配置文件,不要浪费时间进行优化,除非您已经确定您正在优化的内容实际上需要花费足够的时间进行优化。这是一个好主意,但Python可能会对日志执行额外的范围检查,并且它的实现可能与OP的libs不同。另外,差距是否总是在7%左右?因为那可能只是实验性错误。+1:你的和我的不同,因为你在计算一个变化的值,而我的值被编译器优化为零。所以这个错误是我的,不是你的,我想啊,很有趣。当你做同样的事情时,你会得到类似的结果吗?不,指数函数的泰勒级数比自然对数的收敛速度快。但这可能是无关紧要的,因为数学库最有可能使用极小极大多项式,而不是泰勒多项式。exp比登录测试慢得多的原因可能是它在大部分时间都会溢出,这需要处理。请注意,exp(i)溢出已经在i=700左右。日志没有溢出。我已经修改了我的测试来补偿这个问题。谢谢你提供的信息。:)你的考试有点不公平。。。计算一个介于1和100之间的数字的对数相当简单(它是0和~4.6之间的一个双精度数)。计算机
$ 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
#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
#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
ln(1+x) = x - x^2/2 + x^3/3 ...
e^x = 1 + x + x^2/2! + x^3/3! + x^4/4! ...