Problem Gleitkommatypen Assoziativgesetz

saeba

Grünschnabel
Hallo allersetis,

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

ich habe mir folgendes ausgedacht:
C++:
#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 ?
 
Zuletzt bearbeitet von einem Moderator:
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?
 
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 ?
 
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?
 
danke für deine schnelle Hilfe :)
also ich habe es gleich mal ausprobiert:

C++:
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 :)
 
Zuletzt bearbeitet von einem Moderator:
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:
C++:
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.
 
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
 
Zuletzt bearbeitet:
zunächst einmal was ich los werde muss ich finde es echt klasse das hier in diesem Forum ein geholfen wird :D...

also ich habe das nun probiert:

C++:
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
share-6A34_4EB095D7.html


ich habe trotzdem zwei mal das selbe Ergebnis :confused:

@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 ****?
 
Zuletzt bearbeitet von einem Moderator:
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:
C++:
cin >> a;
cin >> b;
result = a + b;
cin >> c;
result = c;
 
Hi.

Folgendes funktioniert bei mir:
C++:
#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ß
 
Zurück