私の質問は、Rの組み込みの指数乱数ジェネレーターである関数に触発されましたrexp()
。指数分布の乱数を生成しようとする場合、多くの教科書では、このWikipediaページで概説されている逆変換方法を推奨しています。このタスクを実行する他の方法があることを知っています。特に、Rのソースコードは、Ahrens&Dieter(1972)の論文で概説されているアルゴリズムを使用しています。
アーレンスディーター(AD)法が正しいことを確信しました。それでも、逆変換(IT)メソッドと比較して、これらのメソッドを使用する利点はわかりません。ADは、ITよりも実装が複雑なだけではありません。スピードメリットもないようです。以下に、両方の方法のベンチマークを行うためのRコードと、それに続く結果を示します。
invTrans <- function(n)
-log(runif(n))
print("For the inverse transform:")
print(system.time(invTrans(1e8)))
print("For the Ahrens-Dieter algorithm:")
print(system.time(rexp(1e8)))
結果:
[1] "For the inverse transform:"
user system elapsed
4.227 0.266 4.597
[1] "For the Ahrens-Dieter algorithm:"
user system elapsed
4.919 0.265 5.213
2つの方法のコードを比較すると、ADは少なくとも2つの均一な乱数(C関数を使用unif_rand()
)を描画して、1つの指数乱数を取得します。ITは1つの均一な乱数のみを必要とします。対数を取るのがより均一な乱数を生成するよりも遅いかもしれないと想定していたため、おそらくRコアチームはITの実装に反対しました。対数を取る速度はマシンに依存する可能性があることを理解していますが、少なくとも私にとってはその逆です。おそらく、ITの数値精度に関連して、0の対数の特異性に関係する問題があるのでしょうか。しかし、その後、R
ソースコードsexp.cは、Cコードの次の部分が一様乱数uから先頭ビットを削除するため、ADの実装も数値精度を失うことを示しています。
double u = unif_rand();
while(u <= 0. || u >= 1.) u = unif_rand();
for (;;) {
u += u;
if (u > 1.)
break;
a += q[0];
}
u -= 1.;
uは後でsexp.cの残りの部分で均一な乱数としてリサイクルされます。これまでのところ、
- ITはコーディングが簡単です
- ITはより高速であり、
- ITとADの両方が数値精度を失う可能性があります。
RがADを唯一の利用可能なオプションとして実装している理由を誰かが説明していただければ幸いですrexp()
。
rexp(n)
ボトルネックになる単一のシナリオを考えることができないことを考えると、速度の違いは、変更を強く主張するものではありません(少なくとも私にとって)。どちらがより数値的に信頼できるかははっきりしませんが、数値の精度についてもっと心配するかもしれません。