Passed
Push — 6.0 ( 4ac4e1...87e1d7 )
by Olivier
01:56
created

Number::precision_from()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 10
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
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
The doc comment float|int|numeric-string at position 4 could not be parsed: Unknown type name 'numeric-string' at position 4 in float|int|numeric-string.
Loading history...
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
Documentation Bug introduced by
The doc comment float|int|numeric-string at position 4 could not be parsed: Unknown type name 'numeric-string' at position 4 in float|int|numeric-string.
Loading history...
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
Documentation Bug introduced by
The doc comment float|int|numeric-string at position 4 could not be parsed: Unknown type name 'numeric-string' at position 4 in float|int|numeric-string.
Loading history...
48
     *
49
     * @return array{ 0: int, 1: string|null}
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{ at position 2 could not be parsed: the token is null at position 2.
Loading history...
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
Documentation Bug introduced by
The doc comment float|int|numeric-string at position 4 could not be parsed: Unknown type name 'numeric-string' at position 4 in float|int|numeric-string.
Loading history...
71
     *
72
     * @return float|int|numeric-string
0 ignored issues
show
Documentation Bug introduced by
The doc comment float|int|numeric-string at position 4 could not be parsed: Unknown type name 'numeric-string' at position 4 in float|int|numeric-string.
Loading history...
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