Andreas Korthaus: kleine Rundungsfrage

Hallo!

Hab da grad mal ein kleines Brett vorm Kopf ;-)

Ich habe Zahlen mit vielen Nachkommastellen, z.B. sowas:

4.23723526844534

So, jetzt möchte ich die Zahl nach 2 Nachkommastellen abschneiden und in  mit "," als Dezimaltrennzeichen versehen.

Ich will also nicht runden, sondern abschneiden - oder halt immer abrunden (floor() kennt leider gar keine Nachkommastellen).

Ich dachte an sowas:

$zahl = 4.23723526844534;
$nachkommastellen = 2;

echo substr(number_format($zahl,$nachkommastellen+1,',','.')0,-1);

Weil ich jetzt allerdings die letzten Tage so viel rumgerechnet habe, und so viele "außergewöhnliche" Auswirkungen von Rundungsfehlern miterleben durfte, bin ich mir da jetzt wirklich unsicher ob das so funktioniert ;-)

Eigentlich ist das doch OK, oder?

Grüße
Andreas

--
SELFHTML Linkverzeichnis: http://aktuell.de.selfhtml.org/links/
  1. Hi,

    $zahl = 4.23723526844534;
    $nachkommastellen = 2;

    sowas?
    $x =  123.123456789;
    echo number_format($x, 2, ",", ".");

    Gruesse, Joachim

    --
    Am Ende wird alles gut.
    1. Hi!

      sowas?
      $x =  123.123456789;
      echo number_format($x, 2, ",", ".");

      Nein, gerade das will ich nicht:

      $ php -r "echo number_format(2.345,2);"
      2.35

      Ich will aber nicht 2.35, sondern 2.34 ;-)

      Also:

      $ php -r "echo substr(number_format(2.345,2+1),0,-1);"
      2.34

      Die Frage ist nur - funktioniert das wirklich 100-prozentig, oder kann es da mit ungünstigen Zahlen auch mal daneben gehen?

      Grüße
      Andreas

      --
      SELFHTML Tipps & Tricks: http://aktuell.de.selfhtml.org/tippstricks/
      1. Hello,

        Die Frage ist nur - funktioniert das wirklich 100-prozentig, oder kann es da mit ungünstigen Zahlen auch mal daneben gehen?

        Was ist denn, wenn die Zahlen zu klein werden oder zwei Tausender-Separatoren enthalten? Was soll denn dann angezeigt werden?

        Harzliche Grüße aus http://www.annerschbarrich.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau
        1. Hi!

          Was ist denn, wenn die Zahlen zu klein werden oder zwei Tausender-Separatoren enthalten? Was soll denn dann angezeigt werden?

          Die Zahlen sind Ergebnisse von Berechnungen in PHP, die ursprünglichen Zahlen stammen aus der DB, DECIMAL(20,10). Haben also keine 1000er Trennzeichen, erst bei der Ausgabe-Formatierung.

          Die Zahlen können nicht zu klein werden, im Moment würde 0 angezeigt, aber der Fall darf schon aus geschäftslogischen Gründen nicht eintreten, wird also validiert.

          Die Nachkommastellen sind einstellbar, so dass immer eine Sinnvolle Zahl  herauskommt. Ich denke so wie ich es gemacht habe sollte es gehen, oder?

          Die Variante voN Joachim müsste ich dan so oder so duch noch eine Funktion schicken, um eben für die Ausgabe zu formatieren. Wobei das wirkliche Abschneiden in seiner Variante mir eigentlich mehr entgegenkommt...

          Grüße
          Andreas

          --
          SELFHTML Feature Artikel: http://aktuell.de.selfhtml.org/artikel/
          1. Hi,

            Wobei das wirkliche Abschneiden in seiner Variante mir eigentlich mehr entgegenkommt...

            Ich denke, wenn Du die Zahl waehrend des Abschneidens als String behandelst, schliesst Du sicher mathematische Unvorhersehbarkeiten aus...

            Gruesse, Joachim

            --
            Am Ende wird alles gut.
            1. Hi Joachim!

              Wobei das wirkliche Abschneiden in seiner Variante mir eigentlich mehr entgegenkommt...
              Ich denke, wenn Du die Zahl waehrend des Abschneidens als String behandelst, schliesst Du sicher mathematische Unvorhersehbarkeiten aus...

              Ja, das sehe ich auch so. Allerdings gibt es dabei dann Probleme wenn man auf einmal ne runde Zahl hat. An number_format() stört mich, dass es überhaupt mir round() arbeitet.

              number_format() macht z.B. hier Probleme:
              php -r "echo substr(number_format(1.99999,2+1),0,-1);";"
              2.00

              _genau_ das darf nicht passieren.

              Nunja, dann nehme ich Deine Version mal als Grundlage und überlege mir eine eigene Funktion, die auch das Fehlen des Dezimal-Trennzeichens berücksichtigt.

              Grüße
              Andreas

              --
              SELFHTML Feature Artikel: http://aktuell.de.selfhtml.org/artikel/
              1. Hallo Andreas,

                Nunja, dann nehme ich Deine Version mal als Grundlage und überlege mir eine eigene Funktion, die auch das Fehlen des Dezimal-Trennzeichens berücksichtigt.

                aber Himmel: das ist doch ganz simpel. Ich mach sowas immer mit einer eigenen Funktion. Nun willst Du sicher auch wissen wie? nagut:

                $zahl = 1.23456...
                $zahl *= 100;             (ergibt: 123.456...)
                $zahl = (integer)$zahl;   (ergibt 123 - nach belieben auch mit floor())
                $zahl = (string)$zahl;    (ergibt '123')
                $kommazahl = substr($zahl, 0, -2).','.substr($zahl, -2);
                ergibt: '1,23'

                ist jetzt ungetestet, kann kleinere Syntaxfehler enthalten.

                Gruß, Andreas

                --
                Schluß mit der deutschen Sprache ihre Diskrimination!
                1. Hello,

                  Wenn ich das richtig verstanden habe, geht es doch gar nicht um den dezimalen Anteil, sondern um eine Darstellung in Zehnern

                  aus 2.300,98 sollen 2.30 werden.

                  Habe ich das richtig verstanden?
                  Welche Dimensionsbezeichnung hängst Du denn dann an?

                  Müsste dann nicht ggf. 2,30 daraus werden?

                  2,30 TausendEuro...

                  Harzliche Grüße aus http://www.annerschbarrich.de

                  Tom

                  --
                  Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                  Nur selber lernen macht schlau
                  1. Hi Tom!

                    Wenn ich das richtig verstanden habe, geht es doch gar nicht um den dezimalen Anteil, sondern um eine Darstellung in Zehnern

                    aus 2.300,98 sollen 2.30 werden.

                    Habe ich das richtig verstanden?

                    nein ;-)

                    Es geht nur um die Rundung/das Abschneiden.

                    Grüße
                    Andreas

                    --
                    SELFHTML Linkverzeichnis: http://aktuell.de.selfhtml.org/links/
                    1. Hello,

                      Na gut:

                      1. Aus der zahl einen String machen
                      2. Prüfen ob ein Punkt drin ist und daran teilen
                      3. in linken Teil von rechts nach links jeweils nach drei Stellen einen Punkt einfügen
                      4. rechten Teil mit Nullen auf gewünschte Länge auffüllen
                      5. linken und rechten Teil mit Komma zusammenkleben

                      Das könnte man nun bestimmt alles in eine geschachtelte Funktion packen.
                      Besser fürs Verständnis wäre es bestimmt, eine eigene mittels mehrerer leicht verständlicher Statements daraus zu bauen.

                      Harzliche Grüße aus http://www.annerschbarrich.de

                      Tom

                      --
                      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                      Nur selber lernen macht schlau
                      1. Hi!

                        1. Aus der zahl einen String machen
                        2. Prüfen ob ein Punkt drin ist und daran teilen
                        3. in linken Teil von rechts nach links jeweils nach drei Stellen einen Punkt einfügen
                        4. rechten Teil mit Nullen auf gewünschte Länge auffüllen
                        5. linken und rechten Teil mit Komma zusammenkleben

                        Ich hatte gehofft da einfacher drum herum zu kommen, naja, dann geht es wohl nicht anders.

                        Grüße
                        Andreas

                        --
                        SELFHTML Tipps & Tricks: http://aktuell.de.selfhtml.org/tippstricks/
                        1. Hello,

                          Ich hatte gehofft da einfacher drum herum zu kommen, naja, dann geht es wohl nicht anders.

                          Vinzenz hat es ja schon erklärt.
                          Ein weiteres Handicap ist bei der Rechenmethode die Verschiebung der Toleranzen. Es besteht ja nur ein begrenzter Wertebereich und durch das Hochmultiplizieren und wieder Teilen wird der einseitig verändert.

                          Die Methode, die Digits in ihrer Dezimaldarstellung als String zu behandeln ist also auch diesem Grund die bessere. Und Die Funktion schreibst Du ja nur einmal und benutzt sie dann immer wieder. Kannst sei ja hier veröffentlichen. Fehlt nur noch ein passender Name dafür.

                          Wir können ja auch auf einem Webserver einen "GetPHP-Bereich" mit solchen Funktionen aufmachen *g* Dann können wir demnächst immer fragen: schon im Archiv gesucht? Schon im GetPHP-Bereich recherchiert? Schon bei Google geschaut? Schon gespendet? ;-)

                          Harzliche Grüße aus http://www.annerschbarrich.de

                          Tom

                          --
                          Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                          Nur selber lernen macht schlau
                          1. Hi!

                            Die Methode, die Digits in ihrer Dezimaldarstellung als String zu behandeln ist also auch diesem Grund die bessere. Und Die Funktion schreibst Du ja nur einmal und benutzt sie dann immer wieder. Kannst sei ja hier veröffentlichen. Fehlt nur noch ein passender Name dafür.

                            Ich nenne die Funktion erstmal "abrunden" ;-)

                            function abrunden($zahl,$stellen=2,$trenn=',') {
                                $dec = strrpos($zahl,'.');
                                if ($dec === FALSE) $dec = strlen($zahl);
                                return substr($zahl,0,$dec).$trenn.substr(str_pad(substr($zahl,$dec+1),$stellen,'0'),0,$stellen);
                            }

                            Die sollte dann auch mit Zahlen ohne Dezimaltrennzeichen und mit weniger Nachkommastellen als gefordert auskommen.

                            Was meint Ihr dazu - ist das in etwa so wie Ihr das machen würdet?

                            Vielleicht noch kurz erläutert:

                            $dec = strrpos($zahl,'.');
                             - ermittelt die Position des Dezimaltrennzeichens

                            if ($dec === FALSE) $dec = strlen($zahl);
                             - falls kein Dezimaltrennzeichen gefunden, setze Trennzeichen-Position auf die Länge des Strings

                            return substr($zahl,0,$dec).$trenn.substr(str_pad(substr($zahl,$dec+1),$stellen,'0'),0,$stellen);
                            }
                             - der Rückgabestring wird aus 3 Teilen zusammengesetzt:
                             -> Teilstring bis zum Dezimaltrennzeichen
                             -> $trenn (neues Trennzeichen, normalerweise ',')
                             -> dem Nachkommateil - erstmal alle Nachkommastellen verwenden, falls zu wenige, mit Nullen auffüllen (auf vorgegebene Länge $stellen), dann alles abschneiden was über $stellen hinausgeht.

                            Hab ich jetzt was nicht bedacht?

                            Wir können ja auch auf einem Webserver einen "GetPHP-Bereich" mit solchen Funktionen aufmachen *g* Dann können wir demnächst immer fragen: schon im Archiv gesucht? Schon im GetPHP-Bereich recherchiert? Schon bei Google geschaut? Schon gespendet? ;-)

                            ;-)

                            Grüße
                            Andreas

                            --
                            SELFHTML Feature Artikel: http://aktuell.de.selfhtml.org/artikel/
                            1. Hello,

                              Ich nenne die Funktion erstmal "abrunden" ;-)

                              function abrunden($zahl,$stellen=2,$trenn=',') {
                                  $dec = strrpos($zahl,'.');
                                  if ($dec === FALSE) $dec = strlen($zahl);
                                  return substr($zahl,0,$dec).$trenn.substr(str_pad(substr($zahl,$dec+1),$stellen,'0'),0,$stellen);
                              }

                              Die sollte dann auch mit Zahlen ohne Dezimaltrennzeichen und mit weniger Nachkommastellen als gefordert auskommen.

                              Was meint Ihr dazu - ist das in etwa so wie Ihr das machen würdet?

                              Vielleicht noch kurz erläutert:

                              $dec = strrpos($zahl,'.');

                              • ermittelt die Position des Dezimaltrennzeichens

                              Da könnten auch mehrere drinstecken, wenn $zahl nicht vom richtigen Typ ist.

                              Das sollte man mit substr_count() vorher prüfen.
                              Außerdem sollte man prüfen, ob es sich überhaupt um eine gültige numerische Darstellung handelt.

                              Und da es eigentlich nur zwei Möglichkeiten gibt, würde ich die Eingabe- und Ausgabeformate einfach mit DE|US bezeichnen, oder so ähnlich.

                              if ($dec === FALSE) $dec = strlen($zahl);

                              • falls kein Dezimaltrennzeichen gefunden, setze Trennzeichen-Position auf die Länge des Strings

                              Jein. es würde reichen, das einfach an den String dranzuhängen

                              $ausgabe = $links.$dezimalzeichen.substr(strpad($rechts,$stellen,'0'),0,$stellen);

                              wobei $links auch noch Tausendertrennzeichen enthalten kann.

                              return substr($zahl,0,$dec).$trenn.substr(str_pad(substr($zahl,$dec+1),$stellen,'0'),0,$stellen);
                              }

                              • der Rückgabestring wird aus 3 Teilen zusammengesetzt:
                                -> Teilstring bis zum Dezimaltrennzeichen
                                -> $trenn (neues Trennzeichen, normalerweise ',')
                                -> dem Nachkommateil - erstmal alle Nachkommastellen verwenden, falls zu wenige, mit Nullen auffüllen (auf vorgegebene Länge $stellen), dann alles abschneiden was über $stellen hinausgeht.

                              Hab ich jetzt was nicht bedacht?

                              siehe Anzahl der Dezimalrennzeichen und ob es überhaupt eine numerische Darstellung ist.

                              Du wirst es vielleicht nicht glaube, aber sich dachte mir, das machst Du soch mal eben mit links. Aber ich habe alle Lösungen immer wieder verworfen. Regular Expressions waren mir irgendwie zu teuer, aber wahrschinlich ist preg_match() für die Eingangsprüfung soch das Richtige.
                              Und dann einfach zwei teile draus machen und zwei For-Schleifen. Eine die vom Punkt nach rechts läuft und eine die vom Punkt nach links läuft und die Tausendertrenner einfügt.

                              Harzliche Grüße aus http://www.annerschbarrich.de

                              Tom

                              --
                              Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                              Nur selber lernen macht schlau
                          2. Hallo Tom,

                            Wir können ja auch auf einem Webserver einen "GetPHP-Bereich" mit solchen Funktionen aufmachen *g* Dann können wir demnächst immer fragen: ... Schon im GetPHP-Bereich recherchiert?

                            Off Topic TOm,
                            find' ich gut!

                            Hat bitworks da noch Kapazitäten? http://www.bitworks.de/getPHP/

                            Freundliche Grüsse,

                            Vinzenz

                            1. Hello,

                              Off Topic TOm,
                              find' ich gut!

                              Hat bitworks da noch Kapazitäten? http://www.bitworks.de/getPHP/

                              Ja, auf der der Seite http://selfhtml.bitworks.de oder besser auf einer Extraseite?
                              http://getphp.bitworks.de

                              Ich meinte das durchaus ernst.
                              So nach und nach entstehen immer wieder kleine nützliche Tools, an denen man manchmal ganz schön lange knabbert, bis die Lösung einen dann förmlich anspringt. Man müsste sie aber auch kategorisieren und dokumentieren. Sowas ähnliches gibt (oder gab?) es schon von Köhntopp. Die Seiten finde ich aber nicht mehr. Und er ging mir auch oft zu wenig auf die Grenzfälle ein. Es ist aber wenig sinnvoll, nur die richtige Lösung zu zeigen, ohne auf die möglichen Fallen hinzuweisen.

                              Die kleinen Lösungen fallen aber auch oft in mehrere Kategorien. Es müsste also auch ein Such- und Verweissystem entstehen.

                              Lust hätte ich schon dazu, denn sonst versickern die Ideen doch immer wieder.

                              Müsste man sich also erstmal Gedanken machen, wie man das aufbaut, sodass wirklich jeder etwas beitragen kann, der eine gute Idee hatte, die aber nicht unredigiert im Raume stehen bleibt und redaktionell eingepflegt wird.

                              • HTML-Elemente erzeugen (Selects, Radiogroups, Tables, Bildergalerien, ...)
                              • Typkontrollen
                              • Typumwandlungen
                              • ...

                              Man sollte das auch nicht mit PEAR verwechseln, denn das sind meistens komplexere Klassen für größere Anwendugnen. Der Ball sollte schon erheblich flacher gehalten werden in "getPHP".

                              Harzliche Grüße aus http://www.annerschbarrich.de

                              Tom

                              --
                              Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                              Nur selber lernen macht schlau
                              1. Hallo Tom,

                                Ja, auf der der Seite http://selfhtml.bitworks.de oder besser auf einer Extraseite?
                                http://getphp.bitworks.de
                                Ich meinte das durchaus ernst.

                                Das war mir trotz *g* schon klar. Ich lese doch nicht erst seit heute mit :-)

                                So nach und nach entstehen immer wieder kleine nützliche Tools, an denen man manchmal ganz schön lange knabbert, bis die Lösung einen dann förmlich anspringt. Man müsste sie aber auch kategorisieren und dokumentieren. Sowas ähnliches gibt (oder gab?) es schon von Köhntopp. Die Seiten finde ich aber nicht mehr. Und er ging mir auch oft zu wenig auf die Grenzfälle ein. Es ist aber wenig sinnvoll, nur die richtige Lösung zu zeigen, ohne auf die möglichen Fallen hinzuweisen.

                                Das Problem in diesem Thread mit der auf den ersten Blick überzeugenden Lösung von Andreas Lindig ist ein schönes Beispiel für solche Fallen.

                                Ich geb' zu, dass ich zu bequem bin, ein Testprogramm zu schreiben, dass ggf. einen Wert findet, für den seine Funktion einen falschen Wert zurückliefert (falls es diesen Fall überhaupt gibt) und noch bequemer, um die Richtigkeit seiner Lösung nachzuweisen *g*.

                                Dass Dich diese Grenzfälle beschäftigen, weiß jeder, der hier aufmerksam mitliest, ich sage nur: "konkurrierender Zugriff".

                                Lust hätte ich schon dazu, denn sonst versickern die Ideen doch immer wieder.

                                Müsste man sich also erstmal Gedanken machen, wie man das aufbaut, sodass wirklich jeder etwas beitragen kann, der eine gute Idee hatte, die aber nicht unredigiert im Raume stehen bleibt und redaktionell eingepflegt wird.

                                Hmm, hier weitermachen oder eigener Thread? Ich erinnere mich an Deinen Dialog mit Dennis Arbeiten mit Flatfiles :-)

                                • HTML-Elemente erzeugen (Selects, Radiogroups, Tables, Bildergalerien, ...)
                                • Typkontrollen
                                • Typumwandlungen
                                • ...

                                Freundliche Grüsse,

                                Vinzenz

                                1. Hello,

                                  Hmm, hier weitermachen oder eigener Thread? Ich erinnere mich an Deinen Dialog mit Dennis Arbeiten mit Flatfiles :-)

                                  Der ist ja noch nicht einmal ganz zu Ende gebracht. Aber da war mir nun zuviel eigenes Gedöns dazwischen gekommen. Wir sollten eine Möglichkeit für solche Dauerthreads schaffen. Die müssten dann auch einmal im Monat aufgeräumt werden durch "Abstimmung" aller Beteiligten, welche Passagen ins Nirwana können oder in die Anekdoten- oder Zotensammlungen... Wie das genau gehen könnte, weiß ich auch noch nicht, da ja oft ein fachlicher Beitrag auch Menscheleien oder Dummtüch enthält ;-)

                                  • HTML-Elemente erzeugen (Selects, Radiogroups, Tables, Bildergalerien, ...)
                                  • Typkontrollen
                                  • Typumwandlungen

                                  - IO-Operationen (Bausteine)

                                  • ...

                                  In diesem Fall haben wir eigentlich den Aufhänger im Thread, nämlich das anfänglich gaaanz einfache Problem von Andreas, das sich bei näherer Betrachtung als gar nicht so prophan herausstellt.

                                  Speziell die dabei aufkommenden Überlegungen sollte man festhalten.

                                  Harzliche Grüße aus http://www.annerschbarrich.de

                                  Tom

                                  --
                                  Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                                  Nur selber lernen macht schlau
                  2. Hi,

                    aus 2.300,98 sollen 2.30 werden.

                    Habe ich das richtig verstanden?

                    keine Ahnung, aber ich vermute, daß Du mal wieder um 3 Ecken zuviel denkst. Ich habe es so verstanden:

                    aus 2.300,98 (zweitausenddreihundertkommaneunacht)
                    wird '2300,98'

                    der von Dir gesetzte Punkt kommt doch in einem Float-Wert gar nicht wirklich vor.

                    Gruß, Andreas

                    --
                    Schluß mit der deutschen Sprache ihre Diskrimination!
                2. Hallo Andreas,

                  aber Himmel: das ist doch ganz simpel. Ich mach sowas immer mit einer eigenen Funktion. Nun willst Du sicher auch wissen wie? nagut:

                  $zahl = 1.23456...
                  $zahl *= 100;             (ergibt: 123.456...)

                  Bist Du Dir 100% sicher, dass diese Rechenoperation in _allen_ Fällen _keinen_ Rundungsfehler an der entscheidenden Dezimalstelle erzeugt?

                  Wie Joachim es bereits gesagt hat: Betrachten als String vermeidet auf _jeden_ Fall Rundungsprobleme und sollte genau deswegen verwendet werden.

                  Rechenoperationen würde ich genau aus diesem Grund vermeiden, auch wenn die Lösung bestechend einfach aussieht.

                  Freundliche Grüsse,

                  Vinzenz

                  1. Hi,

                    $zahl = 1.23456...
                    $zahl *= 100;             (ergibt: 123.456...)

                    Bist Du Dir 100% sicher, dass diese Rechenoperation in _allen_ Fällen _keinen_ Rundungsfehler an der entscheidenden Dezimalstelle erzeugt?

                    kann ich mir jetzt nicht vorstellen, weil doch gar nichts gerundet wird, die Zahl wird nicht verändert, sondern nur das Komma verschoben, wenn ich float richtig verstehe. Aber dazu sollten sich vielleicht mal richtige Programmierer äußern ;-)

                    Wie Joachim es bereits gesagt hat: Betrachten als String vermeidet auf _jeden_ Fall Rundungsprobleme und sollte genau deswegen verwendet werden.

                    mach ich ja später auch. Aber erstmal muß das Komma verschoben werden. Denn im String-Datentyp hast Du zunächstmal kein Komma. Du mußt doch wissen, wo es hin muss.

                    Gruß, Andreas

                    --
                    Schluß mit der deutschen Sprache ihre Diskrimination!
                    1. Hi!

                      kann ich mir jetzt nicht vorstellen, weil doch gar nichts gerundet wird, die Zahl wird nicht verändert, sondern nur das Komma verschoben, wenn ich float richtig verstehe. Aber dazu sollten sich vielleicht mal richtige Programmierer äußern ;-)

                      Das glaube ich auch. Mein Problem ist, dass ich eben nicht 100%ig sicher bin. Ich weiß dass Rechenoperationen im Computer anders verlaufen, als wenn man selber rechnet. Es sieht oft nur so aus als würde der Rechner exakt genau so rechnen, wenn man vieel Nachkommastellen nach hinten guckt, hat man dann auf einmal Nachkommastellen, die da normalerweise gar nicht hingehören. Bei besonders ungünstigen Zahlen, kann sich dies auf die Zahlen v orne auswirken. Normalerweise passiert das nicht, aber im Augenblick habe ich mit Zahlen mit 10 Nachkommastellen zu tun, damit wird gerechnet, geteilt... da treten dann auf einmal Fehler auf, mit denen man "normalerweise" nie gerechnet hätte.

                      Jedenfalls habe ich mit mal eine Funktion mit Stringfunktionen gebastelt:

                      function abrunden($zahl,$stellen=2) {
                        $dec = strrpos($zahl, ".");
                        if ($dec === FALSE) $dec = strlen($zahl);
                        return substr($zahl,0,$dec).','.str_pad(substr($zahl,$dec+1,$stellen),$stellen,'0');
                      }

                      Du Funktion macht dann aus

                      echo abrunden(1.999999); // 1,99

                      genau wie Deine Methode.

                      mach ich ja später auch. Aber erstmal muß das Komma verschoben werden. Denn im String-Datentyp hast Du zunächstmal kein Komma. Du mußt doch wissen, wo es hin muss.

                      Du machst eine Multiplikation und 2 Typenumwandlungen. Ich mache keine Berechnung und nur eine Typenumwandlung, von Float -> String.

                      Deine Methode finde ich natürlich schöner, und ich habe dabei auch keine Idee wie man da einen Fehler reinbringen könnte, aber das heißt ja noch nichts ;-)

                      Grüße
                      Andreas

                      --
                      SELFHTML Tipps & Tricks: http://aktuell.de.selfhtml.org/tippstricks/
                      1. Es sieht oft nur so aus als würde der Rechner exakt genau so rechnen, wenn man vieel Nachkommastellen nach hinten guckt, hat man dann auf einmal Nachkommastellen, die da normalerweise gar nicht hingehören.

                        ich glaube, das liegt daran, daß die Zahlen immer abgeschnitten werden, also bei jedem Rechenschritt. Wenn die Genauigkeit von Float erreicht ist, wird die Zahl abgeschnitten und der Rechner hat keine Ahnung, ob die auf- oder abzurunden gewesen wäre.

                        function abrunden($zahl,$stellen=2) {
                          $dec = strrpos($zahl, ".");

                        naja, im Grunde machst Du ja nicht viel anderes als ich, nur daß Du das Komma als Zeichen verschiebst und ich mathematisch. Aber weißt Du denn, ob so eine implizite Stringumwandlung ohne Rundungsfehler geschieht? Das wäre doch die entscheidende Frage. Anscheinend macht number_format() das ja nicht korrekt, oder hattest Du da nicht diese Fehler? Und number_format() macht doch nicht viel anderes als abrunden(), außer daß es eben kaufmännisch rundet. Oder war das Dein einziges Problem?

                        und ich habe dabei auch keine Idee wie man da einen Fehler reinbringen könnte,

                        naja, vielleicht mal Grenzwerte testen, also Zahlen, die vor oder nach dem Komma die Grenze des Floatbereichs erreichen. Hab jetzt keine Ahnung wo das ist, meine C-Qualen sind zum Glück schon länger vorbei ;-)

                        Gruß, Andreas

                        --
                        Schluß mit der deutschen Sprache ihre Diskrimination!
                        1. Hi!

                          ich glaube, das liegt daran, daß die Zahlen immer abgeschnitten werden, also bei jedem Rechenschritt. Wenn die Genauigkeit von Float erreicht ist, wird die Zahl abgeschnitten und der Rechner hat keine Ahnung, ob die auf- oder abzurunden gewesen wäre.

                          Das Problem ist - wie stellst Du Bruchzahlen dar? Bei 1/3 ist es offensichtlich unmöglich, aber selbst 1/10 funktioniert - wie Vinzenz schrieb - ebenfalls nicht. Solche Zahlen werden nur "annäherungsweise" gespeichert. Normalerweise bekommt man davon dann auch nichts mit, eben nur wenn man extreme Zahlen hat.

                          function abrunden($zahl,$stellen=2) {
                            $dec = strrpos($zahl, ".");

                          naja, im Grunde machst Du ja nicht viel anderes als ich, nur daß Du das Komma als Zeichen verschiebst und ich mathematisch.

                          Ja, das ist auf dem Papier zwar viel eleganter, die Frage ist, ob es auch gleich genau ist.

                          Aber weißt Du denn, ob so eine implizite Stringumwandlung ohne Rundungsfehler geschieht? Das wäre doch die entscheidende Frage.

                          Aber diese Umwandlung findet ja so oder so statt wenn Du die Zahl anzeigen willst. Aber ich wandle exakt die gewünschte Zahl direkt um, und rechne nicht noch vorher damit rum.

                          Anscheinend macht number_format() das ja nicht korrekt, oder hattest Du da nicht diese Fehler?

                          Number-Format macht es halt nicht so wie ich es in diesem speziellen Fall benötige: Ich muss _immer_ abrunden. Es gibt keine PHP-Funktion die das mit Nachkommastellen kann. Ich habe ja testweise versucht, number_format() zu verwenden, immer 1 Stelle mehr ausgeben zu lassen, und die dann abzuschneiden - dabei kommen ggfs. falsche Ergebnisse raus.

                          Und number_format() macht doch nicht viel anderes als abrunden(), außer daß es eben kaufmännisch rundet. Oder war das Dein einziges Problem?

                          abrunden() rundet _immer_ ab, das heißt 1,999 wird zu 1,99 und nicht zu 2,00 - wie es bei number_format() der Fall wäre.

                          naja, vielleicht mal Grenzwerte testen, also Zahlen, die vor oder nach dem Komma die Grenze des Floatbereichs erreichen. Hab jetzt keine Ahnung wo das ist, meine C-Qualen sind zum Glück schon länger vorbei ;-)

                          Ich kenne mich nicht gut genug mit sowas aus, um entsprechende Grenzwerte zu formulieren. Das Problem ist: nur weil eine Funktion mit einigen Beispielen gut funktioniert, heißt dass noch lange nicht, dass es mit jeder Zahl korrekt funktioniert.

                          Grüße
                          Andreas

                          --
                          SELFHTML Linkverzeichnis: http://aktuell.de.selfhtml.org/links/
                        2. Hello,

                          ich glaube, das liegt daran, daß die Zahlen immer abgeschnitten werden, also bei jedem Rechenschritt. Wenn die Genauigkeit von Float erreicht ist, wird die Zahl abgeschnitten und der Rechner hat keine Ahnung, ob die auf- oder abzurunden gewesen wäre.

                          Es handelt sich dabei um ein ganz einfaches Quantisierungsproblem, was aber in diesem Fall ungefähr aufs Gleiche rauskommt. Es fehlen bei jedem Rechenschritt die "Feinheiten", es wird immer abgerundet.

                          Harzliche Grüße aus http://www.annerschbarrich.de

                          Tom

                          --
                          Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                          Nur selber lernen macht schlau
                    2. Hallo Andreas,

                      Hi,

                      $zahl = 1.23456...
                      $zahl *= 100;             (ergibt: 123.456...)

                      Bist Du Dir 100% sicher, dass diese Rechenoperation in _allen_ Fällen _keinen_ Rundungsfehler an der entscheidenden Dezimalstelle erzeugt?

                      kann ich mir jetzt nicht vorstellen, weil doch gar nichts gerundet wird, die Zahl wird nicht verändert, sondern nur das Komma verschoben, wenn ich float richtig verstehe.

                      Nein, Du verstehst Gleitpunktzahlen falsch. Es gibt kein Komma, das einfach verschoben werden kann. Bereits die einfache Gleitpunktzahl

                      0.1

                      läßt sich nicht exakt darstellen :-(

                      Siehe z.B. Datentypen in C.

                      mach ich ja später auch. Aber erstmal muß das Komma verschoben werden. Denn im String-Datentyp hast Du zunächstmal kein Komma. Du mußt doch wissen, wo es hin muss.

                      Es ist kein Problem mit den Stringfunktionen das Dezimaltrennzeichen zu finden, bzw. herauszufinden, dass keines vorhanden ist.

                      Arbeitest Du rein mit Stringfunktionen, so kannst Du das richtige Ergebnis garantieren. Warum das Risiko der Gleitpunktarithmetik eingehen?

                      <zitat quelle="siehe Link">
                      int main()
                      {
                         float i=0.0;
                         for (i=0.0; i != 1.0; i += 0.1)
                           printf("%f",i);
                         return(0);
                      }
                      </zitat>

                      Das ist eine Endlosschleife (in C) :-)

                      Freundliche Grüsse,

                      Vinzenz

    2. Hi,»» Hi,

      $zahl = 4.23723526844534;
      $nachkommastellen = 2;

      sowas?
      $x =  123.123456789;
      echo number_format($x, 2, ",", ".");

      ups, Du wolltest abschneiden... sollte doch so gehen... ?:
      $x =  123.678456789;
      echo substr($x, 0,strrpos($x, ".") +3);

      Gruesse, Joachim

      --
      Am Ende wird alles gut.
  2. gudn tach!

    ich habe jetzt nicht _alles_ gelesen, was auf das ausgangsposting geantwortet wurde, aber was spricht denn einfach gegen:

    $zahl=4.23723526844534; // oder sonstwas
    $neue_zahl=floor(100*$zahl)/100;
    // fuer das komma dann noch ein aufruf von str_replace;

    hier ist doch die einzige voraussetzung, dass die anzahl der vorkommastellen nicht zu hoch ist.

    prost
    seth

    1. Hello seth,

      $zahl=4.23723526844534; // oder sonstwas
      $neue_zahl=floor(100*$zahl)/100;
      // fuer das komma dann noch ein aufruf von str_replace;

      Wenn Du mitgelesen hättest, wüsstest Du schon, dass das nicht die ideale Lösung ist, nur eine bequeme.

      Harzliche Grüße aus http://www.annerschbarrich.de

      Tom

      --
      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
      Nur selber lernen macht schlau
    2. Hallo seth,

      ich habe jetzt nicht _alles_ gelesen, was auf das ausgangsposting geantwortet wurde, aber was spricht denn einfach gegen:

      $zahl=4.23723526844534; // oder sonstwas
      $neue_zahl=floor(100*$zahl)/100;

      Andreas Lindig ist weitgehend mit Dir einverstanden, siehe https://forum.selfhtml.org/?t=92388&m=557019.

      hier ist doch die einzige voraussetzung, dass die anzahl der vorkommastellen nicht zu hoch ist.

      Sehr schön, dass Du Einschränkungen machst :-)

      Wenn man eine Funktion schreibt, warum nicht eine, die _keine_ Einschränkungen nötig hat? Eine, die komplett auf Stringfunktionen aufsetzt? Eine, die nicht mit den Risiken der Gleitpunktarithmetik behaftet ist?

      Freundliche Grüsse,

      Vinzenz

      1. gudn tach!

        $zahl=4.23723526844534; // oder sonstwas
        $neue_zahl=floor(100*$zahl)/100;

        Andreas Lindig ist weitgehend mit Dir einverstanden, siehe https://forum.selfhtml.org/?t=92388&m=557019.

        hmm, verblueffend wie sehr das verlinke posting meinen worten gleicht. evtl. liegt es daran, dass es meine worte sind. ;-)

        hier ist doch die einzige voraussetzung, dass die anzahl der vorkommastellen nicht zu hoch ist.

        Sehr schön, dass Du Einschränkungen machst :-)

        die je nach anwendungsbereich (wurde jener eigentlich schon explizit irgendwo genannt?) irrelevant sind.
        auf http://www.php.net/manual/en/language.types.float.php steht geschrieben: "The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (that's 64 bit IEEE format)"
        14 stellen... bei den meisten anwendungen sollte also diese einschraenkung keine rolle spielen. ansonsten ist von konventionellen float abzuraten.

        Wenn man eine Funktion schreibt, warum nicht eine, die _keine_ Einschränkungen nötig hat? Eine, die komplett auf Stringfunktionen aufsetzt? Eine, die nicht mit den Risiken der Gleitpunktarithmetik behaftet ist?

        ich sehe das risiko bei *100 und /100 nicht (abgesehen von den bereits genannten langen zahlen). vorteil koennte neben der bequemlichkeit die geschwindigkeit sein. wie viele zahlen sollen denn gerundet werden?
        hmm, wobei die zahlen ja zunaechst als string (aus der datenbank) vorliegen, oder? und wieder draengt sich mir die frage nach der anwendung auf.

        prost
        seth

        1. Hoi!

          Andreas Lindig ist weitgehend mit Dir einverstanden, siehe https://forum.selfhtml.org/?t=92388&m=557019.

          hmm, verblueffend wie sehr das verlinke posting meinen worten gleicht. evtl. liegt es daran, dass es meine worte sind. ;-)

          Vielleicht ein 2. Ich? ;-)

          hier ist doch die einzige voraussetzung, dass die anzahl der vorkommastellen nicht zu hoch ist.

          Sehr schön, dass Du Einschränkungen machst :-)

          die je nach anwendungsbereich (wurde jener eigentlich schon explizit irgendwo genannt?) irrelevant sind.

          Also, die DB-Felder für die Werte mit denen gerechnet wird, haben alle DECIMAL (20,10), das heißt insgesamt 20 Stellen, davon 10 Nachkommastellen. In der Praxis werde nicht alle verwendet werden, aber 12 Stellen werden durchaus vorkommen, im Extremfall vielleicht 15. Bei dem konkreten Problem geht es darum, dass ich ein Feld vorbelegen will, und zwar mit der nächst möglichen, kleineren Zahl. Ich habe z.B. irgendwas gerechnet, und habe dann in PHP ein Ergebnis von 1.999999999. Jetzt soll der nächst mögliche niedrigere, auf 2 Nachkommastellen beschränkte Wert ausgegeben werden, also 1.99, bzw. 1,99. Die Anzahl der Nachkommastellen ist nicht fest, sondern kann zwischen 0 und 10 liegen. Meistens sind es 2-5. Hierbei darf ich mich nicht verrechnen, denn wenn jetzt aus Versehen ein Wert von 2,00 eingetragen würde, dann würde dieser am Ende durch die Validierung fallen, und es gibt eine häßliche Fehlermeldung. Bei den konkreten Zahlen sehe ich noch kein Problem, Aber was wenn man sowas hat wie

          12,345,678.12345 ?

          auf http://www.php.net/manual/en/language.types.float.php steht geschrieben: "The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (that's 64 bit IEEE format)"
          14 stellen... bei den meisten anwendungen sollte also diese einschraenkung keine rolle spielen. ansonsten ist von konventionellen float abzuraten.

          "precision of roughly 14 decimal digits" von diesem _roughly_ bekomme ich ja gerade meine Bauchschmerzen ;-)

          ich sehe das risiko bei *100 und /100 nicht (abgesehen von den bereits genannten langen zahlen). vorteil koennte neben der bequemlichkeit die geschwindigkeit sein. wie viele zahlen sollen denn gerundet werden?

          Performance ist absolut vernachlässigbar.

          hmm, wobei die zahlen ja zunaechst als string (aus der datenbank) vorliegen, oder?

          ja, und damit wird gerechnet. Oder es wird schon in der DB gerechnet (im SQL-Statement), ich weiß gar nicht wieviele Nachkommastellen dann zurückgegeben werden.

          und wieder draengt sich mir die frage nach der anwendung auf.

          immer noch?

          Grüße
          Andreas

          --
          SELFHTML Tipps & Tricks: http://aktuell.de.selfhtml.org/tippstricks/
          1. Hello,

            "precision of roughly 14 decimal digits" von diesem _roughly_ bekomme ich ja gerade meine Bauchschmerzen ;-)

            Das liegt eben daran, dass die binären Schritt-Grenzen nicht mit den dezimalen Schrittgrenzen beim Digitwechsel übereinstimmen. Bei Binärzahlen stimmen Digit-Schritt und Wertschritt ja überein, Dezimalen haben eben immer eine Untermenge von 10 Schritten pro Schritt von Digit zu Digit.

            Deshalb spricht man auch oft von "zweieinhalbstelliger Anzeige". Die eine Dezimalstelle kennt dann eben nur eine Untermenge der möglichen Dezimalen. Bei frühzeitlichen Digitalmessgeräten war das dann meistens nur die 1, da die aus dem Digitalisierer noch als Übertrag abfiel.

            Harzliche Grüße aus http://www.annerschbarrich.de

            Tom

            --
            Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
            Nur selber lernen macht schlau
  3. number_format($Zahl, $Nachkommastellen, ',', '.')

    1. number_format($Zahl, $Nachkommastellen, ',', '.')

      $ php -r "echo number_format(1.99999, 2, ',', '.');"
      2,00

      --
      SELFHTML Linkverzeichnis: http://aktuell.de.selfhtml.org/links/
      1. ja, ja, is ja gut.
        man sollte erst lesen, dann antworten. und nicht umgekehrt.

        1. Hi!

          man sollte erst lesen, dann antworten. und nicht umgekehrt.

          korrekt ;-)

          Grüße
          Andreas

          --
          SELFHTML Tipps & Tricks: http://aktuell.de.selfhtml.org/tippstricks/
        2. Hi,

          ja, ja, is ja gut.
          man sollte erst lesen, dann antworten. und nicht umgekehrt.

          wer denkt, lebt!

          Gruss,
          Ludger

          --
          "Ist der Hund gesund, freut sich der Mensch!"