diff --git a/src/Number.php b/src/Number.php index 9c81786..101c26a 100644 --- a/src/Number.php +++ b/src/Number.php @@ -127,30 +127,71 @@ public static function fileSize(int|float $bytes, int $precision = 0, ?int $maxP * @param int|null $maxPrecision * @return string */ - public static function forHumans(int|float $number, int $precision = 0, ?int $maxPrecision = null): string + public static function abbreviate(int|float $number, int $precision = 0, ?int $maxPrecision = null): string { - $units = [ - 3 => 'thousand', - 6 => 'million', - 9 => 'billion', - 12 => 'trillion', - 15 => 'quadrillion', - ]; + return static::forHumans($number, $precision, $maxPrecision, abbreviate: true); + } + + /** + * Convert the number to its human readable equivalent. + * + * @param int $number + * @param int $precision + * @param int|null $maxPrecision + * @return string + */ + public static function forHumans(int|float $number, int $precision = 0, ?int $maxPrecision = null, bool $abbreviate = false): string + { + return static::summarize($number, $precision, $maxPrecision, $abbreviate ? [ + 3 => 'K', + 6 => 'M', + 9 => 'B', + 12 => 'T', + 15 => 'Q', + ] : [ + 3 => ' thousand', + 6 => ' million', + 9 => ' billion', + 12 => ' trillion', + 15 => ' quadrillion', + ]); + } + + /** + * Convert the number to its human readable equivalent. + * + * @param int $number + * @param int $precision + * @param int|null $maxPrecision + * @param array $units + * @return string + */ + protected static function summarize(int|float $number, int $precision = 0, ?int $maxPrecision = null, array $units = []): string + { + if (empty($units)) { + $units = [ + 3 => 'K', + 6 => 'M', + 9 => 'B', + 12 => 'T', + 15 => 'Q', + ]; + } switch (true) { case $number === 0: return '0'; case $number < 0: - return sprintf('-%s', static::forHumans(abs($number), $precision, $maxPrecision)); + return sprintf('-%s', static::summarize(abs($number), $precision, $maxPrecision, $units)); case $number >= 1e15: - return sprintf('%s quadrillion', static::forHumans($number / 1e15, $precision, $maxPrecision)); + return sprintf('%s'.end($units), static::summarize($number / 1e15, $precision, $maxPrecision, $units)); } $numberExponent = floor(log10($number)); $displayExponent = $numberExponent - ($numberExponent % 3); $number /= pow(10, $displayExponent); - return trim(sprintf('%s %s', static::format($number, $precision, $maxPrecision), $units[$displayExponent] ?? '')); + return trim(sprintf('%s%s', static::format($number, $precision, $maxPrecision), $units[$displayExponent] ?? '')); } /** diff --git a/tests/Feature/NumberTest.php b/tests/Feature/NumberTest.php index b1c3762..f073d25 100644 --- a/tests/Feature/NumberTest.php +++ b/tests/Feature/NumberTest.php @@ -178,3 +178,56 @@ $this->assertSame('-1 quadrillion', Number::forHumans(-1000000000000000)); $this->assertSame('-1 thousand quadrillion', Number::forHumans(-1000000000000000000)); }); + +it('abbreviate numbers into summarized strings', function () { + + $this->assertSame('1', Number::abbreviate(1)); + $this->assertSame('1.00', Number::abbreviate(1, precision: 2)); + $this->assertSame('10', Number::abbreviate(10)); + $this->assertSame('100', Number::abbreviate(100)); + $this->assertSame('1K', Number::abbreviate(1000)); + $this->assertSame('1.00K', Number::abbreviate(1000, precision: 2)); + $this->assertSame('1K', Number::abbreviate(1000, maxPrecision: 2)); + $this->assertSame('1K', Number::abbreviate(1230)); + $this->assertSame('1.2K', Number::abbreviate(1230, maxPrecision: 1)); + $this->assertSame('1M', Number::abbreviate(1000000)); + $this->assertSame('1B', Number::abbreviate(1000000000)); + $this->assertSame('1T', Number::abbreviate(1000000000000)); + $this->assertSame('1Q', Number::abbreviate(1000000000000000)); + $this->assertSame('1KQ', Number::abbreviate(1000000000000000000)); + + $this->assertSame('123', Number::abbreviate(123)); + $this->assertSame('1K', Number::abbreviate(1234)); + $this->assertSame('1.23K', Number::abbreviate(1234, precision: 2)); + $this->assertSame('12K', Number::abbreviate(12345)); + $this->assertSame('1M', Number::abbreviate(1234567)); + $this->assertSame('1B', Number::abbreviate(1234567890)); + $this->assertSame('1T', Number::abbreviate(1234567890123)); + $this->assertSame('1.23T', Number::abbreviate(1234567890123, precision: 2)); + $this->assertSame('1Q', Number::abbreviate(1234567890123456)); + $this->assertSame('1.23KQ', Number::abbreviate(1234567890123456789, precision: 2)); + $this->assertSame('490K', Number::abbreviate(489939)); + $this->assertSame('489.9390K', Number::abbreviate(489939, precision: 4)); + $this->assertSame('500.00000M', Number::abbreviate(500000000, precision: 5)); + + $this->assertSame('1MQ', Number::abbreviate(1000000000000000000000)); + $this->assertSame('1BQ', Number::abbreviate(1000000000000000000000000)); + $this->assertSame('1TQ', Number::abbreviate(1000000000000000000000000000)); + $this->assertSame('1QQ', Number::abbreviate(1000000000000000000000000000000)); + $this->assertSame('1KQQ', Number::abbreviate(1000000000000000000000000000000000)); + + $this->assertSame('0', Number::abbreviate(0)); + $this->assertSame('-1', Number::abbreviate(-1)); + $this->assertSame('-1.00', Number::abbreviate(-1, precision: 2)); + $this->assertSame('-10', Number::abbreviate(-10)); + $this->assertSame('-100', Number::abbreviate(-100)); + $this->assertSame('-1K', Number::abbreviate(-1000)); + $this->assertSame('-1.23K', Number::abbreviate(-1234, precision: 2)); + $this->assertSame('-1.2K', Number::abbreviate(-1234, maxPrecision: 1)); + $this->assertSame('-1M', Number::abbreviate(-1000000)); + $this->assertSame('-1B', Number::abbreviate(-1000000000)); + $this->assertSame('-1T', Number::abbreviate(-1000000000000)); + $this->assertSame('-1.1T', Number::abbreviate(-1100000000000, maxPrecision: 1)); + $this->assertSame('-1Q', Number::abbreviate(-1000000000000000)); + $this->assertSame('-1KQ', Number::abbreviate(-1000000000000000000)); +});