When a float number needs to be truncated to a certain digit after the floating point, it turns out that it is not easy to be done. For example if the truncating has to be done to second digit after the point, the numbers should be
45.8976 => 45.89, 0.0185 => 0.01
( second digit after the point is not rounded according to the third digit after the point ).
Functions like round()
, number_format()
, sprintf()
round the number and print out
45.8976 => 45.90, 0.0185 => 0.02
I have met two solutions and I am wondering if they are good enough and which one is better to be used
1.
function truncNumber( $number, $prec = 2 )
{
return bccomp( $number, 0, 10 ) == 0 ? $number : round( $number - pow( 0.1, bcadd( $prec, 1 ) ) * 5, $prec );
}
2.
function truncNumber($number, $prec = 2 )
{
return sprintf( "%.".$prec."f", floor( $number*pow( 10, $prec ) )/pow( 10, $prec ) );
}
floor
will do as you ask.
floor(45.8976 * 100) / 100;
You won't find a more direct function for this, since it's a kind of odd thing to ask. Normally you'll round mathematically correct. Out of curiosity - What do you need this for?
this is my solution:
/**
* @example truncate(-1.49999, 2); // returns -1.49
* @example truncate(.49999, 3); // returns 0.499
* @param float $val
* @param int f
* @return float
*/
function truncate($val, $f="0")
{
if(($p = strpos($val, '.')) !== false) {
$val = floatval(substr($val, 0, $p + 1 + $f));
}
return $val;
}
function truncate($value)
{
if ($value < 0)
{
return ceil((string)($value * 100)) / 100;
}
else
{
return floor((string)($value * 100)) / 100;
}
}
Why does PHP not handle mathamatic formulas the way we would expect, e.g. floor(10.04 * 100) = 1003
when we all know it should be 1004
.
This issue is not just in PHP but can be found in all langauges, depending on the relative error in the langauge used.
PHP uses IEEE 754 double precision format which has a relative error of about 1.11e-16. (resource)
The real issue is that the floor function casts the float value into an int value, e.g. (int)(10.04 * 100) = 1003
as we see in the floor function earlier. (resource)
So to overcome this issue we can cast the float to a string, a string can represent any value accurately, then the floor function will cast the string to an int accurately.
To truncate numbers the "best" is to use (I took a number here that works for my example):
$number = 120,321314;
$truncate_number = number_format($number , 1); // 120,3
$truncate_number = number_format($number , 2); // 120,32
$truncate_number = number_format($number , 3); // 120,321
Hope this help is easy than other answers here, but it is easy only for the cases it works for. Here is a case it does not work for (demo):
$number = 10.046;
echo number_format($number , 2); // 10.05
The number_format function is tricky, you can solve your problem this way (from php.net):
To prevent the rounding that occurs when next digit after last significant decimal is 5 (mentioned by several people below):
<?php
function fnumber_format($number, $decimals='', $sep1='', $sep2='') {
if (($number * pow(10 , $decimals + 1) % 10 ) == 5)
$number -= pow(10 , -($decimals+1));
return number_format($number, $decimals, $sep1, $sep2);
}
$t=7.15;
echo $t . " | " . number_format($t, 1, '.', ',') . " | " . fnumber_format($t, 1, '.', ',') . "\n\n";
//result is: 7.15 | 7.2 | 7.1
$t=7.3215;
echo $t . " | " . number_format($t, 3, '.', ',') . " | " . fnumber_format($t, 3, '.', ',') . "\n\n";
//result is: 7.3215 | 7.322 | 7.321
} ?>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With