C ++ Exp vs. Log: что быстрее? - PullRequest
11 голосов
/ 03 мая 2009

У меня есть приложение на 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 ]

23 голосов
/ 03 мая 2009

AFAIK алгоритмы, сложность та же, разница должна быть только (надеюсь, незначительной) константой. Из-за этого я бы использовал exp(a) > b просто потому, что он не ломается при неверном вводе.

8 голосов
/ 03 мая 2009

Редактировать: Изменен код, чтобы избежать переполнения 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

Немного удивительно, что журнал кажется более быстрым.

Чистая спекуляция:

Возможно, лежащий в основе математический ряд Тейлора сходится быстрее для логарифма или чего-то еще? Мне действительно кажется, что натуральный логарифм легче вычислить, чем показательная функция :

ln(1+x) = x - x^2/2 + x^3/3 ...
e^x = 1 + x + x^2/2! + x^3/3! + x^4/4! ...

Однако не уверен, что библиотека c работает так же. Но это не кажется невероятным.

7 голосов
/ 03 мая 2009

Вам действительно нужно знать? Это займет большую часть вашего рабочего времени? Откуда ты знаешь?

Хуже, это может зависеть от платформы. Тогда что?

Так что обязательно проверяйте, если вам не все равно, но тратить много времени на агонизацию микрооптимизации, как правило, плохая идея.

5 голосов
/ 05 мая 2009

Поскольку вы работаете со значениями << 1, обратите внимание, что x-1> log (x) для x <1, это означает, что x-1 <log (y) подразумевает log (x) <log (y), который уже заботится о 1 / е ~ 37% случаев без необходимости использования журнала или опыта. </p>

3 голосов
/ 03 мая 2009

несколько быстрых тестов в 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 оптимизируются компилятором, поэтому цикл занимает время

Интересно, что в Си они кажутся одинаковыми по скорости (возможно, по причинам, указанным Марком в комментарии)

#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
1 голос
/ 05 мая 2009

Было бы разумно, чтобы log был быстрее ... Exp должен выполнить несколько умножений, чтобы получить ответ, тогда как log должен преобразовать только мантиссу и экспоненту в base-e из base-2.

Обязательно проверяйте границы (как уже говорили многие), если вы используете журнал.

1 голос
/ 03 мая 2009

Это может зависеть от вашей libm, платформы и процессора. Лучше всего написать код, который вызывает exp / log большое количество раз, и использовать time, чтобы вызвать его несколько раз, чтобы увидеть, есть ли заметная разница.

И то, и другое в основном занимает одно и то же время на моем компьютере (Windows), поэтому я бы использовал exp, поскольку он определен для всех значений (при условии, что вы отметили ERANGE). Но если более естественно использовать log, вы должны использовать это вместо попыток оптимизации без веской причины.

0 голосов
/ 04 мая 2009

, если вы уверены, что это горячая точка - ваши компиляторы являются вашими друзьями. Хотя это зависит от платформы (если вы стремитесь к производительности в подобных местах - вы не можете быть независимым от платформы) Так. Вопрос на самом деле в том, что такое asm-инструкция на вашей целевой архитектуре, и циклы задержки +. Без этого это просто спекуляция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...