Total Complexity | 112 |
Total Lines | 612 |
Duplicated Lines | 0 % |
Coverage | 100% |
Changes | 0 |
Complex classes like BC often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use BC, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
11 | class BC |
||
12 | { |
||
13 | public const COMPARE_EQUAL = 0; |
||
14 | public const COMPARE_LEFT_GRATER = 1; |
||
15 | public const COMPARE_RIGHT_GRATER = -1; |
||
16 | |||
17 | protected const DEFAULT_SCALE = 100; |
||
18 | |||
19 | protected const MAX_BASE = 256; |
||
20 | |||
21 | protected const BIT_OPERATOR_AND = 'and'; |
||
22 | protected const BIT_OPERATOR_OR = 'or'; |
||
23 | protected const BIT_OPERATOR_XOR = 'xor'; |
||
24 | |||
25 | 47 | public static function round(string $number, int $precision = 0): string |
|
26 | { |
||
27 | 47 | $number = self::convertScientificNotationToString($number); |
|
28 | 47 | if (self::checkIsFloat($number)) { |
|
29 | 36 | if (self::isNegative($number)) { |
|
30 | 4 | return self::sub($number, '0.' . str_repeat('0', $precision) . '5', $precision); |
|
31 | } |
||
32 | |||
33 | 32 | return self::add($number, '0.' . str_repeat('0', $precision) . '5', $precision); |
|
34 | } |
||
35 | |||
36 | 11 | return self::checkNumber($number); |
|
37 | } |
||
38 | |||
39 | 366 | public static function convertScientificNotationToString(string $number): string |
|
40 | { |
||
41 | // check if number is in scientific notation, first use stripos as is faster then preg_match |
||
42 | 366 | if (false !== stripos($number, 'E') && preg_match('/(-?(\d+\.)?\d+)E([+-]?)(\d+)/i', $number, $regs)) { |
|
43 | // calculate final scale of number |
||
44 | 60 | $scale = $regs[4] + self::getDecimalsLengthFromNumber($regs[1]); |
|
45 | 60 | $pow = self::pow('10', $regs[4], $scale); |
|
46 | 60 | if ('-' === $regs[3]) { |
|
47 | 25 | $number = self::div($regs[1], $pow, $scale); |
|
48 | } else { |
||
49 | 35 | $number = self::mul($pow, $regs[1], $scale); |
|
50 | } |
||
51 | // remove unnecessary 0 and dot from 0.000 is a 0 |
||
52 | 60 | $number = self::trimTrailingZeroes($number); |
|
53 | } |
||
54 | |||
55 | 366 | return self::checkNumber($number); |
|
56 | } |
||
57 | |||
58 | 92 | public static function getDecimalsLengthFromNumber(string $number): int |
|
59 | { |
||
60 | 92 | $check = explode('.', $number); |
|
61 | 92 | if (!empty($check[1])) { |
|
62 | 62 | return strlen($check[1]); |
|
63 | } |
||
64 | |||
65 | 30 | return 0; |
|
66 | } |
||
67 | |||
68 | 147 | public static function pow(string $leftOperand, string $rightOperand, ?int $scale = null): string |
|
69 | { |
||
70 | 147 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|
71 | 147 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|
72 | |||
73 | 147 | if (self::checkIsFloat($rightOperand)) { |
|
74 | 7 | if (null === $scale) { |
|
75 | 2 | return self::powFractional($leftOperand, $rightOperand); |
|
76 | } |
||
77 | |||
78 | 5 | return self::powFractional($leftOperand, $rightOperand, $scale); |
|
79 | } |
||
80 | |||
81 | 147 | if (null === $scale) { |
|
82 | 74 | return bcpow($leftOperand, $rightOperand); |
|
83 | } |
||
84 | |||
85 | 76 | return bcpow($leftOperand, $rightOperand, $scale); |
|
86 | } |
||
87 | |||
88 | 263 | protected static function checkIsFloat(string $number): bool |
|
89 | { |
||
90 | 263 | return false !== strpos($number, '.'); |
|
91 | } |
||
92 | |||
93 | 7 | protected static function powFractional(string $leftOperand, string $rightOperand, ?int $scale = null): string |
|
94 | { |
||
95 | // we need to increased scale to get correct results and avoid rounding error |
||
96 | 7 | $increasedScale = $scale ?? self::getScale(); |
|
97 | 7 | $increasedScale *= 2; |
|
98 | 7 | $decimals = explode('.', $rightOperand); |
|
99 | |||
100 | 7 | return self::checkNumber( |
|
101 | 7 | self::mul( |
|
102 | 7 | self::exp( |
|
103 | 7 | self::mul( |
|
104 | 7 | self::log($leftOperand), |
|
105 | 7 | '0.' . $decimals[1], |
|
106 | 7 | $increasedScale |
|
107 | ) |
||
108 | ), |
||
109 | 7 | self::pow($leftOperand, $decimals[0], $increasedScale), |
|
110 | 7 | $scale |
|
111 | ) |
||
112 | ); |
||
113 | } |
||
114 | |||
115 | 40 | public static function getScale(): int |
|
116 | { |
||
117 | 40 | $sqrt = self::sqrt('2'); |
|
118 | |||
119 | 40 | return strlen(substr($sqrt, strpos($sqrt, '.') + 1)); |
|
120 | } |
||
121 | |||
122 | 45 | public static function sqrt(string $operand, ?int $scale = null): string |
|
123 | { |
||
124 | 45 | $operand = self::convertScientificNotationToString($operand); |
|
125 | |||
126 | 45 | if (null === $scale) { |
|
127 | 41 | return bcsqrt($operand); |
|
128 | } |
||
129 | |||
130 | 5 | return bcsqrt($operand, $scale); |
|
131 | } |
||
132 | |||
133 | 366 | protected static function checkNumber(string $number): string |
|
134 | { |
||
135 | 366 | $number = str_replace('+', '', filter_var($number, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); |
|
136 | 366 | if ('-0' === $number || !is_numeric($number)) { |
|
137 | 27 | return '0'; |
|
138 | } |
||
139 | |||
140 | 363 | return $number; |
|
141 | } |
||
142 | |||
143 | 167 | public static function mul(string $leftOperand, string $rightOperand, ?int $scale = null): string |
|
144 | { |
||
145 | 167 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|
146 | 167 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|
147 | |||
148 | 167 | if (null === $scale) { |
|
149 | 60 | return bcmul($leftOperand, $rightOperand); |
|
150 | } |
||
151 | |||
152 | 109 | return bcmul($leftOperand, $rightOperand, $scale); |
|
153 | } |
||
154 | |||
155 | 15 | public static function exp(string $arg): string |
|
156 | { |
||
157 | 15 | $scale = self::DEFAULT_SCALE; |
|
158 | 15 | $result = '1'; |
|
159 | 15 | for ($i = 299; $i > 0; $i--) { |
|
160 | 15 | $result = self::add(self::mul(self::div($result, (string)$i, $scale), $arg, $scale), (string)1, $scale); |
|
161 | } |
||
162 | |||
163 | 15 | return $result; |
|
164 | } |
||
165 | |||
166 | 160 | public static function add(string $leftOperand, string $rightOperand, ?int $scale = null): string |
|
167 | { |
||
168 | 160 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|
169 | 160 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|
170 | |||
171 | 160 | if (null === $scale) { |
|
172 | 41 | return bcadd($leftOperand, $rightOperand); |
|
173 | } |
||
174 | |||
175 | 122 | return bcadd($leftOperand, $rightOperand, $scale); |
|
176 | } |
||
177 | |||
178 | 131 | public static function div(string $leftOperand, string $rightOperand, ?int $scale = null): string |
|
179 | { |
||
180 | 131 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|
181 | 131 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|
182 | |||
183 | 131 | if ('0' === self::trimTrailingZeroes($rightOperand)) { |
|
184 | 1 | throw new InvalidArgumentException('Division by zero'); |
|
185 | } |
||
186 | |||
187 | 130 | if (null === $scale) { |
|
188 | 45 | return bcdiv($leftOperand, $rightOperand); |
|
1 ignored issue
–
show
|
|||
189 | } |
||
190 | |||
191 | 93 | return bcdiv($leftOperand, $rightOperand, $scale); |
|
1 ignored issue
–
show
|
|||
192 | } |
||
193 | |||
194 | 12 | public static function log(string $arg): string |
|
195 | { |
||
196 | 12 | $arg = self::convertScientificNotationToString($arg); |
|
197 | 12 | if ($arg === '0') { |
|
198 | 1 | return '-INF'; |
|
199 | } |
||
200 | 11 | if (self::COMPARE_RIGHT_GRATER === self::comp($arg, '0')) { |
|
201 | 1 | return 'NAN'; |
|
202 | } |
||
203 | 10 | $scale = self::DEFAULT_SCALE; |
|
204 | 10 | $m = (string)log((float)$arg); |
|
205 | 10 | $x = self::sub(self::div($arg, self::exp($m), $scale), '1', $scale); |
|
206 | 10 | $res = '0'; |
|
207 | 10 | $pow = '1'; |
|
208 | 10 | $i = 1; |
|
209 | do { |
||
210 | 10 | $pow = self::mul($pow, $x, $scale); |
|
211 | 10 | $sum = self::div($pow, (string)$i, $scale); |
|
212 | 10 | if ($i % 2 === 1) { |
|
213 | 10 | $res = self::add($res, $sum, $scale); |
|
214 | } else { |
||
215 | 9 | $res = self::sub($res, $sum, $scale); |
|
216 | } |
||
217 | 10 | $i++; |
|
218 | 10 | } while (self::comp($sum, '0', $scale)); |
|
219 | |||
220 | 10 | return self::add($res, $m, $scale); |
|
221 | } |
||
222 | |||
223 | 64 | public static function comp(string $leftOperand, string $rightOperand, ?int $scale = null): int |
|
224 | { |
||
225 | 64 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|
226 | 64 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|
227 | |||
228 | 64 | if (null === $scale) { |
|
229 | 53 | return bccomp($leftOperand, $rightOperand, max(strlen($leftOperand), strlen($rightOperand))); |
|
230 | } |
||
231 | |||
232 | 21 | return bccomp( |
|
233 | 21 | $leftOperand, |
|
234 | 21 | $rightOperand, |
|
235 | 21 | $scale |
|
236 | ); |
||
237 | } |
||
238 | |||
239 | 78 | public static function sub(string $leftOperand, string $rightOperand, ?int $scale = null): string |
|
240 | { |
||
241 | 78 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|
242 | 78 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|
243 | |||
244 | 78 | if (null === $scale) { |
|
245 | 47 | return bcsub($leftOperand, $rightOperand); |
|
246 | } |
||
247 | |||
248 | 33 | return bcsub($leftOperand, $rightOperand, $scale); |
|
249 | } |
||
250 | |||
251 | 185 | protected static function trimTrailingZeroes(string $number): string |
|
252 | { |
||
253 | 185 | if (false !== strpos($number, '.')) { |
|
254 | 124 | $number = rtrim($number, '0'); |
|
255 | } |
||
256 | |||
257 | 185 | return rtrim($number, '.') ?: '0'; |
|
258 | } |
||
259 | |||
260 | 148 | protected static function isNegative(string $number): bool |
|
261 | { |
||
262 | 148 | return 0 === strncmp('-', $number, 1); |
|
263 | } |
||
264 | |||
265 | 2 | public static function rand(string $min, string $max): string |
|
266 | { |
||
267 | 2 | $max = self::convertScientificNotationToString($max); |
|
268 | 2 | $min = self::convertScientificNotationToString($min); |
|
269 | |||
270 | 2 | $difference = self::add(self::sub($max, $min), '1'); |
|
271 | 2 | $randPercent = self::div((string)mt_rand(), (string)mt_getrandmax(), 8); |
|
272 | |||
273 | 2 | return self::add($min, self::mul($difference, $randPercent, 8), 0); |
|
274 | } |
||
275 | |||
276 | 1 | public static function max(/* args... */): ?string |
|
277 | { |
||
278 | 1 | $max = null; |
|
279 | 1 | foreach (self::getArgs(func_get_args()) as $number) { |
|
280 | 1 | $number = self::convertScientificNotationToString((string)$number); |
|
281 | 1 | if (null === $max) { |
|
282 | 1 | $max = $number; |
|
283 | 1 | } elseif (self::comp((string)$max, $number) === self::COMPARE_RIGHT_GRATER) { |
|
284 | 1 | $max = $number; |
|
285 | } |
||
286 | } |
||
287 | |||
288 | 1 | return $max; |
|
289 | } |
||
290 | |||
291 | 1 | public static function min(/* args... */): ?string |
|
292 | { |
||
293 | 1 | $min = null; |
|
294 | 1 | foreach (self::getArgs(func_get_args()) as $number) { |
|
295 | 1 | $number = self::convertScientificNotationToString((string)$number); |
|
296 | 1 | if (null === $min) { |
|
297 | 1 | $min = $number; |
|
298 | 1 | } elseif (self::comp((string)$min, $number) === self::COMPARE_LEFT_GRATER) { |
|
299 | 1 | $min = $number; |
|
300 | } |
||
301 | } |
||
302 | |||
303 | 1 | return $min; |
|
304 | } |
||
305 | |||
306 | 17 | public static function roundDown(string $number, int $precision = 0): string |
|
307 | { |
||
308 | 17 | $number = self::convertScientificNotationToString($number); |
|
309 | 17 | $multiply = self::pow('10', (string)abs($precision)); |
|
310 | |||
311 | 17 | return $precision < 0 |
|
312 | ? |
||
313 | 4 | self::mul( |
|
314 | 4 | self::floor(self::div($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply, |
|
315 | 4 | $precision |
|
316 | ) |
||
317 | : |
||
318 | 13 | self::div( |
|
319 | 13 | self::floor(self::mul($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply, |
|
320 | 17 | $precision |
|
321 | ); |
||
322 | } |
||
323 | |||
324 | 98 | public static function floor(string $number): string |
|
336 | } |
||
337 | |||
338 | 68 | protected static function checkIsFloatCleanZeros(string &$number): bool |
|
341 | } |
||
342 | |||
343 | 17 | public static function roundUp(string $number, int $precision = 0): string |
|
344 | { |
||
345 | 17 | $number = self::convertScientificNotationToString($number); |
|
346 | 17 | $multiply = self::pow('10', (string)abs($precision)); |
|
347 | |||
348 | 17 | return $precision < 0 |
|
349 | ? |
||
350 | 4 | self::mul( |
|
351 | 4 | self::ceil(self::div($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply, |
|
352 | 4 | $precision |
|
353 | ) |
||
354 | : |
||
355 | 13 | self::div( |
|
356 | 13 | self::ceil(self::mul($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply, |
|
357 | 17 | $precision |
|
358 | ); |
||
359 | } |
||
360 | |||
361 | 41 | public static function ceil(string $number): string |
|
362 | { |
||
363 | 41 | $number = self::convertScientificNotationToString($number); |
|
364 | 41 | if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) { |
|
365 | 22 | $result = 1; |
|
366 | 22 | if (self::isNegative($number)) { |
|
367 | 5 | --$result; |
|
368 | } |
||
369 | 22 | $number = self::add($number, (string)$result, 0); |
|
370 | } |
||
371 | |||
372 | 41 | return self::checkNumber($number); |
|
373 | } |
||
374 | |||
375 | 10 | public static function powMod( |
|
376 | string $leftOperand, |
||
377 | string $rightOperand, |
||
378 | string $modulus, |
||
379 | ?int $scale = null |
||
380 | ): string { |
||
381 | 10 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|
382 | 10 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|
383 | |||
384 | // bcpowmod in 5.6 have don't calculate correct results if scale is empty |
||
385 | 10 | if (null === $scale) { |
|
386 | 4 | return self::mod(self::pow($leftOperand, $rightOperand), $modulus); |
|
387 | } |
||
388 | |||
389 | // cant use bcpowmod here as it don't support floats |
||
390 | 6 | if (self::checkIsFloat($leftOperand) || self::checkIsFloat($rightOperand) || self::checkIsFloat($modulus)) { |
|
391 | 2 | return self::mod(self::pow($leftOperand, $rightOperand, $scale), $modulus, $scale); |
|
392 | } |
||
393 | |||
394 | 4 | return bcpowmod($leftOperand, $rightOperand, $modulus, $scale); |
|
395 | } |
||
396 | |||
397 | 56 | public static function mod(string $leftOperand, string $modulus, ?int $scale = null): string |
|
398 | { |
||
399 | 56 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|
400 | |||
401 | // bcmod in 7.2 is not working properly - for example bcmod(9.9999E-10, -0.00056, 9) should return '-0.000559999' but returns 0.0000000 |
||
402 | |||
403 | // bcmod in php 5.6< don't support scale and floats |
||
404 | // let use this $x - floor($x/$y) * $y; |
||
405 | 56 | if (null === $scale) { |
|
406 | 44 | return self::sub($leftOperand, self::mul(self::floor(self::div($leftOperand, $modulus)), $modulus)); |
|
407 | } |
||
408 | |||
409 | 12 | return self::sub( |
|
410 | 12 | $leftOperand, self::mul(self::floor(self::div($leftOperand, $modulus, $scale)), $modulus, $scale), $scale |
|
411 | ); |
||
412 | } |
||
413 | |||
414 | 8 | public static function fact(string $arg): string |
|
415 | { |
||
416 | 8 | $arg = self::convertScientificNotationToString($arg); |
|
417 | |||
418 | 8 | if (self::checkIsFloat($arg)) { |
|
419 | 1 | throw new InvalidArgumentException('Number has to be an integer'); |
|
420 | } |
||
421 | 7 | if (self::isNegative($arg)) { |
|
422 | 1 | throw new InvalidArgumentException('Number has to be greater than or equal to 0'); |
|
423 | } |
||
424 | |||
425 | 6 | $return = '1'; |
|
426 | 6 | for ($i = 2; $i <= $arg; ++$i) { |
|
427 | 5 | $return = self::mul($return, (string)$i); |
|
428 | } |
||
429 | |||
430 | 6 | return $return; |
|
431 | } |
||
432 | |||
433 | 5 | public static function hexdec(string $hex): string |
|
434 | { |
||
435 | 5 | $remainingDigits = substr($hex, 0, -1); |
|
436 | 5 | $lastDigitToDecimal = (string)hexdec(substr($hex, -1)); |
|
437 | |||
438 | 5 | if ('' === $remainingDigits) { |
|
439 | 5 | return $lastDigitToDecimal; |
|
440 | } |
||
441 | |||
442 | 5 | return self::add(self::mul('16', self::hexdec($remainingDigits)), $lastDigitToDecimal, 0); |
|
443 | } |
||
444 | |||
445 | 6 | public static function dechex(string $decimal): string |
|
455 | } |
||
456 | |||
457 | 12 | public static function bitAnd |
|
458 | ( |
||
459 | string $leftOperand, |
||
460 | string $rightOperand |
||
461 | ): string |
||
462 | { |
||
463 | 12 | return self::bitOperatorHelper($leftOperand, $rightOperand, self::BIT_OPERATOR_AND); |
|
464 | } |
||
465 | |||
466 | 36 | protected static function bitOperatorHelper(string $leftOperand, string $rightOperand, string $operator): string |
|
467 | { |
||
468 | 36 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|
469 | 36 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|
470 | |||
471 | 36 | if (self::checkIsFloat($leftOperand)) { |
|
472 | 3 | throw new InvalidArgumentException('Left operator has to be an integer'); |
|
473 | } |
||
474 | 33 | if (self::checkIsFloat($rightOperand)) { |
|
475 | 3 | throw new InvalidArgumentException('Right operator has to be an integer'); |
|
476 | } |
||
477 | |||
478 | 30 | $leftOperandNegative = self::isNegative($leftOperand); |
|
479 | 30 | $rightOperandNegative = self::isNegative($rightOperand); |
|
480 | |||
481 | 30 | $leftOperand = self::dec2bin(self::abs($leftOperand)); |
|
482 | 30 | $rightOperand = self::dec2bin(self::abs($rightOperand)); |
|
483 | |||
484 | 30 | $maxLength = max(strlen($leftOperand), strlen($rightOperand)); |
|
485 | |||
486 | 30 | $leftOperand = self::alignBinLength($leftOperand, $maxLength); |
|
487 | 30 | $rightOperand = self::alignBinLength($rightOperand, $maxLength); |
|
488 | |||
489 | 30 | if ($leftOperandNegative) { |
|
490 | 7 | $leftOperand = self::recalculateNegative($leftOperand); |
|
491 | } |
||
492 | 30 | if ($rightOperandNegative) { |
|
493 | 7 | $rightOperand = self::recalculateNegative($rightOperand); |
|
494 | } |
||
495 | |||
496 | 30 | $isNegative = false; |
|
497 | 30 | $result = ''; |
|
498 | 30 | if (self::BIT_OPERATOR_AND === $operator) { |
|
499 | 10 | $result = $leftOperand & $rightOperand; |
|
500 | 10 | $isNegative = ($leftOperandNegative and $rightOperandNegative); |
|
501 | 20 | } elseif (self::BIT_OPERATOR_OR === $operator) { |
|
502 | 12 | $result = $leftOperand | $rightOperand; |
|
503 | 12 | $isNegative = ($leftOperandNegative or $rightOperandNegative); |
|
504 | 8 | } elseif (self::BIT_OPERATOR_XOR === $operator) { |
|
505 | 8 | $result = $leftOperand ^ $rightOperand; |
|
506 | 8 | $isNegative = ($leftOperandNegative xor $rightOperandNegative); |
|
507 | } |
||
508 | |||
509 | 30 | if ($isNegative) { |
|
510 | 8 | $result = self::recalculateNegative($result); |
|
511 | } |
||
512 | |||
513 | 30 | $result = self::bin2dec($result); |
|
514 | |||
515 | 30 | return $isNegative ? '-' . $result : $result; |
|
516 | } |
||
517 | |||
518 | 36 | public static function dec2bin(string $number, int $base = self::MAX_BASE): string |
|
519 | { |
||
520 | 36 | return self::decBaseHelper( |
|
521 | $base, static function (int $base) use ($number) { |
||
522 | 35 | $value = ''; |
|
523 | 35 | if ('0' === $number) { |
|
524 | 30 | return chr((int)$number); |
|
525 | } |
||
526 | |||
527 | 33 | while (BC::comp($number, '0') !== BC::COMPARE_EQUAL) { |
|
528 | 33 | $rest = BC::mod($number, (string)$base); |
|
529 | 33 | $number = BC::div($number, (string)$base); |
|
530 | 33 | $value = chr((int)$rest) . $value; |
|
531 | } |
||
532 | |||
533 | 33 | return $value; |
|
534 | 36 | } |
|
535 | ); |
||
536 | } |
||
537 | |||
538 | 37 | protected static function decBaseHelper(int $base, Closure $closure): string |
|
539 | { |
||
540 | 37 | if ($base < 2 || $base > self::MAX_BASE) { |
|
541 | 2 | throw new InvalidArgumentException('Invalid Base: ' . $base); |
|
542 | } |
||
543 | 35 | $orgScale = self::getScale(); |
|
544 | 35 | self::setScale(0); |
|
545 | |||
546 | 35 | $value = $closure($base); |
|
547 | |||
548 | 35 | self::setScale($orgScale); |
|
549 | |||
550 | 35 | return $value; |
|
551 | } |
||
552 | |||
553 | 368 | public static function setScale(int $scale): void |
|
554 | { |
||
555 | 368 | bcscale($scale); |
|
556 | 368 | } |
|
557 | |||
558 | 45 | public static function abs(string $number): string |
|
559 | { |
||
560 | 45 | $number = self::convertScientificNotationToString($number); |
|
561 | |||
562 | 45 | if (self::isNegative($number)) { |
|
563 | 19 | $number = (string)substr($number, 1); |
|
564 | } |
||
565 | |||
566 | 45 | return self::checkNumber($number); |
|
567 | } |
||
568 | |||
569 | 30 | protected static function alignBinLength(string $string, int $length): string |
|
570 | { |
||
571 | 30 | return str_pad($string, $length, self::dec2bin('0'), STR_PAD_LEFT); |
|
572 | } |
||
573 | |||
574 | 11 | protected static function recalculateNegative(string $number): string |
|
575 | { |
||
576 | 11 | $xor = str_repeat(self::dec2bin((string)(self::MAX_BASE - 1)), strlen($number)); |
|
577 | 11 | $number ^= $xor; |
|
578 | 11 | for ($i = strlen($number) - 1; $i >= 0; $i--) { |
|
579 | 11 | $byte = ord($number[$i]); |
|
580 | 11 | if (++$byte !== self::MAX_BASE) { |
|
581 | 11 | $number[$i] = chr($byte); |
|
582 | 11 | break; |
|
583 | } |
||
584 | } |
||
585 | |||
586 | 11 | return $number; |
|
587 | } |
||
588 | |||
589 | 36 | public static function bin2dec(string $binary, int $base = self::MAX_BASE): string |
|
602 | 36 | } |
|
603 | ); |
||
604 | } |
||
605 | |||
606 | 14 | public static function bitOr(string $leftOperand, string $rightOperand): string |
|
607 | { |
||
608 | 14 | return self::bitOperatorHelper($leftOperand, $rightOperand, self::BIT_OPERATOR_OR); |
|
609 | } |
||
610 | |||
611 | 10 | public static function bitXor(string $leftOperand, string $rightOperand): string |
|
612 | { |
||
613 | 10 | return self::bitOperatorHelper($leftOperand, $rightOperand, self::BIT_OPERATOR_XOR); |
|
614 | } |
||
615 | |||
616 | 2 | protected static function getArgs(array $args): array |
|
623 | } |
||
624 | } |
||
625 |