Laden...

Fakultät und Binomialkoeffizient

Erstellt von zerli vor 17 Jahren Letzter Beitrag vor 17 Jahren 6.394 Views
Z
zerli Themenstarter:in
31 Beiträge seit 2004
vor 17 Jahren
Fakultät und Binomialkoeffizient

habe leider in der system.math nichts gefunden wo und unter was muss ich suchen

sollte so ne formel berechnen

im notfall würde die fakultät und der binomialkoffizient auch mit eigenen funktionen gehen
nur wie mach ich das mit der summe richtig

for schleife?
wer ne idee

T
512 Beiträge seit 2006
vor 17 Jahren

Das musst du alles selbst implementieren. Ist ja aber nicht weiter schwer.

Du solltest dir aber unbedingt überlegen, wie genau du das Ergebnis wissen willst. Schon die Fakultät von 21 bringt Int64 zum Überlauf.
Da hilft entweder Double zu verwenden, wodurch du leichte Ungenauigkeiten verkraften musst, oder du suchst dir eine BigInteger Bibliothek für beliebig große ganze Zahlen (wie z.B. bei IronPython mitgeliefert).

Und du solltest so wenig wie möglich Fakultäten benutzen. Siehe die Definition von Wikipedia:

Wenn du double benutzt, wirst du wohl mit der Formel nach dem 1. = am günstigsten Fahren. Wenn du BigInteger benutzt, solltest du die Formel nach dem 2. = benutzen (da sonst gerundet wird).

Und beachte:

Wähle die Variante, wo der untere Teil kleiner ist.

e.f.q.

Aus Falschem folgt Beliebiges

B
1.529 Beiträge seit 2006
vor 17 Jahren

Die Summe machst du mit einer for-Schleife.
Ein größeres Problem sehe ich jedoch bei den Fakultäten. Bereits 13! überschreitet den Zahlbereich von int, 21! den von long. Damit könntest du nur auf BigInts ausweichen, welcher aber wiederum sehr langsam sind.
Die Fließkommatypen sind auch nicht genau genug.

Ich würde mir eine eigene Methode schreiben, welche Zahlen als Dictionary ihrer Faktorpotenzen darstellt. Damit kannst du dann den Binominalkoeffizient durch Kürzen derselben darstellen.

Also:

// Dictionary<Faktor, Potenz>
public Dictionary<int, int> Fakultät( int Zahl )
{
   Dictionary<int,int> intern;
   if (Zahl == 0)
   {
      intern = new Dictionary<int, int>( 0 );
   }
   else
   {
      intern = new Dictionary<int, int>( Zahl );
      for( int i = 1; i <= Zahl ; i++ )
      {
         intern[ i ] = 1;
      }
   }
   return intern;
}

// ZusammenfassenModeEnum
public enum ZME : int
{
   Multiplikation = +1;
   Division = -1;
}

public Dictionary<int, int> Zusammenfassen( Dictionary<int, int> Z, Dictionary<int, int> N, ZME Mode )
{
   Dictionary<int, int> intern = new Dictionary<int, int>( Z );
   List<int> nullExponent = new List<int>();
   foreach( KeyValuePair<int, int> kvp in N )
   {
      intern[kvp.Key] = ((intern.ContainsKey(kvp.Key)) ? intern[kvp.Key] : 0 ) + ((int)Mode * kvp.Value);
      if (intern[kvp.Key] == 0)
         nullExponent.Add( kvp.Key );
   }
   // x hoch null entfernen
   foreach( int val in nullExponent )
      intern.Remove( val );
}

public Dictionary<int, int> BinKoeff( int n, int k )
{
   if (k > n)
      throw new ArgumentException( "n >= k" );
   // [n über k] = n! / (k! * (n-k!));
   return Zusammenfassen( Fakultät(n), Zusammenfassen(Fakultät(k), Fakultät(n-k), ZME.Multiplikation), ZME.Division );
}

public Dictionary<int, int> Summenterm( int K, int G, int O, int i )
{
   // summenterm = BinKoeff( K - O; i ) * BinKoeff( O; G - i ) / BinKoeff( K; G )
   return Zusammenfassen( Zusammenfassen( BinKoeff( K - O, i ), BinKoeff( O, G - i ), ZME.Multiplikation ), BinKoeff( K, G ), ZME.Division );
}

public double Berechne( Dictionary<int, int> Zahl )
{
   double intern = 1;
   foreach( kvp<int, int> in Zahl)
   {
      intern *= Math.Pow( kvp.Key, kvp.Value );
   }
   return intern;
}

public double BerechneWahrscheinlichkeit( int K, int O, int G )
{
   double intern = 0.0;
   for( int i = 0; i <= G - 1; i++ )
   {
      intern += Berechne( Summenterm( K, G, O, i ) );
   }
   return 100*i;
}

Ungetestet, Aufruf per BerechneWahrscheinlichkeit( K, O, G ).

EDIT: Code angepasst

Z
zerli Themenstarter:in
31 Beiträge seit 2004
vor 17 Jahren

muss grad mal abchecken wie gross die werte überhaupt werden können
danke für die antworten

C
980 Beiträge seit 2003
vor 17 Jahren

Normalerweise berechnet man solche Terme logarithmisch, dann sind die grossen Zahlen kein Problem (und exp/ln kürzt sich praktischerweise oft weg). Also:

(a1a2)/(b1b2) = exp(ln(a1) + ln(a2) - ln(b1) - ln(b2))

Der Binomialkoeffizient ist übrigens in Math.NET Iridium fertig implementiert:

http://mathnet.opensourcedotnet.info/Iridium.aspx

Z
zerli Themenstarter:in
31 Beiträge seit 2004
vor 17 Jahren

das ist ja wirklich ein problem hab ich mir gar nicht gedacht muss mir wirklich was
überlegen vieleicht fällt mir ja nohc was ein

aber 52! oder 50! ist schon ne wirklich große zahl

naja danke

C
980 Beiträge seit 2003
vor 17 Jahren

52! = 80658175170943878571660636856403766975289505440883277824000000000000

ln(52!) = 156.3608363

Wie gesagt: Du must für deine Formel keine einzige Fakultät tatsächlich berechnen...