56

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

Justin Yost
  • 2,340
  • 19
  • 31
air
  • 6,136
  • 26
  • 93
  • 125

15 Answers15

144

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
random_user_name
  • 25,694
  • 7
  • 76
  • 115
  • 3
    it should maybe be mentioned that number_format returns a string and not a number. – Philipp Kyeck Aug 03 '12 at 15:48
  • sprintf _does_ round, though. `sprintf("%01.2f", 2.509) != '2.50'`. -1 sorry. – Sepster Oct 29 '15 at 14:15
  • -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!). – Sepster Oct 31 '15 at 04:07
  • I used this and it's works: bcdiv($price,1,2); But this one too: floor(2.56789 * 100) / 100; // 2.56 – William Rossier Mar 09 '16 at 16:13
  • @WilliamRossier - `bcdiv` is the right answer. `floor` has a problem with negative numbers, so is not correct. Nice tip! – random_user_name Mar 10 '16 at 15:21
  • @Reado - can you expand / clarify how bcdiv is incorrect? I'd like to know / correct the answer. – random_user_name Jun 06 '16 at 16:24
  • BEWARE! a zero should not be passed to truncate_number as $number – Muhammad Atif Sep 20 '16 at 13:59
  • 1
    @MuhammadAtif - yes, that's not the correct answer in this post. The correct answer is `bcdiv` – random_user_name Sep 20 '16 at 14:15
  • 1
    By 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) – Андрей Аршинов Jan 30 '17 at 12:28
  • So close. This: `if ( 0 == (int)$number ) { return $number; }` Should be `if ( (int)$number == 0 ) { return $number; }` Just a bit backwards. Thanks for the function. – Bill_VA Oct 31 '17 at 17:29
  • 2
    @Bill_VA - thanks for the comment. Actually, my code is correct (as is yours), and mine follows a "defensive" coding pattern known [Yoda Conditions](https://en.wikipedia.org/wiki/Yoda_conditions). If you forget one of the `=` symbols in _your_ code, you get an unintentional assignment of `0` to the `$number` variable. If you forget one of the `=` symbols in _my_ code, you get an error, and the PHP won't run. – random_user_name Oct 31 '17 at 17:57
  • With `bcdiv(0.20198302, 1, 2)` keep in mind this: `0.20` will be shown as `0.2`. – Jimmy Adaro Feb 19 '18 at 17:50
  • @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. – random_user_name Feb 19 '18 at 17:52
  • floor doesn't work on numbers which are periodic in binary system, try it, for example 'floor(2.092484 * 1000000) / 1000000' => you get '2.092483' – FantomX1 Mar 26 '18 at 13:23
  • @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. – random_user_name Mar 26 '18 at 13:32
  • 1
    Absolute the best answer on the net so far typeof() says it is a double too! – Sol May 21 '19 at 06:00
  • what about `bcmul`? will it give the same results as `bcdiv` in this case? – Nuryagdy Mustapayev Jul 18 '22 at 13:25
13
floor(2.500000550 * 100) / 100;

This should do your task...

Sujit Agarwal
  • 12,348
  • 11
  • 48
  • 79
  • This is the simplest method. number_format still rounds the result. – Justin Oct 04 '13 at 17:38
  • This 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 Oct 29 '15 at 14:22
  • 2
    @Sepster - actually, this has an issue with rounding negative numbers. I've improved my answer to address even that scenario. – random_user_name Oct 30 '15 at 17:15
  • 1
    Good pickup, @cale_b! – Sepster Oct 31 '15 at 04:05
  • This could also very easily be turned into a function where you can input the amount of decimals you'd like to see as well. – GrumpyCrouton Dec 29 '16 at 19:47
6

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"
flu
  • 14,307
  • 8
  • 74
  • 71
  • doesn'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 Mar 26 '18 at 13:22
  • @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 using `round` instead of `intval` should make this more bulletproof. Thanks! – flu Mar 27 '18 at 08:08
  • good 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 – FantomX1 Mar 27 '18 at 21:31
  • How about `preg_replace('/\.\d{2}\K\d+', '', $var)` instead? – mickmackusa May 05 '22 at 03:29
4

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
Liphtier
  • 552
  • 6
  • 13
4

Use the PHP native function bcdiv.

Example:

echo bcdiv(3.22871, 1, 1);  // 3.2
echo bcdiv(3.22871, 1, 2);  // 3.22
echo bcdiv(3.22871, 1, 3);  // 3.228
echo bcdiv(-3.22871, 1, 1); // -3.2
echo bcdiv(-3.22871, 1, 2); // -3.22

For your case:

$var='2.500000550';
echo $var
echo bcdiv($var, 1, 2);  // 2.50
Faisal
  • 4,591
  • 3
  • 40
  • 49
4

try with number_format:

echo number_format('2.50000050', 2); // 2.50
matino
  • 17,199
  • 8
  • 49
  • 58
  • 6
    This 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 Oct 29 '15 at 14:10
  • Also he asked how to delete, you are still keeping the fraction – nights Sep 27 '18 at 07:01
2

someone posted here about

floor(2.500000550 * 100) / 100;

function cutAfterDot($number, $afterDot = 2){
$a = $number * pow(10, $afterDot);
$b = floor($a);
$c = pow(10, $afterDot);
echo "a $a, b $b, c $c<br/>";
return $b/$c ;
}
echo cutAfterDot(2.05,2);

a 205, b 204, c 100
2.04

so in raw form don't use it... But if you add a little epsilon...

function cutAfterDot($number, $afterDot = 2){
        return floor($number * pow(10, $afterDot) + 0.00001) / pow(10, $afterDot);
    }

it works!

1

The following is (what I believe is - please correct me if not) a robust mathematical* solution, based mostly on the information from several other answerers here, and a small amount from me

(*Which is not to suggest there's anything wrong with Liphtier's regex-based answer - just that I can see purists wanting to avoid regex for what is arguably a mathematical problem.)

  • sprintf(), number_format() (and round(), obviously), are all performing a rounding operation so are not appropriate for the non-rounding truncation requested in the question (not on their own, at least).
  • In lieu of an out-of-the-box function, the seemingly most elegant solution was Sujit Agarwal's answer
  • But because of the way floats are stored, we need to use an epsilon - as pointed out in David Constantine's answer (where he also makes the previous solution more general by using pow() to get the right factor based on a specified precision).
  • But then, as pointed out in cale_b's answer, any use of floor() (or presumably ceil()) may produce unintended results for negatives without use of abs().
  • And the value I'm trying to add is:
    • If using a division on abs() to get a negation factor, we need to account for the special case when the input is 0.
    • We should dynamically create the epsilon; A static hard-coded epsilon might be too small or too large, depending on the precision required. I haven't seen this issue addressed in the other answers.

The code I'm using is:

public static function truncate_decimal($number, $leavePlaces = 2)
{
    if ($number == 0) return 0;
    $negate = $number / abs($number);
    $shiftFactor = pow(10, $leavePlaces);
    $epsilon = pow(10, -1 * $leavePlaces);
    return floor(abs($number) * $shiftFactor + $epsilon) / $shiftFactor * $negate;
}
Community
  • 1
  • 1
Sepster
  • 4,800
  • 20
  • 38
1

Already a lot of possible solutions, I just want to add the one that I came up to solve my problem.

function truncate_decimals($number, $decimals=2)
{
  $factor = pow(10,$decimals); 
  $val = intval($number*$factor)/$factor;
  return $val;
}


truncate_decimals(199.9349,2);
// 199.93
victoryoalli
  • 1,897
  • 2
  • 12
  • 11
  • Just tried it it is giving me, which seems correct. truncate_decimals(10056468765.254564) => 10056468765.25 – victoryoalli Dec 23 '21 at 00:13
  • I'll investigate and I'll delete my previous comment. If I find steps to reproduce, ill post them here. – JGCW Dec 23 '21 at 23:05
1

use sprintf

sprintf("%01.2f", $var);
Aurimas Ličkus
  • 9,886
  • 4
  • 24
  • 26
  • 3
    This 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 Oct 29 '15 at 14:07
0

All of the solutions which use number_format are wrong because number_format performs rounding.

The function below should work on all numbers, you can specify the decimal separator for those countries which use ','.

function truncate_decimal($number, $truncate_decimal_length = 2, $decimal_character = '.', $thousands_character = '') {

$number = explode($decimal_character, $number);
$number[1] = substr($number[1], 0, $truncate_decimal_length);
$number_truncated = implode($decimal_character, $number);
return number_format($number_truncated, $truncate_decimal_length, $decimal_character, $thousands_character);

}
leexonline
  • 101
  • 1
  • 2
0

A simple function to follow would be "If greater than 0 floor, else ceil", using a multiplier to raise it above the decimal point temporarily whilst doing it:

function trim_num($num_in, $dec_places = 2) {
    $multiplier = pow(10, $dec_places); // 10, 100, 1000, etc
    if ($num_in > 0) {
        $num_out = floor($num_in * $multiplier) / $multiplier;
    } else {
        $num_out = ceil($num_in * $multiplier) / $multiplier;
    }
    return $num_out;
}
David Bell
  • 183
  • 1
  • 8
0
$num = 118.74999669307;
$cut = substr($num, 0, ((strpos($num, '.')+1)+2));
// Cut the string from first character to a length of 2 past the decimal.
// substr(cut what, start, ( (find position of decimal)+decimal itself)+spaces after decimal) )
echo $cut; 
Sujjad A
  • 124
  • 1
  • 5
0

floor - not quite! (floor rounds negative numbers)

A possible solution from cale_b answer.

static public function rateFloor($rate, $decimals)
{

    $div = "1" . str_repeat("0", $decimals);

    if ($rate > 0) {
        return floor($rate * $div) / $div;
    }

    $return = floor(abs($rate) * $div) / $div;

    return -($return);

}

static public function rateCeil($rate, $decimals)
{

    $div = "1" . str_repeat("0", $decimals);

    if ($rate > 0) {
        return ceil($rate * $div) / $div;
    }

    $return = ceil(abs($rate) * $div) / $div;

    return -($return);

}

Positive

Rate: 0.00302471

Floor: 0.00302400

Ceil: 0.00302500

Negative

Rate: -0.00302471

Floor: -0.00302400

Ceil: -0.00302500

Community
  • 1
  • 1
Jon C.
  • 374
  • 1
  • 4
  • 14
0

If you don't want to round the number but you want to remove the decimal places you can use "substr" method

substr(string, start, length);
substr(4.96, 0, -1);