次のアルゴリズムで集中的に使用される係数の計算に依存するモデルチェッカーを作成しています。
![代替テキスト][1]
q
は double であり、t
double もk
int です。e
指数関数の略です。この係数は、(そのステップの) 前のすべての係数の合計が 1 に達するまで、常に 0 から始まり、変更さq
れt
ないステップで使用されます。k
私の最初の実装は文字通りのものでした:
let rec fact k =
match k with
0 | 1 -> 1
| n -> n * (fact (k - 1))
let coeff q t k = exp(-. q *. t) *. ((q *. t) ** (float k)) /. float (fact k)
k
もちろん、小さなしきい値 (15-20) を超えた場合、階乗全体を計算することは不可能だったので、これはそれほど長くは続きませんでした: 明らかに結果がおかしくなり始めました。そこで、インクリメンタル除算を行って全体を再配置しました。
let rec div_by_fact v d =
match d with
1. | 0. -> v
| d -> div_by_fact (v /. d) (d -. 1.)
let coeff q t k = div_by_fact (exp(-. q *. t) *. ((q *. t) ** (float k))) (float k)
q
このバージョンは、とt
で十分な「通常」の場合は非常にうまく機能しますが、たとえばq = 50.0
、一連の 0t = 100.0
から計算を開始しk = 0 to 100
、特定の数から最後まで NaN が続きます。
もちろん、これは、数値が 0 に近づき始める操作または同様の問題によって引き起こされます。
式を最適化して、幅広い入力に対して十分に正確な結果を得る方法について何か考えはありますか?
すべてがすでに 64 ビットである必要があります (デフォルトで double を使用する OCaml を使用しているため)。128 ビットの double を使用する方法もあるかもしれませんが、その方法はわかりません。
私は OCaml を使用していますが、C、C++、Java など、どの言語でもアイデアを提供できます。私はそれらすべてをかなり使用しました。