Hello, I'm writing a model-checker which relies on the computation of a coefficient which is used intensively by the algorithms which is the following:
where q
is double, t
a double too and k an int. e
stands for exponential function. This coefficient is used in steps in which q
and t
don't change while k
always starts from 0 until the sum of all previous coefficients (of that step) reaches 1.
My first implementation was a licteral one:
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)
Of course this didn't last so much since computing the whole factorial was just unfeasable when k
went over a small threshold (15-20): obviously results started to go crazy. So I rearranged the whole thing by doing incremental divisions:
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)
This version works quite well when q
and t
are enough 'normal' but when things gets strange, eg q = 50.0
and t = 100.0
and I start to calculate it from k = 0 to 100
what I get is a serie of 0s followed by nans from a certain number until the end.
Of course this is caused by operations with numbers that start to get too near to 0 or similar problems.
Do you have any idea in how I can optimize the formula to be able to give enough accurate results over a wide spread of inputs?
Everything should be already 64 bit (since I'm using OCaml which uses doubles by default). Maybe there is a way to use 128 bit dobules too but I don't know how.
I'm using OCaml but you can provide ideas in whatever language you want: C, C++, Java, etc.. I quite used all of them.
Thanks in advance