Brauche dringend Hilfe bei Aufgabenstellung!



  • Hallo,

    Ich bin Mechatronik Student im erstem Semester und beherrsche die meisten Grundkenntnisse von C.

    Letzte Woche bekamen wir diese Aufgabenstellung von unserem Prof mit der ich überhaupt nichts anfangen kann.

    Aufgabenstellung:
    " IEEE-Zahlendarstellung
    Finden Sie die kleinste positive ganze Zahl, die nicht als Float-Wert dargestellt werden kann. Schrei-ben Sie dazu ein C-Programm, das diese Zahl auf dem Windows-System im Pool ermittelt, indem es sukzessive alle positiven ganzen Zahlen durchgeht (Bitte ohne den Optimierungsschalter -O2 kompi-lieren). Begründen Sie, warum diese Zahl nicht als Float-Wert dargestellt werden kann, indem Sie die 32-Bit-IEEE-Darstellung der Vorgänger- und Nachfolgerzahl angeben."

    mit Windows-System Pool ist wahrscheinlich das Rechner-Netz der Räume unserer Hochschule gemeint.

    Falls mir jemand weiterhelfen kann wäre dies sehr nett. Ich wäre schon froh einen Ansatz zu haben.

    Danke schon mal und mit freundlichen Grüßen,

    Andreas


  • Mod

    Das ist doch bereits eine Schritt für Schritt Anleitung. Wo genau hakt es denn?



  • dreyjey1993 schrieb:

    Falls mir jemand weiterhelfen kann wäre dies sehr nett. Ich wäre schon froh einen Ansatz zu haben.

    Danke schon mal und mit freundlichen Grüßen,

    Andreas

    Vielleicht wird's klarer mit nachfolgendem Progrämmchen:

    #include <stdio.h>
    int main ( void )
    {
        unsigned n = 123456789;
        float f = n;            // f sollte jetzt den gleichen Wert wie n haben, ...
        printf ("%u\n",n);
        printf ("%.f\n",f);     // ... hat es aber nicht!
        return 0;
    }
    

    viele grüße
    ralph



  • Okay, es gibt also ganze Zahlen de nicht als float dargestellt können. Man muss also nur bei "1" anfangen und die Zahlen dann unter einer float variable speichern und diese beiden zahlen dann vergleichen die beiden ungleich sind, richtig? Okay das Programm wäre mir somit klar aber aus welchem Grund lassen sich manche Zahlen nicht als float wert darstellen?

    Danke für die schnelle Hilfe, MfG Andreas


  • Mod

    dreyjey1993 schrieb:

    Okay, es gibt also ganze Zahlen de nicht als float dargestellt können. Man muss also nur bei "1" anfangen und die Zahlen dann unter einer float variable speichern und diese beiden zahlen dann vergleichen die beiden ungleich sind, richtig?

    Prinzipiell die richtige Idee, aber technisch musst du noch einen Trick beachten: Wie vergleichst du? Denn wenn in C ein Rechenoperator (unter anderem Vergleiche) auf Zahlen unterschiedlichen Typs angewendet werden, dann müssen dazu zuerst die Typen aneinander angeglichen werden, denn so direkt kann ein Computer normalerweise keine Fließkommazahl mit einer Ganzzahl vergleichen. Die Regel, was wohin konvertiert wird, ist für dich (bei diesem Programm) jedoch eher hinderlich. Denn Fließkommatypen gehen vor, das heißt, wenn ein Operand ein Fließkommatyp ist, dann wird der andere Operand ebenfalls zu diesem Fließkommatyp. Die genauen Regeln kann man im Sprachstandard nachlesen, aber dies reicht erst einmal, um das Problem zu verstehen. Wenn du also folgendes machst:

    int ausgangswert = 84765834643883;
    float als_float = ausgangswert;
    if (als_float != ausgangswert)   // Hier wird ausgangswert zu float konvertiert!
      // ...
    

    dann wird das niemals true ergeben, denn du vergleichst ja die Zahl als float mit der gleichen Zahl als float, was logischerweise beides das gleiche ist.

    Wie du das Problem lösen kannst, überlasse ich dir mal als Übungsaufgabe.

    Okay das Programm wäre mir somit klar aber aus welchem Grund lassen sich manche Zahlen nicht als float wert darstellen?

    Was weißt du denn darüber, wie Fließkommazahlen, genauer Fließkommazahlen in IEEE 754 Format? Falls du nichts darüber wissen solltest (was mich bei der Aufgabenstellung wundern würde), wie könntest du dann etwas darüber heraus finden?



  • Hmm, also ich hab das jetzt so gemacht und es funktioniert...

    #include <stdio.h>
    #include <conio.h>
    
    void main()
    {
    	int i = 1;
    	float f = 1;
    
    	while (f == i)
    	{
    		i = i++;
    		f = i;
    	}
    
    	printf ("Die Zahl %d kann nicht als float Wert dargestellt werden!", i);
    
    	_getch();
    }
    

    Die Ausgabe ist dann:

    "Die Zahl 16777217 kann nicht als float Wert dargestellt werden!"

    Warum diese Zahl nicht als float Wert dargestellt werden kann liegt wohl an der Binären Darstellung dieser Zahl, aber die Aufgabe ist erst zur übernächsten Woche und somit wird dies bestimmt noch in einer Vorlesung erklärt, da wir bis jetzt noch nichts darüber hatten. Ich versuch noch ein bisschen über IEEE 754 Zahlendarstellungen herauszufinden.

    Ansonsten danke an euch das ihr so schnell helfen konntet, ist echt ein super Forum hier 😃



  • Hallo,

    das Thema hatte ich gestern in der Vorlesung vorgestellt.

    Gruß
    Ihr Prof.



  • SeppJ hat doch gerade erklärt, dass das (f == i) die falsch Art des Vergleichs ist.

    Zudem wäre es natürlich interessant, wie f jetzt aussieht.
    Warum gibst du es nicht auch noch mit aus.

    Kennst du die wissenschaftlische Notation von Zahlen?



  • Hehe, da kann man nicht mal ein Forum besuchen ohne das man gleich vom Professor entdeckt wird. Somit weiß ich wenigstens das ich das richtige Forum gewählt habe, wenn sogar unser Professor hier Aktiv ist 😉

    das Thema hatte ich gestern in der Vorlesung vorgestellt

    ... zu der ich leider nicht erschienen bin, naja dann werde ich mir diese Kleinigkeit wohl nachfragen müssen, ist ja noch Zeit 🙂


  • Mod

    dreyjey1993 schrieb:

    Hmm, also ich hab das jetzt so gemacht und es funktioniert...

    #include <stdio.h>
    #include <conio.h>
    
    void main()
    {
    	int i = 1;
    	float f = 1;
    
    	while (f == i)
    	{
    		i = i++;
    		f = i;
    	}
    
    	printf ("Die Zahl %d kann nicht als float Wert dargestellt werden!", i);
    
    	_getch();
    }
    

    Die Ausgabe ist dann:

    "Die Zahl 16777217 kann nicht als float Wert dargestellt werden!"

    Falls das da so raus kommt, dann ist das reiner Zufall, da du mit i = i++; undefiniertes Verhalten baust. Wenn man da eine korrektes Inkrement nimmt, dann sollte das Programm endlos laufen, aus den genannten Gründen.



  • Kann das vielleicht an dem Optimierungsschalter-O2 liegen? Ich weis nämlich nicht wie man diesen ausschaltet, falls er überhaut an ist 😕


  • Mod

    dreyjey1993 schrieb:

    Kann das vielleicht an dem Optimierungsschalter-O2 liegen? Ich weis nämlich nicht wie man diesen ausschaltet, falls er überhaut an ist 😕

    Möglich, aber das tut doch nichts zur Sache. Sobald du einen Ausdruck wie i = i++ hast, ist das Verhalten undefiniert. Was konkret passiert mag von Optimierungsstufen und anderem abhängen, aber in allen Fällen ist es falsch. Hier ein paar Möglichkeiten, wie man eine Variable i korrekt um 1 erhöhen kann:

    ++i;
    i++;
    i += 1;
    i = i + 1;
    

    Wenn du das so machst, wirst du feststellen, dass dein Programm niemals abbricht. Was korrekt ist, weil dein Vergleich nicht das macht, was du denkst. Falls das Programm dennoch abbricht, auf egal welcher Optimierungsstufe, dann ist dein Compiler kaputt 🙂 .



  • SeppJ schrieb:

    dann sollte das Programm endlos laufen, aus den genannten Gründen.

    Nein, bei (f == i) wird in der FPU 64-bittig verglichen (Win32-Default). Das falsche f ist bereits mit 32 Bit auf dem Stack gespeichert worden, kann also in der FPU nicht mehr richtiger werden, und das richtige i wird in der FPU zu 64-Bit-Float umgewandelt - darstellbar, also weiterhin richtig.

    Immer vorausgesetzt, mit "Float" ist ein "32-Bit-Float" gemeint und die Operationen laufen über die FPU.

    viele grüße
    ralph


  • Mod

    rkhb schrieb:

    SeppJ schrieb:

    dann sollte das Programm endlos laufen, aus den genannten Gründen.

    Nein, bei (f == i) wird in der FPU 64-bittig verglichen (Win32-Default). Das falsche f ist bereits mit 32 Bit auf dem Stack gespeichert worden, kann also in der FPU nicht mehr richtiger werden, und das richtige i wird in der FPU zu 64-Bit-Float umgewandelt - darstellbar, also weiterhin richtig.

    Immer vorausgesetzt, mit "Float" ist ein "32-Bit-Float" gemeint und die Operationen laufen über die FPU.

    viele grüße
    ralph

    Sicher? Das würde klar dem Sprachstandard widersprechen, der hier fordert, dass i zu float wird und eben nicht double. Unter meinem Linuxsystem läuft das Programm auch tatsächlich ewig. Weiterhin ist an deiner Erklärung einiges faul, zum Beispiel setzt eine X87-FPU (und nur die kann gemeint sein, wenn das Programm unter Win läuft) intern 80-Bit ein.



  • ich hab jetzt mein "i = i++" mit einfach nur "i++" ersetzt und das Programm verhält sich immer noch gleich, keine Endlosschleife... hab auch schon die Einstellungen von Visual Studio zurückgesetzt und den Code in ein neues Programm übertragen. Somit dürfte der Compiler doch eigentlich keine Fehler haben, oder ?


  • Mod

    dreyjey1993 schrieb:

    ich hab jetzt mein "i = i++" mit einfach nur "i++" ersetzt und das Programm verhält sich immer noch gleich, keine Endlosschleife... hab auch schon die Einstellungen von Visual Studio zurückgesetzt und den Code in ein neues Programm übertragen. Somit dürfte der Compiler doch eigentlich keine Fehler haben, oder ?

    Nun, wenn "rkhb" mit seiner Erklärung recht hat, dann tritt hier wohl das berüchtigte implementierungsabhängige Verhalten beim Umwandeln von Ganz- in Fließkomma auf und hat tatsächlich Auswirkung auf das Programmverhalten. Dein Programm ist dadurch zwar nicht direkt falsch, aber das Verhalten ist unportabel, wie du an dem Bericht zu meinem System siehst. Wenn du dir, wie oben angeregt, Gedanken machst, wie du den Vergleich mit Integertypen durchführen kannst, dann würde das Programm auf allen Systemen funktionieren (auf denen sizeof(int) >= sizeof(float)).


  • Mod

    SeppJ schrieb:

    rkhb schrieb:

    SeppJ schrieb:

    dann sollte das Programm endlos laufen, aus den genannten Gründen.

    Nein, bei (f == i) wird in der FPU 64-bittig verglichen (Win32-Default). Das falsche f ist bereits mit 32 Bit auf dem Stack gespeichert worden, kann also in der FPU nicht mehr richtiger werden, und das richtige i wird in der FPU zu 64-Bit-Float umgewandelt - darstellbar, also weiterhin richtig.

    Immer vorausgesetzt, mit "Float" ist ein "32-Bit-Float" gemeint und die Operationen laufen über die FPU.

    viele grüße
    ralph

    Sicher? Das würde klar dem Sprachstandard widersprechen, der hier fordert, dass i zu float wird und eben nicht double. Unter meinem Linuxsystem läuft das Programm auch tatsächlich ewig. Weiterhin ist an deiner Erklärung einiges faul, zum Beispiel setzt eine X87-FPU (und nur die kann gemeint sein, wenn das Programm unter Win läuft) intern 80-Bit ein.

    i wird nat. implizit in float konvertiert, allerdings darf der Compiler mit höherer Genauigkeit rechnen als es dem Zahlentyp entspricht.
    Eine echte Konvertierung (also mit ggf. Verlust von Genauigkeit) in den Zieltyp ist nur für Zuweisungen und Casts garantiert.
    Aus diesem Grunde ist das Verhalten des Programmes konform (f hat die Genauigkeit verloren, bei i ist sie noch da und der Vergleich schlägt irgenwann fehl).. Ein Nichtterminieren wäre aber genauso ok.
    würde das Programm so lauten:

    #include <stdio.h>
    #include <conio.h>
    
    void main()
    {
        int i = 1;
        float f = 1;
    
        while (f == (float)i)
        {
            i++;
            f = i;
        }
    
        printf ("Die Zahl %d kann nicht als float Wert dargestellt werden!", i);
    
        _getch();
    }
    

    sollte auch dreyjey1993 kein positives Ergebnis mehr bekommen. Ganz unabhängig von Compileroptionen im übrigen (-ffast-math & co. nat. ausgenommen). Insofern wage ich zu vermuten, dass nicht einmal dem Aufgabensteller dieser subtile Aspekt von C ganz bewusst ist, anderenfalls macht der Hinweis, kein -O2 zu verwenden, wenig Sinn.



  • ich weis zwar nicht wie ich es mit zwei Integern hinkriegen sollte aber so mit 2 Float sollte es doch auch gehen, oder ?

    int i = 1;
    	float f1 = 1;
    	float f2 = 0;
    
    	while (f1 == f2 + 1)
    	{
    		f2 = f1;
    
    		f1++;
    
    		i++;
    	}
    
    	printf ("Die Zahl %d kann nicht als float Wert dargestellt werden!\n\n", i);
    

    Ergibt zumindest die selbe Ausgabe.



  • Wenn IEEE 754 (gleichbedeutend mit IEC 559) gilt, dann hat float definitiv 32 Bits und es geht:

    http://ideone.com/5WSeeY


  • Mod

    Wutz schrieb:

    Wenn IEEE 754 (gleichbedeutend mit IEC 559) gilt, dann hat float definitiv 32 Bits und es geht:

    http://ideone.com/5WSeeY

    memcmp???


Anmelden zum Antworten