Robert: Tausenderpunkt bei Preisstring

Hallo alle,

ich möchte einen Preis einigermaßen kaufmännisch und augenfreundlich formatieren. Für das Runden auf 2 Stellen und Komma statt Punkt bei den Nachkommastellen nutze ich folgendes:

function kaufm(x)
{
  var k = (Math.round(x * 100) / 100).toString();
  k += (k.indexOf('.') == -1)? '.00' : '00';
  var p = k.indexOf('.'), m = k.indexOf('-.');
  var f = (p == 0 || m == 0)? '0,' : ',';
  return k.substring(0, p) + f + k.substring(p+1, p+3);
}

Aus "1234.567" wird dann "1234,57".

Das funktioniert bestens, aber mir fällt kein geeigneter Ansatz ein, die Tausenderpunkte einzubauen ("1.234,57").

Wüßte jemand eine Erweiterung für o.g. Funktion, die auch bei noch größeren Zahlen, wie zB 1.234.567,89, funktioniert?

Danke
Robert

  1. Hi Robert,

    so ganz spontan fällt mir folgendes ein:

    Zähle die Zeichen von hinten ab dem Komma und setze jedes dritte Zeichen einen Punkt. Oder so ähnlich.
    Es gibt aber bestimmt noch eine geschicktere Lösung........

    Du weiß auch, dass nach DIN 5008 als Tausendertrennzeichen ein Leerzeichen verwendet werdet sollte?

    Gruß von Tom C

    1. Hi Robert,

      Zähle die Zeichen von hinten ab dem Komma und setze jedes dritte Zeichen einen Punkt. Oder so ähnlich.
      Es gibt aber bestimmt noch eine geschicktere Lösung........

      Nach der Suche ich :)

      Du weiß auch, dass nach DIN 5008 als Tausendertrennzeichen ein Leerzeichen verwendet werdet sollte?

      Nein weiß ich nicht, käme bei dem Problem hier aber auf das gleiche raus, Leerzeichen oder Punkt einzufügen.

      MfG
      Robert

  2. Hallo Robert,

    ich möchte einen Preis einigermaßen kaufmännisch und augenfreundlich formatieren. Für das Runden auf 2 Stellen und Komma statt Punkt bei den Nachkommastellen nutze ich folgendes:

    schau dir dazu mal diese Funktion an:

    http://www.sara-online.de/programmierecke/js/number_format.html

    Abgesehen davon, solltest du sowohl bei deiner Funktion als auch bei der gelinkten eine Sonderfallbehandlung einbauen:

    alle Dezimalzahlen die auf .145, .285, .565 bzw. .575 enden werden ab statt aufgerundet (Fließkomma Präzision)

    Viele Grüße

    Antje

    1. Grüße!

      ich möchte einen Preis einigermaßen kaufmännisch und augenfreundlich formatieren

      schau dir dazu mal diese Funktion an:

      http://www.sara-online.de/programmierecke/js/number_format.html

      Danke! Die Suche hat endlich ein Ende. Das mit der Sonderfallbehandlung bekomm ich schon hin :)

      MfG
      Robert

    2. Hi Antje!

      Abgesehen davon, solltest du sowohl bei deiner Funktion als auch bei der gelinkten eine Sonderfallbehandlung einbauen:

      alle Dezimalzahlen die auf .145, .285, .565 bzw. .575 enden werden ab statt aufgerundet (Fließkomma Präzision)

      Wieso? Das verstehe ich jetzt nicht.

      Grüße
      Andreas

      1. Hallo Andreas

        Abgesehen davon, solltest du sowohl bei deiner Funktion als auch bei der gelinkten eine Sonderfallbehandlung einbauen:

        alle Dezimalzahlen die auf .145, .285, .565 bzw. .575 enden werden ab statt aufgerundet (Fließkomma Präzision)

        Wieso? Das verstehe ich jetzt nicht.

        weil sich diese Zahl nicht als endlicher Binärbruch darstellen läßt und dass führt bei Rechnenoperationen zu einem internen Rundungsfehler.

        Alle diese Rundungsfunktionen (inklusive die von Peter) multiplizeren die Zahl mit der Zehnerpotenz der Stellenzahl, runden dann und dividieren das Ergebnis dann durch die Zehnerpotenz der Stellenzahl

        Das bedeutet, soll 0.145 auf 2 Stellen nach dem Komma gerundet werden, dann ergibt: 0.145 * 100 nicht wie erwartet 14.5 sondern 14.499999999999998. Gerundet ergibt dies aber eben 14 und nicht 15 und damit dann 0.14.

        Wann dieser Fehler auftritt ist abhängig von verschiedenen Faktoren und betrifft übrigens nicht alle Dezimalzahlen mit der beschriebenen Endung. So beeinflußt sogar die Reihenfolge der Rechenoperationen das Ergebnis.

        So führt die Aufgabe Zahl / (1 / 100) durchschnittlich gesehen zu einem schlechteren Ergebnis als Zahl * 100.

        Bei unkritischen Zahlenausgaben spielt der Rundungsfehler meist keine Rolle. In einem Shop-System aber schon.

        Um die Sache zu vervollständigen, ich kann jedem nur raten auf die Verwendung der Methode toFixed zu verzichten. Meine Tests haben ergeben, dass beim Runden auf 2 Stellen nach dem Komma je nach Browser was sehr verschiedenes rauskommt.

        IE:
        rundet alle negativen Zahlen deren Rundungsstelle auf 5 endet, ab statt auf, was tatsächlich jedoch ein Fehler in der Spezifikation ist
        ausserdem werden die Zahlen 0.005, 0.006 ... 0.009 ab statt aufgerundet.

        Mozilla:
        rundet - entgegen der Spezifikation die negativen Zahlen richtig, jedoch wurde ein so schlechter Algorithmus gewählt, dass bei 1000 Durchläufen (von 0.000, 0.001 ... 0.999) ganze 48 Rundungsfehler auftraten. Diese Rundungsfehler wiederholen sich auch bei größeren Zahlen.

        Opera: wie Mozilla, aber statt 48 Rundungsfehler treten sogar 50 Rundungsfehler auf.

        Insgesamt ist das eine verteufelte Sache mit dem Rundungsfehler.

        Viele Grüße

        Antje

        1. :-) hm, wer Lust hat, kann ja mal meine Rundungsfunktion testen bzw. daran seine eigene Rundungsfunktion.

          Ich hoffe zwar, dass meine Lösungsvariante im Bereich bis 10 Stellen nach dem Komma sicher ist, aber so genau weiß dass ja keiner, wenn man nicht alle wirklich durchgeschaut hat.
          Ansonsten, zur Bestimmung der Fehlerquote in der Schleife, verwende ich zur Berechnung des Zählers toFixed(3). Das funktioniert ganz gut und ist in Mozilla, Opera und IE getestet. Zum Testen wird also ein Browser benötigt, der toFixed kann.

          Über ein Feedback würde ich mich schon freuen.

          Viele Grüße

          Antje

          --- Runden ---

          <html>
          <head>
          <title>Test - Ausgabe von toFixed</title>
          <meta name="author" content="Antje Hofmann">
          </head>
          <body>
           <pre><script type="text/javascript">
          <!--
          function strRepeat(n) {  //Rückgabewert: String
                if (isNaN(n)) return this;
                var repeatString = "";
                for (var i=0;i<n;i++) repeatString += this;
                return repeatString;
            }
          String.prototype.strRepeat=strRepeat;

          function replaceFixed(decimalPart) {  //Rückgabewert: String

          var myNumber = Math.abs(this).toString();

          if (myNumber.indexOf("e") >-1) return myNumber;

          decimalPart = parseInt(decimalPart);
            if (isNaN(decimalPart)) decimalPart = 0;

          if (decimalPart > 14) decimalPart = 14;
            if (decimalPart < -20) decimalPart = -20;

          var myIndex = myNumber.indexOf(".");

          var signed = 1;
            if (this < 0) signed = -1;

          if (decimalPart > 0 ) {

          if (myIndex == -1)  myNumber+=".";
              myNumber += ("0").strRepeat(decimalPart)

          myIndex = myNumber.indexOf(".");

          var myNumberArr = new Array();
              myNumberArr[0] = parseInt(myNumber.substr(0,myIndex));
              myNumberArr[1] = String(Math.abs(Math.round(signed*Number(("11" + myNumber.substr(myIndex+1,decimalPart)+"."+myNumber.substr(myIndex+1+decimalPart,1))))));

          if (myNumberArr[1].charAt(1)==2) myNumberArr[0]++;
              else if (myNumberArr[1].charAt(1)==0) myNumberArr[0]--;
              myNumberArr[1] = myNumberArr[1].substr(2,decimalPart);
              myNumber = myNumberArr.join(".");

          } else
               if (decimalPart <= 0) {
                 if (myIndex==-1) myIndex = myNumber.length;
                 if (myNumber.substr(0,myIndex + decimalPart+1) == "") return "0";
                 myNumber = myNumber.substr(0,myIndex + decimalPart) +"."+ myNumber.substr(myIndex + decimalPart,-decimalPart);

          myNumber = String(parseInt(String(Math.abs(Math.round(Number(myNumber)*signed)))+("0").strRepeat(-decimalPart),10));
               } else {
                   return String(Math.round(this));
               }

          if (this<0) return "-"+myNumber;
            else return myNumber;
          }

          Number.prototype.replaceFixed=replaceFixed;

          errors=0; counter=0;
          for (i=0;i<2;i=Number((i+0.001).toFixed(3)))  {
           counter++;
           if (i.toFixed(2) != i.replaceFixed(2)) {
            FixedError ='<span style="color:red;font-weight:bold">';
            errors++;
            }
           else FixedError ='<span>';

          document.writeln(FixedError,i.toFixed(3),": toFixed: ",i.toFixed(2)," -- replaceFixed: ",i.replaceFixed(2),"</span>") }
           document.writeln("Anzahl der Durchläufe: ",counter,"\nrelative Fehlerhäufigkeit: ", errors / counter * 100 +" % \nabsolute Fehlerhäufigkeit ",  errors )

          //-->
          </script></pre>
          </body>
          </html>

  3. gruss Robert,

    ich möchte einen Preis einigermaßen kaufmännisch und
    augenfreundlich formatieren.
    ...
    ...
    Wüßte jemand eine Erweiterung für o.g. Funktion, die
    auch bei noch größeren Zahlen, wie zB 1.234.567,89,
    funktioniert?

    die methoden

    Number.fixedDigits bzw.
       String.fixedDigits

    liefern Dir das gewuenschte ergebnis;

    beschrieben wird das ganze unter
       http://www.pseliger.de/jsExtendedApi/_reference_jsApi_trimConvertFormat.html;

    beispiele dazu finden sich unter
       http://www.pseliger.de/jsExtendedApi/_examples_jsApi_trimConvertFormat.html;

    runterladen muss man sich dazu nur
       http://www.pseliger.de/jsExtendedApi/jsApi.NumberString.flexibleConverting.js

    viel erfolg - by(t)e by(t)e - peterS. - pseliger@gmx.net

    --
    sh:| fo:) ch:? rl:| br:& n3:} n4:# ie:| mo:{ va:| de:[ zu:] fl:) ss:) ls:& js:)