using System;
namespace Legalsoft.Truffer
{
public class Binomialdist : Beta
{
private int n { get; set; }
private double pe { get; set; }
private double fac { get; set; }
public Binomialdist(int nn, double ppe)
{
this.n = nn;
this.pe = ppe;
if (n <= 0 || pe <= 0.0 || pe >= 1.0)
{
throw new Exception("bad args in Binomialdist");
}
fac = Globals.gammln(n + 1.0);
}
public double p(int k)
{
if (k < 0)
{
throw new Exception("bad k in Binomialdist");
}
if (k > n)
{
return 0.0;
}
return Math.Exp(k * Math.Log(pe) + (n - k) * Math.Log(1.0 - pe) + fac - Globals.gammln(k + 1.0) - Globals.gammln(n - k + 1.0));
}
public double cdf(int k)
{
if (k < 0)
{
throw new Exception("bad k in Binomialdist");
}
if (k == 0)
{
return 0.0;
}
if (k > n)
{
return 1.0;
}
return 1.0 - betai((double)k, n - k + 1.0, pe);
}
public int invcdf(double p)
{
int inc = 1;
if (p <= 0.0 || p >= 1.0)
{
throw new Exception("bad p in Binomialdist");
}
int k = Math.Max(0, Math.Min(n, (int)(n * pe)));
int kl;
int ku;
if (p < cdf(k))
{
do
{
k = Math.Max(k - inc, 0);
inc *= 2;
} while (p < cdf(k));
kl = k;
ku = k + inc / 2;
}
else
{
do
{
k = Math.Min(k + inc, n + 1);
inc *= 2;
} while (p > cdf(k));
ku = k;
kl = k - inc / 2;
}
while (ku - kl > 1)
{
k = (kl + ku) / 2;
if (p < cdf(k))
{
ku = k;
}
else
{
kl = k;
}
}
return kl;
}
}
}