Variable ist zu klein



  • Ich hab mich grad mal hingesetzt und noch ein bißchen rumgerechnet.
    Ohne große Klimmzüge komme ich mit dieser Version wohl bis n=34.

    MfG Jester



  • Kannste mal Code posten dann wieß ich auch wat du mit Abchätzung meins. Bin net so gut in Mathe.



  • Also ich benutze immer folgende Funktion

    template<typename T>
      T Binomial(unsigned n, unsigned k)
    {
      if(k > n) return 0;
      if(k == n) return 1;
    
      T rval = 1;
      for(unsigned i = n; i != k; --i)
        rval *= i;
      for(unsigned i = n - k; i != 1; --i)
        rval /= i;
    
      return rval;
    }
    


  • Hab den Code grad nicht greifbar. Kommt heute abend (nacht) irgendwann oder morgen früh.

    MfG Jester



  • Man könnte ja auch eine zu große Zahl durch 65535 teilen, den Ganzzahlwert in einer unsigned _int64 und den Rest in einer unsigned int-Variable speichern. Zur Ausgabe mit cout rechnet man dann rückwärts



  • *knock* *knock*. Ich habe doch eine funktionierende Lösung gepostet. Wenn du die so aufrufst...

    unsigned long long x = Binomial<unsigned long long>(n, k);
    unsigned __int64 y = Binomial<unsigned __int64>(n, k);
    

    ...dann solltest du relativ hohe Werte erhalten können. Deine Idee mit dem dividieren funktioniert auch nur begrenzt und ist viel aufwändiger (NR sux 😃 ).



  • MaSTaH schrieb:

    unsigned long long x = Binomial<unsigned long long>(n, k);
    

    unsigned long long funktioniert bei mir nicht

    unsigned __int64 y = Binomial<unsigned __int64>(n, k);
    

    Mit der Variante kommst du bis 20!. Wenn du es aber machst, wie ich beschrieben hab (bloß mit zwei unsigned _int64), dann kommt man bis 34!.

    (NR sux 😃 ).

    Was heißt das???



  • Für die Praxis: Einfach logarithmisch rechnen mit double-Werten. Damit kommt man sehr weit!
    ln(k!) = Sum(i=1..k){ln(i)}

    #include <math.h>
    double LogFak(int k)
    {
    	double dLogSum = 0;
    	while(k > 1)
    	{
    		dLogSum += log((double) k);
    		--k;
    	}
    	return dLogSum;
    }
    


  • #define MERKE_ERSTE 1000 //Zum Beschleunigen die ersten paar Werte merken
    double LogFak(int k)
    {
    	static int siValid = 1; //Index, bis zu dem Array-Inhalt gueltig ist
    	static double sadLogFak[MERKE_ERSTE] = { 0 };
    	if(k <= siValid)
    		return sadLogFak[k];
    	double dLogSum = saLogFak[siValid];
    	int i = siValid + 1;
    	while(i < MERKE_ERSTE)
    	{
    		dLogSum += log((double) i);
    		sadLogFak[i] = dLogSum;
    		++i;
    	}
    	siValid = i - 1;
    	while(i <= k)
    	{
    		dLogSum += log((double) i);
    		++i;
    	}
    	return dLogSum;
    }
    


  • Sorry, kann noch keinen Logarithmus. Kannst du mir mal zeigen, was ich mit dem return-Wert anfangen soll und wieso der return-Wert bei 1 bis 999 gleich ist (wenn #define MAX_WERT 10000, dann sind sogar alle return-Werte bis 9999 gleich) 🙄 .



  • CME386 schrieb:

    unsigned long long funktioniert bei mir nicht

    Kann auch nicht jeder Compiler. Nur gcc, VC++ (>7)...

    CME386 schrieb:

    Mit der Variante kommst du bis 20!. Wenn du es aber machst, wie ich beschrieben hab (bloß mit zwei unsigned _int64), dann kommt man bis 34!

    Wieso Fakultät? Ich denke du willst 'nen Binomialkoeffizienten? Meine Variante kürzt schon vor dem berechnen des Bruches.

    CME386 schrieb:

    Was heißt das???

    "Neue Rechtschreibung" (NR) suckt. -> wg. aufwändig



  • Hast Recht, MaSTaH,
    ich hatte es eilig und hab deinen Code falsch gelesen. Liegt wohl daran, dass ich erst gestern Abend mit Templates angefangen hab. Aber jetzt seh ich, dass du Recht hast. 😉



  • Ist nur ein Funktionstemplate, damit man den Rückgabetyp bestimmen kann. Nix besonderes.


Anmelden zum Antworten