647 Stimmen

Formattieren einer Zahl mit genau zwei Dezimalstellen in JavaScript

Ich habe diese Codezeile, die meine Zahlen auf zwei Dezimalstellen rundet. Aber ich bekomme Zahlen wie diese: 10.8, 2.4, usw. Das entspricht nicht meiner Vorstellung von zwei Dezimalstellen, also wie kann ich das folgende verbessern?

Math.round(preis*Math.pow(10,2))/Math.pow(10,2);

Ich möchte Zahlen wie 10.80, 2.40, usw. Die Verwendung von jQuery ist für mich in Ordnung.

1 Stimmen

Dein Code ist genau das, wonach ich gesucht habe (um die Gleitkommagenauigkeit auf 7 Dezimalstellen für kleinere JSON-Dateien zu reduzieren). Das Überspringen von Math.pow für die Geschwindigkeit val = Math.round(val * 10000000) / 10000000);

0 Stimmen

Da die aktuell akzeptierte Antwort aufgrund der sich verschlimmernden Ungenauigkeiten immanenten in den Zahlen (0.565, 0.575, 1.005) möglicherweise ein falsches Ergebnis für einen breiten Wertebereich liefert, würde ich vorschlagen, noch einmal einen Blick auf diese Antwort zu werfen, die sie korrekt berechnet.

0 Stimmen

Vielleicht möchten Sie eine sprintf-Bibliothek für JavaScript einfügen stackoverflow.com/questions/610406/…

114voto

astorije Punkte 2586

Dies ist ein altes Thema, aber immer noch hochrangige Google-Ergebnisse und die angebotenen Lösungen teilen dasselbe Problem mit Dezimalzahlen. Hier ist die (sehr generische) Funktion, die ich verwende, Dank MDN:

function round(value, exp) {
  if (typeof exp === 'undefined' || +exp === 0)
    return Math.round(value);

  value = +value;
  exp = +exp;

  if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
    return NaN;

  // Shift
  value = value.toString().split('e');
  value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));

  // Shift back
  value = value.toString().split('e');
  return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}

Wie man sehen kann, haben wir diese Probleme nicht:

round(1.275, 2);   // Gibt 1.28 zurück
round(1.27499, 2); // Gibt 1.27 zurück

Diese Generizität bietet auch einige coole Sachen:

round(1234.5678, -2);   // Gibt 1200 zurück
round(1.2345678e+2, 2); // Gibt 123.46 zurück
round("123.45");        // Gibt 123 zurück

Um die Frage des OP zu beantworten, muss man Folgendes eingeben:

round(10.8034, 2).toFixed(2); // Gibt "10.80" zurück
round(10.8, 2).toFixed(2);    // Gibt "10.80" zurück

Oder für eine präzisere, weniger generische Funktion:

function round2Fixed(value) {
  value = +value;

  if (isNaN(value))
    return NaN;

  // Shift
  value = value.toString().split('e');
  value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + 2) : 2)));

  // Shift back
  value = value.toString().split('e');
  return (+(value[0] + 'e' + (value[1] ? (+value[1] - 2) : -2))).toFixed(2);
}

Sie können es aufrufen mit:

round2Fixed(10.8034); // Gibt "10.80" zurück
round2Fixed(10.8);    // Gibt "10.80" zurück

Verschiedene Beispiele und Tests (Dank an @t-j-crowder!):

function round(value, exp) {
  if (typeof exp === 'undefined' || +exp === 0)
    return Math.round(value);

  value = +value;
  exp = +exp;

  if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
    return NaN;

  // Shift
  value = value.toString().split('e');
  value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));

  // Shift back
  value = value.toString().split('e');
  return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}
function naive(value, exp) {
  if (!exp) {
    return Math.round(value);
  }
  var pow = Math.pow(10, exp);
  return Math.round(value * pow) / pow;
}
function test(val, places) {
  subtest(val, places);
  val = typeof val === "string" ? "-" + val : -val;
  subtest(val, places);
}
function subtest(val, places) {
  var placesOrZero = places || 0;
  var naiveResult = naive(val, places);
  var roundResult = round(val, places);
  if (placesOrZero >= 0) {
    naiveResult = naiveResult.toFixed(placesOrZero);
    roundResult = roundResult.toFixed(placesOrZero);
  } else {
    naiveResult = naiveResult.toString();
    roundResult = roundResult.toString();
  }
  $("")
    .append($("").text(JSON.stringify(val)))
    .append($("").text(placesOrZero))
    .append($("").text(naiveResult))
    .append($("").text(roundResult))
    .appendTo("#results");
}
test(0.565, 2);
test(0.575, 2);
test(0.585, 2);
test(1.275, 2);
test(1.27499, 2);
test(1234.5678, -2);
test(1.2345678e+2, 2);
test("123.45");
test(10.8034, 2);
test(10.8, 2);
test(1.005, 2);
test(1.0005, 2);

table {
  border-collapse: collapse;
}
table, td, th {
  border: 1px solid #ddd;
}
td, th {
  padding: 4px;
}
th {
  font-weight: normal;
  font-family: sans-serif;
}
td {
  font-family: monospace;
}

      Eingabe
      Stellen
      Naiv
      Gründlich

5 Stimmen

Wie gibt es keinen einfachen Weg, dies zu tun? Rettet ES6?

0 Stimmen

Vielen Dank für das Posten des MDN Polyfills. Auf der verlinkten MDN-Seite ist der Polyfill nicht mehr verfügbar. Ich frage mich, warum er entfernt wurde...

0 Stimmen

Wie kann ich es verwenden, um den Wert bis zur ersten Dezimalstelle zu erhalten, wie z.B. 3.0421 sollte 3.0 zurückgeben?

45voto

Miguel Punkte 2843

Normalerweise füge ich das meiner persönlichen Bibliothek hinzu und nach einigen Vorschlägen und der Verwendung der Lösung von @TIMINeutron und der Anpassung für die Dezimalstellenlänge, passt diese am besten:

function precise_round(num, decimals) {
   var t = Math.pow(10, decimals);   
   return (Math.round((num * t) + (decimals>0?1:0)*(Math.sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals);
}

wird für die gemeldeten Ausnahmen funktionieren.

3 Stimmen

Precise_round(1.275,2) ist 1.27?

0 Stimmen

Precise_round(6,2) gibt 6 zurück (keine Dezimalstellen wie in der Frage gefordert)

2 Stimmen

@Imre Ändern Sie den Rückgabewert in (Math.round(num*Math.pow(10,decimals))/Math.pow(10,decimals)‌​).toFixed(2); und Sie werden dieses Problem nicht mehr haben.

23voto

user15102407 Punkte 127

SCHNELL UND EINFACH

parseFloat(number.toFixed(2))

Beispiel

let number = 2.55435930

let roundedString = number.toFixed(2)    // "2.55"

let twoDecimalsNumber = parseFloat(roundedString)    // 2.55

let directly = parseFloat(number.toFixed(2))    // 2.55

2 Stimmen

Nachdem ich eine Weile gesucht hatte, hat es endlich bei mir funktioniert, einfach und leicht.

1 Stimmen

Ja, mit den oben erwähnten Einschränkungen bezüglich toFixed, die ungenaue Rundungsergebnisse für Dinge wie 1.005 zurückgeben können. Du SOLLTEST diese Einschränkungen in deiner Antwort erwähnen.

0 Stimmen

ParseFloat(13.99999).toFixed(2) > "14.00" parseFloat(parseFloat(13.99999).toFixed(2)) > 14

20voto

Gerard de Visser Punkte 6810

Ein Weg, um sicherzustellen, dass Sie eine Zahl mit 2 Dezimalstellen erhalten:

(Math.round(num*100)/100).toFixed(2)

Wenn dies zu Rundungsfehlern führt, können Sie das folgende verwenden, wie James es in seinem Kommentar erklärt hat:

(Math.round((num * 1000)/10)/100).toFixed(2)

7 Stimmen

Dies ist der beste und einfachste Weg, um es zu tun. Aufgrund von Fließkommapräzision ergibt 1,275 * 100 = 127,49999999999999, was zu geringfügigen Fehlern beim Runden führen könnte. Um dies zu beheben, können wir mit 1000 multiplizieren und durch 10 teilen, da (1,275 * 1000)/10 = 127,5. Wie folgt: var answer = (Math.round((num * 1000)/10)/100).toFixed(2);

0 Stimmen

(Math.round((1.015 * 1000)/10)/100).toFixed(2) gibt immer noch 1.01; sollte es nicht 1.02 sein?

0 Stimmen

(Math.round((99999999999999.9999 * 1000)/10)/100).toFixed(4) gibt "100000000000000.0000" zurück

18voto

tfrascaroli Punkte 1108

Ich weiß nicht, warum ich keinen Kommentar zu einer vorherigen Antwort hinzufügen kann (vielleicht bin ich hoffnungslos blind, ich weiß es nicht), aber ich bin mit einer Lösung auf Grundlage der Antwort von @Miguel gekommen:

function precise_round(num,decimals) {
   return Math.round(num*Math.pow(10, decimals)) / Math.pow(10, decimals);
}

Und seine beiden Kommentare (von @bighostkim und @Imre):

  • Problem mit precise_round(1.275,2), das nicht 1,28 zurückgibt
  • Problem mit precise_round(6,2), das nicht 6,00 zurückgibt (wie er wollte).

Meine endgültige Lösung lautet wie folgt:

function precise_round(num,decimals) {
    var sign = num >= 0 ? 1 : -1;
    return (Math.round((num*Math.pow(10,decimals)) + (sign*0.001)) / Math.pow(10,decimals)).toFixed(decimals);
}

Wie Sie sehen können, musste ich eine kleine "Korrektur" hinzufügen (es ist nicht das, was es ist, aber da Math.round verlustbehaftet ist - Sie können es auf jsfiddle.net überprüfen - dies ist der einzige Weg, den ich kannte, um es zu "beheben"). Es fügt 0,001 zur bereits gepaddeten Zahl hinzu, sodass eine 1 drei 0 an den Nachkommastellen hinzugefügt werden. Es sollte also sicher sein, es zu verwenden.

Danach habe ich .toFixed(dezimal) hinzugefügt, um die Zahl immer im korrekten Format auszugeben (mit der richtigen Anzahl von Dezimalstellen).

Das ist im Grunde genommen alles. Verwenden Sie es gut ;)

EDIT: Funktionalität zur "Korrektur" von negativen Zahlen hinzugefügt.

2 Stimmen

Die "Korrektur" ist meistens sicher, aber z.B. precise_round(1.27499,2) gibt jetzt auch 1.28 zurück... Es ist nicht Math.round, das Verluste verursacht; sondern die Art und Weise, wie Computer Fließkommazahlen intern speichern. Im Grunde genommen sind einige Werte zum Scheitern verurteilt, bevor die Daten überhaupt Ihre Funktion erreichen :)

0 Stimmen

@Imre, du hast absolut recht. Deshalb erkläre ich, was diese 0,001 dort macht, falls jemand es "genauer genau" machen möchte oder sogar löschen (wenn Sie zufällig einen Supercomputer mit 2 Mbytes pro Float haben, was ich nicht glaube, dass hier jemand hat ;)

1 Stimmen

Eigentlich ist die Sprachspezifikation ziemlich spezifisch darin, 64 Bits für Zahlenwerte zu verwenden, daher würde es nichts ändern, ob man einen Supercomputer hat/benutzt :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X