1 | <?php |
||||
2 | |||||
3 | namespace BCMathExtended; |
||||
4 | |||||
5 | /** |
||||
6 | * Class BC |
||||
7 | * @package BCMathExtended |
||||
8 | */ |
||||
9 | class BC |
||||
10 | { |
||||
11 | const COMPARE_EQUAL = 0; |
||||
12 | const COMPARE_LEFT_GRATER = 1; |
||||
13 | const COMPARE_RIGHT_GRATER = -1; |
||||
14 | |||||
15 | const DEFAULT_SCALE = 100; |
||||
16 | |||||
17 | const MAX_BASE = 256; |
||||
18 | |||||
19 | const BIT_OPERATOR_AND = 'and'; |
||||
20 | const BIT_OPERATOR_OR = 'or'; |
||||
21 | const BIT_OPERATOR_XOR = 'xor'; |
||||
22 | |||||
23 | /** |
||||
24 | * @param int|string $number |
||||
25 | * @param int $precision |
||||
26 | * @return string |
||||
27 | */ |
||||
28 | 47 | public static function round($number, $precision = 0) |
|||
29 | { |
||||
30 | 47 | $number = self::convertScientificNotationToString($number); |
|||
31 | 47 | if (self::checkIsFloat($number)) { |
|||
32 | 36 | if (self::isNegative($number)) { |
|||
33 | 4 | return self::sub($number, '0.' . str_repeat('0', $precision) . '5', $precision); |
|||
34 | } |
||||
35 | |||||
36 | 32 | return self::add($number, '0.' . str_repeat('0', $precision) . '5', $precision); |
|||
37 | } |
||||
38 | |||||
39 | 11 | return self::checkNumber($number); |
|||
40 | } |
||||
41 | |||||
42 | /** |
||||
43 | * @param int|string|float $number |
||||
44 | * @return string |
||||
45 | */ |
||||
46 | 365 | public static function convertScientificNotationToString($number) |
|||
47 | { |
||||
48 | // check if number is in scientific notation, first use stripos as is faster then preg_match |
||||
49 | 365 | if (false !== stripos($number, 'E') && preg_match('/(-?(\d+\.)?\d+)E([+-]?)(\d+)/i', $number, $regs)) { |
|||
50 | // calculate final scale of number |
||||
51 | 60 | $scale = $regs[4] + self::getDecimalsLengthFromNumber($regs[1]); |
|||
52 | 60 | $pow = self::pow(10, $regs[4], $scale); |
|||
53 | 60 | if ('-' === $regs[3]) { |
|||
54 | 25 | $number = self::div($regs[1], $pow, $scale); |
|||
55 | } else { |
||||
56 | 35 | $number = self::mul($pow, $regs[1], $scale); |
|||
57 | } |
||||
58 | // remove unnecessary 0 and dot from 0.000 is a 0 |
||||
59 | 60 | $number = self::trimTrailingZeroes($number); |
|||
0 ignored issues
–
show
|
|||||
60 | } |
||||
61 | |||||
62 | 365 | return self::checkNumber($number); |
|||
63 | } |
||||
64 | |||||
65 | /** |
||||
66 | * @param int|string|float $number |
||||
67 | * @return void |
||||
68 | */ |
||||
69 | 121 | private static function trimTrailingZeroes($number) { |
|||
70 | 121 | if (false !== strpos($number, '.')) { |
|||
71 | 116 | $number = rtrim($number, '0'); |
|||
72 | } |
||||
73 | 121 | return rtrim($number, '.') ?: '0'; |
|||
0 ignored issues
–
show
|
|||||
74 | } |
||||
75 | |||||
76 | /** |
||||
77 | * @param int|string|float $number |
||||
78 | * @return int |
||||
79 | */ |
||||
80 | 92 | public static function getDecimalsLengthFromNumber($number) |
|||
81 | { |
||||
82 | 92 | $check = explode('.', $number); |
|||
83 | 92 | if (!empty($check[1])) { |
|||
84 | 62 | return strlen($check[1]); |
|||
85 | } |
||||
86 | |||||
87 | 30 | return 0; |
|||
88 | } |
||||
89 | |||||
90 | /** |
||||
91 | * @param string $leftOperand |
||||
92 | * @param string $rightOperand |
||||
93 | * @param null|int $scale |
||||
94 | * @return string |
||||
95 | */ |
||||
96 | 147 | public static function pow($leftOperand, $rightOperand, $scale = null) |
|||
97 | { |
||||
98 | 147 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|||
99 | 147 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|||
100 | |||||
101 | 147 | if (self::checkIsFloat($rightOperand)) { |
|||
102 | 7 | if (null === $scale) { |
|||
103 | 2 | return self::powFractional($leftOperand, $rightOperand); |
|||
104 | } |
||||
105 | |||||
106 | 5 | return self::powFractional($leftOperand, $rightOperand, $scale); |
|||
107 | } |
||||
108 | |||||
109 | 147 | if (null === $scale) { |
|||
110 | 74 | return bcpow($leftOperand, $rightOperand); |
|||
111 | } |
||||
112 | |||||
113 | 76 | return bcpow($leftOperand, $rightOperand, $scale); |
|||
114 | } |
||||
115 | |||||
116 | /** |
||||
117 | * @param int|string $number |
||||
118 | * @return bool |
||||
119 | */ |
||||
120 | 263 | private static function checkIsFloat($number) |
|||
121 | { |
||||
122 | 263 | return false !== strpos($number, '.'); |
|||
123 | } |
||||
124 | |||||
125 | /** |
||||
126 | * @param string $leftOperand |
||||
127 | * @param string $rightOperand |
||||
128 | * @param null|int $scale |
||||
129 | * @return string |
||||
130 | */ |
||||
131 | 7 | private static function powFractional($leftOperand, $rightOperand, $scale = null) |
|||
132 | { |
||||
133 | // we need to increased scale to get correct results and avoid rounding error |
||||
134 | 7 | $increasedScale = null === $scale ? self::getScale() : $scale; |
|||
135 | 7 | $increasedScale *= 2; |
|||
136 | 7 | $decimals = explode('.', $rightOperand); |
|||
137 | |||||
138 | 7 | return self::checkNumber( |
|||
139 | 7 | self::mul( |
|||
140 | 7 | self::exp( |
|||
141 | 7 | self::mul( |
|||
142 | 7 | self::log($leftOperand), |
|||
143 | 7 | '0.' . $decimals[1], |
|||
144 | 7 | $increasedScale |
|||
145 | ) |
||||
146 | ), |
||||
147 | 7 | self::pow($leftOperand, $decimals[0], $increasedScale), |
|||
148 | 7 | $scale |
|||
149 | ) |
||||
150 | ); |
||||
151 | } |
||||
152 | |||||
153 | /** |
||||
154 | * @return int |
||||
155 | */ |
||||
156 | 40 | public static function getScale() |
|||
157 | { |
||||
158 | 40 | $sqrt = self::sqrt('2'); |
|||
159 | |||||
160 | 40 | return strlen(substr($sqrt, strpos($sqrt, '.') + 1)); |
|||
161 | } |
||||
162 | |||||
163 | /** |
||||
164 | * @param string $operand |
||||
165 | * @param null|int $scale |
||||
166 | * @return string |
||||
167 | */ |
||||
168 | 45 | public static function sqrt($operand, $scale = null) |
|||
169 | { |
||||
170 | 45 | $operand = self::convertScientificNotationToString($operand); |
|||
171 | |||||
172 | 45 | if (null === $scale) { |
|||
173 | 41 | return bcsqrt($operand); |
|||
174 | } |
||||
175 | |||||
176 | 5 | return bcsqrt($operand, $scale); |
|||
177 | } |
||||
178 | |||||
179 | /** |
||||
180 | * @param int|string $number |
||||
181 | * @return int|string |
||||
182 | */ |
||||
183 | 365 | private static function checkNumber($number) |
|||
184 | { |
||||
185 | 365 | $number = str_replace('+', '', filter_var($number, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); |
|||
186 | 365 | if ('-0' === $number || !is_numeric($number)) { |
|||
187 | 27 | return '0'; |
|||
188 | } |
||||
189 | |||||
190 | 362 | return $number; |
|||
191 | } |
||||
192 | |||||
193 | /** |
||||
194 | * @param string $leftOperand |
||||
195 | * @param string $rightOperand |
||||
196 | * @param null|int $scale |
||||
197 | * @return string |
||||
198 | */ |
||||
199 | 167 | public static function mul($leftOperand, $rightOperand, $scale = null) |
|||
200 | { |
||||
201 | 167 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|||
202 | 167 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|||
203 | |||||
204 | 167 | if (null === $scale) { |
|||
205 | 60 | return bcmul($leftOperand, $rightOperand); |
|||
206 | } |
||||
207 | |||||
208 | 109 | return bcmul($leftOperand, $rightOperand, $scale); |
|||
209 | } |
||||
210 | |||||
211 | /** |
||||
212 | * @param string $arg |
||||
213 | * @return string |
||||
214 | */ |
||||
215 | 15 | public static function exp($arg) |
|||
216 | { |
||||
217 | 15 | $scale = self::DEFAULT_SCALE; |
|||
218 | 15 | $result = '1'; |
|||
219 | 15 | for ($i = 299; $i > 0; $i--) { |
|||
220 | 15 | $result = self::add(self::mul(self::div($result, $i, $scale), $arg, $scale), 1, $scale); |
|||
221 | } |
||||
222 | |||||
223 | 15 | return $result; |
|||
224 | } |
||||
225 | |||||
226 | /** |
||||
227 | * @param string $leftOperand |
||||
228 | * @param string $rightOperand |
||||
229 | * @param null|int $scale |
||||
230 | * @return string |
||||
231 | */ |
||||
232 | 160 | public static function add($leftOperand, $rightOperand, $scale = null) |
|||
233 | { |
||||
234 | 160 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|||
235 | 160 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|||
236 | |||||
237 | 160 | if (null === $scale) { |
|||
238 | 41 | return bcadd($leftOperand, $rightOperand); |
|||
239 | } |
||||
240 | |||||
241 | 122 | return bcadd($leftOperand, $rightOperand, $scale); |
|||
242 | } |
||||
243 | |||||
244 | /** |
||||
245 | * @param string $leftOperand |
||||
246 | * @param string $rightOperand |
||||
247 | * @param null|int $scale |
||||
248 | * @return string |
||||
249 | */ |
||||
250 | 130 | public static function div($leftOperand, $rightOperand, $scale = null) |
|||
251 | { |
||||
252 | 130 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|||
253 | 130 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|||
254 | |||||
255 | 130 | if (null === $scale) { |
|||
256 | 45 | return bcdiv($leftOperand, $rightOperand); |
|||
257 | } |
||||
258 | |||||
259 | 93 | return bcdiv($leftOperand, $rightOperand, $scale); |
|||
260 | } |
||||
261 | |||||
262 | /** |
||||
263 | * @param string $arg |
||||
264 | * @return string |
||||
265 | */ |
||||
266 | 12 | public static function log($arg) |
|||
267 | { |
||||
268 | 12 | $arg = self::convertScientificNotationToString($arg); |
|||
269 | 12 | if ($arg === '0') { |
|||
270 | 1 | return '-INF'; |
|||
271 | } |
||||
272 | 11 | if (self::COMPARE_RIGHT_GRATER === self::comp($arg, '0')) { |
|||
273 | 1 | return 'NAN'; |
|||
274 | } |
||||
275 | 10 | $scale = self::DEFAULT_SCALE; |
|||
276 | 10 | $m = (string)log((float)$arg); |
|||
277 | 10 | $x = self::sub(self::div($arg, self::exp($m), $scale), '1', $scale); |
|||
278 | 10 | $res = '0'; |
|||
279 | 10 | $pow = '1'; |
|||
280 | 10 | $i = 1; |
|||
281 | do { |
||||
282 | 10 | $pow = self::mul($pow, $x, $scale); |
|||
283 | 10 | $sum = self::div($pow, $i, $scale); |
|||
284 | 10 | if ($i % 2 === 1) { |
|||
285 | 10 | $res = self::add($res, $sum, $scale); |
|||
286 | } else { |
||||
287 | 9 | $res = self::sub($res, $sum, $scale); |
|||
288 | } |
||||
289 | 10 | $i++; |
|||
290 | 10 | } while (self::comp($sum, '0', $scale)); |
|||
291 | |||||
292 | 10 | return self::add($res, $m, $scale); |
|||
293 | } |
||||
294 | |||||
295 | /** |
||||
296 | * @param string $leftOperand |
||||
297 | * @param string $rightOperand |
||||
298 | * @param null|int $scale |
||||
299 | * @return int |
||||
300 | */ |
||||
301 | 64 | public static function comp($leftOperand, $rightOperand, $scale = null) |
|||
302 | { |
||||
303 | 64 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|||
304 | 64 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|||
305 | |||||
306 | 64 | if (null === $scale) { |
|||
307 | 53 | return bccomp($leftOperand, $rightOperand, max(strlen($leftOperand), strlen($rightOperand))); |
|||
308 | } |
||||
309 | |||||
310 | 21 | return bccomp( |
|||
311 | 21 | $leftOperand, |
|||
312 | 21 | $rightOperand, |
|||
313 | 21 | $scale |
|||
314 | ); |
||||
315 | } |
||||
316 | |||||
317 | /** |
||||
318 | * @param string $leftOperand |
||||
319 | * @param string $rightOperand |
||||
320 | * @param null|int $scale |
||||
321 | * @return string |
||||
322 | */ |
||||
323 | 78 | public static function sub($leftOperand, $rightOperand, $scale = null) |
|||
324 | { |
||||
325 | 78 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|||
326 | 78 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|||
327 | |||||
328 | 78 | if (null === $scale) { |
|||
329 | 47 | return bcsub($leftOperand, $rightOperand); |
|||
330 | } |
||||
331 | |||||
332 | 33 | return bcsub($leftOperand, $rightOperand, $scale); |
|||
333 | } |
||||
334 | |||||
335 | /** |
||||
336 | * @param $number |
||||
337 | * @return bool |
||||
338 | */ |
||||
339 | 148 | private static function isNegative($number) |
|||
340 | { |
||||
341 | 148 | return 0 === strncmp('-', $number, 1); |
|||
342 | } |
||||
343 | |||||
344 | /** |
||||
345 | * @param int|string $min |
||||
346 | * @param int|string $max |
||||
347 | * @return string |
||||
348 | */ |
||||
349 | 2 | public static function rand($min, $max) |
|||
350 | { |
||||
351 | 2 | $max = self::convertScientificNotationToString($max); |
|||
352 | 2 | $min = self::convertScientificNotationToString($min); |
|||
353 | |||||
354 | 2 | $difference = self::add(self::sub($max, $min), 1); |
|||
355 | 2 | $randPercent = self::div(mt_rand(), mt_getrandmax(), 8); |
|||
356 | |||||
357 | 2 | return self::add($min, self::mul($difference, $randPercent, 8), 0); |
|||
358 | } |
||||
359 | |||||
360 | /** |
||||
361 | * @param array|int|string,... |
||||
362 | * @return null|string |
||||
363 | */ |
||||
364 | 1 | public static function max() |
|||
365 | { |
||||
366 | 1 | $max = null; |
|||
367 | 1 | $args = func_get_args(); |
|||
368 | 1 | if (is_array($args[0])) { |
|||
369 | 1 | $args = $args[0]; |
|||
370 | } |
||||
371 | 1 | foreach ($args as $number) { |
|||
372 | 1 | $number = self::convertScientificNotationToString($number); |
|||
373 | 1 | if (null === $max) { |
|||
374 | 1 | $max = $number; |
|||
375 | 1 | } elseif (self::comp((string)$max, $number) === self::COMPARE_RIGHT_GRATER) { |
|||
376 | 1 | $max = $number; |
|||
377 | } |
||||
378 | } |
||||
379 | |||||
380 | 1 | return $max; |
|||
381 | } |
||||
382 | |||||
383 | /** |
||||
384 | * @param array|int|string,... |
||||
385 | * @return null|string |
||||
386 | */ |
||||
387 | 1 | public static function min() |
|||
388 | { |
||||
389 | 1 | $min = null; |
|||
390 | 1 | $args = func_get_args(); |
|||
391 | 1 | if (is_array($args[0])) { |
|||
392 | 1 | $args = $args[0]; |
|||
393 | } |
||||
394 | 1 | foreach ($args as $number) { |
|||
395 | 1 | $number = self::convertScientificNotationToString($number); |
|||
396 | 1 | if (null === $min) { |
|||
397 | 1 | $min = $number; |
|||
398 | 1 | } elseif (self::comp((string)$min, $number) === self::COMPARE_LEFT_GRATER) { |
|||
399 | 1 | $min = $number; |
|||
400 | } |
||||
401 | } |
||||
402 | |||||
403 | 1 | return $min; |
|||
404 | } |
||||
405 | |||||
406 | /** |
||||
407 | * @param int|string $number |
||||
408 | * @param int $precision |
||||
409 | * @return string |
||||
410 | */ |
||||
411 | 17 | public static function roundDown($number, $precision = 0) |
|||
412 | { |
||||
413 | 17 | $number = self::convertScientificNotationToString($number); |
|||
414 | 17 | $multiply = self::pow(10, (string)abs($precision)); |
|||
415 | |||||
416 | 17 | return $precision < 0 |
|||
417 | ? |
||||
418 | 4 | self::mul( |
|||
419 | 4 | self::floor(self::div($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply, |
|||
420 | 4 | $precision |
|||
421 | ) |
||||
422 | : |
||||
423 | 13 | self::div( |
|||
424 | 13 | self::floor(self::mul($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply, |
|||
425 | 17 | $precision |
|||
426 | ); |
||||
427 | } |
||||
428 | |||||
429 | /** |
||||
430 | * @param int|string $number |
||||
431 | * @return string |
||||
432 | */ |
||||
433 | 98 | public static function floor($number) |
|||
434 | { |
||||
435 | 98 | $number = self::convertScientificNotationToString($number); |
|||
436 | 98 | if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) { |
|||
437 | 38 | $result = 0; |
|||
438 | 38 | if (self::isNegative($number)) { |
|||
439 | 7 | --$result; |
|||
440 | } |
||||
441 | 38 | $number = self::add($number, $result, 0); |
|||
442 | } |
||||
443 | |||||
444 | 98 | return self::checkNumber($number); |
|||
445 | } |
||||
446 | |||||
447 | /** |
||||
448 | * @param int|string $number |
||||
449 | * @return bool |
||||
450 | */ |
||||
451 | 68 | private static function checkIsFloatCleanZeros(&$number) |
|||
452 | { |
||||
453 | 68 | return false !== strpos($number = self::trimTrailingZeroes($number), '.'); |
|||
0 ignored issues
–
show
$number = self::trimTrailingZeroes($number) of type void is incompatible with the type string expected by parameter $haystack of strpos() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
Are you sure the assignment to
$number is correct as self::trimTrailingZeroes($number) targeting BCMathExtended\BC::trimTrailingZeroes() seems to always return null.
This check looks for function or method calls that always return null and whose return value is assigned to a variable. class A
{
function getObject()
{
return null;
}
}
$a = new A();
$object = $a->getObject();
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.
Loading history...
|
|||||
454 | } |
||||
455 | |||||
456 | /** |
||||
457 | * @param int|string $number |
||||
458 | * @param int $precision |
||||
459 | * @return string |
||||
460 | */ |
||||
461 | 17 | public static function roundUp($number, $precision = 0) |
|||
462 | { |
||||
463 | 17 | $number = self::convertScientificNotationToString($number); |
|||
464 | 17 | $multiply = self::pow(10, (string)abs($precision)); |
|||
465 | |||||
466 | 17 | return $precision < 0 |
|||
467 | ? |
||||
468 | 4 | self::mul( |
|||
469 | 4 | self::ceil(self::div($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply, |
|||
470 | 4 | $precision |
|||
471 | ) |
||||
472 | : |
||||
473 | 13 | self::div( |
|||
474 | 13 | self::ceil(self::mul($number, $multiply, self::getDecimalsLengthFromNumber($number))), $multiply, |
|||
475 | 17 | $precision |
|||
476 | ); |
||||
477 | } |
||||
478 | |||||
479 | /** |
||||
480 | * @param int|string $number |
||||
481 | * @return string |
||||
482 | */ |
||||
483 | 41 | public static function ceil($number) |
|||
484 | { |
||||
485 | 41 | $number = self::convertScientificNotationToString($number); |
|||
486 | 41 | if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) { |
|||
487 | 22 | $result = 1; |
|||
488 | 22 | if (self::isNegative($number)) { |
|||
489 | 5 | --$result; |
|||
490 | } |
||||
491 | 22 | $number = self::add($number, $result, 0); |
|||
492 | } |
||||
493 | |||||
494 | 41 | return self::checkNumber($number); |
|||
495 | } |
||||
496 | |||||
497 | /** |
||||
498 | * @param string $leftOperand |
||||
499 | * @param string $rightOperand |
||||
500 | * @param string $modulus |
||||
501 | * @param null|int $scale |
||||
502 | * @return string |
||||
503 | */ |
||||
504 | 10 | public static function powMod($leftOperand, $rightOperand, $modulus, $scale = null) |
|||
505 | { |
||||
506 | 10 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|||
507 | 10 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|||
508 | |||||
509 | // bcpowmod in 5.6 have don't calculate correct results if scale is empty |
||||
510 | 10 | if (null === $scale) { |
|||
511 | 4 | return self::mod(self::pow($leftOperand, $rightOperand), $modulus); |
|||
512 | } |
||||
513 | |||||
514 | // cant use bcpowmod here as it don't support floats |
||||
515 | 6 | if (self::checkIsFloat($leftOperand) || self::checkIsFloat($rightOperand) || self::checkIsFloat($modulus)) { |
|||
516 | 2 | return self::mod(self::pow($leftOperand, $rightOperand, $scale), $modulus, $scale); |
|||
517 | } |
||||
518 | |||||
519 | 4 | return bcpowmod($leftOperand, $rightOperand, $modulus, $scale); |
|||
520 | } |
||||
521 | |||||
522 | /** |
||||
523 | * @param string $leftOperand |
||||
524 | * @param string $modulus |
||||
525 | * @param null|int $scale |
||||
526 | * @return string |
||||
527 | */ |
||||
528 | 56 | public static function mod($leftOperand, $modulus, $scale = null) |
|||
529 | { |
||||
530 | 56 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|||
531 | |||||
532 | // 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 |
||||
533 | |||||
534 | // bcmod in php 5.6< don't support scale and floats |
||||
535 | // let use this $x - floor($x/$y) * $y; |
||||
536 | 56 | if (null === $scale) { |
|||
537 | 44 | return self::sub($leftOperand, self::mul(self::floor(self::div($leftOperand, $modulus)), $modulus)); |
|||
538 | } |
||||
539 | |||||
540 | 12 | return self::sub( |
|||
541 | 12 | $leftOperand, self::mul(self::floor(self::div($leftOperand, $modulus, $scale)), $modulus, $scale), $scale |
|||
542 | ); |
||||
543 | } |
||||
544 | |||||
545 | /** |
||||
546 | * @param string $arg |
||||
547 | * @return string |
||||
548 | * @throws \InvalidArgumentException |
||||
549 | */ |
||||
550 | 8 | public static function fact($arg) |
|||
551 | { |
||||
552 | 8 | $arg = self::convertScientificNotationToString($arg); |
|||
553 | |||||
554 | 8 | if (self::checkIsFloat($arg)) { |
|||
555 | 1 | throw new \InvalidArgumentException('Number has to be an integer'); |
|||
556 | } |
||||
557 | 7 | if (self::isNegative($arg)) { |
|||
558 | 1 | throw new \InvalidArgumentException('Number has to be greater than or equal to 0'); |
|||
559 | } |
||||
560 | |||||
561 | 6 | $return = '1'; |
|||
562 | 6 | for ($i = 2; $i <= $arg; ++$i) { |
|||
563 | 5 | $return = self::mul($return, $i); |
|||
564 | } |
||||
565 | |||||
566 | 6 | return $return; |
|||
567 | } |
||||
568 | |||||
569 | /** |
||||
570 | * @param string $hex |
||||
571 | * @return string |
||||
572 | */ |
||||
573 | 5 | public static function hexdec($hex) |
|||
574 | { |
||||
575 | 5 | $remainingDigits = substr($hex, 0, -1); |
|||
576 | 5 | $lastDigitToDecimal = \hexdec(substr($hex, -1)); |
|||
577 | |||||
578 | 5 | if ('' === $remainingDigits) { |
|||
579 | 5 | return $lastDigitToDecimal; |
|||
580 | } |
||||
581 | |||||
582 | 5 | return self::add(self::mul(16, self::hexdec($remainingDigits)), $lastDigitToDecimal, 0); |
|||
583 | } |
||||
584 | |||||
585 | /** |
||||
586 | * @param string $decimal |
||||
587 | * @return string |
||||
588 | */ |
||||
589 | 6 | public static function dechex($decimal) |
|||
590 | { |
||||
591 | 6 | $quotient = self::div($decimal, 16, 0); |
|||
592 | 6 | $remainderToHex = \dechex((int)self::mod($decimal, 16)); |
|||
593 | |||||
594 | 6 | if (self::comp($quotient, 0) === 0) { |
|||
595 | 6 | return $remainderToHex; |
|||
596 | } |
||||
597 | |||||
598 | 6 | return self::dechex($quotient) . $remainderToHex; |
|||
599 | } |
||||
600 | |||||
601 | /** |
||||
602 | * @param string $leftOperand |
||||
603 | * @param string $rightOperand |
||||
604 | * @return string |
||||
605 | */ |
||||
606 | 12 | public static function bitAnd($leftOperand, $rightOperand) |
|||
607 | { |
||||
608 | 12 | return self::bitOperatorHelper($leftOperand, $rightOperand, self::BIT_OPERATOR_AND); |
|||
609 | } |
||||
610 | |||||
611 | /** |
||||
612 | * @param string $leftOperand |
||||
613 | * @param string $rightOperand |
||||
614 | * @param string $operator |
||||
615 | * @return string |
||||
616 | */ |
||||
617 | 36 | private static function bitOperatorHelper($leftOperand, $rightOperand, $operator) |
|||
618 | { |
||||
619 | 36 | $leftOperand = self::convertScientificNotationToString($leftOperand); |
|||
620 | 36 | $rightOperand = self::convertScientificNotationToString($rightOperand); |
|||
621 | |||||
622 | 36 | if (self::checkIsFloat($leftOperand)) { |
|||
623 | 3 | throw new \InvalidArgumentException('Left operator has to be an integer'); |
|||
624 | } |
||||
625 | 33 | if (self::checkIsFloat($rightOperand)) { |
|||
626 | 3 | throw new \InvalidArgumentException('Right operator has to be an integer'); |
|||
627 | } |
||||
628 | |||||
629 | 30 | $leftOperandNegative = self::isNegative($leftOperand); |
|||
630 | 30 | $rightOperandNegative = self::isNegative($rightOperand); |
|||
631 | |||||
632 | 30 | $leftOperand = self::dec2bin(self::abs($leftOperand)); |
|||
633 | 30 | $rightOperand = self::dec2bin(self::abs($rightOperand)); |
|||
634 | |||||
635 | 30 | $maxLength = max(strlen($leftOperand), strlen($rightOperand)); |
|||
636 | |||||
637 | 30 | $leftOperand = self::alignBinLength($leftOperand, $maxLength); |
|||
638 | 30 | $rightOperand = self::alignBinLength($rightOperand, $maxLength); |
|||
639 | |||||
640 | 30 | if ($leftOperandNegative) { |
|||
641 | 7 | $leftOperand = self::recalculateNegative($leftOperand); |
|||
642 | } |
||||
643 | 30 | if ($rightOperandNegative) { |
|||
644 | 7 | $rightOperand = self::recalculateNegative($rightOperand); |
|||
645 | } |
||||
646 | |||||
647 | 30 | $isNegative = false; |
|||
648 | 30 | $result = ''; |
|||
649 | 30 | if (self::BIT_OPERATOR_AND === $operator) { |
|||
650 | 10 | $result = $leftOperand & $rightOperand; |
|||
651 | 10 | $isNegative = ($leftOperandNegative and $rightOperandNegative); |
|||
652 | 20 | } elseif (self::BIT_OPERATOR_OR === $operator) { |
|||
653 | 12 | $result = $leftOperand | $rightOperand; |
|||
654 | 12 | $isNegative = ($leftOperandNegative or $rightOperandNegative); |
|||
655 | 8 | } elseif (self::BIT_OPERATOR_XOR === $operator) { |
|||
656 | 8 | $result = $leftOperand ^ $rightOperand; |
|||
657 | 8 | $isNegative = ($leftOperandNegative xor $rightOperandNegative); |
|||
658 | } |
||||
659 | |||||
660 | 30 | if ($isNegative) { |
|||
661 | 8 | $result = self::recalculateNegative($result); |
|||
662 | } |
||||
663 | |||||
664 | 30 | $result = self::bin2dec($result); |
|||
665 | |||||
666 | 30 | return $isNegative ? '-' . $result : $result; |
|||
667 | } |
||||
668 | |||||
669 | /** |
||||
670 | * @param string $number |
||||
671 | * @param int $base |
||||
672 | * @return string |
||||
673 | */ |
||||
674 | 36 | public static function dec2bin($number, $base = self::MAX_BASE) |
|||
675 | { |
||||
676 | 36 | return self::decBaseHelper( |
|||
677 | 36 | $base, function ($base) use ($number) { |
|||
678 | 35 | $value = ''; |
|||
679 | 35 | if ('0' === $number) { |
|||
680 | 30 | return chr((int)$number); |
|||
681 | } |
||||
682 | |||||
683 | 33 | while (BC::comp($number, '0') !== BC::COMPARE_EQUAL) { |
|||
684 | 33 | $rest = BC::mod($number, $base); |
|||
685 | 33 | $number = BC::div($number, $base); |
|||
686 | 33 | $value = chr((int)$rest) . $value; |
|||
687 | } |
||||
688 | |||||
689 | 33 | return $value; |
|||
690 | 36 | } |
|||
691 | ); |
||||
692 | } |
||||
693 | |||||
694 | /** |
||||
695 | * @param int $base |
||||
696 | * @param \Closure $closure |
||||
697 | * @return string |
||||
698 | */ |
||||
699 | 37 | private static function decBaseHelper($base, \Closure $closure) |
|||
700 | { |
||||
701 | 37 | if ($base < 2 || $base > self::MAX_BASE) { |
|||
702 | 2 | throw new \InvalidArgumentException('Invalid Base: ' . $base); |
|||
703 | } |
||||
704 | 35 | $orgScale = self::getScale(); |
|||
705 | 35 | self::setScale(0); |
|||
706 | |||||
707 | 35 | $value = $closure($base); |
|||
708 | |||||
709 | 35 | self::setScale($orgScale); |
|||
710 | |||||
711 | 35 | return $value; |
|||
712 | } |
||||
713 | |||||
714 | /** |
||||
715 | * @param null|int $scale |
||||
716 | */ |
||||
717 | 367 | public static function setScale($scale) |
|||
718 | { |
||||
719 | 367 | bcscale($scale); |
|||
720 | 367 | } |
|||
721 | |||||
722 | /** |
||||
723 | * @param int|string $number |
||||
724 | * @return string |
||||
725 | */ |
||||
726 | 45 | public static function abs($number) |
|||
727 | { |
||||
728 | 45 | $number = self::convertScientificNotationToString($number); |
|||
729 | |||||
730 | 45 | if (self::isNegative($number)) { |
|||
731 | 19 | $number = (string)substr($number, 1); |
|||
732 | } |
||||
733 | |||||
734 | 45 | return self::checkNumber($number); |
|||
735 | } |
||||
736 | |||||
737 | /** |
||||
738 | * @param string $string |
||||
739 | * @param int $length |
||||
740 | * @return string |
||||
741 | */ |
||||
742 | 30 | private static function alignBinLength($string, $length) |
|||
743 | { |
||||
744 | 30 | return str_pad($string, $length, self::dec2bin('0'), STR_PAD_LEFT); |
|||
745 | } |
||||
746 | |||||
747 | /** |
||||
748 | * @param string $number |
||||
749 | * @return string |
||||
750 | */ |
||||
751 | 11 | private static function recalculateNegative($number) |
|||
752 | { |
||||
753 | 11 | $xor = str_repeat(self::dec2bin(self::MAX_BASE - 1), strlen($number)); |
|||
754 | 11 | $number ^= $xor; |
|||
755 | 11 | for ($i = strlen($number) - 1; $i >= 0; $i--) { |
|||
756 | 11 | $byte = ord($number[$i]); |
|||
757 | 11 | if (++$byte !== self::MAX_BASE) { |
|||
758 | 11 | $number[$i] = chr($byte); |
|||
759 | 11 | break; |
|||
760 | } |
||||
761 | } |
||||
762 | |||||
763 | 11 | return $number; |
|||
764 | } |
||||
765 | |||||
766 | /** |
||||
767 | * @param string $binary |
||||
768 | * @param int $base |
||||
769 | * @return string |
||||
770 | */ |
||||
771 | 36 | public static function bin2dec($binary, $base = self::MAX_BASE) |
|||
772 | { |
||||
773 | 36 | return self::decBaseHelper( |
|||
774 | 36 | $base, function ($base) use ($binary) { |
|||
775 | 35 | $size = strlen($binary); |
|||
776 | 35 | $return = '0'; |
|||
777 | 35 | for ($i = 0; $i < $size; ++$i) { |
|||
778 | 35 | $element = ord($binary[$i]); |
|||
779 | 35 | $power = BC::pow($base, $size - $i - 1); |
|||
780 | 35 | $return = BC::add($return, BC::mul($element, $power)); |
|||
781 | } |
||||
782 | |||||
783 | 35 | return $return; |
|||
784 | 36 | } |
|||
785 | ); |
||||
786 | } |
||||
787 | |||||
788 | /** |
||||
789 | * @param string $leftOperand |
||||
790 | * @param string $rightOperand |
||||
791 | * @return string |
||||
792 | */ |
||||
793 | 14 | public static function bitOr($leftOperand, $rightOperand) |
|||
794 | { |
||||
795 | 14 | return self::bitOperatorHelper($leftOperand, $rightOperand, self::BIT_OPERATOR_OR); |
|||
796 | } |
||||
797 | |||||
798 | /** |
||||
799 | * @param string $leftOperand |
||||
800 | * @param string $rightOperand |
||||
801 | * @return string |
||||
802 | */ |
||||
803 | 10 | public static function bitXor($leftOperand, $rightOperand) |
|||
804 | { |
||||
805 | 10 | return self::bitOperatorHelper($leftOperand, $rightOperand, self::BIT_OPERATOR_XOR); |
|||
806 | } |
||||
807 | } |
||||
808 |
This check looks for function or method calls that always return null and whose return value is assigned to a variable.
The method
getObject()
can return nothing but null, so it makes no sense to assign that value to a variable.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.