Home > Software engineering >  How to create custom rounding in PHP?
How to create custom rounding in PHP?

Time:08-16

I am trying to make an algorithm that will round according to these conditions:

  • 1 or 2 cents - rounded down to "0"
  • 3 or 4 cents - rounds up to 5 cents
  • 5 cents - 5 cents left
  • 6 or 7 cents - rounds down to 5 cents
  • 8 or 9 cents - rounds up to "0"

So, it should look like this:

PRICE| AFTER
9.90 | 9.90
9.91 | 9.90
9.92 | 9.90
9.93 | 9.95
9.94 | 9.95
9.95 | 9.95
9.96 | 9.95
9.97 | 9.95
9.98 | 10.0
9.99 | 10.0
10.0 | 10.0

My code is here, but looks strange. For numbers like 10.99 result becomes 10.10:

 function roundDown(float $price): float
    {
        [$number, $decimals] = explode('.', sprintf('%.2f', $price));
        [, $second] = str_split($decimals);

        $table = [
            0 => 0,
            1 => -1,
            2 => -2,
            3 => 2,
            4 => 1,
            5 => 0,
            6 => -1,
            7 => -2,
            8 => 2,
            9 => 1,
        ];

        return $number . '.' . str_pad((float)$decimals (float)$table[$second], 2, '0', STR_PAD_LEFT);
    }

Thanks in advance.

CodePudding user response:

What about this?

function roundDown(float $price): float
{
    $denominator = 20;

    return round(round($price * $denominator) / $denominator, 2, PHP_ROUND_HALF_UP);
}

CodePudding user response:

You have forgotten to carry the hundreds when you reach 100: 1.99 0.01 needs to become 2.00

Sticking to your current approach, you could check if the new "decimals" reach 100 or higher after your adj, and if so increment the "number":

function roundDown(float $price): float
{
    [$number, $decimals] = explode('.', sprintf('%.2f', $price));
    [, $second] = str_split($decimals);

    $table = [
        0 => 0,
        1 => -1,
        2 => -2,
        3 => 2,
        4 => 1,
        5 => 0,
        6 => -1,
        7 => -2,
        8 => 2,
        9 => 1,
    ];

    $newDecimals = (float)$decimals (float)$table[$second];
    if ( $newDecimals > 99 ) {
        $number  = 1;
        $newDecimals -= 100;
    }
    return $number . '.' . str_pad($newDecimals, 2, '0', STR_PAD_LEFT);
}

(There are various other ways to improve the code, or implement the requirement a different way, but I wanted to point out the specific bug in your current attempt, and the simplest change that fixes it.)

CodePudding user response:

I would avoid the string manipulation at the end and set the values in $table to be the actuals values to be added or subtracted and then do the arithmetic at the end.

function roundDown(float $price): float
{
    [$number, $decimals] = explode('.', sprintf('%.2f', $price));
    [, $second] = str_split($decimals);

    $table = [
        0 => 0,
        1 => -0.01,
        2 => -0.02,
        3 => 0.02,
        4 => 0.01,
        5 => 0,
        6 => -0.01,
        7 => -0.02,
        8 => 0.02,
        9 => 0.01,
    ];

    return $price   $table[$second];
}
  •  Tags:  
  • php
  • Related