Test Failed
Pull Request — dev (#87)
by Jordan
13:18
created

Numbers::make()   A

Complexity

Conditions 6
Paths 10

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 14
c 0
b 0
f 0
nc 10
nop 4
dl 0
loc 27
ccs 11
cts 11
cp 1
crap 6
rs 9.2222
1
<?php
2
3
namespace Samsara\Fermat;
4
5
use Samsara\Exceptions\UsageError\IntegrityConstraint;
6
use Samsara\Fermat\Provider\ConstantProvider;
7
use Samsara\Fermat\Types\Base\Interfaces\Numbers\DecimalInterface;
8
use Samsara\Fermat\Types\Base\Interfaces\Numbers\FractionInterface;
9
use Samsara\Fermat\Types\Base\Interfaces\Numbers\NumberInterface;
10
use Samsara\Fermat\Types\Base\Selectable;
11
use Samsara\Fermat\Values\ImmutableFraction;
12
use Samsara\Fermat\Values\ImmutableDecimal;
13
use Samsara\Fermat\Values\MutableFraction;
14
use Samsara\Fermat\Values\MutableDecimal;
15
16
class Numbers
17
{
18
19
    public const MUTABLE = MutableDecimal::class;
20
    public const IMMUTABLE = ImmutableDecimal::class;
21
    public const MUTABLE_FRACTION = MutableFraction::class;
22
    public const IMMUTABLE_FRACTION = ImmutableFraction::class;
23
    /* 105 digits after decimal, which is going to be overkill in almost all places */
24
    public const PI = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679';
25
    /* Tau (2pi) to 100 digits */
26
    public const TAU = '6.283185307179586476925286766559005768394338798750211641949889184615632812572417997256069650684234136';
27
    /* Euler's Number to 100 digits */
28
    public const E = '2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427';
29
    /* Golden Ratio to 100 digits */
30
    public const GOLDEN_RATIO = '1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137';
31
    /* Natural log of 10 to 100 digits */
32
    public const LN_10 = '2.302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298';
33
    /* The value of i^i */
34
    public const I_POW_I = '0.2078795763507619085469556198349787700338778416317696080751358830554198772854821397886002778654260353';
35
36
    protected static $defaultCalcMode = Selectable::CALC_MODE_PRECISION;
37
38
    /**
39
     * @param $type
40
     * @param $value
41
     * @param int|null $scale
42
     * @param int $base
43
     *
44
     * @return ImmutableDecimal|MutableDecimal|ImmutableFraction|MutableFraction|NumberInterface|FractionInterface
45
     * @throws IntegrityConstraint
46
     */
47
    public static function make($type, $value, $scale = null, $base = 10)
48
    {
49
50
        if (is_object($type)) {
51
            $type = get_class($type);
52 135
        }
53
54
        if ($type === static::IMMUTABLE) {
55 135
            return new ImmutableDecimal(trim($value), $scale, $base);
56 103
        }
57
58
        if ($type === static::MUTABLE) {
59 135
            return new MutableDecimal(trim($value), $scale, $base);
60 135
        }
61
62
        if ($type === static::IMMUTABLE_FRACTION) {
63 21
            return self::makeFractionFromString($type, $value, $base);
64 12
        }
65
66
        if ($type === static::MUTABLE_FRACTION) {
67 12
            return self::makeFractionFromString($type, $value, $base);
68 11
        }
69
70
        throw new IntegrityConstraint(
71 4
            '$type must be an implemented concrete class that is supported',
72 3
            'Provide a type that implements NumberInterface or CoordinateInterface (the Numbers class contains constants for the built in ones)',
73
            'The $type argument was not an implementation of NumberInterface or CoordinateInterface'
74
        );
75 1
    }
76 1
77 1
    /**
78 1
     * @param $type
79
     * @param $value
80 1
     * @param int|null $scale
81
     * @param int $base
82
     *
83
     * @return NumberInterface
84
     * @throws IntegrityConstraint
85
     */
86
    public static function makeFromBase10($type, $value, $scale = null, $base = 10): NumberInterface
87
    {
88
        /**
89
         * @var ImmutableDecimal|MutableDecimal
90
         */
91
        $number = self::make($type, $value, $scale, 10);
92
93
        return $number->convertToBase($base);
0 ignored issues
show
Bug introduced by
The method convertToBase() does not exist on Samsara\Fermat\Values\MutableFraction. ( Ignorable by Annotation )

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

93
        return $number->/** @scrutinizer ignore-call */ convertToBase($base);

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...
Bug introduced by
The method convertToBase() does not exist on Samsara\Fermat\Values\ImmutableFraction. ( Ignorable by Annotation )

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

93
        return $number->/** @scrutinizer ignore-call */ convertToBase($base);

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...
94
    }
95
96
    /**
97
     * @param string|object $type
98
     * @param int|float|string|array|NumberInterface|DecimalInterface|FractionInterface $value
99 1
     * @param int|null $scale
100
     * @param int $base
101
     *
102
     * @return ImmutableDecimal|MutableDecimal|NumberInterface|ImmutableDecimal[]|MutableDecimal[]|NumberInterface[]
103
     * @throws IntegrityConstraint
104 1
     */
105
    public static function makeOrDont($type, $value, $scale = null, $base = 10)
106 1
    {
107
108
        if (is_object($value)) {
109
            if ($value instanceof $type) {
110
                return $value;
111
            }
112
113
            if ($value instanceof NumberInterface) {
0 ignored issues
show
introduced by
$value is always a sub-type of Samsara\Fermat\Types\Bas...Numbers\NumberInterface.
Loading history...
114
                return static::make($type, $value->getValue(), $scale, $base);
0 ignored issues
show
Bug introduced by
The method getValue() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Samsara\Fermat\Types\Bas...Numbers\NumberInterface. ( Ignorable by Annotation )

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

114
                return static::make($type, $value->/** @scrutinizer ignore-call */ getValue(), $scale, $base);
Loading history...
115
            }
116
        } elseif (is_array($value)) {
117
            $newInput = [];
118 126
119
            foreach ($value as $key => $item) {
120
                $newInput[$key] = static::makeOrDont($type, $item, $scale, $base);
121 126
            }
122 97
123 97
            return $newInput;
124
        } elseif (is_string($value) || is_int($value) || is_float($value)) {
0 ignored issues
show
introduced by
The condition is_float($value) is always true.
Loading history...
125
            $isImaginary = strpos($value, 'i') !== false;
126 4
127 4
            if (is_numeric($value) || $isImaginary) {
128
                return static::make($type, $value, $scale, $base);
129 116
            }
130 14
        }
131
132 14
        throw new IntegrityConstraint(
133 14
            '$input must be an int, float, numeric string, or an implementation of NumberInterface',
134
            'Provide any of the MANY valid inputs',
135
            'The $input argument was not numeric or an implementation of NumberInterface. Given value: '.$value
136 14
        );
137 116
138 116
    }
139
140 116
    /**
141 116
     * @param string $type
142
     * @param string $value
143
     * @param int $base
144
     *
145
     * @return FractionInterface|ImmutableFraction|MutableFraction
146
     * @throws IntegrityConstraint
147
     */
148
    public static function makeFractionFromString(string $type, string $value, int $base = 10): FractionInterface
149
    {
150
        $parts = explode('/', $value);
151
152
        if (count($parts) > 2) {
153
            throw new IntegrityConstraint(
154
                'Only one division symbol (/) can be used',
155
                'Change the calling code to not provide more than one division symbol',
156
                'makeFractionFromString needs either one or zero division symbols in the $value argument; '.$value.' given'
157
            );
158
        }
159
160
        /** @var ImmutableDecimal $numerator */
161 11
        $numerator = self::make(self::IMMUTABLE, trim(ltrim($parts[0])))->round();
162
        /** @var ImmutableDecimal $denominator */
163 11
        $denominator = isset($parts[1]) ? self::make(self::IMMUTABLE, trim(ltrim($parts[1])))->round() : self::makeOne();
164
165 11
        if ($type === self::IMMUTABLE_FRACTION) {
166
            return new ImmutableFraction($numerator, $denominator, $base);
167
        }
168
169
        if ($type === self::MUTABLE_FRACTION) {
170
            return new MutableFraction($numerator, $denominator, $base);
171
        }
172
173
        throw new IntegrityConstraint(
174 11
            'Type must be an implementation of FractionInterface',
175
            'Alter to calling code to use the correct type',
176 11
            'makeFractionFromString can only make objects which implement the FractionInterface; '.$type.' given'
177
        );
178 11
    }
179 11
180
    /**
181
     * @param int|null $scale
182 3
     *
183 3
     * @return DecimalInterface
184
     * @throws IntegrityConstraint
185
     */
186
    public static function makePi(int $scale = null)
187
    {
188
189
        if (!is_null($scale)) {
190
            if ($scale < 1) {
191
                throw new IntegrityConstraint(
192
                    '$scale must be at least 1',
193
                    'Provide a scale within range',
194
                    'The pi constant cannot have a scale less than 1'
195
                );
196
            }
197
198
            if ($scale > 100) {
199 34
                return self::make(self::IMMUTABLE, ConstantProvider::makePi($scale), $scale);
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::make(self::...makePi($scale), $scale) also could return the type Samsara\Fermat\Values\Im...\Values\MutableFraction which is incompatible with the documented return type Samsara\Fermat\Types\Bas...umbers\DecimalInterface.
Loading history...
200
            }
201
202 34
            return self::make(self::IMMUTABLE, self::PI, $scale)->truncateToScale($scale);
0 ignored issues
show
Bug introduced by
The method truncateToScale() does not exist on Samsara\Fermat\Values\ImmutableFraction. ( Ignorable by Annotation )

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

202
            return self::make(self::IMMUTABLE, self::PI, $scale)->/** @scrutinizer ignore-call */ truncateToScale($scale);

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...
Bug introduced by
The method truncateToScale() does not exist on Samsara\Fermat\Values\MutableFraction. ( Ignorable by Annotation )

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

202
            return self::make(self::IMMUTABLE, self::PI, $scale)->/** @scrutinizer ignore-call */ truncateToScale($scale);

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...
203 26
        }
204 1
205 1
        return self::make(self::IMMUTABLE, self::PI, 100);
1 ignored issue
show
Bug Best Practice introduced by
The expression return self::make(self::IMMUTABLE, self::PI, 100) also could return the type Samsara\Fermat\Values\Im...\Values\MutableFraction which is incompatible with the documented return type Samsara\Fermat\Types\Bas...umbers\DecimalInterface.
Loading history...
206 1
207 1
    }
208
209
    /**
210
     * @param int|null $scale
211 26
     *
212 1
     * @return DecimalInterface
213
     * @throws IntegrityConstraint
214
     */
215 26
    public static function makeTau($scale = null)
216
    {
217
        if (!is_null($scale)) {
218 23
            if ($scale < 1) {
219
                throw new IntegrityConstraint(
220
                    '$scale must be at least 1',
221
                    'Provide a scale within range',
222
                    'The E constant cannot have a scale less than 1'
223
                );
224
            }
225
226
            if ($scale > 100) {
227
                $pi = self::make(self::IMMUTABLE, ConstantProvider::makePi($scale), $scale + 2);
228 23
                return $pi->multiply(2)->truncateToScale($scale);
229
            }
230 23
231 10
            return self::make(self::IMMUTABLE, self::TAU, $scale)->truncateToScale($scale);
232 1
        }
233 1
234 1
        return self::make(self::IMMUTABLE, self::TAU, 100);
1 ignored issue
show
Bug Best Practice introduced by
The expression return self::make(self::IMMUTABLE, self::TAU, 100) also could return the type Samsara\Fermat\Values\Im...\Values\MutableFraction which is incompatible with the documented return type Samsara\Fermat\Types\Bas...umbers\DecimalInterface.
Loading history...
235 1
    }
236
237
    /**
238
     * @param int|null $scale
239 10
     *
240 1
     * @return DecimalInterface
241 1
     * @throws IntegrityConstraint
242
     */
243
    public static function make2Pi($scale = null)
244 10
    {
245
        return self::makeTau($scale);
246
    }
247 23
248
    /**
249
     * @param int|null $scale
250
     *
251
     * @return DecimalInterface
252
     * @throws IntegrityConstraint
253
     */
254
    public static function makeE(int $scale = null)
255
    {
256 23
257
        if (!is_null($scale)) {
258 23
            if ($scale < 1) {
259
                throw new IntegrityConstraint(
260
                    '$scale must be at least 1',
261
                    'Provide a scale within range',
262
                    'The E constant cannot have a scale less than 1'
263
                );
264
            }
265
266
            if ($scale > 100) {
267 9
                return self::make(self::IMMUTABLE, ConstantProvider::makeE($scale), $scale);
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::make(self::...:makeE($scale), $scale) also could return the type Samsara\Fermat\Values\Im...\Values\MutableFraction which is incompatible with the documented return type Samsara\Fermat\Types\Bas...umbers\DecimalInterface.
Loading history...
268
            }
269
270 9
            return self::make(self::IMMUTABLE, self::E, $scale)->truncateToScale($scale);
271 7
        }
272 1
273 1
        return self::make(self::IMMUTABLE, self::E, 100);
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::make(self::IMMUTABLE, self::E, 100) also could return the type Samsara\Fermat\Values\Im...\Values\MutableFraction which is incompatible with the documented return type Samsara\Fermat\Types\Bas...umbers\DecimalInterface.
Loading history...
274 1
275 1
    }
276
277
    /**
278
     * @param int|null $scale
279 7
     *
280 1
     * @return NumberInterface
281
     * @throws IntegrityConstraint
282
     */
283 7
    public static function makeGoldenRatio($scale = null)
284
    {
285
286 4
        if (!is_null($scale)) {
287
            if ($scale > 100 || $scale < 1) {
288
                throw new IntegrityConstraint(
289
                    '$scale must be between 1 and 100 inclusive',
290
                    'Provide a scale within range',
291
                    'The Golden Ratio constant cannot have a scale higher than the constant stored (100)'
292
                );
293
            }
294
295
            return self::make(self::IMMUTABLE, self::GOLDEN_RATIO, $scale)->truncateToScale($scale);
296 1
        }
297
298
        return self::make(self::IMMUTABLE, self::GOLDEN_RATIO, 100);
299 1
300 1
    }
301 1
302 1
    /**
303 1
     * @param int|null $scale
304 1
     *
305
     * @return NumberInterface
306
     * @throws IntegrityConstraint
307
     */
308 1
    public static function makeNaturalLog10($scale = null)
309
    {
310
311 1
        if (!is_null($scale)) {
312
            if ($scale > 100 || $scale < 1) {
313
                throw new IntegrityConstraint(
314
                    '$scale must be between 1 and 100 inclusive',
315
                    'Provide a scale within range',
316
                    'The natural log of 10 constant cannot have a scale higher than the constant stored (100)'
317
                );
318
            }
319
320
            return self::make(self::IMMUTABLE, self::LN_10, $scale)->truncateToScale($scale);
321 2
        }
322
323
        return self::make(self::IMMUTABLE, self::LN_10, 100);
324 2
325 1
    }
326 1
327 1
    /**
328 1
     * @param int|null $scale
329 1
     *
330
     * @return ImmutableDecimal
331
     * @throws IntegrityConstraint
332
     */
333 1
    public static function makeOne($scale = null)
334
    {
335
        return self::make(self::IMMUTABLE, 1, $scale);
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::make(self::IMMUTABLE, 1, $scale) also could return the type Samsara\Fermat\Values\Im...\Values\MutableFraction which is incompatible with the documented return type Samsara\Fermat\Values\ImmutableDecimal.
Loading history...
336 2
    }
337
338
    /**
339
     * @param int|null $scale
340
     *
341
     * @return ImmutableDecimal
342
     * @throws IntegrityConstraint
343
     */
344
    public static function makeZero($scale = null)
345
    {
346 68
        return self::make(self::IMMUTABLE, 0, $scale);
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::make(self::IMMUTABLE, 0, $scale) also could return the type Samsara\Fermat\Values\Im...\Values\MutableFraction which is incompatible with the documented return type Samsara\Fermat\Values\ImmutableDecimal.
Loading history...
347
    }
348 68
349
    public static function getDefaultCalcMode(): int
350
    {
351
        return self::$defaultCalcMode;
352
    }
353
354
    public static function setDefaultCalcMode(int $mode): void
355
    {
356
        self::$defaultCalcMode = $mode;
357 58
    }
358
359
}