Delete digits after two decimal points, without rounding the value
Solution 1
TL;DR:
The PHP native function bcdiv seems to do precisely what is required, and properly.
To simply "truncate" a number, bcdiv($var, 1, 2);
where 2 is the number of decimals to preserve (and 1 is the denomenator - dividing the number by 1 allows you to simply truncate the original number to the desired decimal places)
Full Answer (for history)
This turns out to be more elusive than one might think.
After this answer was (incorrectly) upvoted quite a bit, it has come to my attention that even sprintf will round.
Rather than delete this answer, I'm turning it into a more robust explanation / discussion of each proposed solution.
number_format - Incorrect. (rounds)
Try using number format:
$var = number_format($var, 2, '.', ''); // Last two parameters are optional
echo $var;
// Outputs 2.50
If you want it to be a number, then simply type-cast to a float:
$var = (float)number_format($var, 2, '.', '');
Note: as has been pointed out in the comments, this does in fact round the number.
sprintf - incorrect. (sprintf also rounds)
If not rounding the number is important, then per the answer below, use sprintf:
$var = sprintf("%01.2f", $var);
floor - not quite! (floor rounds negative numbers)
floor, with some math, will come close to doing what you want:
floor(2.56789 * 100) / 100; // 2.56
Where 100 represents the precision you want. If you wanted it to three digits, then:
floor(2.56789 * 1000) / 1000; // 2.567
However, this has a problem with negative numbers. Negative numbers still get rounded, rather than truncated:
floor(-2.56789 * 100) / 100; // -2.57
"Old" Correct answer: function utilizing floor
So a fully robust solution requires a function:
function truncate_number( $number, $precision = 2) {
// Zero causes issues, and no need to truncate
if ( 0 == (int)$number ) {
return $number;
}
// Are we negative?
$negative = $number / abs($number);
// Cast the number to a positive to solve rounding
$number = abs($number);
// Calculate precision number for dividing / multiplying
$precision = pow(10, $precision);
// Run the math, re-applying the negative value to ensure returns correctly negative / positive
return floor( $number * $precision ) / $precision * $negative;
}
Results from the above function:
echo truncate_number(2.56789, 1); // 2.5
echo truncate_number(2.56789); // 2.56
echo truncate_number(2.56789, 3); // 2.567
echo truncate_number(-2.56789, 1); // -2.5
echo truncate_number(-2.56789); // -2.56
echo truncate_number(-2.56789, 3); // -2.567
New Correct Answer
Use the PHP native function bcdiv
echo bcdiv(2.56789, 1, 1); // 2.5
echo bcdiv(2.56789, 1, 2); // 2.56
echo bcdiv(2.56789, 1, 3); // 2.567
echo bcdiv(-2.56789, 1, 1); // -2.5
echo bcdiv(-2.56789, 1, 2); // -2.56
echo bcdiv(-2.56789, 1, 3); // -2.567
Solution 2
floor(2.500000550 * 100) / 100;
This should do your task...
Solution 3
You're requesting a function that returns "2.50"
and not 2.5
, so you aren't talking about arithmetic here but string manipulation. Then preg_replace
is your friend:
$truncatedVar = preg_replace('/\.(\d{2}).*/', '.$1', $var);
// "2.500000050" -> "2.50", "2.509" -> "2.50", "-2.509" -> "2.50", "2.5" -> "2.5"
If you want to do it with arithmetic, simply use:
$truncatedVar = round($var * 100) / 100);
// "2.500000050" -> "2.5", "2.599" -> "2.59", "-2.599" -> "2.59"
Solution 4
try with number_format:
echo number_format('2.50000050', 2); // 2.50
Solution 5
number_format rounds the number
php > echo number_format(128.20512820513, 2)."\n";
128.21
I used preg_replace to really cut the string
php > echo preg_replace('/(\.\d\d).*/', '$1', 128.20512820513)."\n";
128.20
air
Updated on July 09, 2022Comments
-
air almost 2 years
i have value in php variable like that
$var='2.500000550'; echo $var
what i want is to delete all decimal points after 2 digits.
like now value of variable will be
$var='2.50'; echo $var
keep in mind this value is coming from mysql databse
but when i use
round php function
i got round but i dont need round, i just need to delete all digits after 2 decimal simple.i have tired,
flot()
and lot of other option no success.Thanks
-
Philipp Kyeck over 11 yearsit should maybe be mentioned that number_format returns a string and not a number.
-
Justin over 10 yearsThis is the simplest method. number_format still rounds the result.
-
Sepster over 8 yearsThis is rounds, then truncates. So if
$var == 2.509
then the above will return 2.51, not 2.50. So does not answer the question that explicitly states "not round". -
Sepster over 8 yearsThis is rounds, then truncates. So if the input number was 2.509 then the above will return 2.51, not 2.50. So does not answer the question that explicitly states "not round"
-
Sepster over 8 yearssprintf does round, though.
sprintf("%01.2f", 2.509) != '2.50'
. -1 sorry. -
Sepster over 8 yearsThis should be marked as the answer IMHO, @air. All other answers round prior to truncation, such that the rounding is only evident when it results in increment of the last desired (in this case, 2nd) decimal place. This solution avoids that by effectively moving the decimal point two places right (by multiplying by 100), truncating (using floor), then moving it back 2 places left (divide by 100). Genius in its simplicity.
-
Sepster over 8 yearsAn explanation as to why
floor(205)
is returning 204 here, can be found at php.net/manual/en/function.floor.php#114204 -
random_user_name over 8 years@Sepster - actually, this has an issue with rounding negative numbers. I've improved my answer to address even that scenario.
-
random_user_name over 8 yearsThis actually will round negative numbers.
-
Sepster over 8 yearsGood pickup, @cale_b!
-
Sepster over 8 years-1 removed. No +1 though as still not quite right - try this for 2.05. :-) You need to factor in an epsilon to account for float storage irregularities - refer @David Constantine's answer (and now, mine!).
-
William Rossier about 8 yearsI used this and it's works: bcdiv($price,1,2); But this one too: floor(2.56789 * 100) / 100; // 2.56
-
random_user_name about 8 years@WilliamRossier -
bcdiv
is the right answer.floor
has a problem with negative numbers, so is not correct. Nice tip! -
random_user_name almost 8 years@Reado - can you expand / clarify how bcdiv is incorrect? I'd like to know / correct the answer.
-
Muhammad Atif over 7 yearsBEWARE! a zero should not be passed to truncate_number as $number
-
random_user_name over 7 years@MuhammadAtif - yes, that's not the correct answer in this post. The correct answer is
bcdiv
-
GrumpyCrouton over 7 yearsThis could also very easily be turned into a function where you can input the amount of decimals you'd like to see as well.
-
Андрей Аршинов about 7 yearsBy the way, bcadd($num_FLO, 0, $prec_INT) is preffered if you only need to delete digits because it's working faster that div or mul operations)
-
Bill_VA over 6 yearsSo close. This:
if ( 0 == (int)$number ) { return $number; }
Should beif ( (int)$number == 0 ) { return $number; }
Just a bit backwards. Thanks for the function. -
random_user_name over 6 years@Bill_VA - thanks for the comment. Actually, my code is correct (as is yours), and mine follows a "defensive" coding pattern known Yoda Conditions. If you forget one of the
=
symbols in your code, you get an unintentional assignment of0
to the$number
variable. If you forget one of the=
symbols in my code, you get an error, and the PHP won't run. -
Jimmy Adaro about 6 yearsWith
bcdiv(0.20198302, 1, 2)
keep in mind this:0.20
will be shown as0.2
. -
random_user_name about 6 years@JimmyAdaro - this is not about formatting a guaranteed number of decimal places, this is about truncating to a maximum number of decimal places, without rounding. Therefore, your comment is "correct / expected" behavior.
-
FantomX1 about 6 yearsdoesn't work on numbers which are periodic in binary system, try it, for example 'intval(2.092484 * 1000000) / 1000000' => you get '2.092483' , however yours string minupulation with preg_replace works very well, big up from me, thank you
-
FantomX1 about 6 yearsfloor doesn't work on numbers which are periodic in binary system, try it, for example 'floor(2.092484 * 1000000) / 1000000' => you get '2.092483'
-
random_user_name about 6 years@FantomX1 - Floor is not the answer. It is included in my post only to demonstrate why it is not the answer.
bcdiv
, which is at the top and the bottom of my post, is the correct answer. -
flu about 6 years@FantomX1 You're absolutely right. If I wanted to be a nitpicker I'd say that the OP asked for two digits and
'intval(2.092484 * 100) / 100' is
2.09` but I think usinground
instead ofintval
should make this more bulletproof. Thanks! -
FantomX1 about 6 yearsgood point with two decimals, me personally needed 6 though, round removes periodic number infinite sequence that's true, but you don't always want to round like for example me when I compare data against remote system, where mysql column does exactly what your string replace, just cuts off from a specific ordinal digit I want to have always returned 2.09 no matter if its 2.094 or 2.096, therefore round is of no use for me, but preg replace works
-
nights over 5 yearsAlso he asked how to delete, you are still keeping the fraction
-
Sol almost 5 yearsAbsolute the best answer on the net so far typeof() says it is a double too!
-
Adarsh Mohan almost 5 yearsThis wont work with "2.500000550" as the value. You will get "2.50000055" as the result as per your solution.
-
Fahad Ahmed almost 5 yearsYou have to increase the length, substr(2.500000550, 0, -6); then you will get '2.50',
-
Adarsh Mohan almost 5 yearsThe data comes from a mysql database, so that should be dynamic
-
victoryoalli over 2 yearsJust tried it it is giving me, which seems correct. truncate_decimals(10056468765.254564) => 10056468765.25
-
JGCW over 2 yearsI'll investigate and I'll delete my previous comment. If I find steps to reproduce, ill post them here.
-
mickmackusa almost 2 yearsHow about
preg_replace('/\.\d{2}\K\d+', '', $var)
instead?