Brauche dringend Hilfe bei Aufgabenstellung!



  • 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???



  • SeppJ schrieb:

    Sicher?

    Getestet und disassembliert auf MingW-GCC, CygWin-GCC, MSVC, PellesC, BCC32, LCC32, OpenWatcom, TCC. Reicht das?

    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.

    1. Ich gehe mal davon aus, dass der Sprachstandard hier ein Mindestverhalten postuliert. Ansonsten wüsste ich gerne, wo ich nachschlagen kann.

    2. Zumindest 32-Bit-Windows geht hier einen Sonderweg, indem die FPU auf 64 Bit Präzision (bzw. 53 Bit in MS-Speak) gesetzt wird. Und zwar - zu meinem Verdruss - jedes Mal, wenn ein Programm gestartet wird. Das ist bei Microsoft nur in Nebensätzen dokumentiert, z.B: "On NT-based systems, the FPU is set to long real precision (that is, double or 53-bit), with all exceptions masked ..." (http://msdn.microsoft.com/en-us/library/windows/hardware/ff565388).

    viele grüße
    ralph


  • Mod

    rkhb schrieb:

    1. Ich gehe mal davon aus, dass der Sprachstandard hier ein Mindestverhalten postuliert.

    Das ist der Fall (s.o.):
    C90: 6.2.1.5 /2
    C99/C11: 6.3.1.8 /2 (unverändert)
    Jedes einigermaßen brauchbare Buch zum Thema erwähnt früher oder später, dass wenn IEEE-konforme Zwischenergebnisse benötigt werden, man am besten explizite Zuweisungen einfügt.


Anmelden zum Antworten