Eulersche Zahl, lustiges Problem (haha)

Dieses Thema im Forum "C/C++" wurde erstellt von tr0nix, 17.01.2005.

  1. tr0nix

    tr0nix der-mit-dem-tux-tanzt

    Dabei seit:
    11.07.2003
    Beiträge:
    1.585
    Zustimmungen:
    0
    Ort:
    Schweiz, Opfikon/Glattbrugg
    Sali zaeme

    Ich bin gerade wieder am C lernen und implementiere gerade den Algorithmus zum ausrechnen der eulerschen Zahl.

    Mit dem Exponent 1 und der oben stehenden Formel erhalte ich das Resultat von 2.7182818... was laut wikipedia.org auch korrekt ist.

    Ich definiere eine gewisse Genauigkeit die man eingeben kann. Sprich als Beispiel eine Genauigkeit von 1E-10. Wenn x^y/y! nun kleiner ist, als die Genauigkeit, bricht er ab.

    Beim y = 16 bricht er bei mir jedoch ab, da das Resultat im negativen Bereich liegt.

    Hier mein Code (ja ich weiss es gibt pow() in math.h fuer Exponentialrechnen):
    Code:
    #include <stdio.h>
    
    int main(void)
    {
            double e, resultat, potenz, genauigkeit;
            int x, i, i_fak;
    
            printf("EULERSCHE ZAHL BERECHNEN\n");
            printf("------------------------\n\n");
            printf("Bitte x eingeben: "); scanf("%d", &x);
            printf("Bitte Genauigkeit eingeben: "); scanf("%lf", &genauigkeit);
    
            e = x + 1;
            i = 2;
            i_fak = 2;
            potenz = x;
    
            do
            {
                    potenz *= x;
                    resultat = potenz / i_fak;
                    e += resultat;
    
                    printf("resultat: %1.20lf - e: %1.20lf - schritt: %d\n", resultat, e, i - 1);
                    i_fak *= ++i;
            } while( resultat > genauigkeit );
    
            printf("Die Potenz der Eulersche Zahl mit Exponent %d ist: %1.20lf\n", x, e);
    }
    
    Das lustige nun: ich habe herrausgefunden, dass i_fak ueber den gueltigen Bereich des int hinausgeht. So schlau wie ich bin, habe ich daraus also ein "unsigned int" gemacht. Danach kommen jedoch nach dem Ueberschreiten des Grenzwertes so lustige Ausgaben wie:
    Code:
    resultat: Infinity - e: Infinity - schritt: 33 - potenz: 1.000000 - i_fak: 0
    Was ist das? Infinity als Ausgabe fuer einen int? Wie kann man dies am besten abfangen?

    Gruess
    Joel
     
  2. Anzeige

    Schau dir mal diese Kategorie an. Dort findest du bestimmt etwas.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  3. #2 etuli, 17.01.2005
    Zuletzt bearbeitet: 17.01.2005
    etuli

    etuli Betrunken

    Dabei seit:
    12.04.2003
    Beiträge:
    278
    Zustimmungen:
    0
    Die eulersche Zahl laesst sich ueberigens auch wesentlich einfacher ueber lim (1+1/n)^n bestimmen, wobei der limes n gegen unendlich laufen laesst. Waehlst du also n nur gross genug, so bekommst du ein entsprechend genaues Ergebnis. :D

    Wenn du eine andere sinnlose Aufgabe brauchst, kannst du ja mal die sqrt von 2 berechnen.

    Wird der Wertbereich von unsigned int ueberschritten, gehts wieder bei 0 los, da ((unsigned int)-1 = 0xff...ff) + 1 = 0

    mfg
     
  4. thorus

    thorus GNU-Freiheitskämpfer

    Dabei seit:
    03.11.2002
    Beiträge:
    757
    Zustimmungen:
    0
    Ort:
    Passau, Niederbayern
    Nein, das Inf steht bei den doubles. ;)
    Das Problem bei unsigned ist, wie etuli schon gesagt hat, dass es mit 0 weitergeht, sprich, dein resultat wird nicht negativ bzw. so klein wie du es für die Genauigkeit haben willst und du gehst natürlich Richtung unendlich.

    Ich habe in deinem Programm die ints durch long ersetzt und die scanfs/printfs angepasst. Funktioniert super, bis ca. 1e-19:
    Code:
    resultat: 0.50000000000000000000 - e: 2.50000000000000000000 - schritt: 1
    resultat: 0.16666666666666665741 - e: 2.66666666666666651864 - schritt: 2
    resultat: 0.04166666666666666435 - e: 2.70833333333333303727 - schritt: 3
    resultat: 0.00833333333333333322 - e: 2.71666666666666634100 - schritt: 4
    resultat: 0.00138888888888888894 - e: 2.71805555555555544700 - schritt: 5
    resultat: 0.00019841269841269841 - e: 2.71825396825396836675 - schritt: 6
    resultat: 0.00002480158730158730 - e: 2.71827876984127003723 - schritt: 7
    resultat: 0.00000275573192239859 - e: 2.71828152557319224769 - schritt: 8
    resultat: 0.00000027557319223986 - e: 2.71828180114638451315 - schritt: 9
    resultat: 0.00000002505210838544 - e: 2.71828182619849290091 - schritt: 10
    resultat: 0.00000000208767569879 - e: 2.71828182828616871092 - schritt: 11
    resultat: 0.00000000016059043837 - e: 2.71828182844675936281 - schritt: 12
    resultat: 0.00000000001147074560 - e: 2.71828182845823018710 - schritt: 13
    resultat: 0.00000000000076471637 - e: 2.71828182845899490871 - schritt: 14
    resultat: 0.00000000000004779477 - e: 2.71828182845904287035 - schritt: 15
    resultat: 0.00000000000000281146 - e: 2.71828182845904553488 - schritt: 16
    resultat: 0.00000000000000015619 - e: 2.71828182845904553488 - schritt: 17
    resultat: 0.00000000000000000822 - e: 2.71828182845904553488 - schritt: 18
    resultat: 0.00000000000000000041 - e: 2.71828182845904553488 - schritt: 19
    resultat: -0.00000000000000000024 - e: 2.71828182845904553488 - schritt: 20
    Die Potenz der Eulersche Zahl mit Exponent 1 ist: 2.71828182845904553488
    
    Oder mit mehr Nachkommastellen:
    Code:
    EULERSCHE ZAHL BERECHNEN
    ------------------------
    
    Bitte x eingeben: 1
    Bitte Genauigkeit eingeben: 1e-19
    resultat: 0.500000000000000000000000000000 - e: 2.500000000000000000000000000000 - schritt: 1
    resultat: 0.166666666666666666671184175719 - e: 2.666666666666666666738946811499 - schritt: 2
    resultat: 0.041666666666666666667796043930 - e: 2.708333333333333333477893622998 - schritt: 3
    resultat: 0.008333333333333333333728615375 - e: 2.716666666666666666912419159097 - schritt: 4
    resultat: 0.001388888888888888888848890111 - e: 2.718055555555555555854313487529 - schritt: 5
    resultat: 0.000198412698412698412698370683 - e: 2.718253968253968254212629696021 - schritt: 6
    resultat: 0.000024801587301587301587296335 - e: 2.718278769841269841426104059146 - schritt: 7
    resultat: 0.000002755731922398589065186217 - e: 2.718281525573192240101752514825 - schritt: 8
    resultat: 0.000000275573192239858906513452 - e: 2.718281801146384479969317360393 - schritt: 9
    resultat: 0.000000025052108385441718774685 - e: 2.718281826198492865352684955127 - schritt: 10
    resultat: 0.000000002087675698786809897890 - e: 2.718281828286168564116562218480 - schritt: 11
    resultat: 0.000000000160590438368216145993 - e: 2.718281828446759002416294181970 - schritt: 12
    resultat: 0.000000000011470745597729724714 - e: 2.718281828458229747993643576898 - schritt: 13
    resultat: 0.000000000000764716373181981648 - e: 2.718281828458994464408834956792 - schritt: 14
    resultat: 0.000000000000047794773323873853 - e: 2.718281828459042259076364200787 - schritt: 15
    resultat: 0.000000000000002811457254345521 - e: 2.718281828459045070629437890197 - schritt: 16
    resultat: 0.000000000000000156192069685862 - e: 2.718281828459045226754550728110 - schritt: 17
    resultat: 0.000000000000000008220635246624 - e: 2.718281828459045234994487239000 - schritt: 18
    resultat: 0.000000000000000000411031762331 - e: 2.718281828459045235428168107994 - schritt: 19
    resultat: -0.000000000000000000235333429436 - e: 2.718281828459045235211327673497 - schritt: 20
    Die Potenz der Eulersche Zahl mit Exponent 1 ist: 2.718281828459045235211327673497
    Dann hab ich mir gedacht, jetzt gibts ihm den Rest, also die doubles zu long doubles und die longs zu long longs mit den entsprechenden Anpassungen fuer die Ein-/Ausgabe. Das hat aber leider trotzdem nichts gebracht, keine Ahnung warum.
    Hier scheint long und long long überzulaufen. Dass diese Datentypen so wie es aussieht die selben Wertigkeitsbereiche haben, könnte an meiner Architektur liegen, weil ich AMD64 habe. Probier einfach mal ein bisschen rum.

    Aber nicht vergessen: unsigned ist nicht ohne Weiteres möglich! Du könntest prüfen, ob i_fak 0 ist, weil eigentlich sollte man unendlich nur bei 1/0 (potenz/i_fak) bekommen. Aber das habe ich nicht getestet.

    Viel Spaß dabei noch! ;)
     
  5. Xanti

    Xanti Mouse Organist

    Dabei seit:
    05.09.2004
    Beiträge:
    1.855
    Zustimmungen:
    0
    Tja, das war mit Ansage. Die Fakultät wächst halt besonders schnell an.

    Gruss, Phorus
     
  6. tr0nix

    tr0nix der-mit-dem-tux-tanzt

    Dabei seit:
    11.07.2003
    Beiträge:
    1.585
    Zustimmungen:
    0
    Ort:
    Schweiz, Opfikon/Glattbrugg
    Sali Jungens

    Naja, ich mache das Buch zum zweiten mal durch - allerdings liegen etwa 1 1/2 Jahre dazwischen und ich bin nicht am Ball geblieben so, dass ich mich nochmals neu reinarbeiten muss. "long" war mir noch ein Begriff, hier jedoch noch nicht im Buch beschrieben.

    Das mit dem "overflow" von normalen, signed Werten kannte ich - also dass das erste bit von 0 zu 1 wurde und somit den gesamten Wert negativierte.

    thorus: es waer ja schoen, wenn ich es nach 0 checken koennte, dies ist allerdings nicht moeglich da ich ja nicht in "einer"-Schritten incrementiere sondern exponentiell arbeite.

    Ich meine folgendes:
    angenommen wir haben eine Grenze von 100. 101 wuerde wieder in 0 Resultieren. Wenn ich jetzt 11 * 9 mache, kriege ich 99. Wenn ich die Grenze ueberschreite mit 12 * 9 kriege ich jedoch nicht 0 sondern 8. Der Check:
    Laesst sich auch nicht bei allen Rechnungen benutzen. Das "ueberschreiben" der Grenze ist IMHO also echt schwer zu detektieren - besonders bei Userinput.


    Was ich dazu nicht verstehe ist folgendes:
    Teilweise sind die i_fak im negativen Bereich. Im Code steht jedoch:
    unsigned int i_fak;
    i_fak *= ++i;

    Wobei i immer positiv ist und nur inkrementiert wird. Wie wird das negativ?
     
  7. #6 etuli, 17.01.2005
    Zuletzt bearbeitet: 17.01.2005
    etuli

    etuli Betrunken

    Dabei seit:
    12.04.2003
    Beiträge:
    278
    Zustimmungen:
    0
    Das Problem ueber die Fakultaet zu loesen ist sinnlos, wie gesagt. Die Faklutaet waechst zu stark. Besser ist eine Loesung, die sich durch ausklammern einer beliebigen Partialsummer der e-Reihe ergibt. (siehe Anhang)

    Code:
    #include <stdio.h>
    
    double e_help(double x, unsigned int i, unsigned int n)
    {
    	 if(i == n)
    		  return(1);
    	 return( 1 + (x / i) * e_help(x, i + 1, n));
    }
    
    double e(double x, unsigned long n)
    {
    	 return( e_help(x, 1, n));
    }
    
    int main()
    {
    	 printf( "%.40lf\n", e(1.0,100000));
    }
    
    [edit]
    Das liegt in einer falschen Darstellung deinerseits. Etwa mit printf und %d. Du muesstest %u verwenden, oder entsprechend anderes.
     

    Anhänge:

    • foo.png
      foo.png
      Dateigröße:
      5,8 KB
      Aufrufe:
      20
  8. #7 tr0nix, 17.01.2005
    Zuletzt bearbeitet: 17.01.2005
    tr0nix

    tr0nix der-mit-dem-tux-tanzt

    Dabei seit:
    11.07.2003
    Beiträge:
    1.585
    Zustimmungen:
    0
    Ort:
    Schweiz, Opfikon/Glattbrugg
    $ ./test
    Segmentation Fault(coredump)

    Hab ich was verpasst? :-) Habs auf Solaris 10 kompiliert.

    // Edit
    Aaah, mit 1000 Durchgaengen funktionierts! Interessanter Code, zwar wohl nicht das, was in der Beispielaufgabe erwartet war, aber interessant!
     
  9. #8 etuli, 17.01.2005
    Zuletzt bearbeitet: 17.01.2005
    etuli

    etuli Betrunken

    Dabei seit:
    12.04.2003
    Beiträge:
    278
    Zustimmungen:
    0
    Du hast n zu gross gewaehlt vermutlich. Oder n ist allg. bei dir zu gross. Loesung ist die Ueberfuehrung in eine Schleife. :D

    Code:
    double e(double x, unsigned int n)
    {
    	 unsigned int i;
    	 double r = 1;
    
    	 for( ; n > 0 ; n --)
    		  r = r * (x / n) + 1;
    	 return( r);
    }
    
    Womit wird dann wieder waeren bei (1 + x/n)^n = e^x. ;o)

    mfg
     
  10. tr0nix

    tr0nix der-mit-dem-tux-tanzt

    Dabei seit:
    11.07.2003
    Beiträge:
    1.585
    Zustimmungen:
    0
    Ort:
    Schweiz, Opfikon/Glattbrugg
    Jeps, habs oben noch mit nem Edit nachgefuegt. Sag mal, bist du eigentlich Mathestudent oder was :)! Hab einfach die gegebene Formel versucht umzusetzen, diese umzuformen war ich nicht imstande!
     
  11. etuli

    etuli Betrunken

    Dabei seit:
    12.04.2003
    Beiträge:
    278
    Zustimmungen:
    0
    "Nur" Informatikstudient. :)
     
  12. tr0nix

    tr0nix der-mit-dem-tux-tanzt

    Dabei seit:
    11.07.2003
    Beiträge:
    1.585
    Zustimmungen:
    0
    Ort:
    Schweiz, Opfikon/Glattbrugg
    Na du hast Glueck.. ich zweifle hier unterdessen langsam an mir selbst! Jetzt ist die naechste Aufgabe, ein Programm zu schreiben, dass den Sinus berechnet.

    Die zu implementierende Formel ist:
    (Siehe Reihenentwicklung Sinus auf http://de.wikipedia.org/wiki/Sinus)

    Wieso stimmt das, was ich unten habe nicht? Ich kriege total verrueckte Werte mit der Zeit!
    Sollte sein: 0.05233595624294383

    Code:
    #include <stdio.h>
    
    int main(void)
    {
            int i, i_switch;
            double x, x_exp, res, summe, fak;
    
            printf("x: "); scanf("%lf", &x);
    
            i = 3;
            x_exp = x;
            fak = 1;
            res = 0;
            i_switch = -1;
            summe = x;
    
            do {
                    x_exp *= x * x;
                    fak *= (i - 1) * i;
                    res = x_exp / fak;
                    i += 2;
    
                    printf("Rechne Summe %lf + (%d * %lf) = ", summe, i_switch, res);
    
                    summe += (i_switch * res);
    
                    printf("%lf\n", summe);
    
                    i_switch *= -1;
            } while ( i != 15 );
    
            printf("Resultat: %lf\n", summe);
    }
    
    
    Ich habe es sogar haendisch nachgerechnet und bis zu der Fakultaet 9 dieselben Resultate gekriegt.

    Mach ich hier in Mathe was falsch? Ich weiss der while-Abbruch ist ein wenig unsauber, aber bin am debuggen und viel scheint sich an dem Resultat danach auch nicht zu aendern.
     
  13. etuli

    etuli Betrunken

    Dabei seit:
    12.04.2003
    Beiträge:
    278
    Zustimmungen:
    0
    Die Formel von oben ist soweit richtig. Allerdings reicht es, wenn du berechnest fuer jeden Summand der Summe, und wenn i dein Zaehler von 0 bis k ist, mit 1er Schritten:

    Code:
    (-1)^k * x^(2k+1)
    -------------------
    (2k+1)!
    
     
  14. tr0nix

    tr0nix der-mit-dem-tux-tanzt

    Dabei seit:
    11.07.2003
    Beiträge:
    1.585
    Zustimmungen:
    0
    Ort:
    Schweiz, Opfikon/Glattbrugg
    Hm, hey langsam macht mir Mathe wieder spass! Ich hatte irgendwie immer Probleme, aber wenn ich solche mathematischen Aufgaben zusammen mit Programmieren lösen soll, finde ich wieder gefallen an all den Formeln und besonders Motivation, mich darin zu vertiefen!

    Du hast die letzte Aufgabe bereits mit Einzelschritten und einem rekursiven Loop gelöst - aber ändert sich etwas am Resultat? Was mich verwirrte, war ja, dass sin(3) im Taschenrechner nicht zu demselben Resultat kam, wie ich mit meinem Code.

    Werde mal versuchen, deinen Code ähnlich deiner ersten Lösung (mit rekursiven Aufrufen) zu lösen!

    Thx auf alle Fälle für deine Geduld :winke:
     
  15. Anzeige

    Vielleicht findest du HIER Antworten.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  16. #14 Lord Kefir, 19.01.2005
    Lord Kefir

    Lord Kefir König

    Dabei seit:
    10.06.2004
    Beiträge:
    944
    Zustimmungen:
    0
    Öhm, in einem ordentlich Buch über's Programmieren sollten (finde ich) am Anfang wenigstens Datentypen beschrieben werden. Was hast Du denn für ein Buch, wenn ich mal nachfragen darf?!

    Mfg, Lord Kefir
     
  17. tr0nix

    tr0nix der-mit-dem-tux-tanzt

    Dabei seit:
    11.07.2003
    Beiträge:
    1.585
    Zustimmungen:
    0
    Ort:
    Schweiz, Opfikon/Glattbrugg
    Es ist schon ein schlaues Buch. Es hat einfach zuerst die "einfachen" Datentypen beschrieben wie int und char und kommt dann zu den Schleifen und Abfragen. Also basic Syntax und geht dann weiter mit den erweiterten Datentypen.
     
Thema:

Eulersche Zahl, lustiges Problem (haha)

Die Seite wird geladen...

Eulersche Zahl, lustiges Problem (haha) - Ähnliche Themen

  1. Dateien selektieren und zählen

    Dateien selektieren und zählen: Hallo, das ist mein erster Beitrag, bitte entschuldigt, falls nicht alles richtig geschrieben ist. Ich muss meine erste Hausaufgabe als...
  2. »Humble Staff Picks« mit zahlreichen Linux-Spielen

    »Humble Staff Picks« mit zahlreichen Linux-Spielen: Das Humble-Bundle-Team hat ein weiteres »Humble Bundle« geschnürt. Unter dem Titel »Humble Staff Picks« finden sich zahlreiche Spiele, die auch...
  3. Linux Presentation Day 2016.1 in zahlreichen Städten

    Linux Presentation Day 2016.1 in zahlreichen Städten: Am 30. April wollen User Groups, Studenten, Unternehmen und Bildungseinrichtungen in mehr als 80 deutschen Städten den Linux Presentation Day...
  4. Nmap 7.10 mit zahlreichen neuen Skripten und Fingerabdrücken

    Nmap 7.10 mit zahlreichen neuen Skripten und Fingerabdrücken: Der Nmap-Entwickler Gordon »Fyodor« Lyon hat bekannt gegeben, dass eine neue Version des populären, freien Netzwerkscanners veröffentlicht wurde....
  5. Nmap 7.10 mit zahlreichen neuen Skripten und Fingerabdrücken

    Nmap 7.10 mit zahlreichen neuen Skripten und Fingerabdrücken: Der Nmap-Entwickler Gordon »Fyodor« Lyon hat bekannt gegeben, dass eine neue Version des populären, freien Netzwerkscanners veröffentlicht wurde....