Я столкнулся с этим вопросом, когда был на собеседовании при приеме на работу в CS. Я понятия не имею об этом, не говоря уже о реализации кода …

Могу я получить несколько советов?

P.S. exp () - это функция y = e ^ x, а ln () - это y = ln (x)

8
mitcc 28 Мар 2014 в 10:51
1
Каково желаемое время работы?
 – 
Nikunj Banka
28 Мар 2014 в 10:54
2
Вам придется выполнять итерации exp(y) по различным значениям y и проверять, какое значение ближе всего к x.
 – 
Abhishek Bansal
28 Мар 2014 в 10:57
Не требуется. Таким образом, мы можем предположить, что время работы не является строгим.
 – 
mitcc
28 Мар 2014 в 10:58
4
Бинарный поиск, может быть? Или попробуйте метод Ньютона на e ^ x - значение = 0. Помните, d/dx (e ^ x) = e ^ x
 – 
Ani
28 Мар 2014 в 11:16
2
Ясно, что решение должно использовать экспоненциальную функцию, обратную логарифму. Таким образом, вы должны решить exp(y) = x (и не использовать Тейлора). Ньютон даст вам самую быструю сходимость, но вам нужно проверить, имеет ли значение выбор начального значения.
 – 
Yves Daoust
28 Мар 2014 в 14:46

3 ответа

Лучший ответ

Вы можете найти значение в журнале времени путем двоичного поиска ответа. Это возможно, потому что log X - монотонно возрастающая функция.

(любезно предоставлено WolframAlpha ) .

Например, если значение, логарифм которого мы должны вычислить (предположим, что это X), больше 1, тогда начните с предположения, что answer = X. Увеличьте степень e ^ answer и проверьте, больше или меньше значение чем X. Теперь в зависимости от того, больше или меньше полученное вами значение X, вы можете уточнить свои пределы. Поиск прекращается, когда вы достигли подходящего диапазона вашего ответа.

double log(double X){
        double lo = 1;
        double hi = X;

        while(true){
            double mid = (lo+hi)/2;
            double val = power(e, mid);
            if(val > X){
                hi = mid;
            }
            if(val < X){
                lo = mid;
            }
            if(abs(val-X) < error){
                return mid;
            }
        }
    }

Точно так же, если значение X меньше 1, вы можете свести этот случай к уже рассмотренному нами, т.е. когда X больше 1. Например, если X = 0,04, то

Журнал 0,04 = журнал (4/100) = (журнал 4) - (журнал 100)

13
Nikunj Banka 28 Мар 2014 в 11:49
Почему вам нужно разделить регистр для X>1 и X<1?
 – 
justhalf
28 Мар 2014 в 11:24
Поскольку для x<1 у нас есть ln(x)>x - таким образом, если мы начнем поиск со значением меньше, чем x, мы никогда не закончим (потому что (lo+hi/2) также будет меньше, чем x)
 – 
Alma Do
28 Мар 2014 в 11:29
Что будет низким в этом случае? Значение logX может быть -Infinity. И у нас нет нижней границы в этом случае.
 – 
Nikunj Banka
28 Мар 2014 в 11:30
3
Я понимаю. Тогда для случая X<1, я думаю, вам следует вместо этого сделать ln(1/X) = -ln(X). И помните, что вопрос о ln(X), который является натуральным логарифмом, а не основанием 10.
 – 
justhalf
28 Мар 2014 в 11:34
Я вижу, что это также хороший способ уменьшить проблему, когда X < ​​1. Однако я никогда не упоминал базу 10 в ответе.
 – 
Nikunj Banka
28 Мар 2014 в 12:12

Если X положительный, то логарифм можно найти с помощью метода Ньютона.

X_ {0} = 0

X_ {n + 1} = X_ {n} - (ехр (X_ {n}) - X) / (ехр (X_ {n})

Очень быстрая сходимость.

8
TooTone 29 Мар 2014 в 04:05
Вторая строка может быть упрощена до X_{n+1} = X_{n} + X / exp(X_{n}) - 1.
 – 
Salix alba
28 Мар 2014 в 13:43
1
Опечатка: знаменатель (exp(X_{n}) - 1). Но везде ли гарантирована сходимость?
 – 
Yves Daoust
28 Мар 2014 в 14:39
@YvesDaoust: я думаю, что знаменатель правильный. X здесь константа, значение, для которого мы пытаемся найти натуральный логарифм. (Возможно, было бы понятнее, если бы X переименовали в Y, а X_i оставили бы как есть.)
 – 
Mark Dickinson
28 Мар 2014 в 17:40
Ой, мой плохой! На меня повлияло обозначение (X_{n} против X).
 – 
Yves Daoust
28 Мар 2014 в 17:45
Гораздо быстрее и проще в реализации
 – 
TooTone
29 Мар 2014 в 04:05

Адаптация этого ответа для масштабирования X в диапазоне [0, e]. Мы знаем кое-что о ln(x), ln(x) определено только для 0 ln(1)=0, результаты могут быть любым числом от -infinity до + infinity. ln(x^a) = a * ln(x) в частности ln(x^(-1)) = - ln(x), ln(X/e) = ln(X)-ln(e) так ln(X) = ln(X/e) + 1.

double E = exp(1);
double ln(double X) {
    if(X<0) return NaN;
    // use recursion to get approx range
    if(X<1) {
       return - ln( 1 / X );
    }
    if(X>E) {
       return ln(X/E) + 1;
    }
    // X is now between 1 and e
    // Y is between 0 and 1

    double lo = 0;
    double hi = 1;

    while(true){
        double mid = (lo+hi)/2;
        double val = exp(mid);
        if(val > X){
            hi = mid;
        }
        if(val < X){
            lo = mid;
        }
        if(abs(val-X) < error){
            return mid;
        }
    }
}

Если вы посмотрите на фактические реализации математических функций в библиотеках. Они выполняют довольно много работы по предварительному масштабированию, чтобы сузить диапазоны входных данных, вероятно, более агрессивно, чем это делается здесь.

5
Community 23 Май 2017 в 15:10