Выполните очень маленькие (или большие) экспоненциальные вычисления

Экспоненциальный предел большинства 32-битных машин

exp( +/-700 )

Но я хотел бы сделать экспоненциальный расчет

res = exp( x ) / exp( d )

когда x или d больше 700, я использую тот факт, что

exp( x + y ) = exp( x ) . exp( y )

Таким образом, мой расчет будет что-то вроде

res = (exp( x - z ).exp(z)) / (exp( d - z ).exp(z))

или же

res = exp( x - z ) / exp( d - z )

где (х-я) < 700

Но этот подход в некоторых случаях несовершенен, например, когда x = 6000 и d = 10000
Если мы используем z = 5300, то

res = exp( 6000 - 5300 ) / exp( 10000 - 5300 )

res = exp( 700 ) / exp( 47000 )

Но exp (47000) = 0 на 32-битной машине.

Если я заменю z = 9300, то получу противоположный эффект.

res = exp( -3300 ) / exp( 700 )

Так, как я мог решить вышеупомянутые уравнения (это должно возвратить 32-битное допустимое число, я думаю), учитывая ограничения компьютера?

редактировать
Причина для этого я использую формулу

P( a ) = P(y1) * P(y2) * P(y3) ... P(yN)

Чтобы предотвратить переполнение, я делаю

a = log( P(y1) ) + log( P(y2) ) +  log (P(y3)) ... log( P(yN) )

b = log( P(z1) ) + log( P(z2) ) +  log (P(z3)) ... log( P(zN) )

...

z = log( P(zz1) ) + log( P(zz2) ) +  log (P(zz3)) ... log( P(zzN) )

чтобы получить общее количество, которое я делаю

total = a + b ... z

и рассчитать процент я делаю

(exp(a) / exp( total ) ) * 100

но возможно, что «а» и / или «всего» больше 700

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

2

Решение

Неважно, что ответом должно быть 32-битное число, если некоторые из промежуточных шагов в вычислениях не являются.

Для математики, которая выходит за границы типа int или long, вам, вероятно, нужно начать использовать что-то вроде GMP.

https://gmplib.org/

4

Другие решения

Я предполагаю, что вы хотите вычислить это:

p = exp(a) / exp(b)

И с тех пор a^b/a^c == a^(b-c) это сводится к

p = exp(a - b)

который может быть легко вычислен если эта разница ниже этого критического показателя.

Если это не так, то ваш результат не может быть представлен примитивными типами данных, такими как double (потому что он либо очень большой, либо очень маленький), вам понадобятся какие-то числа произвольной точности, возможно, предоставленные какой-то библиотекой.

Но если вам нужно только напечатать результат или как-то его сохранить, вы можете легко вычислить даже очень большие числа:

Для этого вы переходите на основание 10 (для отображения), поэтому вычисляете эквивалентную степень (tExponent = log10(eExponent)), и получите это значение в допустимом диапазоне между std::numeric_limits::max_exponent10 а также std::numeric_limits::min_exponent10, сохраняя разницу как коэффициент масштабирования.

Сейчас у меня просто есть быстрый и грязный живой пример, показ

exp(90000) / exp(100)  =  1.18556 scaled by 10^39043

(Проверьте на Вольфрам альфа)


Примечание: когда я писал это, было довольно поздно вечером. Я оставляю это здесь для «альтернативного» подхода.

Теперь, как правило, есть

a^b = [a^(b/c)]^c

И с тех пор

(a/b)^c = (a^c)/(b^c)

держит тоже, Я предполагаю, что самый простой подход здесь — это просто разделить оба показателя, пока один из них выше вашего критического значения, затем возвести в степень, разделить результаты и, наконец, использовать делитель предыдущих показателей в качестве показателя для частного:

double large_exp_quot(
double eNum,
double eDenom,
unsigned int const critical = 200) {
if (abs(eNum - eDenom) > critical) {
throw out_of_range{"That won't work, resulting exponent is too large"};
}
unsigned int eDivisor = 1;
while (abs(eNum) > critical or abs(eDenom) > critical) {
eNum /= 2;
eDenom /= 2;
eDivisor *= 2;
}
return pow(exp(eNum) / exp(eDenom), eDivisor);
}

Но это будет работать только в том случае, если результат ваших вычислений действительно может быть сохранен с использованием примитивных типов данных C ++, в этом случае double, Пример, который вы привели … с показателями 6000 и 10000 … явно не представлен double (его e^(-4000) и при этом невероятно маленький)

2

Численно нестабильные вычисления: exp (a) / exp (b)
Эквивалентное стабильное вычисление: exp (a — b)

Численно нестабильные вычисления: Πя = 1..n пя
Эквивалентное стабильное вычисление: exp (Σя = 1..n войти (ря))

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector