Числовая точность для журнала (1-exp (x)) - PullRequest
4 голосов
/ 26 июля 2011

Я занимаюсь математикой с действительно большими числами (я использую Python, но этот вопрос не относится к Python).Для одного значения у меня есть формула, которая дает мне f(t) = Pr(X < t).Я хочу использовать эту формулу, чтобы получить Pr(X >= t) = 1 - f(t).Поскольку f(t) возвращает значения очень близкие к нулю, я использую преобразование журнала и сохраняю log( f(t) ) вместо f(t).Мой log( f(t) ) порядка -1e5 или около того.

Для умножения это работает довольно хорошо.log( f(t) * g ) = log( f(t) ) + log(g).

Но очень сложно вычислить log( 1 - f(t) ), используя только log( f(t) );Я мог бы, конечно, временно возвести в степень значение, которое я храню и вычисляю log( 1 - exp( log( f(t) ) ), но это вернет log( 1 - 0.0 ) = 0.0, потому что log( f(t) ) так близко к нулю.

Вы можете спросить: «Почему вы заботитесь«Если оно близко к нулю, то 1 минус очень близко к 1.»Ну, это хорошая мысль, которую вы сделали.Ты умное печенье.

Проблема в том, что я хочу использовать это для ранжирования значений, поэтому мне действительно важно, если одно значение равно log(0.999), а другое - log(0.9999).Вы также можете спросить: «Ну, почему бы вам просто не оценить log( f(t) ), а затем изменить порядок, чтобы получить рейтинг для log( 1 - f(t) )».Опять же, я не могу не указать, насколько хороши ваши вопросы.Очень приятно было с вами пообщаться.

Но вот в чем проблема: я не хочу просто ранжироваться по 1 - f(t);Я на самом деле хочу ранжироваться на основе Pr(X >= t) * g(t) = (1 - f(t)) g(t).После взятия логов я получаю log( 1 - f(t) ) + log( g(t) );ранжирование, основанное только на f(t), не даст правильного ответа.

В прошлом я писал небольшую функцию Python для вычисления log(a + b) из log(a) и log(b):

def log_add(logA,logB):
    if logA == log(0):
        return logB
    if logA<logB:
        return log_add(logB,logA)
    return log( 1 + math.exp(logB-logA) ) + logA

Это помогает сначала нормализовать их так, чтобы они были близко друг к другу, а затем возвести в степень, когда они близко друг к другу.

К сожалению, я не смог заставить тот же трюк работать для моего вычитания, потому чтоне существует коэффициента нормализации, который бы сближал log(1) и log( f(t) ), потому что они так далеко друг от друга.

Кто-нибудь знает, как это решить?Это похоже на такую ​​классическую проблему;Я действительно ожидал / надеюсь / молюсь, что есть умная функция, которая работает на битовом уровне, которая может дать мне log(1-x) от log(x).Кроме того, если вы знаете , как это работает, я бы очень, очень хотел бы знать.

Ура!Оливер

1 Ответ

2 голосов
/ 28 июля 2011

Если log(f(t)) действительно равно -1e5 (или аналогичного порядка величины), то 0.0 - лучшее представление с плавающей запятой log(1-f(t)). В самом деле, f(t) = exp(-1e5) так, согласно ряду Тейлора, который упоминал Дьюир, log(1-f(t)) = -exp(-1e5) (это на самом деле не точное равенство, но это очень хорошее приближение). Теперь -exp(-1e5) = -3.56e-43430, но между 0 и -4e-324 нет чисел с плавающей запятой, поэтому наилучшее представление с плавающей запятой - 0.0.

Итак, то, что вы хотите сделать, невозможно при стандартных числах с плавающей запятой.

Имеет ли это значение? Вы говорите, что хотите ранжироваться на основе Pr(X >= t) * g(t) = (1 - f(t)) g(t), что эквивалентно ранжированию на log( 1 - f(t) ) + log( g(t) ). Выше мы обнаружили, что log(1-f(t)) = -3.56e-43430, поэтому этот термин будет иметь значение только в том случае, если различные значения log(g(t)) отличаются не более чем на это крошечное число и если ваши вычисления достаточно точны, чтобы его можно было различить по этим крошечным числам ( если вы используете стандартные числа с плавающей точкой, то ваши вычисления никогда не будут достаточно точными). Другими словами, если log(f(t)) действительно равно -1e5 или аналогично, то вы можете просто ранжировать на g(t).

Однако, возможно, что log(f(t)) имеет порядок -1e5, но иногда оно принимает значения, близкие к нулю, например -10 или -1. В этом случае вы не можете просто проигнорировать это, и вы действительно должны ранжироваться log(1-f(t)) + log(g(t)). Вы должны написать это, используя функцию math.log1p: rank by log1p(-f(t)) + log(g(t)). Причина в том, что если f (t) близко к нулю, то log(1-f(t)) является неточным, но log1p(-f(t)) является точным. Если f (t) очень близко к нулю, например, когда log(f(t)) = -1e5, то log1p(-f(t)) = 0.0, потому что это лучшее, что он может сделать, используя стандартные числа с плавающей запятой.

Я использую выражение "стандартные числа с плавающей запятой" по причине. Можно использовать числа с плавающей точкой с большей точностью, и если вы действительно хотите захватывать крошечные числа, такие как -3.56e-43430, это то, что вам следует делать. В Python есть одна возможность: mpmath (к сожалению, похоже, что она не поддерживает функцию log1p). Имейте в виду, что это намного медленнее, чем стандартные числа с плавающей запятой, и, как я уже сказал, я не думаю, что вам это понадобится. Тем не менее, стоит попробовать, если вы хотите лучше понять эти проблемы.

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