2016-09-29 41 views
0

進出口特林在math.stackexchange來計算這個使用超幾何分佈,我得到一些幫助一個probabilty但我有問題,在Java計算這個超幾何分佈都不盡如人意的Java

我不是這方面的專家,我一直特林沒有運氣來弄明白,我知道這個問題是我的Java代碼,因爲當我嘗試在我的計算公式,我得到正確的結果whitch在這種情況下

這是公式

是0.364

enter image description here

二項式計算這樣

(K k) = K!/((K - k)! * k!)

這是IM如何試圖在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!這是一個龐大的數字。

任何幫助理解

回答

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 

還有幾個參數的組合,讓數字溢出。幸運的是,您可以用BigInteger替換long變量(並相應地調整運算符)。其餘的應該工作得很好。

+0

我不得不用'BigInteger'替換'long',因爲我遇到了大數目的問題,但是現在一切都很順利,非常感謝 –