round - redondear cantidad php
¿Cómo ceil, piso y números redondos? (4)
Necesito imitar la funcionalidad exacta de las funciones ceil() , floor() y round() en los números bcmath . Ya encontré una pregunta muy similar, pero desafortunadamente la respuesta proporcionada no es lo suficientemente buena para mí, ya que carece de soporte. para los números negativos y el argumento de precisión para la función round () falta .
Me preguntaba si alguien puede encontrar una solución bastante corta y elegante para este problema.
Todas las aportaciones son apreciadas, gracias!
Aquí hay algunos que admiten números negativos y argumentos de precisión para el redondeo.
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;
}
Después de una noche perdida tratando de resolver este problema, creo que he encontrado una solución bastante simple, aquí está:
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;
}
Creo que no me perdí nada, si alguien puede detectar algún error, por favor, hágamelo saber. Aquí hay algunas pruebas:
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
function bcnegative($n)
{
return strpos($n, ''-'') === 0; // Is the number less than 0?
}
function bcceil($n)
{
return bcnegative($n) ? ''-'' . bcfloor(substr($n, 1))
: bcadd(strtok($n, ''.''), strtok(''.'') != 0);
}
function bcfloor($n)
{
return bcnegative($n) ? ''-'' . bcceil(substr($n, 1)) : strtok($n, ''.'');
}
function bcround($n, $p = 0)
{
$e = bcpow(10, $p + 1);
return bcdiv(bcadd(bcmul($n, $e, 0), bcnegative($n) ? -5 : 5), $e, $p);
}
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));