C ++ Exp与Log:哪个更快?

时间:2009-05-03 16:59:11

标签: c++ math performance

我有一个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";

8 个答案:

答案 0 :(得分:23)

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

答案 1 :(得分:8)

编辑:修改代码以避免exp()溢出。这导致两个功能之间的差距大大缩小。谢谢,fredrikj。

代码:

#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会更快地收敛日志或什么?在我看来,natural logarithmexponential 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库的功能是否也是这样。但这似乎不太可能。

答案 2 :(得分:7)

真的需要知道吗?这会占用你运行时间的很大一部分吗?你怎么知道的?

更糟糕的是,它可能取决于平台。什么?

当然,如果你关心的话,测试它,但是花费大量时间在微优化上苦苦挣扎通常是一个坏主意。

答案 3 :(得分:5)

因为您正在处理值&lt;&lt; 1,注意x-1>对于x <1,log(x), 这意味着x-1&lt; log(y)表示log(x)&lt; log(y),已经 无需使用log或exp即可处理1 / e~37%的案例。

答案 4 :(得分:3)

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

答案 5 :(得分:1)

它可能取决于您的libm,平台和处理器。您最好编写一些代码,这些代码会多次调用exp / log,并使用time调用它几次以查看是否存在明显差异。

两者在我的计算机上基本上都是同一时间(Windows),所以我使用exp,因为它是为所有值定义的(假设你检查ERANGE)。但是如果使用log更自然,那么你应该使用它而不是在没有充分理由的情况下进行优化。

答案 6 :(得分:1)

日志更快是有意义的...... Exp必须执行几次乘法才能得到答案,而log只需将尾数和指数从base-2转换为base-e。

如果您正在使用日志,请务必进行边界检查(正如许多其他人所说)。

答案 7 :(得分:0)

如果您确定这是热点 - 编译器instrinsics是您的朋友。虽然它依赖于平台(如果你在这样的地方寻求性能 - 你不能与平台无关) 所以。问题实际上是 - 哪一个是对目标架构的asm指令 - 以及延迟+周期。如果没有这个,那就是纯粹的猜测。