Passed
Branch master (7fff96)
by Jordan
06:01
created

BaseConversionProvider::convertStringToBaseTen()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 7.456

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 9
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 12
ccs 4
cts 10
cp 0.4
crap 7.456
rs 9.9666
1
<?php
2
3
namespace Samsara\Fermat\Provider;
4
5
use Samsara\Fermat\Enums\NumberBase;
6
use Samsara\Fermat\Numbers;
7
use Samsara\Fermat\Types\Base\Interfaces\Numbers\DecimalInterface;
8
use Samsara\Fermat\Values\ImmutableDecimal;
9
10
/**
11
 *
12
 */
13
class BaseConversionProvider
14
{
15
16
    private static array $chars = [
17
        '0',
18
        '1',
19
        '2',
20
        '3',
21
        '4',
22
        '5',
23
        '6',
24
        '7',
25
        '8',
26
        '9',
27
        'A',
28
        'B',
29
        'C',
30
        'D',
31
        'E',
32
        'F'
33
    ];
34
35
    /**
36
     * @param DecimalInterface $number
37
     * @param NumberBase|null $toBase
38
     * @return string
39
     */
40 59
    public static function convertFromBaseTen(DecimalInterface $number, ?NumberBase $toBase = null): string
41
    {
42 59
        $base = $toBase ?? $number->getBase();
43
44 59
        return self::_toBase($number, $base->value);
45
    }
46
47
    /**
48
     * @param string $number
49
     * @param NumberBase $fromBase
50
     * @return string
51
     */
52 2
    public static function convertStringToBaseTen(string $number, NumberBase $fromBase): string
53
    {
54 2
        if (str_contains($number, '.')) {
55
            $sign = str_starts_with($number, '-') ? '-' : '';
56
            [$intPart, $decPart] = explode('.', $number);
57
            $intPart = self::_fromBase($intPart, $fromBase->value);
58
            $decPart = strrev(self::_fromBase(strrev($decPart), $fromBase->value));
59
60
            return $sign.$intPart.'.'.$decPart;
61
        } else {
62 2
            $sign = str_starts_with($number, '-') ? '-' : '';
63 2
            return $sign.self::_fromBase($number, $fromBase->value);
64
        }
65
    }
66
67 59
    private static function _toBase(DecimalInterface $input, int $base): string
68
    {
69 59
        $baseNum = Numbers::make(Numbers::IMMUTABLE, $base, $input->getScale());
70 59
        $inputInt = Numbers::make(Numbers::IMMUTABLE, $input->getWholePart());
71 59
        $inputDec = Numbers::make(Numbers::IMMUTABLE, strrev($input->getDecimalPart()));
72
73 59
        $intPart = self::_toBasePart($baseNum, $inputInt);
74 59
        $decPart = self::_toBasePart($baseNum, $inputDec);
75
76 59
        $sign = $input->isNegative() ? '-' : '';
77
78 59
        return $sign.$intPart.'.'.strrev($decPart);
79
    }
80
81 2
    private static function _fromBase(string $number, int $base): string
82
    {
83 2
        if (str_starts_with($number, '-')) {
84 1
            $number = trim($number, '-');
85
        }
86
87 2
        $output = Numbers::makeZero();
88 2
        $input = str_split($number);
89 2
        $input = array_reverse($input);
0 ignored issues
show
Bug introduced by
It seems like $input can also be of type true; however, parameter $array of array_reverse() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

89
        $input = array_reverse(/** @scrutinizer ignore-type */ $input);
Loading history...
90 2
        $pos = 0;
91 2
        $base = Numbers::make(Numbers::IMMUTABLE, $base);
92
93 2
        foreach ($input as $char) {
94 2
            $output = $output->add($base->pow($pos)->multiply(array_search($char, self::$chars)));
0 ignored issues
show
Bug introduced by
The method pow() does not exist on integer. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

94
            $output = $output->add($base->/** @scrutinizer ignore-call */ pow($pos)->multiply(array_search($char, self::$chars)));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
95 2
            $pos++;
96
        }
97
98 2
        return $output->getAsBaseTenRealNumber();
99
    }
100
101 59
    public static function _toBasePart(ImmutableDecimal $baseNum, ImmutableDecimal $startVal): string
102
    {
103 59
        if ($startVal->isGreaterThan(0)) {
104 59
            $stringVal = '';
105 59
            $runningTotal = Numbers::make(Numbers::IMMUTABLE, $startVal->getAsBaseTenRealNumber());
106 59
            while ($runningTotal->isGreaterThan(0)) {
107 59
                $current = gmp_div_qr($runningTotal->getAsBaseTenRealNumber(), $baseNum->getAsBaseTenRealNumber());
108 59
                $mod = (int)$current[1];
109 59
                $stringVal = self::$chars[$mod] . $stringVal;
110 59
                $runningTotal = Numbers::make(Numbers::IMMUTABLE, $current[0]);
111
            }
112
        } else {
113 59
            $stringVal = '0';
114
        }
115
116 59
        return $stringVal;
117
    }
118
119
}