2016-09-29 2 views
0

Ich bin ein gelegten Wahrscheinlichkeit unter Verwendung eines Hypergeometrische Verteilung zu berechnen Tring i im math.stackexchange dazu etwas Hilfe bekommen, aber ich habe Probleme Berechnung dieses in JavaHypergeometrische Verteilung nicht gut funktionieren java

Ich bin kein Experte auf diesem aufweist, i wurde tring es ohne Glück, um herauszufinden, ich kenne das Problem auf meinem Java-Code ist, weil, wenn ich die Formel auf meinem Rechner versuche ich das richtige Ergebnis erhalten whitch 0.364 in diesem Fall ist

Dies ist die Formel

enter image description here

Binomialmodelle wird auf diese Weise berechnet

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

Dies ist, wie im diese versuchen, Code in Java zu replizieren

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)); 
} 

Diese 0,77 gedruckt wird jedoch die richtige Antwort 0,364 Online Example

ist Ich werde das in Android verwenden, der maximale Wert, den ich in überschreiten werde N ist 3910 Ich muss BigDecimals seit ich verwenden muss 3910 berechnen! und das ist eine riesige Anzahl.

Jede Hilfe ist

geschätzt

Antwort

1

Der Rest divideAndRemainder() ist nicht der Bruchteil einer Dezimaldarstellung. Sie müssten den Rest durch den tatsächlichen Divisor teilen.

Aber eigentlich brauchen Sie nicht BigDecimal. Sie brauchen nur eine kluge Art, es zu berechnen. Lassen Sie uns die Formel für den Binomialkoeffizienten und zum Beispiel n=5, k=3 überprüfen. Dann:

c(5, 3) = (5 * 4 * 3 * 2 * 1)/((2 * 1) * (3 * 2 * 1)) 

Wie Sie sehen, bricht der (n-k)! Teil vollständig aus und Sie am Ende mit

c(5, 3) = (5 * 4 * 3)/(3 * 2 * 1) 
     = 5/3 * 4/2 * 3/1 

So brauchen Sie nur k Fraktionen multiplizieren. Und wenn Sie die Brüche immer reduzieren, brauchen Sie keine sehr großen Zahlen. Tatsächlich ist die Berechnung der hypergeometrischen Verteilung auch ein Bruchteil, in dem Sie Dinge wieder reduzieren können, um die Zahlen klein zu halten. Hier ist ein C# -Code, der das tut. Es ist nichts Besonderes und übersetzt fast genau auf 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)); 
    } 
} 

Ergebnis:

0.364080877494384 

Es gibt immer noch ein paar Parameter-Kombinationen sind, die die Zahlen Überlauf lassen. Glücklicherweise können Sie einfach die Variablen long durch BigInteger ersetzen (und die Operatoren entsprechend anpassen). Der Rest sollte dann gut funktionieren.

+0

Ich musste die "Long" durch "BigInteger" ersetzen, weil ich Probleme mit großen Zahlen hatte, aber jetzt funktioniert alles sehr gut –

Verwandte Themen