2009-10-29 4 views
17

ich müssen imitieren die genaue Funktionalität der ceil(), floor() und round() Funktionen auf bcmath Zahlen, I've already found a very similar question aber leider the answer provided isn't good enough for me da es Unterstützung für negative Zahlen fehlt und die Präzision Argument für die Funktion round() fehlt .Wie ccm, floor und round bcmath zahlen?

Ich frage mich, ob jemand eine ziemlich kurze und elegante Lösung für dieses Problem finden kann.

Alle Eingabe ist dankbar, danke!

Antwort

23

Nach einer Nacht verloren versucht, dieses Problem, das ich habe ich eine ziemlich einfache Lösung gefunden glauben zu lösen, hier ist es:

function bcceil($number) 
{ 
    if (strpos($number, '.') !== false) { 
     if (preg_match("~\.[0]+$~", $number)) return bcround($number, 0); 
     if ($number[0] != '-') return bcadd($number, 1, 0); 
     return bcsub($number, 0, 0); 
    } 
    return $number; 
} 

function bcfloor($number) 
{ 
    if (strpos($number, '.') !== false) { 
     if (preg_match("~\.[0]+$~", $number)) return bcround($number, 0); 
     if ($number[0] != '-') return bcadd($number, 0, 0); 
     return bcsub($number, 1, 0); 
    } 
    return $number; 
} 

function bcround($number, $precision = 0) 
{ 
    if (strpos($number, '.') !== false) { 
     if ($number[0] != '-') return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision); 
     return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision); 
    } 
    return $number; 
} 

Ich glaube, ich habe nichts verpassen, wenn jemand Finde irgendeinen Fehler, lass es mich wissen. Hier sind einige Tests:

assert(bcceil('4') == ceil('4')); // true 
assert(bcceil('4.3') == ceil('4.3')); // true 
assert(bcceil('9.999') == ceil('9.999')); // true 
assert(bcceil('-3.14') == ceil('-3.14')); // true 

assert(bcfloor('4') == floor('4')); // true 
assert(bcfloor('4.3') == floor('4.3')); // true 
assert(bcfloor('9.999') == floor('9.999')); // true 
assert(bcfloor('-3.14') == floor('-3.14')); // true 

assert(bcround('3', 0) == number_format('3', 0)); // true 
assert(bcround('3.4', 0) == number_format('3.4', 0)); // true 
assert(bcround('3.5', 0) == number_format('3.5', 0)); // true 
assert(bcround('3.6', 0) == number_format('3.6', 0)); // true 
assert(bcround('1.95583', 2) == number_format('1.95583', 2)); // true 
assert(bcround('5.045', 2) == number_format('5.045', 2)); // true 
assert(bcround('5.055', 2) == number_format('5.055', 2)); // true 
assert(bcround('9.999', 2) == number_format('9.999', 2)); // true 
+0

bcceil ('4') würde '3' anstelle von 4 zurückgeben, wie es sollte. Dasselbe Problem mit bcsub. Eine gute Idee, bcadd ($ number, 0, 0) zu verwenden, um die Dezimalzahlen abzuschneiden, habe ich selbst nicht gedacht. –

+0

Ich meinte würde 5, nicht 3. –

+0

@reko_t: Der Fehler auf bcceil() behoben, aber ich konnte den Fehler, den Sie in der bcfloor() - Funktion erwähnt reproduzieren. –

3

Hier sind diejenigen, die negative Zahlen und Präzisionsargument für das Runden unterstützen.

function bcceil($val) { 
    if (($pos = strpos($val, '.')) !== false) { 
     if ($val[$pos+1] != 0 && $val[0] != '-') 
      return bcadd(substr($val, 0, $pos), 1, 0); 
     else 
      return substr($val, 0, $pos); 
    } 
    return $val; 
} 

function bcfloor($val) { 
    if (($pos = strpos($val, '.')) !== false) { 
     if ($val[$pos+1] != 0 && $val[0] == '-') 
      return bcsub(substr($val, 0, $pos), 1, 0); 
     else 
      return substr($val, 0, $pos); 
    } 
    return $val; 
} 

function bcround($val, $precision = 0) { 
    if (($pos = strpos($val, '.')) !== false) { 
     if ($precision > 0) { 
      $int = substr($val, 0, $pos); 
      $pos2 = ++$pos+$precision; 
      if ($pos2 < strlen($val)) { 
       $val2 = sprintf('%s.%s', substr($val, $pos, $pos2-$pos), substr($val, $pos2)); 
       $val2 = $val2[0] >= 5 ? bcceil($val2) : bcfloor($val2); 
       if (strlen($val2) > $precision) 
        return bcadd($int, $val[0] == '-' ? -1 : 1, 0); 
       else 
        return sprintf('%s.%s', $int, rtrim($val2, '0')); 
      } 
      return $val; 
     } else { 
      if ($val[$pos+1] >= 5) 
       return ($val[0] == '-' ? bcfloor($val) : bcceil($val)); 
      else 
       return ($val[0] == '-' ? bcceil($val) : bcfloor($val)); 
     } 
    } 
    return $val; 
} 
+0

Ich habe es noch nicht getestet, aber ich glaube, bcround (99,999, 2) gibt fälschlicherweise 99,100, nicht wahr? –

+0

Nein: $ php -r 'include "bc.php"; var_dump (bcround (99,999, 2)); string (3) "100" –

+0

Der Teil "if (strlen ($ val2)> $ precision)" soll das verhindern. :) –

0
function getBcRound($number, $precision = 0) 
{ 
    $precision = ($precision < 0) 
       ? 0 
       : (int) $precision; 
    if (strcmp(bcadd($number, '0', $precision), bcadd($number, '0', $precision+1)) == 0) { 
     return bcadd($number, '0', $precision); 
    } 
    if (getBcPresion($number) - $precision > 1) { 
     $number = getBcRound($number, $precision + 1); 
    } 
    $t = '0.' . str_repeat('0', $precision) . '5'; 
    return $number < 0 
      ? bcsub($number, $t, $precision) 
      : bcadd($number, $t, $precision); 
} 

function getBcPresion($number) { 
    $dotPosition = strpos($number, '.'); 
    if ($dotPosition === false) { 
     return 0; 
    } 
    return strlen($number) - strpos($number, '.') - 1; 
} 

var_dump(getBcRound('3', 0) == number_format('3', 0)); 
var_dump(getBcRound('3.4', 0) == number_format('3.4', 0)); 
var_dump(getBcRound('3.56', 0) == number_format('3.6', 0)); 
var_dump(getBcRound('1.95583', 2) == number_format('1.95583', 2)); 
var_dump(getBcRound('5.045', 2) == number_format('5.045', 2)); 
var_dump(getBcRound('5.055', 2) == number_format('5.055', 2)); 
var_dump(getBcRound('9.999', 2) == number_format('9.999', 2)); 
var_dump(getBcRound('5.0445', 5) == number_format('5.044500', 5)); 
var_dump(getBcRound('5.0445', 4) == number_format('5.04450', 4)); 
var_dump(getBcRound('5.0445', 3) == number_format('5.0445', 3)); 
var_dump(getBcRound('5.0445', 2) == number_format('5.045', 2)); 
var_dump(getBcRound('5.0445', 1) == number_format('5.05', 1)); 
var_dump(getBcRound('5.0445', 0) == number_format('5.0', 0));// 
var_dump(getBcRound('5.04455', 2) == number_format('5.045', 2)); 
var_dump(getBcRound('99.999', 2) == number_format('100.000', 2)); 
var_dump(getBcRound('99.999') == number_format('99.999', 0)); 
var_dump(getBcRound('99.999', 'a') == number_format('99.999', 0)); 
var_dump(getBcRound('99.999', -1.5) == number_format('99.999', 0)); 
var_dump(getBcRound('-0.00001', 2) == number_format('-0.000', 2)); 
var_dump(getBcRound('-0.0000', 2) == number_format('0', 2)); 
var_dump(getBcRound('-4.44455', 2) == number_format('-4.445', 2)); 
var_dump(getBcRound('-4.44555', 0) == number_format('-4.5', 0)); 
var_dump(getBcRound('-4.444444444444444444444444444444444444444444445', 0) == number_format('-4.5', 0));