Hugo Egon Balder: Umwandlung 'des Variablentyps float' nach 'int'

Hallo Forum,

irgendwas habe ich bei der Umwandlung von Variablentypen offensichtlich falsch verstanden.

<?php  
  $test=1352190216.3794;  
  echo"<pre>".var_dump($test)."</pre><br /><br />\n"; // Gibt aus: float(1352190216.3794)  
  $test=$test*10000;  
  echo"<pre>".var_dump($test)."</pre><br /><br />\n"; // Gibt aus: float(13521902163794)  
  $test=(integer)$test;  
  echo"<pre>".var_dump($test)."</pre><br /><br />\n"; // Gibt aus: int(1345115986)  
?>

Die ersten beiden var_dump Ausgaben sind mir klar, die dritte nicht. Die Variable '$test' ist zwar nun wie gewünscht vom Typ 'Integer', aber wieso hat sie den Wert 1345115986? Erwarten würde ich weiterhin den Wert 13521902163794.

Kann mir bitte wer erklären, wie es zu dem 1345115986 kommt?

Danke im Voraus!

MfG

Hugo Egon Balder

  1. Hi,

    Die ersten beiden var_dump Ausgaben sind mir klar, die dritte nicht. Die Variable '$test' ist zwar nun wie gewünscht vom Typ 'Integer', aber wieso hat sie den Wert 1345115986? Erwarten würde ich weiterhin den Wert 13521902163794.

    http://www.php.net/manual/en/language.types.integer.php#language.types.integer.overflow

    MfG ChrisB

    --
    RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
    1. Hallo Chris,

      danke für die Antwort!

      http://www.php.net/manual/en/language.types.integer.php#language.types.integer.overflow

      Mit anderen Worten: 13521902163794 ist zu hoch, um vom Server als Integer gesehen werden zu können!?

      Bleibt die Frage, wie der Wert 1345115986 zustande kommt.

      MfG

      Hugo Egon Balder

      1. Tach!

        http://www.php.net/manual/en/language.types.integer.php#language.types.integer.overflow
        Mit anderen Worten: 13521902163794 ist zu hoch, um vom Server als Integer gesehen werden zu können!?

        Nur auf 32-Bit-Systemen. Auf 64-Bit-Systemen ist der Wertebereich von Integer deutlich größer.

        Bleibt die Frage, wie der Wert 1345115986 zustande kommt.

        Es wird sich sicherlich eine Antwort auf diese Frage finden lassen, aber sie ist uninteressant, weil man mit ihr nichts weiter anfangen kann, um das grundlegende Problem zu lösen. Das Handbuch beschränkt sich auch nur auf die Aussage "undefiniertes Ergebnis": "If the float is beyond the boundaries of integer [...], the result is undefined, since the float doesn't have enough precision to give an exact integer result."

        Was nimmt man nun? Wenn man ein 64-Bit-System voraussetzen kann, kann man auch mit solch großen Integer-Werten arbeiten. In 32-Bit-Systemen muss man sich entscheiden, ob man den Wert bis auf die letzte Stelle genau braucht, dann muss man zu einem Ersatz auf String-Basis greifen, wie ihn die Extensions BCMath und GMP anbieten. Ist man mit der Präzision - oder besser gesagt, der technisch bedingen Ungenauigkeit - von Floats zufrieden, dann kann man diese nehmen.

        dedlfix.

        1. Hallo Chris, dedlfix und suit,

          danke für Eure Antworten! Mist ist Mist - OK, ich brauche den Wert also nicht hinterfragen.

          Meine Frage ist somit beantwortet!

          MfG

          Hugo Egon Balder

      2. Mit anderen Worten: 13521902163794 ist zu hoch, um vom Server als Integer gesehen werden zu können!?

        Integer kennt maximal 4294967296 Zustände, in einem 32-Bit-System (2^32)

        (2^32)/2-1 = 2147483647 als höchsten positiven Wert.

        Bleibt die Frage, wie der Wert 1345115986 zustande kommt.

        Weil das ergebnis nicht definiert ist:

        "If the float is beyond the boundaries of integer (usually +/- 2.15e+9 = 2^31), the result is undefined, since the float doesn't have enough precision to give an exact integer result. No warning, not even a notice will be issued when this happens!"

        Sprich dabei kommt Mist raus und keiner kann dir sagen warum.

  2. 13521902163794 soll rauskommen.
    13521902163794 = C4C502CD752 in Hex.
    int hat nur 4 Bytes = 8 Hexstellen. Von C4C502CD752 bleiben die unteren 8 Hexstellen übrig, also 502CD752. Und das entspricht dezimal 1345115986.
    Ist also sogar nachvollziehbar, auch wenn es rechnerisch trotzdem Mist ist :-)

    1. 13521902163794 soll rauskommen.
      13521902163794 = C4C502CD752 in Hex.
      int hat nur 4 Bytes = 8 Hexstellen. Von C4C502CD752 bleiben die unteren 8 Hexstellen übrig, also 502CD752. Und das entspricht dezimal 1345115986.
      Ist also sogar nachvollziehbar, auch wenn es rechnerisch trotzdem Mist ist :-)

      Das ist in der Tat nachvollziehbar - hast du das jetzt selbst nachgerechnet oder hast dafür auch den Code, der dafür verantwortlich ist? Sprich ist das "immer so" auch wenn es nicht definiert ist?

      1. Tach!

        Ist also sogar nachvollziehbar, auch wenn es rechnerisch trotzdem Mist ist :-)
        Das ist in der Tat nachvollziehbar - hast du das jetzt selbst nachgerechnet oder hast dafür auch den Code, der dafür verantwortlich ist? Sprich ist das "immer so" auch wenn es nicht definiert ist?

        Sagte ich ja, das muss etwas deterministisches sein. Ich wüsste jetzt auch nicht, warum es nicht so sein sollte. Vermutlich wird es bei sehr viel größeren Werten etwas anders aussehen, nämlich dann, wenn der Exponent so groß ist, dass die begrenzte Präzision des Floats nur noch ein paar Nullen in den unteren Stellen hinterlassen kann. Aber was bringt es jetzt zu wissen, wie das Ergebnis zustandekommt und ob das immer nach dieser Regel passiert? Der beabsichtigte Wert ist verlorengegangen und andere werden beim Überlauf auch verlorengehen. Sie kommen durch das Wissen nicht zurück, noch kann man damit den Verlust verhindern. Man muss nur wissen, _dass_ Verluste beim Konvertieren auftreten können und ab welchen Werten das passiert.

        dedlfix.

        1. Aber was bringt es jetzt zu wissen, wie das Ergebnis zustandekommt und ob das immer nach dieser Regel passiert?

          Nein, mir gings darum, zu wissen "wer" dafür verantwortlich ist - sprich ob da der C-Unterbau dafür sorgt und das PHP eigentlich garnichts angeht oder ob die Typecasting-Routine selbst geschrieben ist.

          1. Tach!

            Aber was bringt es jetzt zu wissen, wie das Ergebnis zustandekommt und ob das immer nach dieser Regel passiert?
            Nein, mir gings darum, zu wissen "wer" dafür verantwortlich ist - sprich ob da der C-Unterbau dafür sorgt und das PHP eigentlich garnichts angeht oder ob die Typecasting-Routine selbst geschrieben ist.

            Auch das ist nicht weiter wichtig, weil man es nicht beeinflussen kann. Es ist aber eine allgemeine technische Einschränkung, die unter Beibehaltung der verwendeten Typen in keinem System gelöst werden kann. In den begrenzten Werteumfang eines 32-Bit-Integer passt nicht mehr rein, egal wer das da reinzuschreiben versucht.

            dedlfix.

            1. Auch das ist nicht weiter wichtig, weil man es nicht beeinflussen kann.

              Natürlich ist es nicht wichtig - es ist auch nicht wichtig, das Ende unserer Sonne oder den Durchmesser VY Canis Majoris zu kennen, kann man eh nicht beeinflussen - interessant ist es aber allemal :)

              In den begrenzten Werteumfang eines 32-Bit-Integer passt nicht mehr rein, egal wer das da reinzuschreiben versucht.

              Jein - PHP behandelt integer als Vorzeichenbehaftet Ganzzahl, wenn man das Vorzeichen entfernt, verdoppelt sich der mögliche Spielraum ;)

              Aber einfacher ist es hier einfach eine 64-Bit-Version zu verwenden - 32-Bit-Systeme sind hoffentlich schon am aussterben, ich hab' schon lange keinen modernen Webserver mit 32-Bit-OS mehr gesehen.

              1. Tach!

                In den begrenzten Werteumfang eines 32-Bit-Integer passt nicht mehr rein, egal wer das da reinzuschreiben versucht.
                Jein - PHP behandelt integer als Vorzeichenbehaftet Ganzzahl, wenn man das Vorzeichen entfernt, verdoppelt sich der mögliche Spielraum ;)

                Auch wenn du es anscheind nicht ernst gemeint hast ... Wie willst du das als PHP-Anwender erreichen? PHP kennt nur Int, keinen UInt und auch keinen Schalter, der aus dem einen das andere macht. Man kann auch nicht erkennen, ob der Wert übergelaufen ist oder nicht. Er lässt sich nicht mehr in den ursprünglichen Wert zurückbringen. Ich sehe an dieser Stelle keinen Spielraum.

                Aber einfacher ist es hier einfach eine 64-Bit-Version zu verwenden - 32-Bit-Systeme sind hoffentlich schon am aussterben, ich hab' schon lange keinen modernen Webserver mit 32-Bit-OS mehr gesehen.

                Die PHP-Windows-Binarys gibt es (offiziell) nur als 32-Bit-Version.

                dedlfix.

                1. Auch wenn du es anscheind nicht ernst gemeint hast ... Wie willst du das als PHP-Anwender erreichen?

                  Trivial:

                  Du subtrahierst einfach von jeder Ganzzahl 2.147.483.647 und schon hast du deinen Verfügbaren Zahlenraum erhöht ;)

                  Die PHP-Windows-Binarys gibt es (offiziell) nur als 32-Bit-Version.

                  Das wusste ich nicht - mit PHP unter Windows hatte ich schon ewig nichts mehr zu tun - aber das ist interessant zu wissen, wenn mal einer meiner Kunde auf die Idee kommen sollte, einen Windows-Server anzuschaffen.

                  1. Tach!

                    Auch wenn du es anscheind nicht ernst gemeint hast ... Wie willst du das als PHP-Anwender erreichen?
                    Trivial:
                    Du subtrahierst einfach von jeder Ganzzahl 2.147.483.647 und schon hast du deinen Verfügbaren Zahlenraum erhöht ;)

                    Da fehlt noch, dass du dir irgendwo extra merken musst, ob das solch eine manipulierte Zahl ist oder nicht. Dann wars das mit der Trivialität. Wenn du nun nicht zwei einzelne Variablen (Wert und Flag) herumliegen lassen willst, kommst du kaum um ein Objekt herum (ein Array mit zwei Einträgen ist auch nicht einfacher).

                    Die PHP-Windows-Binarys gibt es (offiziell) nur als 32-Bit-Version.
                    Das wusste ich nicht - mit PHP unter Windows hatte ich schon ewig nichts mehr zu tun - aber das ist interessant zu wissen, wenn mal einer meiner Kunde auf die Idee kommen sollte, einen Windows-Server anzuschaffen.

                    Naja, er muss dann auch als Anforderung haben, solch große Zahlen damit verarbeiten zu wollen. Ansonsten stört das ja nicht weiter.

                    dedlfix.

      2. hast du das jetzt selbst nachgerechnet oder hast dafür auch den Code, der dafür verantwortlich ist?

        Windows Taschenrechner, mit Wechsel zwischen Dezimal und Hexmodus :-)

        Sprich ist das "immer so" auch wenn es nicht definiert ist?

        Ich weiß nicht von was das alles abhängt, vom Aufbau der CPU und evtl. auch vom PHP Code für den Cast?
        Dieses Verhalten ist für mich für die Multiplikation zweier int nachvollziehbar und logisch. Der Überlauf läuft einfach ins leere, während die unteren Stellen dabei nach wie vor richtig verrechnet werden. Ähnlich wie ein Tacho der von 999999 nach 1000000 überläuft und die 1 gibts einfach nicht. Das ergibt sich auch aus der Architektur des Rechenwerks von selbst, ohne was besonderes dafür einzubauen.

        Wie es beim Casten von Fließkommazahlen aussieht weiß ich nicht, würd mich grad auch interessieren.
        Es ist schon irgendwie naheliegend für mich dass die Konvertierung ähnlich läuft, also dass dabei eine "zu große" int Zahl entsteht von der auch wieder die unteren Stellen übrig bleiben.
        Andrerseits ist float ganz anders aufgebaut als int. Vielleicht kommt je nach Code/Fließkommaeinheit doch was ganz anderes raus.
        Wär interessant wenn jemand da noch was wüsste.