Christian Seiler: Float-Zahl kürzen (74,34324148823 ==> 74,34)

Beitrag lesen

Hallo,

ich muss cm ins inch umwandeln (kein problem), aber es entsteht ein Problem dabei, die Inch-Zahl ist ca. 10 Stellig nach dem Komma. Ich braucher aber 2 Stellen vor, und 2 Stellen nach dem Komma.
Wie kürze ich diese Zahl, mit Verbindung von JavaScript. Die cm-Zahl ist dynamisch, bewegt sich zwischen 160cm und 190cm.

Wenn Dir kleinere Probleme beim Runden egal sind (es gibt bei Float-Zahlen prinzipiell einige Dinge, die anders reagieren, als bei Dezimalzahlen - und das irgendwie "hinzubiegen" ist alles andere als trivial), dann kannst Du das Math-Objekt um eine Funktion erweitern:

Math.roundToPlaces = function (number, places) {  
 var p = Math.pow(10, places);  
 var f = number * p;  
 if (f >= 0.0) {  
  f  = Math.floor(f + 0.5);  
 } else {  
  f = Math.ceil(f - 0.5);  
 }  
 f = f / p;  
 if (isFinite(f)) {  
  return f;  
 } else {  
  return number;  
 }  
};

Das rundet Dir arithmetisch, d.h. 0.5 immer zur nächsthöheren Zahl. Du kannst aber z.B. auch Banker's Rounding verwenden, dann nutze Math.round():

Math.roundToPlaces = function (number, places) {  
 var p = Math.pow(10, places);  
 var f = number * p;  
 f = Math.round(f);  
 f = f / p;  
 if (isFinite(f)) {  
  return f;  
 } else {  
  return number;  
 }  
};

Auf Grund der oben erwähnten Probleme funktioniert das aber nicht immer genau so, wie erwartet:

Math.roundToPlaces(1.255, 2)   -> gibt 1.25 obwohl man mit *beiden*
                                  Verfahren

Ich habe mich vor einiger Zeit mal mit dem Thema "Runden" intensiver auseinandergesetzt und ein RFC geschrieben, wie PHPs round()-Funktion verbessert werden kann (die bisherige Implementierung entspricht meiner obigen). Mein Vorschlag ist hier zu sehen: http://wiki.php.net/rfc/rounding, dort auch mit allen möglichen teils komplizierten Erklärungen.

Ich habe den Algorithmus mal nach Javascript portiert (ist nicht besonders effizient, funktioniert aber):

(function () {  
 Math.ROUND_MODE_HALF_UP = 1;  
 Math.ROUND_MODE_HALF_DOWN = 2;  
 Math.ROUND_MODE_HALF_EVEN = 3;  
 Math.ROUND_MODE_HALF_ODD = 4;  
  
 var roundHelper = function (value, mode) {  
  var tmp_value;  
  if (value >= 0.0) {  
   tmp_value = Math.floor(value + 0.5);  
   if ((mode == Math.ROUND_MODE_HALF_DOWN && value == (-0.5 + tmp_value)) ||  
    (mode == Math.ROUND_MODE_HALF_EVEN && value == (0.5 + 2 * Math.floor(tmp_value/2.0))) ||  
    (mode == Math.ROUND_MODE_HALF_ODD && value == (0.5 + 2 * Math.floor(tmp_value/2.0) - 1.0)))  
   {  
    tmp_value -= 1.0;  
   }  
  } else {  
   tmp_value = Math.ceil(value - 0.5);  
   if ((mode == Math.ROUND_MODE_HALF_DOWN && value == (0.5 + tmp_value)) ||  
    (mode == Math.ROUND_MODE_HALF_EVEN && value == (-0.5 + 2 * Math.ceil(tmp_value/2.0))) ||  
    (mode == Math.ROUND_MODE_HALF_ODD && value == (-0.5 + 2 * Math.ceil(tmp_value/2.0) + 1.0)))  
   {  
    tmp_value += 1.0;  
   }  
  }  
  return tmp_value;  
 };  
  
 Math.roundToPlaces = function (value, places, mode) {  
  if (typeof(places) == 'undefined') places = 0;  
  if (typeof(mode) == 'undefined') mode = Math.ROUND_MODE_HALF_UP;  
  
  var f1, f2;  
  var precision_places = 14 - Math.floor(Math.log(Math.abs(value))/Math.LN10);  
  
  f1 = Math.pow(10.0, Math.abs(places));  
  
  if (precision_places > places && precision_places - places < 15) {  
   f2 = Math.pow(10.0, Math.abs(precision_places));  
   if (precision_places >= 0) {  
    tmp_value = value * f2;  
   } else {  
    tmp_value = value / f2;  
   }  
   tmp_value = roundHelper(tmp_value, mode);  
   f2 = Math.pow(10.0, Math.abs(places - precision_places));  
   // places < precision_places  
   tmp_value = tmp_value / f2;  
  } else {  
   if (places >= 0) {  
    tmp_value = value * f1;  
   } else {  
    tmp_value = value / f1;  
   }  
   // rounding not necessary  
   if (Math.abs(tmp_value) >= 1e15) {  
    return value;  
   }  
  }  
  
  tmp_value = roundHelper(tmp_value, mode);  
  
  if (Math.abs(places) < 23) {  
   if (places > 0) {  
    tmp_value = tmp_value / f1;  
   } else {  
    tmp_value = tmp_value * f1;  
   }  
  } else {  
   var str = "" + tmp_value + "e" + (-places);  
   tmp_value = parseFloat(str);  
   if (!isFinite(tmp_value)) {  
    tmp_value = value;  
   }  
  }  
  
  return tmp_value;  
 };  
})();

Damit solltest Du wie Du es erwartest runden können, d.h. Math.roundToPlaces(1.255, 2) gibt wirklich 1.26 und nicht 1.25 etc.

Viele Grüße,
Christian