4

私は本当に大きな数でいくつかの数学をやっています(私はPythonを使用していますが、この質問はPython固有ではありません)。1つの値について、私は私に与える式を持っています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.0log( f(t) )

「なぜ気にするのですか?ゼロに近い場合は、1から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)。また、それがどのように機能するかを知っているなら、私は本当に、本当に知りたいです。

乾杯!オリバー

4

1 に答える 1

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これは、関数rankbyを使用して記述する必要がありますlog1p(-f(t)) + log(g(t))。その理由は、f(t)がゼロに近い場合、log(1-f(t))不正確ですlog1p(-f(t))が正確であるためです。f(t)がゼロに非常に近い場合(の場合など)log(f(t)) = -1e5log1p(-f(t)) = 0.0それが標準の浮動小数点数を使用して実行できる最善の方法であるためです。

「標準浮動小数点数」という表現を使用しているのには理由があります。より正確に浮動小数点数を使用することは可能であり、本当にそのような小さな数をキャプチャしたい場合-3.56e-43430は、それを行う必要があります。1つの可能性はPythonでmpmathです(残念ながら、それは関数をサポートしていないようですlog1p)。これは標準の浮動小数点数よりもはるかに遅いことに注意してください。私が言ったように、これは必要ないと思います。ただし、これらの問題をよりよく理解したい場合は、一見の価値があります。

于 2011-07-28T09:46:31.997 に答える