-
Notifications
You must be signed in to change notification settings - Fork 54
/
Binomial.fs
71 lines (64 loc) · 3.56 KB
/
Binomial.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
namespace FSharp.Stats.SpecialFunctions
open System
/// Special mathematical functions
module Binomial =
///<summary>
/// Returns the binomial coeffcient (n | k) via the factorial formula.
///
/// for some combinations of n and k, this might result in overflows.
///
/// The caller is responsible to handle edge cases such as nan, infinity, and -infinity in the input
///</summary>
///<param name="n">input for n in the computation of (n | k)</param>
///<param name="k">input for k in the computation of (n | k)</param>
let _coeffcient (n:int) (k:int) =
if ( n < 0 || k < 0 || k > n) then invalidArg "Binomial.coeffcient" ""
if (n < 171) then
//floor (0.5 + Factorial.factorial n / ((Factorial.factorial k) * (Factorial.factorial (n-k))))
Factorial.factorial n / ((Factorial.factorial k) * (Factorial.factorial (n-k)))
else
floor (0.5 + exp ((Factorial._factorialLn n) - (Factorial._factorialLn k) - (Factorial._factorialLn (n-k))))
///<summary>
/// Returns the binomial coeffcient (n | k) via the factorial formula.
///
/// for some combinations of n and k, this might result in overflows.
///
/// Edge cases in the input (nan, infinity, and -infinity) are catched and handled.
///
/// This might be slower than the unchecked version `_coefficient` but does not require input sanitation to get expected results for these cases.
///</summary>
///<param name="n">input for n in the computation of (n | k)</param>
///<param name="k">input for k in the computation of (n | k)</param>
let coeffcient (n:int) (k:int) =
if ( n < 0 || k < 0 || k > n) then invalidArg "Binomial.coeffcient" ""
if (n < 171) then
//floor (0.5 + Factorial.factorial n / ((Factorial.factorial k) * (Factorial.factorial (n-k))))
Factorial.factorial n / ((Factorial.factorial k) * (Factorial.factorial (n-k)))
else
floor (0.5 + exp ((Factorial.factorialLn n) - (Factorial.factorialLn k) - (Factorial.factorialLn (n-k))))
///<summary>
/// Returns the natural logarithm of the binomial coeffcient (n | k) via the factorial formula.
///
/// for some combinations of n and k, this might result in overflows.
///
/// The caller is responsible to handle edge cases such as nan, infinity, and -infinity in the input
///</summary>
///<param name="n">input for n in the computation of ln(n | k)</param>
///<param name="k">input for k in the computation of ln(n | k)</param>
let _coeffcientLn (n:int) (k:int) =
if ( n < 0 || k < 0 || k > n) then invalidArg "Binomial.coeffcient" ""
(Factorial._factorialLn n) - (Factorial._factorialLn k) - (Factorial._factorialLn (n-k))
///<summary>
/// Returns the natural logarithm of the binomial coeffcient (n | k) via the factorial formula.
///
/// for some combinations of n and k, this might result in overflows.
///
/// Edge cases in the input (nan, infinity, and -infinity) are catched and handled.
///
/// This might be slower than the unchecked version `_coefficient` but does not require input sanitation to get expected results for these cases.
///</summary>
///<param name="n">input for n in the computation of ln(n | k)</param>
///<param name="k">input for k in the computation of ln(n | k)</param>
let coeffcientLn (n:int) (k:int) =
if ( n < 0 || k < 0 || k > n) then invalidArg "Binomial.coeffcient" ""
(Factorial.factorialLn n) - (Factorial.factorialLn k) - (Factorial.factorialLn (n-k))