Среднее значение очень малых значений - PullRequest
3 голосов
/ 09 сентября 2011

Я пытаюсь вычислить логарифм среднего некоторых очень маленьких значений. Для текущего набора данных крайние точки:

log_a=-1.6430e+03;
log_b=-3.8278e+03;

Таким образом, в действительности я хочу вычислить (a+b) / 2 или log((a+b)/2), поскольку я знаю, что (a+b)/2 слишком мал, чтобы хранить его как двойное число.

Я рассмотрел попытку дополнить все константой, чтобы вместо хранения log_a я бы сохранил log_a+c, но кажется, что a и b достаточно далеко друг от друга, чтобы дополнить log_b достаточно, чтобы сделать exp(log_b+c) вычислимым, я бы в итоге сделал exp(log_a+c) слишком большим.

Я упускаю какой-то очевидный способ сделать это вычисление? Насколько я знаю, MATLAB не позволит мне использовать ничего, кроме двойной точности, поэтому я озадачен тем, как я могу сделать это простое вычисление.

РЕДАКТИРОВАТЬ: Чтобы уточнить: я могу вычислить точный ответ для этих конкретных значений. Для других запусков алгоритма значения будут другими и могут быть ближе друг к другу. До сих пор было несколько хороших предложений для приближений; если точное решение не представляется возможным, есть ли другие приближения для более общих чисел / величин значений?

Ответы [ 4 ]

4 голосов
/ 09 сентября 2011

Mystical имеет правильную идею, но для более общего решения, которое дает вам логарифм среднего арифметического вектора log_v чисел, уже используемых в домене журнала:

max_log = max(log_v);
logsum = max_log + log(sum(exp(log_v-max_log)));
logmean = logsum - log(length(log_v));

ЭтоРаспространенная проблема в статистическом машинном обучении, поэтому, если вы выполните поиск в Google для logsum.m, вы найдете несколько разных версий функций MATLAB, которые исследователи написали для этой цели.Например, вот ссылка Github на версию, которая использует те же соглашения о вызовах, что и sum.

4 голосов
/ 09 сентября 2011

Ну, exp(log_b) настолько меньше, чем exp(log_a), что вы можете полностью игнорировать этот термин и все же получить правильный ответ относительно двойной точности:

exp(log_a) = 2.845550077506*10^-714
exp(log_b) = 4.05118588390*10^-1663

Если вы на самом деле пытаетесьчтобы вычислить (exp(log_a) + exp(log_b)) / 2, ответ в любом случае опустился бы до нуля.Так что это на самом деле не имеет значения, если вы не пытаетесь взять другой логарифм в конце.

Если вы пытаетесь вычислить:

log((exp(log_a) + exp(log_b)) / 2)

Лучше всего изучить разницумежду log_a и log_b.Если разница велика, просто примите окончательное значение равным большему члену - log (2), так как меньший член будет достаточно мал, чтобы полностью исчезнуть.

РЕДАКТИРОВАТЬ:

ТакВаш окончательный алгоритм может выглядеть следующим образом:

  1. Проверьте величины.Если abs(log_a - log_b) > 800.Возврат max(log_a,log(b)) - log(2).
  2. Проверьте любую величину (они будут близко друг к другу в этой точке).Если он намного больше или меньше 1, добавьте / вычтите постоянную из log_a и log_b.
  3. . Выполните расчет.
  4. Если значения были масштабированы на шаге 2.Уменьшите результат.

РЕДАКТИРОВАТЬ 2:

Вот еще лучшее решение:

if (log_a > log_b)
    return log_a + log(1 + exp(log_b - log_a)) - log(2)
else
    return log_b + log(1 + exp(log_a - log_b)) - log(2)

Это будет работать, если log_a и log_bне слишком большой или отрицательный.

0 голосов
/ 09 сентября 2011

Что ж, если вам не нравится мое предыдущее предложение полностью изменить платформы и вы ищете приблизительное значение, почему бы просто не использовать вместо него среднее геометрическое (exp ((log_a + log_b) / 2)?

0 голосов
/ 09 сентября 2011

Используйте http://wolframalpha.com.Например, как обсуждал Mysticial, ваш расчет log (exp (-1.6430e + 03) + exp (-3.8278e + 03) / 2) приблизительно равен log_a.Точнее он равен ...

1642 ....

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