Passed
Push — dev ( c3b672...0c0d88 )
by Jordan
04:34 queued 03:46
created

Numbers::makeTau()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 11
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 20
ccs 12
cts 12
cp 1
crap 4
rs 9.9
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 87
    public static function make($type, $value, $scale = null, $base = 10)
48
    {
49
50 87
        if (is_object($type)) {
51 69
            $type = get_class($type);
52
        }
53
54 87
        if ($type === static::IMMUTABLE) {
55 87
            return new ImmutableDecimal(trim($value), $scale, $base);
56
        }
57
58 15
        if ($type === static::MUTABLE) {
59 10
            return new MutableDecimal(trim($value), $scale, $base);
60
        }
61
62 8
        if ($type === static::IMMUTABLE_FRACTION) {
63 8
            return self::makeFractionFromString($type, $value, $base);
64
        }
65
66 3
        if ($type === static::MUTABLE_FRACTION) {
67 3
            return self::makeFractionFromString($type, $value, $base);
68
        }
69
70
        throw new IntegrityConstraint(
71
            '$type must be an implemented concrete class that is supported',
72
            '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
    }
76
77
    /**
78
     * @param $type
79
     * @param $value
80
     * @param int|null $scale
81
     * @param int $base
82
     *
83
     * @return NumberInterface
84
     * @throws IntegrityConstraint
85
     */
86 1
    public static function makeFromBase10($type, $value, $scale = null, $base = 10): NumberInterface
87
    {
88
        /**
89
         * @var ImmutableDecimal|MutableDecimal
90
         */
91 1
        $number = self::make($type, $value, $scale, 10);
92
93 1
        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
     * @param int|null $scale
100
     * @param int $base
101
     *
102
     * @return ImmutableDecimal|MutableDecimal|NumberInterface|ImmutableDecimal[]|MutableDecimal[]|NumberInterface[]
103
     * @throws IntegrityConstraint
104
     */
105 81
    public static function makeOrDont($type, $value, $scale = null, $base = 10)
106
    {
107
108 81
        if (is_object($value)) {
109 55
            if ($value instanceof $type) {
110 55
                return $value;
111
            }
112
113 2
            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 2
                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 81
        } elseif (is_array($value)) {
117 3
            $newInput = [];
118
119 3
            foreach ($value as $key => $item) {
120 3
                $newInput[$key] = static::makeOrDont($type, $item, $scale, $base);
121
            }
122
123 3
            return $newInput;
124 81
        } 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 81
            $isImaginary = strpos($value, 'i') !== false;
126
127 81
            if (is_numeric($value) || $isImaginary) {
128 81
                return static::make($type, $value, $scale, $base);
129
            }
130
        }
131
132
        throw new IntegrityConstraint(
133
            '$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
        );
137
138
    }
139
140
    /**
141
     * @param string $type
142
     * @param string $value
143
     * @param int $base
144
     *
145
     * @return FractionInterface|ImmutableFraction|MutableFraction
146
     * @throws IntegrityConstraint
147
     */
148 9
    public static function makeFractionFromString(string $type, string $value, int $base = 10): FractionInterface
149
    {
150 9
        $parts = explode('/', $value);
151
152 9
        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 9
        $numerator = self::make(self::IMMUTABLE, trim(ltrim($parts[0])))->round();
162
        /** @var ImmutableDecimal $denominator */
163 9
        $denominator = isset($parts[1]) ? self::make(self::IMMUTABLE, trim(ltrim($parts[1])))->round() : self::makeOne();
164
165 9
        if ($type === self::IMMUTABLE_FRACTION) {
166 9
            return new ImmutableFraction($numerator, $denominator, $base);
167
        }
168
169 3
        if ($type === self::MUTABLE_FRACTION) {
170 3
            return new MutableFraction($numerator, $denominator, $base);
171
        }
172
173
        throw new IntegrityConstraint(
174
            'Type must be an implementation of FractionInterface',
175
            'Alter to calling code to use the correct type',
176
            'makeFractionFromString can only make objects which implement the FractionInterface; '.$type.' given'
177
        );
178
    }
179
180
    /**
181
     * @param int|null $scale
182
     *
183
     * @return DecimalInterface
184
     * @throws IntegrityConstraint
185
     */
186 15
    public static function makePi(int $scale = null)
187
    {
188
189 15
        if (!is_null($scale)) {
190 7
            if ($scale < 1) {
191 1
                throw new IntegrityConstraint(
192 1
                    '$scale must be at least 1',
193 1
                    'Provide a scale within range',
194 1
                    'The pi constant cannot have a scale less than 1'
195
                );
196
            }
197
198 7
            if ($scale > 100) {
199 1
                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 7
            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
        }
204
205 13
        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
207
    }
208
209
    /**
210
     * @param int|null $scale
211
     *
212
     * @return DecimalInterface
213
     * @throws IntegrityConstraint
214
     */
215 13
    public static function makeTau($scale = null)
216
    {
217 13
        if (!is_null($scale)) {
218 1
            if ($scale < 1) {
219 1
                throw new IntegrityConstraint(
220 1
                    '$scale must be at least 1',
221 1
                    'Provide a scale within range',
222 1
                    'The E constant cannot have a scale less than 1'
223
                );
224
            }
225
226 1
            if ($scale > 100) {
227 1
                $pi = self::make(self::IMMUTABLE, ConstantProvider::makePi($scale), $scale + 2);
228 1
                return $pi->multiply(2)->truncateToScale($scale);
229
            }
230
231 1
            return self::make(self::IMMUTABLE, self::TAU, $scale)->truncateToScale($scale);
232
        }
233
234 13
        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
    }
236
237
    /**
238
     * @param int|null $scale
239
     *
240
     * @return DecimalInterface
241
     * @throws IntegrityConstraint
242
     */
243 13
    public static function make2Pi($scale = null)
244
    {
245 13
        return self::makeTau($scale);
246
    }
247
248
    /**
249
     * @param int|null $scale
250
     *
251
     * @return DecimalInterface
252
     * @throws IntegrityConstraint
253
     */
254 7
    public static function makeE(int $scale = null)
255
    {
256
257 7
        if (!is_null($scale)) {
258 5
            if ($scale < 1) {
259 1
                throw new IntegrityConstraint(
260 1
                    '$scale must be at least 1',
261 1
                    'Provide a scale within range',
262 1
                    'The E constant cannot have a scale less than 1'
263
                );
264
            }
265
266 5
            if ($scale > 100) {
267 1
                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 5
            return self::make(self::IMMUTABLE, self::E, $scale)->truncateToScale($scale);
271
        }
272
273 4
        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
275
    }
276
277
    /**
278
     * @param int|null $scale
279
     *
280
     * @return NumberInterface
281
     * @throws IntegrityConstraint
282
     */
283 1
    public static function makeGoldenRatio($scale = null)
284
    {
285
286 1
        if (!is_null($scale)) {
287 1
            if ($scale > 100 || $scale < 1) {
288 1
                throw new IntegrityConstraint(
289 1
                    '$scale must be between 1 and 100 inclusive',
290 1
                    'Provide a scale within range',
291 1
                    'The Golden Ratio constant cannot have a scale higher than the constant stored (100)'
292
                );
293
            }
294
295 1
            return self::make(self::IMMUTABLE, self::GOLDEN_RATIO, $scale)->truncateToScale($scale);
296
        }
297
298 1
        return self::make(self::IMMUTABLE, self::GOLDEN_RATIO, 100);
299
300
    }
301
302
    /**
303
     * @param int|null $scale
304
     *
305
     * @return NumberInterface
306
     * @throws IntegrityConstraint
307
     */
308 2
    public static function makeNaturalLog10($scale = null)
309
    {
310
311 2
        if (!is_null($scale)) {
312 1
            if ($scale > 100 || $scale < 1) {
313 1
                throw new IntegrityConstraint(
314 1
                    '$scale must be between 1 and 100 inclusive',
315 1
                    'Provide a scale within range',
316 1
                    'The natural log of 10 constant cannot have a scale higher than the constant stored (100)'
317
                );
318
            }
319
320 1
            return self::make(self::IMMUTABLE, self::LN_10, $scale)->truncateToScale($scale);
321
        }
322
323 2
        return self::make(self::IMMUTABLE, self::LN_10, 100);
324
325
    }
326
327
    /**
328
     * @param int|null $scale
329
     *
330
     * @return ImmutableDecimal
331
     * @throws IntegrityConstraint
332
     */
333 37
    public static function makeOne($scale = null)
334
    {
335 37
        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
    }
337
338
    /**
339
     * @param int|null $scale
340
     *
341
     * @return ImmutableDecimal
342
     * @throws IntegrityConstraint
343
     */
344 29
    public static function makeZero($scale = null)
345
    {
346 29
        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
349 93
    public static function getDefaultCalcMode(): int
350
    {
351 93
        return self::$defaultCalcMode;
352
    }
353
354
    public static function setDefaultCalcMode(int $mode): void
355
    {
356
        self::$defaultCalcMode = $mode;
357
    }
358
359
}