20

In PHP (using built-in functions) I'd like to convert/format a number with decimal, so that only the non-zero decimals show. However, another requirement of mine is that if it's a number without a decimal value, I'd still like to show that zero. Examples:

9.000 -> 9.0
9.100 -> 9.1
9.120 -> 9.12
9.123 -> 9.123

rtrim($value, "0") almost works. The problem with rtrim is that it leaves 9.000 as 9.. sprintf() seemed like a candidate, but I couldn't get it to have a variable amount of decimals. number_format() serves a different purpose, and those were all I could come up with...

Again, I'd like to point out that I am not looking for your homemade solutions to this, I'm looking for a way to accomplish this using internal PHP functionality. I can write a function that will accomplish this easily myself, so hold answers like that.

Salman A
  • 262,204
  • 82
  • 430
  • 521
Alex
  • 3,429
  • 4
  • 36
  • 66

11 Answers11

9

I don't think theres a way to do that. A regex is probably your best solution:

$value = preg_replace('/(\.[0-9]+?)0*$/', '$1', $value);

Demo:

php> $a = array('0.000', '0.0001', '0.0101', '9.000', '9.100', '9.120', '9.123');
php> foreach($a as $b) { echo $b . ' => ' . preg_replace('/(\.[0-9]+?)0*$/', '$1', $b)."\n"; }
0.000 => 0.0
0.0001 => 0.0001
0.0101 => 0.0101
9.000 => 9.0
9.100 => 9.1
9.120 => 9.12
9.123 => 9.123
ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • This does not work as "9.01" would become "91". Needs some grouping! – James Anderson Mar 25 '11 at 08:18
  • You put me on the right track, although your answer isn't valid PHP (the order of your parameters is wrong). The proper way to do this, using preg_replace is preg_replace('/(?<!\.)0*$/', '', $value). So thanks for pushing me in the right direction. I'll award you the answer for helping me find the answer. – Alex Mar 25 '11 at 08:18
  • I think you need `preg_replace($value'/\.?0*$/','')` to handle things like 123.4500 – Joel Lee Mar 25 '11 at 08:20
  • @James The $ sign means end of string. The pattern will not match ".0" in the middle of "9.01". – Joel Lee Mar 25 '11 at 08:23
  • 2
    Joel true but "9.000" becomes "9" and "9.100" will stay "9.100". – James Anderson Mar 25 '11 at 08:30
  • Mixed up the argument order. now it works. Btw, if none of you got a warning you should change your PHP config. – ThiefMaster Mar 25 '11 at 08:36
  • Sorry but -1, just because it still fails (see @JamesAnderson comment). – Alix Axel Apr 12 '12 at 14:04
  • @ThiefMaster: Still fails for `9.000` (should be `9.0`). This (http://stackoverflow.com/a/5429996/89771) handles it correctly. – Alix Axel Apr 12 '12 at 15:52
8

If you want a built-in solution and you're using a PHP version later than 4.2 you could try floatval():

echo floatval(9.200);

prints

9.2

but

echo floatval(9.123);

prints

9.123

Hope this helps.

Federico Zancan
  • 4,846
  • 4
  • 44
  • 60
7

try something like this

$number = 2.00;
echo floor_dec($number,$deg);

    function floor_dec($number, $deg = null)
    {
        if ($deg == null)
            return $number * 1000 / 1000;
        else
            return $number * pow(10, $deg) / pow(10, $deg);
    }

will display "2"

Mike Wrather
  • 71
  • 1
  • 2
5

Shouldn't it be?:

$value = preg_replace('~0*$~', '', $value);

The PHP preg_replace syntax is

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
Community
  • 1
  • 1
James Anderson
  • 27,109
  • 7
  • 50
  • 78
2

A trailing zero is significant:

  • A value of 9.0 implies, that the real value is more than 8.9 and less than 9.1
  • A value of 9.00000 implies, that the real value is more than 8.99999 and less than 9.00001

Therefore, your requirement is quite unusual. That's the reason why no function exists to do what you want.

Oswald
  • 31,254
  • 3
  • 43
  • 68
  • 6
    This is more for display purposes than scientific accuracy. I know that's what significance means, which is why I put "non-zero" in parentheses. I suppose I could've worded my question better. – Alex Mar 25 '11 at 08:17
  • The rules for significant digits is also only for display purposes. During calculation, the highest possible accuracy is used. Only when the final result should be displayed, it is rounded to an adequate accuracy (so as not to imply an accuracy that the input never had). – Oswald Mar 25 '11 at 08:28
2
<?php
    $numbers = array(
        "9.000",
        "9.100",
        "9.120",
        "9.123"
    );
    foreach($numbers as $number) {
        echo sprintf(
            "%s -> %s\n",
            $number,
            (float) $number == (int) $number ? number_format($number, 1) : (float) $number
        );
    }
?>

Output:

9.000 -> 9.0
9.100 -> 9.1
9.120 -> 9.12
9.123 -> 9.123
Salman A
  • 262,204
  • 82
  • 430
  • 521
1

Out of the box that isn't possible because you have two different ways of treating the fragment of your floats. You'll first have to determine how many non-zero numbers there are in your fragment and then act accordingly with sprintf.

<?php

$numbers = array(
    '9.000',
    '9.100',
    '9.120',
    '9.123',
);

foreach ($numbers as $number) {

    $decimals = strlen(str_replace('0','', array_pop(explode('.', $number))));
    $decimals = $decimals ?: 1;
    echo $number . " => " . sprintf("%.{$decimals}f", $number);

    echo "<br/>";

}
ChrisR
  • 14,370
  • 16
  • 70
  • 107
0

How about

preg_replace(/\\.$/,'.0',rtrim($value,'0'))
Simon MᶜKenzie
  • 8,344
  • 13
  • 50
  • 77
Therabill
  • 1
  • 1
0

Assuming the number is encoded as or cast to a string, here's a general purpose approach:

$value = is_numeric($value) ? strval($value + 0) : $value;
Giles B
  • 411
  • 4
  • 7
-1

My solution is to let php handle it as a number (is *1) and then treat it as a string (my example I was using percentages stored as a decimal with 2 decimal places):

printf('%s%% off', $value*1);

This outputs:

0.00  => 0% off
0.01  => 0.01% off
20.00 => 20% off
20.50 => 20.5% off
-2

rtrim($value, "0") almost works. The problem with rtrim is that it leaves 9.000 as 9.

So just rtrim($value, "0.") and you're done.