Passed
Push — master ( d07e18...834c41 )
by kacper
01:45
created

src/BCMathExtended/BC.php (4 issues)

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
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 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.

Loading history...
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
Bug Best Practice introduced by
The expression return rtrim($number, '.') ?: '0' returns the type string which is incompatible with the documented return type void.
Loading history...
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 ignore-type  annotation

453
        return false !== strpos(/** @scrutinizer ignore-type */ $number = self::trimTrailingZeroes($number), '.');
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 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.

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