TobiasN: Nachkommastellen abschneiden, wenn Null

Hallo,

ich stehe vor folgendem an sich eigentlich vermutlich simplen (PHP-)Problem, komme aber einfach nicht mehr weiter:
Eine Zahl (die einen Preis ausdrückt) aus einer Datenbank hat vier Nachkommastellen. Da dies gefälliger aussieht, soll sie nur mit zwei Nachkommastellen ausgegeben werden, sofern dadurch keine Informationen verloren gehen.
Habe schon einige Kombinationen aus number_format() und anderen String-Funktionen getestet - aber entweder gehen immer alle Nullen am Ende drauf (unerwünschtes Ergebnis : 111,1), oder es wird nach zwei Nachkommastellen gerundet oder abgeschnitten.

Hat jemand vielleicht diesbezüglich einen Tipp für mich?

Danke!

Tobias

  1. Hi!

    Hat jemand vielleicht diesbezüglich einen Tipp für mich?

    Bring bitte ein paar Beispiele, was wie werden soll und wie nicht. Ich kann mir noch nicht genau vorstellen, was du vorhast.

    Wenn number_format() nicht hilft und sprintf() auch nicht, dann musst du dir wohl was eigenes programmieren.

    Lo!

    1. Bring bitte ein paar Beispiele, was wie werden soll und wie nicht. Ich kann mir noch nicht genau vorstellen, was du vorhast.

      Ich habe ihn so verstanden.

      1,1000 -> 1,10
      2,0000 -> 2? (laut Überschrift, vielleicht auch 2,00)
      5,2457 -> 5,2457
      2,1730 -> 2,173

      Ich hatte vor einer Weile mal ergebnislos gesucht, wie man auf n Signifikante Stellen rundet. Vermutlich "muß" man hi wie da regex nehmen.

      1. Grüße,
        Schleife mit modulo 10^i?
        Abbruch falls !=0
        MFG
        bleicher

        --
        __________________________-

        FirefoxMyth
        1. @@bleicher:

          nuqneH

          Schleife mit modulo 10^i?

          ?? Wohl nicht. Eher mit Logarithmus.

          Qapla'

          --
          Alle Menschen sind klug. Die einen vorher, die anderen nachher. (John Steinbeck)
          1. Grüße,

            ?? Wohl nicht. Eher mit Logarithmus.

            hm -

            was ist 17,3450000%100 in PHP noch mal?
            MFG
            bleicher

            --
            __________________________-

            FirefoxMyth
            1. Hi!

              was ist 17,3450000%100 in PHP noch mal?

              Ein Syntaxfehler.

              Lo!

      2. @@Texter mit x:

        nuqneH

        Ich hatte vor einer Weile mal ergebnislos gesucht, wie man auf n Signifikante Stellen rundet. Vermutlich "muß" man hi wie da regex nehmen.

        Reguläre Ausdrücke für numerische Berechnungen? Wohl kaum.

        Darstellung der Zahl durch Mantisse und Exponent, Rundung der Mantisse auf die gewünschre Anzahl von Stellen.

        auf 3 signifikante Stellen gerundet:
           123456 = 1.23456 · 10⁵  ≈ 1.23 · 10⁵  = 123000
        0.0123456 = 1.23456 · 10⁻² ≈ 1.23 · 10⁻² = 0.0123

        Qapla'

        --
        Alle Menschen sind klug. Die einen vorher, die anderen nachher. (John Steinbeck)
        1. Reguläre Ausdrücke für numerische Berechnungen? Wohl kaum.

          Richtig.

          1. @@Texter mit x:

            nuqneH

            Reguläre Ausdrücke für numerische Berechnungen? Wohl kaum.
            Richtig.

            Obwohl … ;-)

            Qapla'

            --
            Alle Menschen sind klug. Die einen vorher, die anderen nachher. (John Steinbeck)
      3. Hi Leute,

        sorry für die offensichtlich mehrdeutig gestellte Frage!
        Wie es aussieht bin ich mindestens 1x richtig verstanden worden. :-)

        Ich habe ihn so verstanden.

        1,1000 -> 1,10
        2,0000 -> 2? (laut Überschrift, vielleicht auch 2,00)

        2,00

        5,2457 -> 5,2457
        2,1730 -> 2,173

        Sprich: Zwei Nachkommastellen sollen immer ausgegeben werden, wenn es darüber hinaus von 0 abweichende Stellen gibt, dann sollen diese ebenfalls ausgegeben werden.
        Alternativ könnte man auch immer entweder 2 oder 4 Nachkommastellen ausgeben - selbst, wenn nur drei Stellen vergeben sind.

        1,1000 -> 1,10
        2,0000 -> 2,00
        5,2457 -> 5,2457
        2,1730 -> 2,1730

        Ob letzteres nun mit drei oder vier Stellen ausgegeben wird ist zweitrangig.
        Natürlich könnte ich das ganze schon kompliziert zusammenbauen, in etwa wie folgt - aber ich wäre auf der Suche nach einer eleganteren und potentiell ressourcensparenderen Lösung.

        $zahl = ...
        $zahl_formatiert = number_format();
        if($zahl == $zahl_formatiert) print($zahl_formatiert);
        else print($zahl);

        Dürfte funktionieren, ist aber natürlich sehr unsauber, weil es damit spielt, dass PHP das mit den Variablentypen nicht so genau nimmt...

        Danke auf jeden Fall schon mal für eure ganzen Antworten - und vielleicht kann mir ja nun, da die Frage anhand von Beispielen verdeutlich ist - jemand noch nen Tipp geben? Den printf()-Tipp teste ich gerade noch... vielleicht war das auch schon der entscheidende Hinweis!

        Tobias

        1. Hi!

          sorry für die offensichtlich mehrdeutig gestellte Frage!
          Wie es aussieht bin ich mindestens 1x richtig verstanden worden. :-)

          Geahnt, was du haben willst, habe ich auch, jedoch reicht das nicht, um konkreten Code zu produzieren. Und das "richtig verstanden" war vermutlich auch ein "richtig geraten".

          Natürlich könnte ich das ganze schon kompliziert zusammenbauen, in etwa wie folgt - aber ich wäre auf der Suche nach einer eleganteren und potentiell ressourcensparenderen Lösung.

          PHP hat nicht für jeden Spezialfall eine Funktion.

          $zahl = ...
          $zahl_formatiert = number_format();
          if($zahl == $zahl_formatiert) print($zahl_formatiert);
          else print($zahl);

          Dürfte funktionieren, ist aber natürlich sehr unsauber, weil es damit spielt, dass PHP das mit den Variablentypen nicht so genau nimmt...

          Warum soll das unsauber sein? Implizierte Typumwandlung gehört zu PHPs Philosophie und kann damit im PHP-Sinne nicht unsauber sein. Wenn du willst, und das sauberer findest, nimm explizite Typumwandlung. Ein anderes Ergebnis bekommst du damit aber nicht. Einen Einfluss kann höchstens die Ungenauigkeit der Fließkommazahlen darstellen. Nicht jede Zahl lässt sich exakt mit endlichen Ziffern abbilden, weder im Dezimal- noch im Binärsystem. Das ist jedoch prinzipbedingt und kein PHP-typisches Phänomen.

          Du schriebst von Preisen. Diese sollte exakt sein und nicht am Fließkommazahlenfehler kranken. Deshalb hast du da hoffentlich einen Money- oder Decimal-Typ im DBMS verwendet. Abgesehen davon, wirst du vermutlich einen String geliefert bekommen und keinen Zahlentyp. Prüf das mal mit var_dump().

          Danke auf jeden Fall schon mal für eure ganzen Antworten - und vielleicht kann mir ja nun, da die Frage anhand von Beispielen verdeutlich ist - jemand noch nen Tipp geben? Den printf()-Tipp teste ich gerade noch... vielleicht war das auch schon der entscheidende Hinweis!

          Kaum, *printf() produziert keine unterschiedlichen langen Nachkommazahlen.

          Lo!

          1. Und das "richtig verstanden" war vermutlich auch ein "richtig geraten".

            Nach nochmaligem Überlegen muß ich sagen, es ist eindeutig. Allerdings hätte er was anderes meinen können als das was er geschrieben hat.

            Nicht jede Zahl lässt sich exakt mit endlichen Ziffern abbilden, weder im Dezimal- noch im Binärsystem.

            Aber jeder realexistierende Preis mit vier Nachkommastellen.

            1. @@Texter mit x:

              nuqneH

              Nicht jede Zahl lässt sich exakt mit endlichen Ziffern abbilden, weder im Dezimal- noch im Binärsystem.

              Aber jeder realexistierende Preis mit vier Nachkommastellen.

              ??

              Der endliche Dezimalbruch 0.1 ist ein unendlicher Binärbruch: [latex]0.000\overline{1100}[/latex]

              Qapla'

              --
              Alle Menschen sind klug. Die einen vorher, die anderen nachher. (John Steinbeck)
              1. Nicht jede Zahl lässt sich exakt mit endlichen Ziffern abbilden, weder im Dezimal- noch im Binärsystem.

                Aber jeder realexistierende Preis mit vier Nachkommastellen.

                ??

                Der endliche Dezimalbruch 0.1 ist ein unendlicher Binärbruch: [latex]0.000\overline{1100}[/latex]

                0.1 ist aber nicht "weder im Dezimal- noch im Binärsystem" abzubilden.

                1. Hi!

                  Nicht jede Zahl lässt sich exakt mit endlichen Ziffern abbilden, weder im Dezimal- noch im Binärsystem.
                  Aber jeder realexistierende Preis mit vier Nachkommastellen.
                  Der endliche Dezimalbruch 0.1 ist ein unendlicher Binärbruch: [latex]0.000\overline{1100}[/latex]
                  0.1 ist aber nicht "weder im Dezimal- noch im Binärsystem" abzubilden.

                  Ich schrieb "exakt abbilden". Wenn sich eine Ziffernfolge unendlich wiederholen müsste, um genau die Zahl und nicht etwas Gerundetes abzubilden, brauchst du unendlich viel Speicher. Du musst also irgendwo einen Kompromss eingehen, der dir im weiteren Verlauf Ungenauigkeiten einhandeln kann. Genau aus dem Grunde und auch wegen der höheren signifikanten Stellenanzahl gibt es die Decimal- oder Money-Typen, die zum Speichern keine Fließkommadarstellung mit Brüchen verwenden, sondern die einzelnen Ziffern eindeutig abbilden.

                  Lo!

                  1. Nicht jede Zahl lässt sich exakt mit endlichen Ziffern abbilden, weder im Dezimal- noch im Binärsystem.
                    Aber jeder realexistierende Preis mit vier Nachkommastellen.
                    Der endliche Dezimalbruch 0.1 ist ein unendlicher Binärbruch: [latex]0.000\overline{1100}[/latex]
                    0.1 ist aber nicht "weder im Dezimal- noch im Binärsystem" abzubilden.

                    Ich schrieb "exakt abbilden". Wenn sich eine Ziffernfolge unendlich wiederholen müsste, ...

                    Bei einer Zahl die nicht unendlich groß ist "mit vier Nachkommastellen"?

                    1. Hi!

                      Nicht jede Zahl lässt sich exakt mit endlichen Ziffern abbilden, weder im Dezimal- noch im Binärsystem.
                      Aber jeder realexistierende Preis mit vier Nachkommastellen.
                      Der endliche Dezimalbruch 0.1 ist ein unendlicher Binärbruch: [latex]0.000\overline{1100}[/latex]
                      0.1 ist aber nicht "weder im Dezimal- noch im Binärsystem" abzubilden.
                      Ich schrieb "exakt abbilden". Wenn sich eine Ziffernfolge unendlich wiederholen müsste, ...
                      Bei einer Zahl die nicht unendlich groß ist "mit vier Nachkommastellen"?

                      Das Dezimalsystem unterscheidet sich vom Binärsystem. Das was im Dezimalsystem endlich ist, ist das nicht unbedingt im Binärsystem. Ein Beispiel dazu gab ja Gunnar schon. Hier noch ein anderes Beispiel: der Bruch 1/3 lässt sich in der Form wunderbar endlich darstellen, im Dezimalsystem hingegen nicht mehr.

                      Lo!

                      1. Das Dezimalsystem unterscheidet sich vom Binärsystem. Das was im Dezimalsystem endlich ist, ist das nicht unbedingt im Binärsystem. Ein Beispiel dazu gab ja Gunnar schon. Hier noch ein anderes Beispiel: der Bruch 1/3 lässt sich in der Form wunderbar endlich darstellen, im Dezimalsystem hingegen nicht mehr.

                        Ich weiß.

  2. Hi,

    Eine Zahl (die einen Preis ausdrückt) aus einer Datenbank hat vier Nachkommastellen.

    rechnet ihr da wirklich mit Hundertstel-Cents? Wow. Mir kommen schon die Zehntel an der Tankstelle, die einfach nicht aussterben wollen, lächerlich vor.

    Da dies gefälliger aussieht, soll sie nur mit zwei Nachkommastellen ausgegeben werden, sofern dadurch keine Informationen verloren gehen.

    Was heißt "falls keine Informationen verlorengehen"? Endpreise -also die Beträge, die in einem Angebot oder in einer Rechnung auftauchen- sollten IMHO immer nur so genau angegeben sein, wie sie auch bezahlt werden. Ergibt sich rechnerisch ein Endbetrag von 184.627EUR, dann sollte dieser Wert in einem Dokument, das nach draußen geht, grundsätzlich nur mit zwei Nachkommastellen angegeben werden. Ob man grundsätzlich abrundet, grundsätzlich aufrundet oder mathematisch korrekt rundet, bleibt einem selbst überlassen, solange es eindeutig geregelt ist.

    Habe schon einige Kombinationen aus number_format() und anderen String-Funktionen getestet - aber entweder gehen immer alle Nullen am Ende drauf (unerwünschtes Ergebnis : 111,1), oder es wird nach zwei Nachkommastellen gerundet oder abgeschnitten.

    Was gefällt dir an sprintf("%.2f", $preis) nicht?

    So long,
     Martin

    --
    "Hier steht, deutsche Wissenschaftler hätten es im Experiment geschafft, die Lichtgeschwindigkeit auf wenige Zentimeter pro Sekunde zu verringern." - "Toll. Steht da auch, wie sie es gemacht haben?" - "Sie haben den Lichtstrahl durch eine Behörde geleitet."
    1. Da dies gefälliger aussieht, soll sie nur mit zwei Nachkommastellen ausgegeben werden, sofern dadurch keine Informationen verloren gehen.

      Was heißt "falls keine Informationen verlorengehen"?

      Nur Nullen entfernen.

      1. Hi,

        Was heißt "falls keine Informationen verlorengehen"?

        Nur Nullen entfernen.

        Dann könnte das

        unerwünschtes Ergebnis : 111,1

        aber nicht unerwünscht sein.

        MfG ChrisB

        --
        Light travels faster than sound - that's why most people appear bright until you hear them speak.
        1. Was heißt "falls keine Informationen verlorengehen"?

          Nur Nullen entfernen.

          Dann könnte das

          unerwünschtes Ergebnis : 111,1
          aber nicht unerwünscht sein.

          Daß nur Nullen entfernt werden sollen, sagt nichts darüber aus, inwiefern Nullen entfernt werden sollen. Aber ob zwei oder keine Nachkommastellen bestehen bleiben sollen, wenn beide Nullen sind (bzw. alle vier), da bin ich mir auch nicht sicher.

  3. Wenn Du bei sowas wie Stringfunktionen bleiben willst, dann wäre

    $preis = '111,1230';  
    echo preg_replace('/(.*,[0-9]{2}([1-9]{1,2})?).*/', '$1', $preis);
    

    eine mögliche Option. (alles worauf ein Komma, zwei Ziffern zwischen 0 und 9 und optional eine oder zwei Ziffern zwischen 1 und 9 folgt)
    Man könnte da noch was ändern, z.B. wenn man den Fall abdecken will, daß irreguläre Angaben in der Datenbank stehen.

  4. Hi,

    vielen Dank für eure ausführlichen und zahlreichen Antworten.
    Mit eurer Hilfe bin ich zu folgender Lösung gekommen:

    $Preis_zweistellig = number_format($Datenbankoutput["Preis"], 2, ',', ' ');
       $Preis_vierstellig = number_format($Datenbankoutput["Preis"], 4, ',', ' ');
       if(rtrim($Preis_zweistellig, "0") == rtrim($Preis_vierstellig, "0")) $Preis_Ausgabe = $Preis_zweistellig;
       else $Preis_Ausgabe = $Preis_vierstellig;
       print($Preis_Ausgabe);

    Dadurch werden entweder zwei Nachkommastellen ausgegeben, oder - wenn in der dritten und/oder vierten Stelle noch etwas anderes als eine Null steht - vier Nachkommastellen angegeben. Sieht vermutlich besser aus, als wenn es mal 2, mal 3 und mal 4 Nachkommastellen gibt.
    Der Preis ist in der Datenbank übrigens als DECIMAL(7,4) gespeichert.

    Danke auch für die Info bzgl. der impliziten Typenumwandlung - hat mir das "schlechte Gewissen" genommen ;-) .

    Danke euch!

    Grüße
    Tobias