37

I've googled this a lot but i can't find any helpful functions based on my queries.

What i want is:

100 -> 100
1000 -> 1,000
142840 -> 142,840

BUT

2023150 -> 2.023M ( i still want 3 additional numbers for more accuracy )
5430120215 -> 5.430B

I would totally appreciate any custom functions to dynamically choose the limit if possible.

ouflak
  • 2,458
  • 10
  • 44
  • 49
CodeOverload
  • 47,274
  • 54
  • 131
  • 219

14 Answers14

63

Use number_format():

if ($n < 1000000) {
    // Anything less than a million
    $n_format = number_format($n);
} else if ($n < 1000000000) {
    // Anything less than a billion
    $n_format = number_format($n / 1000000, 3) . 'M';
} else {
    // At least a billion
    $n_format = number_format($n / 1000000000, 3) . 'B';
}

I would totally appreciate any custom functions to dynamically choose the limit if possible.

If "limit" refers to the number of decimal places (the precision), that's easy:

function custom_number_format($n, $precision = 3) {
    if ($n < 1000000) {
        // Anything less than a million
        $n_format = number_format($n);
    } else if ($n < 1000000000) {
        // Anything less than a billion
        $n_format = number_format($n / 1000000, $precision) . 'M';
    } else {
        // At least a billion
        $n_format = number_format($n / 1000000000, $precision) . 'B';
    }

    return $n_format;
}
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
34

I took the answer BoltClock provided and tweaked it a bit with ease of configuration in mind.

// Shortens a number and attaches K, M, B, etc. accordingly
function number_shorten($number, $precision = 3, $divisors = null) {

    // Setup default $divisors if not provided
    if (!isset($divisors)) {
        $divisors = array(
            pow(1000, 0) => '', // 1000^0 == 1
            pow(1000, 1) => 'K', // Thousand
            pow(1000, 2) => 'M', // Million
            pow(1000, 3) => 'B', // Billion
            pow(1000, 4) => 'T', // Trillion
            pow(1000, 5) => 'Qa', // Quadrillion
            pow(1000, 6) => 'Qi', // Quintillion
        );    
    }

    // Loop through each $divisor and find the
    // lowest amount that matches
    foreach ($divisors as $divisor => $shorthand) {
        if (abs($number) < ($divisor * 1000)) {
            // We found a match!
            break;
        }
    }

    // We found our match, or there were no matches.
    // Either way, use the last defined value for $divisor.
    return number_format($number / $divisor, $precision) . $shorthand;
}
Kyle Challis
  • 981
  • 2
  • 12
  • 28
  • 5
    Nice answer Kyle. A few remarks though: You should use `if(abs($number) < ($divisor * 1000)) {`, otherwise negative numbers will never get shorten. Also, it might be a good idea to instantiate `$divisor` and `$shortand`, just to make sure there's no exception when a user might pass an empty `$divisors`. Thanks! – Luís Cruz Aug 24 '16 at 10:30
  • 5
    Lazily `return 0 + number_format($number / $divisor, $precision) . $shorthand;` to eliminate trailing insignificant zeroes (which I didn't need in my case). – dystopiandev Oct 10 '17 at 16:05
  • 1
    I have also added a round and now it's what I wanted : `return 0 + round(number_format($number / $divisor, $precision),1) . $shorthand;` – PHP kid May 21 '21 at 10:53
  • I don't know why but once the number crosses the billion mark and touches the trillion. this method shows error "non well formed numeric value encountered " – Prakhar Gyawali Jun 30 '21 at 13:13
14
<?php
// Converts a number into a short version, eg: 1000 -> 1k
// Based on: http://stackoverflow.com/a/4371114
function number_format_short( $n, $precision = 1 ) {
    if ($n < 900) {
        // 0 - 900
        $n_format = number_format($n, $precision);
        $suffix = '';
    } else if ($n < 900000) {
        // 0.9k-850k
        $n_format = number_format($n / 1000, $precision);
        $suffix = 'K';
    } else if ($n < 900000000) {
        // 0.9m-850m
        $n_format = number_format($n / 1000000, $precision);
        $suffix = 'M';
    } else if ($n < 900000000000) {
        // 0.9b-850b
        $n_format = number_format($n / 1000000000, $precision);
        $suffix = 'B';
    } else {
        // 0.9t+
        $n_format = number_format($n / 1000000000000, $precision);
        $suffix = 'T';
    }
  // Remove unecessary zeroes after decimal. "1.0" -> "1"; "1.00" -> "1"
  // Intentionally does not affect partials, eg "1.50" -> "1.50"
    if ( $precision > 0 ) {
        $dotzero = '.' . str_repeat( '0', $precision );
        $n_format = str_replace( $dotzero, '', $n_format );
    }
    return $n_format . $suffix;
}
/*
Example Usage:
number_format_short(7201); // Output: 7.2k
Demo:
echo '<table>';
for($d = 0; $d < 16; $d++ ) {
    $n = intval("09" . str_repeat( "0", $d ));
    $n = $n / 10;
    echo number_format_short($n) .'<br>'; // 0.9
    $n = intval("1" . str_repeat( "0", $d ));
    echo number_format_short($n) .'<br>'; // 1.0
    $n = intval("11" . str_repeat( "0", $d ));;
    $n = $n / 10;
    echo number_format_short($n) .'<br>'; // 1.1
}
echo '</table>';
Demo Output:
0.9
1
1.1

9
10
11

90
100
110

0.9K
1K
1.1K

9K
10K
11K

90K
100K
110K

0.9M
1M
1.1M

9M
10M
11M

90M
100M
110M

0.9B
1B
1.1B

9B
10B
11B

90B
100B
110B

0.9T
1T
1.1T

9T
10T
11T

90T
100T
110T

900T
1,000T
1,100T
*/
Nivesh Saharan
  • 365
  • 3
  • 11
9
function number_abbr($number)
{
    $abbrevs = [12 => 'T', 9 => 'B', 6 => 'M', 3 => 'K', 0 => ''];

    foreach ($abbrevs as $exponent => $abbrev) {
        if (abs($number) >= pow(10, $exponent)) {
            $display = $number / pow(10, $exponent);
            $decimals = ($exponent >= 3 && round($display) < 100) ? 1 : 0;
            $number = number_format($display, $decimals).$abbrev;
            break;
        }
    }

    return $number;
}

Works for positives and negatives.

kjdion84
  • 9,552
  • 8
  • 60
  • 87
4

Try this

function custom_number_format($n, $precision = 1) {
        if ($n < 900) {
        // Default
         $n_format = number_format($n);
        } else if ($n < 900000) {
        // Thausand
        $n_format = number_format($n / 1000, $precision). 'K';
        } else if ($n < 900000000) {
        // Million
        $n_format = number_format($n / 1000000, $precision). 'M';
        } else if ($n < 900000000000) {
        // Billion
        $n_format = number_format($n / 1000000000, $precision). 'B';
        } else {
        // Trillion
        $n_format = number_format($n / 1000000000000, $precision). 'T';
    }
    return $n_format;
    }
Clinton Canarias
  • 409
  • 4
  • 15
4

Altough this question was asked quite some time ago I have a different solution, which I think is even more simple:

function shorten($number){
    $suffix = ["", "K", "M", "B"];
    $precision = 1;
    for($i = 0; $i < count($suffix); $i++){
        $divide = $number / pow(1000, $i);
        if($divide < 1000){
            return round($divide, $precision).$suffix[$i];
            break;
        }
    }
}
echo shorten(1000);

I hope that it's still helpful for someone.

Bùi Đức Khánh
  • 3,975
  • 6
  • 27
  • 43
DreiDe
  • 109
  • 1
  • 10
4

Try this. Accounts for the groups k, M, B, T, and Q (quadrillion). Anything higher than 999Q shows as 999Q+.

function number(float $num, int $precision = 2): string
{
    $absNum = abs($num);

    if ($absNum < 1000)
    {
        return (string)round($num, $precision);
    }

    $groups = ['k','M','B','T','Q'];

    foreach ($groups as $i => $group)
    {
        $div = 1000 ** ($i + 1);

        if ($absNum < $div * 1000)
        {
            return round($num / $div, $precision) . $group;
        }
    }

    return '999Q+';
}
reformed
  • 4,505
  • 11
  • 62
  • 88
3

I took a different approach based on the previous solutions. Basically it uses the log() function to get rid of the for statement:

function number_shorten($number, $precision = 3)
{
    $suffixes = ['', 'K', 'M', 'B', 'T', 'Qa', 'Qi'];
    $index = (int) log(abs($number), 1000);
    $index = max(0, min(count($suffixes) - 1, $index)); // Clamps to a valid suffixes' index
    return number_format($number / 1000 ** $index, $precision) . $suffixes[$index];
}

It works for positive and negative numbers.

André Sousa
  • 428
  • 5
  • 9
2

Some Modify
$precision = 1, 2, 3 or 4 ...

function kmb($count, $precision = 2) {
if ($count < 1000000) {
// Anything less than a million
$n_format = number_format($count / 1000) . 'K';
} else if ($count < 1000000000) {
// Anything less than a billion
$n_format = number_format($count / 1000000, $precision) . 'M';
} else {
// At least a billion
$n_format = number_format($count / 1000000000, $precision) . 'B';
}
return $n_format;
}

echo kmb(272937);

273K

echo kmb(2729347);

2.73M

echo kmb(2729347874);

2.73B

CodAIK
  • 715
  • 7
  • 7
1

CakePHP has a Number Helper with a method toReadableSize. You should be able to grok it and come up with something on your own. In it, $this->precision is basically like number_format(), and __n is a singular-or-plural function.

tomb
  • 1,817
  • 4
  • 21
  • 40
Stephen
  • 18,827
  • 9
  • 60
  • 98
1

You can try this

 function number_formation($number, $precision = 3) {
        if ($number < 1000000) {

            $formatted_number = number_format($number); /* less than a million */
        } else if ($number < 1000000000) {

            $formatted_number = number_format($number / 1000000, $precision) . 'M'; /* billion */
        } else {

            $formatted_number = number_format($number  / 1000000000, $precision) . 'B'; /* for billion */
        }

        return $formatted_number;
    }
Manu
  • 31
  • 3
0

I refactored the OG best answer to make it better and a function

public function formatNumber($number)
{
    if ($number < 1000000) {
        // Anything less than a million
        return number_format($number);
    } else if ($number < 1000000000) {
        // Anything less than a billion
        return number_format($number / 1000000, 0) . 'm';
    } else {
        // At least a billion
        return number_format($number / 1000000000, 0) . 'b';
    }
}
0

Here's a modified version that worked really well for my needs. This allows me to specify if I want 5,500,000 to appear as "5.5M" (short style) or "5.5 million" (long style).

function nice_number_format( $n, $style = 'short' ) {
    if ($n < 1000) {
        $n_format = number_format($n);
    } else if ($n < 1000000) {
        $n_format = floatval(number_format($n / 1000, 2));
        $suffix = ($style == 'long' ? ' thousand' : 'K');
    } else if ($n < 1000000000) {
        $n_format = floatval(number_format($n / 1000000, 2));
        $suffix = ($style == 'long' ? ' million' : 'M');
    } else {
        $n_format = floatval(number_format($n / 1000000000, 2));
        $suffix = ($style == 'long' ? ' billion' : 'B');
    } 
    return $n_format . $suffix;
}
MarkPraschan
  • 560
  • 6
  • 8
0

Simply you can use this function:

function shortNumber($number = null)
{
    if($number == 0) {
        $short = 'No data';
    } elseif($number <= 999) {
        $short = $number;
    } elseif($number < 1000000) {
        $short = round($number/1000, 2).'K';
    } elseif($number < 1000000000) {
        $short =  round($number/1000000, 2).'M';
    } elseif($number >= 1000000000) {
        $short = round($number/1000000000, 2).'B';
    }

   return $short;
}

Method:

<?php 
 echo shortNumber(1000)
 // output = 1K
?>

Output

// Output = 1K