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

Beitrag lesen

Hallo nochmal,

Ich habe einen kleinen Fehler in meiner JS-Version entdeckt: tmp_value wird in der eigentliche Rundungsfunktion nicht als Variable deklariert, hier nochmal die korrigierte Fassung:

(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, tmp_value;  
  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;  
 };  
})();

Ich habe auf Ingos Wunsch das ganze auch nach PHP portiert:

define ('ROUND_MODE_HALF_UP', 1);  
define ('ROUND_MODE_HALF_DOWN', 2);  
define ('ROUND_MODE_HALF_EVEN', 3);  
define ('ROUND_MODE_HALF_ODD', 4);  
  
function _round_helper($value, $mode) {  
 if ($value >= 0.0) {  
  $tmp_value = floor($value + 0.5);  
  if (($mode == ROUND_MODE_HALF_DOWN && $value == (-0.5 + $tmp_value)) ||  
   ($mode == ROUND_MODE_HALF_EVEN && $value == (0.5 + 2 * floor($tmp_value / 2.0))) ||  
   ($mode == ROUND_MODE_HALF_ODD && $value == (0.5 + 2 * floor($tmp_value / 2.0) - 1.0)))  
  {  
   $tmp_value -= 1.0;  
  }  
 } else {  
  $tmp_value = ceil($value - 0.5);  
  if (($mode == ROUND_MODE_HALF_DOWN && $value == (0.5 + $tmp_value)) ||  
   ($mode == ROUND_MODE_HALF_EVEN && $value == (-0.5 + 2 * ceil($tmp_value / 2.0))) ||  
   ($mode == ROUND_MODE_HALF_ODD && $value == (-0.5 + 2 * ceil($tmp_value / 2.0) + 1.0)))  
  {  
   $tmp_value += 1.0;  
  }  
 }  
 return $tmp_value;  
}  
  
/**  
 * Round to a certain precision  
 *  
 * This method rounds to the nearest number of a certain precision in the  
 * specified rounding mode. Available modes are:  
 *  
 * ROUND_MODE_HALF_UP: Round .5 away from zero (arithmetic rounding)  
 * ROUND_MODE_HALF_DOWN: Round .5 away towards zero  
 * ROUND_MODE_HALF_EVEN: Round .5 to nearest even number (banker's rounding)  
 * ROUND_MODE_HALF_ODD: Round .5 to nearest odd number  
 *  
 * Please note that PHP does not have a platform-independent FP behaviour  
 * as of PHP 5.2. This will likely change in PHP 5.3. Until then, this method  
 * may still exhibit some strange results in very rare circumstances.  
 *  
 * This is a direct port of the C algorithm in  
 * <http://wiki.php.net/rfc/rounding>. Please note that this code is likely  
 * to be obsolete in PHP 5.3 as PHP's own round() function will likely share the  
 * same signature and implementation as this function.  
 *  
 * @param double $value The value to round  
 * @param int $places The number of places the result should have, may be  
 *                    negative for rounding to 10s or 100s etc.  
 * @param int $mode The rounding mode.  
 * @return double The rounded value  
 */  
function round_to_places($value, $places = 0, $mode = ROUND_MODE_HALF_UP) {  
 $places = (int)$places;  
 $value = (double)$value;  
  
 $precision_places = 14 - (int)floor(log10(abs($value)));  
 $f1 = pow(10.0, abs($places));  
  
 if ($precision_places > $places && $precision_places - $places < 15) {  
  $f2 = pow(10.0, abs($precision_places));  
  if ($precision_places >= 0) {  
   $tmp_value = $value * $f2;  
  } else {  
   $tmp_value = $value / $f2;  
  }  
  $tmp_value = _round_helper($tmp_value, $mode);  
  $f2 = pow(10.0, $precision_places - $places);  
  $tmp_value /= $f2;  
 } else {  
  if ($places >= 0) {  
   $tmp_value = $value * $f1;  
  } else {  
   $tmp_value = $value / $f1;  
  }  
  // rounding not necessary  
  if (abs($tmp_value) >= 1e15) {  
   return $value;  
  }  
 }  
  
 $tmp_value = _round_helper($tmp_value, $mode);  
  
 if (abs($places) < 23) {  
  if ($places > 0) {  
   $tmp_value = $tmp_value / $f1;  
  } else {  
   $tmp_value = $tmp_value * $f1;  
  }  
 } else {  
  $str = sprintf("%15fe%d", $tmp_value, -$places);  
  $tmp_value = (double)$str;  
  if (!is_finite($tmp_value) || is_nan($tmp_value)) {  
   return $value;  
  }  
 }  
  
 return $tmp_value;  
}

Viele Grüße,
Christian