AVK
AVK

Reputation: 645

Number format with a variable decimal place

Is there a built-in/neat way to format a number (just like number_format does), but without any rounding ups/downs?

For instance, number 1234.234 should be formatted as 1,234.234 and another number 1234 should be formatted as 1,234 (i.e. without any trailing .000)

Upvotes: 3

Views: 4369

Answers (6)

Pierre-Olivier Vares
Pierre-Olivier Vares

Reputation: 1769

Based on the arhey's answer

TLDR ;)

You can use number_format to format the number to a fixed-width format, then use rtrim twice to remove trailing zeroes, and dot.

rtrim(rtrim(number_format($number, 3, '.', ','), '0'), '.')

Starting from the last character, rtrim removes it while it is one of those given. In our case, we remove trailing dots, then we remove an eventual trailing zero.

rtrim(rtrim(number_format(1234.123, 3, '.', ','), '0'), '.')
// returns 1,234.123

rtrim(rtrim(number_format(1234.12, 3, '.', ','), '0'), '.')
// returns 1,234.12 (1,234.120, trimmed to 1234.12)

rtrim(rtrim(number_format(1234, 3, '.', ','), '0'), '.')
// returns 1,234 (1,234.000, trimmed to 1234)

rtrim(rtrim(number_format(1200, 3, '.', ','), '0'),'.')
// returns 1,200 (1,200.000, trimmed to 1200., trimmed to 1200)

Formal form, and discussion about the parameters (notably the decimals count)

rtrim(rtrim(number_format($number, <N>, '<D>', ''), '0'), '<D>')

Where :

  • D is the decimal separator. To avoid locale-formatting problems, explicitly specify it
  • N is the maximum digits you number can have.

If you know all your numbers will have less than 3 digits, go and take N=3.

What if you don't know how many decimals are at most ? Well, things are getting more complex. It may worth recalling (as stated in the PHP documentation) that floats are stored :

  • with a precision (a number of digits, without distinction whether they are before or after the decimal separator), not a number of decimals
  • and in their binary form, not their decimal one, and that can lead to rounding errors when reaching precision limit.

For example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....

So there is no universal good value, you'll have to choose it depending on the usual scale of your data.

And that explains why there is no built-in function for that : PHP can't choose for you.

Upvotes: 4

saudes
saudes

Reputation: 232

I really liked arhey's answer, but later realized it has a major flaw. A number like 2100 will get converted to 2,1 instead of 2,100.

Below is how I ended up modifying it.

public function formatDecimal($number)
{
    $stringVal = strval($number); //convert number to string

    $decPosition = strpos($stringVal, ".");

    if ($decPosition !== false) //there is a decimal
    {
        $decPart = substr($stringVal, $decPosition); //grab only the decimal portion

        $result = number_format($stringVal) . rtrim($decPart, ".0");
    }
    else //no decimal to worry about
    {
        $result = number_format($stringVal);
    }

    return $result;
}

It's not as succinct a solution as I was hoping, but in my case I put it into a view helper (I'm using ZF2) and so it's just one simple function call in my view.

Hope this is helpful for someone!

Upvotes: 1

Ivan
Ivan

Reputation: 2579

You can use function:

<?php
function getNumberFormat($number) {
    $numberAr = explode('.', (string)$number);

    $count = 0;
    if (2 === count($numberAr)) {
        $count = strlen($numberAr[1]);
    }

    return number_format($number, $count, ',', '.');
}

$test1 = 1234.234;
$test2 = 1234;                      
echo getNumberFormat($test1); //1,234.234
echo getNumberFormat($test2); //1,234

Upvotes: 2

arhey
arhey

Reputation: 311

rtrim(number_format(1234.234, 3),'.0');
rtrim(number_format(1234, 3),'.0');

Upvotes: 0

Jakub Matczak
Jakub Matczak

Reputation: 15656

Let's begin with that there's no decimal type in PHP. There's float only.

And if you know how float works, then you know that it's usually not possible to store exact decimal value that you think you have, but it's an approximation. That's because you can't express most of decimal numbers in binary system.

Therefore if you say:

$number = 1234.234;

Then you have a float that is close to this value. The real value is:

1234.23399999999992360244505107402801513671875

Therefore PHP can't just guess how do you want to round it. It needs to be specified explicitly.

Upvotes: 0

mitkosoft
mitkosoft

Reputation: 5316

You can define simple custom function for that:

<?php
    function custom_number_format($number, $decimal = '.')
    {
        $broken_number = explode($decimal, $number);
        if (isset($broken_number[1]))
            return number_format($broken_number[0]) . $decimal . $broken_number[1];
        else
            return number_format($broken_number[0]);
    }

    $n1 = '1234.234';
    $n2 = '1234';

    echo custom_number_format($n1);
    echo '<br>';
    echo custom_number_format($n2);
?>

Output is:

1,234.234
1,234

Upvotes: 4

Related Questions