代码之家  ›  专栏  ›  技术社区  ›  Kyle Simek

C++ EXP与日志:哪个更快?

  •  10
  • Kyle Simek  · 技术社区  · 15 年前

    我有一个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";
    
    8 回复  |  直到 15 年前
        1
  •  22
  •   peterchen    15 年前

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

        2
  •  8
  •   Emil H    15 年前

    编辑:修改代码以避免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 对于日志或其他内容,收敛速度更快?在我看来 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库的功能是否是这样的。但这似乎并非完全不可能。

        3
  •  6
  •   dmckee --- ex-moderator kitten    15 年前

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

    更糟糕的是,它可能依赖于平台。那又怎样?

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

        4
  •  5
  •   ackb    15 年前

    由于您使用的是值<<1,请注意x-1>log(x)for x<1, 这意味着x-1<log(y)意味着log(x)<log(y),它已经 处理1/e~37%的病例,无需使用log或exp。

        5
  •  3
  •   cobbal    15 年前

    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
    
        6
  •  1
  •   Mark    15 年前

    它可以依赖于您的libm、平台和处理器。你最好写一些调用的代码 exp / log 多次,并使用 time 打几次电话看看有没有明显的区别。

    两者在我的计算机(Windows)上的时间基本相同,因此我将使用 EXP ,因为它是为所有值定义的(假设您检查 ERANGE )但如果使用更自然 日志 你应该使用它,而不是毫无理由地去优化。

        7
  •  1
  •   ParoXoN    15 年前

    日志越快越好…exp必须执行几次乘法才能得到答案,而log只需要将尾数和指数从base-2转换为base-e。

    如果您使用的是日志,请确保边界检查(正如其他人所说)。

        8
  •  0
  •   Alexey Orlov    15 年前

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