tutorials.de Buch-Aktion 05/2012
ERLEDIGT
JA
ANTWORTEN
10
ZUGRIFFE
343
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    saeba saeba ist offline Rookie
    Registriert seit
    Nov 2011
    Beiträge
    5
    Hallo allersetis,

    ich muss folgendes Programmieren:
    Ich soll beweisen das Gleitkommatypen mit den Operatoren + und * nicht assoziativ sind.

    ich habe mir folgendes ausgedacht:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    
    #include <iostream>
    #include <cstdlib>
    #include <cmath>
    #include <iomanip>
    using namespace std;
    void Assoziativ(){
    // Allgemein gillt a+(b+c) = (a+b)+c
    // Allgemeint gillt (a*b)*c = a*(b*c)
    int a = 3; int b = 7; int c = 2; int result;
    result = a+(b+c); cout<<"3+(7+2) = "<<result<<endl;
    result = (a+b)+c; cout<<"(3+7)+2 = "<<result<<endl;
     
     
    }
    void BeweisFloat(){
    float a = 0.05; float b = 0.70; float c =b-a; float result;
    //a+(b+c)
    result = a+(1+b); cout <<"res1 "<<result<<endl;
    result = (a+b)+1; cout <<"res2 "<<result<<endl;
    }
    void BeweisFloatv2(){
    // Gleitkommatypen float, double und long double
    //double a = 10213.32452e10; double b=1; double c = 11.334; double res;
    //(a+b)+c
    double a = 6.*1024*1024*1024*1024*1024; double res;
    res= a;
    res=res+1;
    res=res+1;
     
    cout << setprecision(15) << setw(12) << res << endl;
    //cout<<res<<endl;
    //a+(b+c)
    res=a+2;
    cout << setprecision(15) << setw(12) << res << endl;
    //cout<<res<<endl;
    //result = a+result2; cout<<" "<<result<<" result 2 "<<result2<<endl;
    //cout<<endl;
    //result2 = (a+b);
    //result = result2+c; cout<<" "<<result<<" result 2 "<<result2<<endl;
    //
     
    }
    int main(){
    Assoziativ();
    cout<<endl;
    BeweisFloat();
    system("pause");
    return 0;
    }

    ich habe eine Methode Beweis das zunächst zeigen soll was mit Assoziativ gemeint ist und mit den anderen Methoden habe ich versucht zu beweisen das mit dem Typ float das Assoziativgesetz nicht gilt. Ich habe aber das Problem das die beiden ergebnisse gleich sind statt unterschiedlich. Ich weiß nicht warum das so ist was mache ich falsch bzw. wie könnte ich es sonst beweisen ?
    Geändert von saeba (01.11.11 um 21:25 Uhr)
     

  2. #2
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Hi und Willkommen bei tutorials.de

    Zum Code: Bitte mach doch irgendeine Art von Zeileneinrückung und verwende cpp statt code.
    So kann man das schwer lesen.

    Zum Problem: Du sollst beweisen, dass das Assoziativg. für + und * nicht gilt!?
    Das tut es aber.
    Bei sämtlichen reellen Zahlen, egal ob ganz oder nicht,
    sowie auch komplexen Zahlen und und...

    Das ist völlig unabhängig von int/float, das ist einfach mathematischer Unsinn.
    Oder meint dein Lehrer die computerbedingte Ungenauigkeit von Kommazahlen?
     
    Netiquette (vA §15) und Nutzungsregeln (vA §4.8) einhalten! Programmcode in Codetags/Codeboxen.
    Sehr gute Beiträge bitte Bewerten (Stern darunter oder "Danke").
    "Funktioniert nicht" ist zu ungenau! Code, Fehlermeldungen, Verhalten des Programms, ...?

  3. #3
    saeba saeba ist offline Rookie
    Registriert seit
    Nov 2011
    Beiträge
    5
    Vielen Dank für die Antwort und für das Herzliche Willkommen ,
    also der Prof meinte das es nicht Assoziativ ist da bei Gleitkommatypen die Reihenfolge der Verknüpfungen was ausmacht also das jeweil zwei unterschiedliche Ergebnisse rauskommen sollen. Allerdings habe so einiges probiert aber ich bekomme es irgendwie nicht hin oder geht das wirklich nicht ?
     

  4. #4
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Hmm...ich nehm einfach mal an, dass die Ungenauigkeit/Begrenztheit
    vom Computerspeicher gemeint ist.

    zB. wenn man auf dem Papier mit 3/7 rechnet, kann man das ja als Bruch verwenden, ohne unendlich viel Kommastellen aufschreiben zu müssen.
    Der Computer kanns aber nur so - und in den 32bit für ein float haben nur begrenzt viel Kommastellen Platz. Der Rest wird praktisch abgeschnitten. Das vorausgesetzt kann es bei anderer Rechenreihenfolge schon zu anderen Ergebnissen kommen.

    3 Zahlen, die ich für * gefunden habe (rein zufällig):
    1.8091
    2.9038
    3.8982

    Für + schau ich noch...

    edit: Für + gehen die drei genannten Zahlen auch.

    Musst du auch erklären, warum es bei denen ungenau wird?
     
    Netiquette (vA §15) und Nutzungsregeln (vA §4.8) einhalten! Programmcode in Codetags/Codeboxen.
    Sehr gute Beiträge bitte Bewerten (Stern darunter oder "Danke").
    "Funktioniert nicht" ist zu ungenau! Code, Fehlermeldungen, Verhalten des Programms, ...?

  5. #5
    saeba saeba ist offline Rookie
    Registriert seit
    Nov 2011
    Beiträge
    5
    danke für deine schnelle Hilfe
    also ich habe es gleich mal ausprobiert:

    Code cpp:
    1
    2
    3
    4
    5
    6
    
    void BeweisFloat(){
    float a = 1.8091; float b = 2.9038; float c =3.8982; float result;
    //a+(b+c)
    result = a+(c+b); cout <<"res1 "<<result<<endl;
    result = (a+b)+c; cout <<"res2 "<<result<<endl;
    }

    ich erhalte folgende Ausgaben:
    res1 8.6111
    res2 8.6111

    müssten eigentlich nicht jetzt unterschiedliche Ergebnisse rauskommen ? Kam bei dir unterschiedliche Ergebnisse raus ? Ja, also ich sollte das schon erklären können warum das ungenau wird aber ohne eien Beweis wird es schwierig
     

  6. #6
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Ja, bei mir sinds unterschiedliche Ergebnisse.
    Das Problem: Standardmäßig werden nicht alle möglichen Kommastellen ausgegeben, nur die ersten 4.
    Wie man das bei cout umstellt müsste ich jetzt selbst nachschauen...aber bei printf gehts so:
    Code cpp:
    1
    
    printf("%.20f\n", result);
    Das statt den cout verwenden.

    Zur theoretischen Erklärung: Hab jetzt leider nicht so viel Zeit, kommt aber in der Nacht noch.
     
    Netiquette (vA §15) und Nutzungsregeln (vA §4.8) einhalten! Programmcode in Codetags/Codeboxen.
    Sehr gute Beiträge bitte Bewerten (Stern darunter oder "Danke").
    "Funktioniert nicht" ist zu ungenau! Code, Fehlermeldungen, Verhalten des Programms, ...?

  7. #7
    Avatar von Jennesta
    Jennesta Jennesta ist offline Mitglied Gold
    Registriert seit
    Sep 2007
    Ort
    Aachen
    Beiträge
    215
    Hallo,
    dein Prof hat in dem Sinne schon recht. Das Assoziativgesetz ist bei Gleitkomma-Darstellung nur eingeschränkt gültig. Vorallem bei Additionen und Multiplikationen von Zahlen aus anderen Größenordnungen kommt es zu diesen Abweichungen, die du finden sollst.

    Dazu ein Beispiel:
    Soll ein Computer zwei Zahlen addieren, muss der Computer die Exponenten der Zahlen angleichen, damit er sie addieren kann. Dadurch verschiebt sich ggf. auch die Mantisse der Zahlen, wodurch niederwertigere 1en verloren gehen könnten. So wird die Zahl in Extremsituationen sehr ungenau und demnach auch das Ergebnis.
    Daher sollte man darauf achten in welcher Reihenfolge man Zahlen in seine Berechnung gibt, da sich sonst diese Ungenauigkeit verstärken oder abschwächen lässt.

    Ich hoffe ich konnte dir helfen.
    Grüße Jennesta
    Geändert von Jennesta (02.11.11 um 00:58 Uhr) Grund: Rechtschreibfehler
     
    Was soll daran kompliziert sein? Es muss doch nur ein Rad bewegt werden, man kann aufsteigen, es kommt die Matschhütte und durch den Regenbogen gelangst du zum hungrigen Affen, der Affenschwanz wird gezogen und bums kommst du zum Paradispark.

  8. #8
    saeba saeba ist offline Rookie
    Registriert seit
    Nov 2011
    Beiträge
    5
    zunächst einmal was ich los werde muss ich finde es echt klasse das hier in diesem Forum ein geholfen wird ...

    also ich habe das nun probiert:

    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    
    void BeweisFloat(){
    float a = 1.8091; float b = 2.9038; float c =3.8982; float result;
    //a+(b+c)
    result = a+(c+b); cout <<"res1 "<<result<<endl;
    printf("%.20f\n", result);
    result = (a+b)+c; cout <<"res2 "<<result<<endl;
    printf("%.20f\n", result);
    }

    und ich erhalte folgende Ausgabe http://imgup.com/share-6A34_4EB095D7.html

    ich habe trotzdem zwei mal das selbe Ergebnis

    @Jennesta
    also im Prinzip verstehe ich was du meinst, ich hatte sowas schon mal gelesen gehabt allerdings ist es gar nicht so einfach die Zahlen und die Reihenfolge so zu wählen oder ich mach was falsch oder rundet mein Compiler auf ****?
     

  9. #9
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Hi

    sorry, dass doch noch nichts mehr gekommen ist...verschlafen

    Zuerst mal zum Code:
    Es kann sein, dass dein Compiler die Berechnung wegoptimiert.
    Es sind ja in jedem Fall die gleichen Zahlen mit dem (eigentlich) gleichen Ergebnis...
    nicht von Benutzereingaben etc. abhängig.

    Mach
    a) cin-Eingaben für die 3 floats, und die passenden Werte eben eintippen.
    b) die Berechnung nicht in eine Zeile.
    Also sowas:
    Code cpp:
    1
    2
    3
    4
    5
    
    cin >> a;
    cin >> b;
    result = a + b;
    cin >> c;
    result = c;
     
    Netiquette (vA §15) und Nutzungsregeln (vA §4.8) einhalten! Programmcode in Codetags/Codeboxen.
    Sehr gute Beiträge bitte Bewerten (Stern darunter oder "Danke").
    "Funktioniert nicht" ist zu ungenau! Code, Fehlermeldungen, Verhalten des Programms, ...?

  10. #10
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Hi.

    Folgendes funktioniert bei mir:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    #include <iostream>
    #include <cstdio>
    #include <iomanip>
     
    using namespace std;
     
    int main(int argc, char *argv[])
    {
      double a = 1234.567, b = 45.67834, c = 0.0004;
      double result1, result2;
     
      result1 = c + b;
      result1 += a;
     
      result2 = (a+b);
      result2 += c; 
     
      cout << "ungleich? " << boolalpha << (result1 != result2) << endl;
      
      cout << setprecision(20) << result1 << endl
           << result2 << endl;
    }
    Mit float könnte es etwas schwieriger werden, da Prozessoren (abhängig des vom Compiler erzeugten Maschinencodes) die Operation evtl. mit höherer Genauigkeit ausführen und dann einfach zum Schluß abschneiden. Welchen Compiler verwendest du denn?

    Gruß
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  11. #11
    saeba saeba ist offline Rookie
    Registriert seit
    Nov 2011
    Beiträge
    5
    Ok ich habe das Problem für die Addition gelöst
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    void BeweisFloat(){
    double a = 1E-100;
    double b = 1E+100;
    double c = 1E+10;
    double res;
    printf("%.20f\n", a);
    printf("%.20f\n", b);
    printf("%.20f\n", c);
    cout<<"a "<<a<<endl; cout<<"b "<<b<<endl; cout<<"c "<<c<<endl;
    //a+(b+c)
    res = a*(b*b); cout <<"res1 "<<res<<endl;
    printf("%.20f\n", res);
    res = (a*b)*b; cout <<"res2 "<<res<<endl;
    printf("%.20f\n", res);
    }

    damit bekomme ich unterschiedliche Ergebnisse...
    @deepthroat danke für deine Hilfe, also ich benutze den MingCompiler, werde deins mal testen...für die Multiplikation habe ich noch keine passenden zahlen gefunden, naja...
     

Ähnliche Themen

  1. Antworten: 7
    Letzter Beitrag: 25.10.11, 08:29
  2. Antworten: 0
    Letzter Beitrag: 11.01.11, 21:40
  3. Gleitkommatypen
    Von chillermiller im Forum C/C++
    Antworten: 1
    Letzter Beitrag: 05.12.08, 15:53
  4. Antworten: 4
    Letzter Beitrag: 22.03.06, 20:50
  5. Antworten: 6
    Letzter Beitrag: 13.06.02, 12:29