note 92920 deleted from function.bcscale by danbrown
| From: | danbrown@php.net | Date: | Fri, 14 Aug 2009 19:43:09 +0000 |
| Subject: | note 92920 deleted from function.bcscale by danbrown | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-159491@lists.php.net to get a copy of this message | ||
Note Submitter: francois dot barbier at gmail dot com
----
The function provided by "mwgamera at gmail dot com"
(http://www.php.net/function.bcscale#79628) 2 comments below doesn't work well with negative
numbers. Example:
<?php
bcscale(3);
var_dump(round(-1, 2)); // float(-1)
var_dump(bcround('-1', 2)); // string(5) "-0.99" => incorrect
$a = bcdiv('-1', '3');
var_dump(round($a, 2)); // float(-0.33)
var_dump(bcround($a, 2)); // string(5) "-0.32" => incorrect
$a = bcdiv('-2', '3');
var_dump(round($a, 2)); // float(-0.67)
var_dump(bcround($a, 2)); // string(5) "-0.66" => incorrect
?>
Here is a modified version that works correctly:
<?php
/**
* Round an arbitrary precision number
*
* @param string $sNumber The value to round.
* @param int $iPrecision The optional number of decimal digits to round
* to, defaults to 0.
* @return string The rounded value.
*/
function bcround($sNumber,
$iPrecision = 0)
{
$iPrecision = (int) $iPrecision;
$sZeros = str_repeat('0', abs($iPrecision));
if (0 > $iPrecision)
{
return bcmul(bcround(bcdiv($sNumber, '1'.$sZeros, 1)), '1'.$sZeros, 0);
}
else
{
$sSign = '';
if ('-' === substr($sNumber, 0, 1))
{
$sSign = '-';
}
return bcadd($sNumber, $sSign.'0.'.$sZeros.'5', $iPrecision);
}
}
?>
Example:
<?php
bcscale(3);
var_dump(round(-1, 2)); // float(-1)
var_dump(bcround('-1', 2)); // string(5) "-1.00" => correct
$a = bcdiv('-1', '3');
var_dump(round($a, 2)); // float(-0.33)
var_dump(bcround($a, 2)); // string(5) "-0.33" => correct
$b = bcdiv('-2', '3');
var_dump(round($b, 2)); // float(-0.67)
var_dump(bcround($b, 2)); // string(5) "-0.67" => correct
?>
Like the round() function, it also accepts negative precision:
<?php
$a = '123456';
var_dump(round($a, -2)); // float(123500);
var_dump(bcround($a, -2)); // string(6) "123500";
$a = '-123456';
var_dump(round($a, -2)); // float(-123500);
var_dump(bcround($a, -2)); // string(6) "-123500";
?>
Bonus: below is a function that does what "Nitrogen"
(http://www.php.net/function.bcscale#88463) did 1 comment below:
<?php
/**
* Strip trailing zeros of an arbitrary precision number
*
* @param string $sNumber The value to trim.
* @param string The modified value.
*/
function bctrim($sNumber)
{
$iPosition = strpos($sNumber, '.');
if (FALSE === $iPosition)
{
return $sNumber;
}
else
{
return substr($sNumber, 0, $iPosition).
rtrim(substr($sNumber, $iPosition), '.0');
}
}
?>
Example:
<?php
var_dump(bctrim('1000')); // string() "1000"
var_dump(bctrim('1000.0000')); // string() "1000"
var_dump(bctrim('1000.1000')); // string() "1000.1"
var_dump(bctrim('1000.0001')); // string() "1000.0001"
?>