2

I have a number that needs to be rounded up to a specific decimal, is there any function in PHP to do that?

I need every number (which reflects an amount of money) to have a specific decimal number. For example:

The decimal needs to be 25, so if I got $ 25.50 I need it to be $ 26.25, and if I got $ 25.10 it needs to be $ 25.25.

I've checked PHP round(), and specifically ceil(), and I've come across this answer in Python, but I'm not sure it applies to my case, because what I need is different.

Any ideas? Even pseudo code as a tip on where to start will help me. Thanks!

Rosamunda
  • 14,620
  • 10
  • 40
  • 70
  • if you got $ 25.49, do you want to have $ 26.25 or $25.25 ? (just wonder whether it can round-down) – Ken Lee Aug 01 '21 at 14:13
  • 7
    **Do not** store money as real numbers. Most real numbers cannot be represented exactly in computers. Rounding does not help because it transform a number that is not exact in another number that, most probably, is not exact either. The best option, if you have to manage only one currency, is to store the amounts in the smallest unit (cents for dollars, eurocents for Euro etc) and represent it as dollars+cents only when you display them. – axiac Aug 01 '21 at 14:13
  • I need to always round up, so it would be 26.25. Thanks for your comment @axiac, actually is something that I haven't thought of. So you mean to store in one cell the dollar aumont (ie. 40) and in another the cents (ie. 25)? When I need to show how much I just put the two together? – Rosamunda Aug 01 '21 at 14:46
  • 1
    @Rosamunda Use one variable which holds the total cent value (including the "dollar" value as a multiple of `100`). No need to have two variables. – Progman Aug 01 '21 at 14:49
  • 1
    The basis for currencies is that [floating point precision](https://www.php.net/manual/en/language.types.float.php) will lead to long-term inaccuracies [(`0.1 + 0.2 === 0.3 (false)`)](https://3v4l.org/qRqiP). So you would store the currency value as an integer and divide the value by the lowest denominator [`$currency = $amount / 100`](https://3v4l.org/MZ722) The other solution is to use [bc math functions](https://www.php.net/manual/en/book.bc.php) – Will B. Aug 01 '21 at 15:17
  • I see, thats another great idea, and I think its simpler. I just take everything to cents and then add enough to reach the number I want. Then I pass everything to dollars again. Great idea @Progman! Thanks! – Rosamunda Aug 01 '21 at 15:23

4 Answers4

4

I think you need a custom function, something like this:

function my_round($number, $decimal = 0.25) {
  $result = floor($number) + $decimal;
  if ($result < $number) $result = ceil($number) + $decimal;
  return $result;
}

print my_round(25.50);
PlayerKillerYKT
  • 294
  • 2
  • 12
3

I modified this answer for your case:

<?php
function roundUp($number){
    $int = floor($number);
    $float = $number-$int;
    if ($float*10 < 2.5)
        $result = $int;
    else
        $result = ceil($number);
    $result+= 0.25;
    echo $number." becomes ".$result."\n";
}

roundUp(25.50);
roundUp(25.10);

Look for demo here

adampweb
  • 1,135
  • 1
  • 9
  • 19
3

Following axiac's advice mentioned in the comments and following this thread, the best way to deal with floating point numbers in the context of currencies, is to treat the dollars and cents' values as 2 separate entities.

One way I can think of it to split the numbers before and after the decimal into 2 separate variables and process accordingly.

<?php

function customRound($amount){
   $amount = strval($amount);
   if(preg_match('/(\d+)\.?(\d{1,2})?/', $amount, $matches) !== 1){
      throw new \Exception("Invalid amount.");
   }
   $dollars = intval($matches[1]);
   $cents = intval($matches[2] ?? 0);
   if($cents < 10) $cents *= 10;
   if($cents <= 25) return $dollars . ".25";
   return ($dollars + 1) . ".25";
}

$tests = [25.51,25.49,26.25,25.10,25.49];

foreach ($tests as $test){
    echo $test," => ",customRound($test),PHP_EOL;
} 
nice_dev
  • 17,053
  • 2
  • 21
  • 35
2

Here's another approach:

<?php

function roundUp($number, $decimal=0.25){
    $dollars = floor($number);
    $cents = $number - $dollars;
    if($cents > $decimal) {
        ++$dollars;
    }
    return $dollars + $decimal;
}

echo roundUp(25.50).PHP_EOL;
echo roundUp(25.10);
mpen
  • 272,448
  • 266
  • 850
  • 1,236