1 | <?php |
||
17 | class DecimalConverter implements Converter |
||
18 | { |
||
19 | /** @var int Precision for fraction conversions */ |
||
20 | private $precision; |
||
21 | |||
22 | /** @var NumberBase Number base used by provided numbers */ |
||
23 | private $source; |
||
24 | |||
25 | /** @var NumberBase Number base used by returned numbers */ |
||
26 | private $target; |
||
27 | |||
28 | /** @var string Number base used by GMP for standard conversions */ |
||
29 | private static $standardBase = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; |
||
30 | |||
31 | /** |
||
32 | * Creates a new instance of DecimalConverter. |
||
33 | * @param NumberBase $source Number base used by the provided numbers |
||
34 | * @param NumberBase $target Number base used by the returned numbers |
||
35 | */ |
||
36 | 114 | public function __construct(NumberBase $source, NumberBase $target) |
|
42 | |||
43 | 33 | public function setPrecision($precision) |
|
47 | |||
48 | 60 | public function convertInteger(array $number) |
|
49 | { |
||
50 | 60 | $decimal = $this->getDecimal($number); |
|
51 | |||
52 | 60 | if ($this->isStandardBase($this->target->getDigitList())) { |
|
53 | 48 | return $this->target->canonizeDigits(str_split(gmp_strval($decimal, $this->target->getRadix()))); |
|
54 | } |
||
55 | |||
56 | 12 | $zero = gmp_init('0'); |
|
57 | 12 | $radix = gmp_init($this->target->getRadix()); |
|
58 | 12 | $result = []; |
|
59 | |||
60 | 12 | while (gmp_cmp($decimal, $zero) > 0) { |
|
61 | 12 | list($decimal, $modulo) = gmp_div_qr($decimal, $radix); |
|
62 | 12 | $result[] = gmp_intval($modulo); |
|
63 | 4 | } |
|
64 | |||
65 | 12 | return $this->target->getDigits(empty($result) ? [0] : array_reverse($result)); |
|
66 | } |
||
67 | |||
68 | 60 | public function convertFractions(array $number) |
|
69 | { |
||
70 | 60 | $target = gmp_init($this->target->getRadix()); |
|
71 | 60 | $dividend = $this->getDecimal($number); |
|
72 | 60 | $divisor = $this->getDecimal( |
|
73 | 60 | [$this->source->getDigit(1)] + array_fill(1, max(count($number), 1), $this->source->getDigit(0)) |
|
74 | 20 | ); |
|
75 | 60 | $digits = $this->getFractionDigitCount(count($number)); |
|
76 | 60 | $zero = gmp_init('0'); |
|
77 | 60 | $result = []; |
|
78 | |||
79 | 60 | for ($i = 0; $i < $digits && gmp_cmp($dividend, $zero) > 0; $i++) { |
|
80 | 57 | list($digit, $dividend) = gmp_div_qr(gmp_mul($dividend, $target), $divisor); |
|
81 | 57 | $result[] = gmp_intval($digit); |
|
82 | 19 | } |
|
83 | |||
84 | 60 | return $this->target->getDigits(empty($result) ? [0] : $result); |
|
85 | } |
||
86 | |||
87 | /** |
||
88 | * Converts the number from source base to a decimal GMP resource. |
||
89 | * @param array $number Digits for the number to convert |
||
90 | * @return resource resulting number as a GMP resource |
||
|
|||
91 | */ |
||
92 | 105 | private function getDecimal(array $number) |
|
93 | { |
||
94 | 105 | if ($this->isStandardBase($this->source->getDigitList())) { |
|
95 | 96 | return gmp_init(implode('', $this->source->canonizeDigits($number)), $this->source->getRadix()); |
|
96 | } |
||
97 | |||
98 | 12 | $number = $this->source->getValues($number); |
|
99 | 12 | $decimal = gmp_init('0'); |
|
100 | 12 | $count = count($number); |
|
101 | 12 | $radix = gmp_init($this->source->getRadix()); |
|
102 | |||
103 | 12 | for ($i = 0; $i < $count; $i++) { |
|
104 | 12 | $decimal = gmp_add($decimal, gmp_mul(gmp_init($number[$i]), gmp_pow($radix, $count - $i - 1))); |
|
105 | 4 | } |
|
106 | |||
107 | 12 | return $decimal; |
|
108 | } |
||
109 | |||
110 | /** |
||
111 | * Tells if the list of digits match those used by GMP. |
||
112 | * @param array $digits List of digits for the number base |
||
113 | * @return bool True if the digits match, false if they do not |
||
114 | */ |
||
115 | 105 | private function isStandardBase(array $digits) |
|
123 | |||
124 | /** |
||
125 | * Determines the number of digits required in the target base. |
||
126 | * @param int $count Number of digits in the original number |
||
127 | * @return int Number of digits required in the target base |
||
128 | */ |
||
129 | 60 | private function getFractionDigitCount($count) |
|
145 | } |
||
146 |
This check compares the return type specified in the
@return
annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.