使用超几何分布来计算概率我在math.stackexchange中得到了一些帮助,但我在java中计算这个有问题
我不是这方面的专家,我一直想弄清楚没有运气,我知道问题出在我的java代码上,因为当我在我的计算器上尝试公式时,我得到了正确的结果,在这种情况下是0.364
这是公式
二分法以这种方式计算
(K k) = K! / ((K - k)! * k!)
这就是我试图在java代码中复制它的方式
public static void main(String[] args){
BigDecimal[] prob = HyperGeometricDistribution(20,2,50,5);
String _prob = prob[0] + "." + prob[1];
System.out.println(_prob);
}
private static BigDecimal fact(BigDecimal n) {
BigDecimal result = BigDecimal.ONE;
while (!n.equals(BigDecimal.ZERO)) {
result = result.multiply(n);
n = n.subtract(BigDecimal.ONE);
}
return result;
}
private static BigDecimal Binomial(int a, int b) {
return fact(BigDecimal.valueOf(a)).divide(fact(BigDecimal.valueOf(a-b)).multiply(fact(BigDecimal.valueOf(b))), BigDecimal.ROUND_DOWN);
}
// K : Number of Successes in Population
// k : number of Successes in Sample
// N : Population Size
// m : Sample Size
private static BigDecimal[] HyperGeometricDistribution(int K,int k, int N, int m){
return (Binomial(K,k).multiply(Binomial(N-K,m-k))).divideAndRemainder(Binomial(N,m));
}
这将打印0.77但正确的答案是0.364 Online Example
我将在android中使用它,我将传递的最大值 N 是3910我需要使用BigDecimals,因为我需要计算3910!这是一个巨大的数字。
感谢任何帮助
答案 0 :(得分:1)
divideAndRemainder()
的其余部分不是十进制表示的小数部分。你需要将余数除以实际除数。
但实际上,您不需要BigDecimal
。你只需要一种聪明的计算方法。让我们检查二项式系数的公式,例如n=5, k=3
。然后:
c(5, 3) = (5 * 4 * 3 * 2 * 1) / ((2 * 1) * (3 * 2 * 1))
如您所见,(n-k)!
部分完全取消,最后以
c(5, 3) = (5 * 4 * 3) / (3 * 2 * 1)
= 5/3 * 4/2 * 3/1
所以你只需要乘以k
分数。如果你总是减少分数,你将不需要非常大的数字。事实上,超几何分布的计算也是一个分数,你可以再次减少事情以保持数字较小。这是一些执行此操作的C#代码。它没什么特别的,几乎完全转化为Java:
static class GCDHelper
{
public static long GCD(long a, long b)
{
while(b != 0)
{
var temp = b;
b = a % b;
a = temp;
}
return a;
}
}
class Fraction
{
public long Numerator;
public long Denominator;
public Fraction(long numerator, long denominator)
{
this.Numerator = numerator;
this.Denominator = denominator;
}
public void Reduce()
{
var gcd = GCDHelper.GCD(Numerator, Denominator);
Numerator /= gcd;
Denominator /= gcd;
}
public double ToNumber() { return (double)Numerator / Denominator; }
}
class Program
{
static void MultiplyBinomialCoefficient(int n, int k, bool inverse, Fraction f)
{
if (k > n / 2)
k = n - k;
for(int i = 1; i <= k; ++i)
{
if (!inverse)
{
f.Numerator *= n - i + 1;
f.Denominator *= i;
}
else
{
f.Denominator *= n - i + 1;
f.Numerator *= i;
}
f.Reduce();
}
}
static double Hypergeometric(int K, int k, int N, int m)
{
var f = new Fraction(1, 1);
MultiplyBinomialCoefficient(K, k, false, f);
MultiplyBinomialCoefficient(N - K, m - k, false, f);
MultiplyBinomialCoefficient(N, m, true, f);
return f.ToNumber();
}
static void Main(string[] args)
{
Console.WriteLine(Hypergeometric(20, 2, 50, 5));
}
}
结果:
0.364080877494384
还有一些参数组合让数字溢出。幸运的是,您只需将long
变量替换为BigInteger
变量(并相应地调整运算符)。其余的应该可以正常工作。