1 | <?php |
||
2 | |||
3 | namespace ICanBoogie\CLDR\Numbers; |
||
4 | |||
5 | use function assert; |
||
6 | use function is_numeric; |
||
7 | use function is_string; |
||
8 | use function preg_match; |
||
9 | use function str_repeat; |
||
10 | use function strlen; |
||
11 | use function strpos; |
||
12 | use function strrpos; |
||
13 | use function substr; |
||
14 | |||
15 | final class Number |
||
16 | { |
||
17 | /** |
||
18 | * Returns the precision of a number. |
||
19 | * |
||
20 | * @param float|int|numeric-string $number |
||
0 ignored issues
–
show
Documentation
Bug
introduced
by
![]() |
|||
21 | */ |
||
22 | public static function precision_from(float|int|string $number): int |
||
23 | { |
||
24 | $number = (string)$number; |
||
25 | $pos = strrpos($number, '.'); |
||
26 | |||
27 | if (!$pos) { |
||
28 | return 0; |
||
29 | } |
||
30 | |||
31 | return strlen($number) - $pos - 1; |
||
32 | } |
||
33 | |||
34 | /** |
||
35 | * Returns a number rounded to the specified precision. |
||
36 | * |
||
37 | * @param float|int|numeric-string $number |
||
0 ignored issues
–
show
|
|||
38 | */ |
||
39 | public static function round_to(float|int|string $number, int $precision): float |
||
40 | { |
||
41 | return round($number + 0, $precision); |
||
42 | } |
||
43 | |||
44 | /** |
||
45 | * Parses a number. |
||
46 | * |
||
47 | * @param float|int|numeric-string $number |
||
0 ignored issues
–
show
|
|||
48 | * |
||
49 | * @return array{ 0: int, 1: string|null} |
||
0 ignored issues
–
show
|
|||
50 | * Where `0` is the integer part and `1` the fractional part. The fractional part is `null` if |
||
51 | * `$number` has no decimal separator. The fractional part is returned as a string to preserve '03' from |
||
52 | * '1.03'. |
||
53 | */ |
||
54 | public static function parse(float|int|string $number, ?int $precision = null): array |
||
55 | { |
||
56 | if ($precision === null) { |
||
57 | $precision = self::precision_from($number); |
||
58 | } |
||
59 | |||
60 | $number = self::round_to($number + 0, $precision); |
||
61 | $number = abs($number); |
||
62 | $number = number_format($number, $precision, '.', ''); |
||
63 | |||
64 | [ $integer, $fractional ] = explode('.', (string)$number) + [ 1 => null ]; |
||
65 | |||
66 | return [ (int)$integer, $fractional ]; |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * @param float|int|numeric-string $number |
||
0 ignored issues
–
show
|
|||
71 | * |
||
72 | * @return float|int|numeric-string |
||
0 ignored issues
–
show
|
|||
73 | */ |
||
74 | public static function expand_compact_decimal_exponent(float|int|string $number, int &$c = 0): float|int|string |
||
75 | { |
||
76 | $c = 0; |
||
77 | |||
78 | if (!is_string($number)) { |
||
79 | return $number; |
||
80 | } |
||
81 | |||
82 | $c_pos = strpos($number, 'c'); |
||
83 | |||
84 | if ($c_pos === false) { |
||
85 | return $number; |
||
86 | } |
||
87 | |||
88 | $c = (int)substr($number, $c_pos + 1); |
||
89 | $number = substr($number, 0, $c_pos); |
||
90 | preg_match('/0+$/', $number, $match); |
||
91 | assert(is_numeric($number)); |
||
92 | $multiplier = (int)('1' . str_repeat('0', $c)); |
||
93 | $number *= $multiplier; |
||
94 | |||
95 | if ($match) { |
||
96 | return $number . $match[0]; // @phpstan-ignore-line |
||
97 | } |
||
98 | |||
99 | return $number; |
||
100 | } |
||
101 | } |
||
102 |