832 Stimmen

Wie geht man mit der Genauigkeit von Fließkommazahlen in JavaScript um?

Ich habe das folgende Dummy-Testskript:

function test() {
  var x = 0.1 * 0.2;
  document.write(x);
}
test();

So wird das Ergebnis gedruckt 0.020000000000000004 während es einfach drucken sollte 0.02 (wenn Sie Ihren Taschenrechner benutzen). Soweit ich verstanden habe, ist dies auf Fehler in der Genauigkeit der Fließkommamultiplikation zurückzuführen.

Hat jemand eine gute Lösung, damit ich in einem solchen Fall das richtige Ergebnis erhalte? 0.02 ? Ich weiß, es gibt Funktionen wie toFixed oder Rundung wäre eine weitere Möglichkeit, aber ich möchte wirklich die ganze Zahl ohne Kürzung und Rundung gedruckt haben. Ich wollte nur wissen, ob jemand von Ihnen eine schöne, elegante Lösung hat.

Natürlich werde ich sonst auf 10 Stellen oder so aufrunden.

157 Stimmen

Eigentlich liegt der Fehler daran, dass es keine Möglichkeit gibt, die 0.1 in eine endliche binäre Gleitkommazahl.

19 Stimmen

Die meisten Brüche lassen sich nicht mit exakter Genauigkeit in eine Dezimalzahl umwandeln. Eine gute Erklärung finden Sie hier: docs.python.org/release/2.5.1/tut/node16.html

8 Stimmen

2voto

willy wonka Punkte 1113

Die mangelnde Präzision bei der Programmierung von Fließkommazahlen

Die mangelnde Präzision bei der Programmierung von Fließkommazahlen ist ein bekanntes Problem in verschiedenen Programmiersprachen. Javascript ist eine von denen, die Probleme mit Fließkommazahlen haben. Dieses Problem ist im Wesentlichen auf die binäre Darstellung von Fließkommazahlen im Speicher zurückzuführen, die von diesen Programmiersprachen verwendet wird.

Hoffen wir, dass Programmiersprachen und Compiler und Hardwareentwickler und -ingenieure sich mit solchen Problemen befassen und sie ein für allemal zumindest bis zur 1024er Fließkommastelle lösen werden... wahrscheinlich wird das ausreichen, um 99,999% aller anderen Entwickler für das nächste Jahrhundert der Programmierung zu beruhigen...

Eine mögliche Lösung: in Ganzzahl umwandeln, berechnen, dann zurück

Eine mögliche Lösung könnte darin bestehen, die Fließkommazahlen in Ganzzahlen umzuwandeln, die Berechnungen durchzuführen und das Ergebnis dann wieder in eine Fließkommazahl umzuwandeln. Das scheint in den meisten Fällen zu funktionieren. Im Prinzip:

function test()
{
  var x = 0.1 * 0.2; // Original approach
  var y = ((0.1*10) * (0.2*10))/100; // The working possible solution
  document.write(x + '<br>' + y);
}
test();

Natürlich kann die Funktion im Bedarfsfall entsprechend angepasst werden, zum Beispiel:

function test()
  {
    var x = 0.12 * 0.23; // Original approach
    var y = ((0.12*100) * (0.23*100))/10000; // The working possible solution
    document.write(x + '<br>' + y);
  }
test();

Sie kann auch automatisiert werden:

function myToInt(v)
{
  let i = 1;
  let r;
  while(r % 1 != 0)
  {
    i = i * 10;
    r = v * i;
  }
  return [r, i];
}

function test()
{
  let x = 0.11111111;
  let y = 0.22222222;
  let a = x * y; // Original approach

  [x, i] = myToInt(x);
  [y, j] = myToInt(y);
  let d = i * j;

  let b = x * y / d; // Another working possible solution
  console.log(a + '\n' + b)  
  document.write(a + '<br>' + b);
}
test();

In diesem Sinne können wir zum Beispiel Folgendes tun:

function myToInt(v)
{
  let i = 1;
  let r;
  while(r % 1 != 0)
  {
    i = i * 10;
    r = v * i;
  }
  return [r, i];
}

function test()
{
  let x = 14898
  let y = 10.8
  let z = 100
  let a = x * y / z ; // Original approach

  [y, i] = myToInt(y);
  let b = (x * y) / (z * i); // Another working possible solution
  console.log(a + '\n' + b)  
  document.write(a + '<br>' + b);
}
test();

2voto

Robert L Punkte 1965

Versuchen Sie meine chiliadische Arithmetik-Bibliothek, die Sie hier sehen können aquí . Wenn Sie eine neuere Version wünschen, kann ich Ihnen eine besorgen.

1voto

Jeeva Punkte 1621

Ich bin nicht so gut im Programmieren, aber ich war wirklich an diesem Thema interessiert, also habe ich versucht zu verstehen, wie man das lösen kann, ohne irgendwelche Bibliotheken oder Skripte zu benutzen

Ich habe dies auf einem Notizblock geschrieben

var toAlgebraic = function(f1, f2) {
    let f1_base = Math.pow(10, f1.split('.')[1].length);
    let f2_base = Math.pow(10, f2.split('.')[1].length);
    f1 = parseInt(f1.replace('.', ''));
    f2 = parseInt(f2.replace('.', ''));

    let dif, base;
    if (f1_base > f2_base) {
        dif = f1_base / f2_base;
        base = f1_base;
        f2 = f2 * dif;
    } else {
        dif = f2_base / f1_base;
        base = f2_base;
        f1 = f1 * dif;
    }

    return (f1 * f2) / base;
};

console.log(0.1 * 0.2);
console.log(toAlgebraic("0.1", "0.2"));

Sie müssen diesen Code vielleicht überarbeiten, denn ich bin nicht gut im Programmieren :)

1voto

Bei der Addition von zwei Float-Wert seine nie geben die genauen Werte, so dass wir brauchen, um diese auf bestimmte Zahl, die uns helfen, zu vergleichen behoben wird.

console.log((parseFloat(0.1) + parseFloat(0.2)).toFixed(1) == parseFloat(0.3).toFixed(1));

1voto

Júlio Paulillo Punkte 596

Ausgabe über die folgende Funktion:

var toFixedCurrency = function(num){
    var num = (num).toString();
    var one = new RegExp(/\.\d{1}$/).test(num);
    var two = new RegExp(/\.\d{2,}/).test(num);
    var result = null;

    if(one){ result = num.replace(/\.(\d{1})$/, '.$10');
    } else if(two){ result = num.replace(/\.(\d{2})\d*/, '.$1');
    } else { result = num*100; }

    return result;
}

function test(){
    var x = 0.1 * 0.2;
    document.write(toFixedCurrency(x));
}

test();

Achten Sie auf die Ausgabe toFixedCurrency(x) .

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