1 | <?php |
||
28 | class ReplaceConverter implements Converter |
||
29 | { |
||
30 | /** @var NumberBase Number base used by provided numbers */ |
||
31 | private $source; |
||
32 | |||
33 | /** @var NumberBase Number base used by returned numbers */ |
||
34 | private $target; |
||
35 | |||
36 | /** @var ReplaceConverter Converter used to convert into common root base */ |
||
37 | private $sourceConverter; |
||
38 | |||
39 | /** @var ReplaceConverter Converter used to convert from common root base */ |
||
40 | private $targetConverter; |
||
41 | |||
42 | /** @var array<string,string> String replacement table for converting numbers */ |
||
43 | private $conversionTable; |
||
44 | |||
45 | /** |
||
46 | * Create new instance of ReplaceConverter. |
||
47 | * |
||
48 | * ReplaceConverter only supports number base combinations that have a |
||
49 | * common root or if the target base is nth root of the source base. In |
||
50 | * addition, due to using string replacement, any number base that has |
||
51 | * conflicting string digits are not supported. |
||
52 | * |
||
53 | * @param NumberBase $source Number base used by the provided numbers |
||
54 | * @param NumberBase $target Number base used by the returned numbers |
||
55 | * @throws InvalidNumberBaseException If the number bases are not supported |
||
56 | */ |
||
57 | 126 | public function __construct(NumberBase $source, NumberBase $target) |
|
58 | { |
||
59 | 126 | $root = $this->getRoot($source, $target); |
|
60 | |||
61 | 108 | if ($root !== $source->getRadix() && $root !== $target->getRadix()) { |
|
62 | 45 | $proxy = new NumberBase($root); |
|
63 | 45 | $this->sourceConverter = new self($source, $proxy); |
|
64 | 45 | $this->targetConverter = new self($proxy, $target); |
|
65 | 15 | } else { |
|
66 | 108 | $this->source = $source; |
|
67 | 108 | $this->target = $target; |
|
68 | 108 | $this->conversionTable = $this->buildConversionTable(); |
|
69 | } |
||
70 | 108 | } |
|
71 | |||
72 | /** |
||
73 | * Determines the common root for the number bases. |
||
74 | * @param NumberBase $source Number base used by the provided numbers |
||
75 | * @param NumberBase $target Number base used by the returned numbers |
||
76 | * @return int The common root for the number bases |
||
77 | * @throws InvalidNumberBaseException If the number bases are not supported |
||
78 | */ |
||
79 | 126 | private function getRoot(NumberBase $source, NumberBase $target) |
|
93 | |||
94 | /** |
||
95 | * Creates string replacement table between source base and target base. |
||
96 | * @return array<string,string> String replacement table for converting numbers |
||
97 | */ |
||
98 | 108 | private function buildConversionTable() |
|
106 | |||
107 | /** |
||
108 | * Creates a conversion table between two lists of digits. |
||
109 | * @param string[] $source Digits for the number base with larger number of digits |
||
110 | * @param string[] $target Digits for the number base with smaller number of digits |
||
111 | * @return array<string,string> String replacement table for converting numbers |
||
112 | */ |
||
113 | 108 | private function createTable($source, $target) |
|
114 | { |
||
115 | 108 | $last = count($target) - 1; |
|
116 | 108 | $size = (int) log(count($source), count($target)); |
|
117 | 108 | $number = array_fill(0, $size, $target[0]); |
|
118 | 108 | $next = array_fill(0, $size, 0); |
|
119 | 108 | $limit = count($source); |
|
120 | 108 | $table = [$source[0] => implode('', $number)]; |
|
121 | |||
122 | 108 | for ($i = 1; $i < $limit; $i++) { |
|
123 | 108 | for ($j = $size - 1; $next[$j] === $last; $j--) { |
|
124 | 93 | $number[$j] = $target[0]; |
|
125 | 93 | $next[$j] = 0; |
|
126 | 31 | } |
|
127 | |||
128 | 108 | $number[$j] = $target[++$next[$j]]; |
|
129 | 108 | $table[$source[$i]] = implode('', $number); |
|
130 | 36 | } |
|
131 | |||
132 | 108 | return $table; |
|
133 | } |
||
134 | |||
135 | 12 | public function setPrecision($precision) |
|
139 | |||
140 | 75 | public function convertInteger(array $number) |
|
144 | |||
145 | 45 | public function convertFractions(array $number) |
|
149 | |||
150 | /** |
||
151 | * Converts the digits from source base to target base. |
||
152 | * @param array $number The digits to convert |
||
153 | * @param bool $fractions True if converting fractions, false if not |
||
154 | * @return array The digits converted to target base |
||
155 | */ |
||
156 | 93 | private function convert(array $number, $fractions = false) |
|
167 | |||
168 | /** |
||
169 | * Replace digits using string replacement. |
||
170 | * @param array $number The digits to convert |
||
171 | * @param bool $fractions True if converting fractions, false if not |
||
172 | * @return array The digits converted to target base |
||
173 | */ |
||
174 | 93 | private function replace(array $number, $fractions = false) |
|
181 | |||
182 | /** |
||
183 | * Pads the digits to correct count for string replacement. |
||
184 | * @param array $number Array of digits to pad |
||
185 | * @param bool $right True to pad from right, false to pad from left |
||
186 | * @return array Padded array of digits |
||
187 | */ |
||
188 | 87 | private function zeroPad(array $number, $right) |
|
199 | |||
200 | /** |
||
201 | * Trims extraneous zeroes from the digit list. |
||
202 | * @param array $number Array of digits to trim |
||
203 | * @param bool $right True to trim from right, false to trim from left |
||
204 | * @return array Trimmed array of digits |
||
205 | */ |
||
206 | 87 | private function zeroTrim(array $number, $right) |
|
216 | } |
||
217 |