log的数值精度(1-exp(x))

时间:2011-07-26 03:07:41

标签: statistics probability numerical-methods

我正在使用非常大的数字进行一些数学运算(我使用的是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 个答案:

答案 0 :(得分:2)

如果log(f(t))确实是-1e5(或类似的数量级),那么0.0是log(1-f(t))的最佳浮点表示。的确,f(t) = exp(-1e5)所以,通过dmuir提到的泰勒系列,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函数来写这个:按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函数)。请注意,这比标准浮点数慢得多,正如我所说,我认为你不需要它。但是,如果你想更好地理解这些问题,那就值得一试。