Test Failed
Push — dev ( 624b6b...51d7f8 )
by Jordan
32:11 queued 17:14
created

Numbers::makeZero()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
3
namespace Samsara\Fermat;
4
5
use Samsara\Exceptions\UsageError\IntegrityConstraint;
6
use Samsara\Fermat\Types\Base\Interfaces\Coordinates\CoordinateInterface;
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\Fraction;
11
use Samsara\Fermat\Values\Geometry\CoordinateSystems\CartesianCoordinate;
12
use Samsara\Fermat\Values\ImmutableFraction;
13
use Samsara\Fermat\Values\ImmutableDecimal;
14
use Samsara\Fermat\Values\MutableFraction;
15
use Samsara\Fermat\Values\MutableDecimal;
16
17
class Numbers
18
{
19
20
    const MUTABLE = MutableDecimal::class;
21
    const IMMUTABLE = ImmutableDecimal::class;
22
    const MUTABLE_FRACTION = MutableFraction::class;
23
    const IMMUTABLE_FRACTION = ImmutableFraction::class;
24
    const CARTESIAN_COORDINATE = CartesianCoordinate::class;
25
    /* 105 digits after decimal, which is going to be overkill in almost all places */
26
    const PI = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679';
27
    /* Tau (2pi) to 100 digits */
28
    const TAU = '6.283185307179586476925286766559005768394338798750211641949889184615632812572417997256069650684234136';
29
    /* Euler's Number to 100 digits */
30
    const E = '2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427';
31
    /* Golden Ratio to 100 digits */
32
    const GOLDEN_RATIO = '1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137';
33
    /* Natural log of 10 to 100 digits */
34
    const LN_10 = '2.302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298';
35
    /* The value of i^i */
36
    const I_POW_I = '0.2078795763507619085469556198349787700338778416317696080751358830554198772854821397886002778654260353';
37
38
    /**
39
     * @param $type
40
     * @param $value
41
     * @param int|null $precision
42
     * @param int $base
43
     *
44
     * @return ImmutableDecimal|MutableDecimal|ImmutableFraction|MutableFraction|CartesianCoordinate|NumberInterface|FractionInterface|CoordinateInterface
45 72
     *@throws IntegrityConstraint
46
     */
47
    public static function make($type, $value, $precision = null, $base = 10)
48 72
    {
49 1
50
        if (is_object($type)) {
51
            $type = get_class($type);
52 72
        }
53 72
54 7
        if ($type == static::IMMUTABLE) {
55 5
            return new ImmutableDecimal(trim($value), $precision, $base);
56 5
        } elseif ($type == static::MUTABLE) {
57 4
            return new MutableDecimal(trim($value), $precision, $base);
58 4
        } elseif ($type == static::IMMUTABLE_FRACTION) {
59 3
            return self::makeFractionFromString($type, $value, $base);
60 1
        } elseif ($type == static::MUTABLE_FRACTION) {
61 1
            return self::makeFractionFromString($type, $value, $base);
62
        } elseif ($type == static::CARTESIAN_COORDINATE && is_array($value)) {
63
            $x = $value[0];
64
65
            if (isset($value[1])) {
66
                $y = $value[1];
67
            } else {
68
                $y = null;
69
            }
70
71
            if (isset($value[2])) {
72
                $z = $value[2];
73
            } else {
74
                $z = null;
75
            }
76
77
            return new CartesianCoordinate($x, $y, $z);
78
        } else {
79
            $reflector = new \ReflectionClass($type);
80
81
            if ($reflector->implementsInterface(FractionInterface::class) && $reflector->isSubclassOf(Fraction::class)) {
82
                return Numbers::makeFractionFromString($reflector->getName(), $value, $base);
83
            }
84
85
            if ($reflector->implementsInterface(CoordinateInterface::class) && is_array($value)) {
86
                /** @var CoordinateInterface $customCoordinate */
87
                $customCoordinate = $reflector->newInstance([
88
                    $value
89
                ]);
90
                return $customCoordinate;
91
            }
92
93
            if ($reflector->implementsInterface(NumberInterface::class)) {
94
                /** @var NumberInterface $customNumber */
95
                $customNumber = $reflector->newInstance([
96
                    trim($value),
97
                    $precision,
98
                    $base
99
                ]);
100
                return $customNumber;
101
            }
102
103
            if ($reflector->implementsInterface(CoordinateInterface::class) && !is_array($value)) {
104
                throw new IntegrityConstraint(
105
                    'The $value for a CoordinateInterface must be an array',
106
                    'Provide an array for the $value',
107
                    'A CoordinateInterface expects the value to be an array of axes and values'
108
                );
109
            }
110 1
        }
111
112
        throw new IntegrityConstraint(
113
            '$type must be an implementation of NumberInterface or CoordinateInterface',
114
            'Provide a type that implements NumberInterface or CoordinateInterface (the Numbers class contains constants for the built in ones)',
115 1
            'The $type argument was not an implementation of NumberInterface or CoordinateInterface'
116
        );
117 1
    }
118
119
    /**
120
     * @param $type
121
     * @param $value
122
     * @param int|null $precision
123
     * @param int $base
124
     * @return NumberInterface
125
     * @throws IntegrityConstraint
126
     */
127
    public static function makeFromBase10($type, $value, $precision = null, $base = 10)
128
    {
129 71
        /**
130
         * @var ImmutableDecimal|MutableDecimal
131
         */
132 71
        $number = self::make($type, $value, $precision, 10);
133 63
134
        return $number->convertToBase($base);
0 ignored issues
show
Bug introduced by
The method convertToBase() does not exist on Samsara\Fermat\Types\Bas...mbers\FractionInterface. ( Ignorable by Annotation )

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

134
        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\Types\Bas...Numbers\NumberInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...Numbers\NumberInterface such as Samsara\Fermat\Types\Decimal or Samsara\Fermat\Types\Decimal. ( Ignorable by Annotation )

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

134
        return $number->/** @scrutinizer ignore-call */ convertToBase($base);
Loading history...
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

134
        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\Ge...ems\CartesianCoordinate. ( Ignorable by Annotation )

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

134
        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

134
        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\Types\Bas...tes\CoordinateInterface. ( Ignorable by Annotation )

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

134
        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...
135 63
    }
136 63
137
    /**
138
     * @param $type
139 2
     * @param int|float|string|NumberInterface|DecimalInterface|FractionInterface $value
140 2
     * @param int|null $precision
141
     * @param int $base
142 61
     *
143 4
     * @return ImmutableDecimal|MutableDecimal|NumberInterface|ImmutableDecimal[]|MutableDecimal[]|NumberInterface[]
144
     * @throws IntegrityConstraint|\ReflectionException
145 4
     */
146 4
    public static function makeOrDont($type, $value, $precision = null, $base = 10)
147
    {
148
149 4
        if (is_object($value)) {
150 61
            $reflector = new \ReflectionClass($value);
151 61
152
            if ($value instanceof $type) {
153
                return $value;
154
            }
155
156
            if ($reflector->implementsInterface(NumberInterface::class)) {
157
                return static::make($type, $value->getValue(), $precision, $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

157
                return static::make($type, $value->/** @scrutinizer ignore-call */ getValue(), $precision, $base);
Loading history...
158
            }
159
        } elseif (is_array($value)) {
0 ignored issues
show
introduced by
The condition is_array($value) is always false.
Loading history...
160
            $newInput = [];
161
162
            foreach ($value as $key => $item) {
163
                $newInput[$key] = static::makeOrDont($type, $item, $precision, $base);
164
            }
165
166
            return $newInput;
167
        } elseif (is_numeric($value)) {
168
            return static::make($type, $value, $precision, $base);
169
        }
170 4
171
        throw new IntegrityConstraint(
172 4
            '$input must be an int, float, numeric string, or an implementation of NumberInterface',
173
            'Provide any of the MANY valid inputs',
174 4
            'The $input argument was not numeric or an implementation of NumberInterface.'
175
        );
176
177
    }
178
179
    /**
180
     * @param     $type
181
     * @param     $value
182
     * @param int $base
183 4
     *
184
     * @return FractionInterface|ImmutableFraction|MutableFraction
185 4
     * @throws IntegrityConstraint|\ReflectionException
186
     */
187 4
    public static function makeFractionFromString($type, $value, $base = 10)
188 4
    {
189 3
        $parts = explode('/', $value);
190 3
191
        if (count($parts) > 2) {
192
            throw new IntegrityConstraint(
193
                'Only one division symbol (/) can be used',
194
                'Change the calling code to not provide more than one division symbol',
195
                'makeFractionFromString needs either one or zero division symbols in the $value argument; '.$value.' given'
196
            );
197
        }
198
199
        /** @var ImmutableDecimal $numerator */
200
        $numerator = Numbers::make(Numbers::IMMUTABLE, trim(ltrim($parts[0])))->round();
0 ignored issues
show
Bug introduced by
The method round() 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

200
        $numerator = Numbers::make(Numbers::IMMUTABLE, trim(ltrim($parts[0])))->/** @scrutinizer ignore-call */ round();

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 round() does not exist on Samsara\Fermat\Types\Bas...mbers\FractionInterface. ( Ignorable by Annotation )

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

200
        $numerator = Numbers::make(Numbers::IMMUTABLE, trim(ltrim($parts[0])))->/** @scrutinizer ignore-call */ round();

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 round() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...Numbers\NumberInterface such as Samsara\Fermat\Types\Bas...umbers\DecimalInterface or Samsara\Fermat\Types\Decimal. ( Ignorable by Annotation )

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

200
        $numerator = Numbers::make(Numbers::IMMUTABLE, trim(ltrim($parts[0])))->/** @scrutinizer ignore-call */ round();
Loading history...
Bug introduced by
The method round() 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

200
        $numerator = Numbers::make(Numbers::IMMUTABLE, trim(ltrim($parts[0])))->/** @scrutinizer ignore-call */ round();

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...
201
        /** @var ImmutableDecimal $denominator */
202
        $denominator = isset($parts[1]) ? Numbers::make(Numbers::IMMUTABLE, trim(ltrim($parts[1])))->round() : Numbers::makeOne();
203
204
        if ($type == self::IMMUTABLE_FRACTION) {
205
            return new ImmutableFraction($numerator, $denominator, $base);
206
        } elseif ($type == self::MUTABLE_FRACTION) {
207
            return new MutableFraction($numerator, $denominator, $base);
208
        } else {
209
            $reflector = new \ReflectionClass($type);
210
211
            if ($reflector->implementsInterface(FractionInterface::class) && $reflector->isSubclassOf(Fraction::class)) {
212
                /** @var FractionInterface|Fraction $customFraction */
213
                $customFraction = $reflector->newInstance([
214
                    $numerator,
215
                    $denominator,
216
                    $base
217
                ]);
218 16
                return $customFraction;
219
            }
220
221 16
            throw new IntegrityConstraint(
222 1
                'Type must be an implementation of FractionInterface',
223 1
                'Alter to calling code to use the correct type',
224 1
                'makeFractionFromString can only make objects which implement the FractionInterface; '.$type.' given'
225 1
            );
226
        }
227
    }
228
229 16
    /**
230 6
     * @param int|null $precision
231
     *
232 12
     * @throws IntegrityConstraint
233
     * @return NumberInterface
234
     */
235
    public static function makePi($precision = null)
236
    {
237
        
238
        if (!is_null($precision) && ($precision > 100 || $precision < 1)) {
239
            throw new IntegrityConstraint(
240
                '$precision must be between 1 and 100 inclusive',
241
                'Provide a precision within range',
242
                'The PI constant cannot have a precision higher than the constant stored (100)'
243 7
            );
244
        }
245 7
        
246 1
        if (!is_null($precision)) {
247 1
            return self::make(self::IMMUTABLE, self::PI, $precision)->truncateToPrecision($precision);
0 ignored issues
show
Bug introduced by
The method truncateToPrecision() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...Numbers\NumberInterface such as Samsara\Fermat\Types\Bas...umbers\DecimalInterface or Samsara\Fermat\Types\Decimal. ( Ignorable by Annotation )

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

247
            return self::make(self::IMMUTABLE, self::PI, $precision)->/** @scrutinizer ignore-call */ truncateToPrecision($precision);
Loading history...
Bug introduced by
The method truncateToPrecision() 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

247
            return self::make(self::IMMUTABLE, self::PI, $precision)->/** @scrutinizer ignore-call */ truncateToPrecision($precision);

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 truncateToPrecision() 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

247
            return self::make(self::IMMUTABLE, self::PI, $precision)->/** @scrutinizer ignore-call */ truncateToPrecision($precision);

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 truncateToPrecision() does not exist on Samsara\Fermat\Types\Bas...mbers\FractionInterface. ( Ignorable by Annotation )

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

247
            return self::make(self::IMMUTABLE, self::PI, $precision)->/** @scrutinizer ignore-call */ truncateToPrecision($precision);

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...
248 1
        } else {
249 1
            return self::make(self::IMMUTABLE, self::PI, 100);
250
        }
251
        
252
    }
253 7
254 1
    /**
255
     * @param int|null $precision
256 7
     *
257
     * @throws IntegrityConstraint
258
     * @return NumberInterface
259
     */
260
    public static function makeTau($precision = null)
261
    {
262
        if (!is_null($precision) && ($precision > 100 || $precision < 1)) {
263
            throw new IntegrityConstraint(
264
                '$precision must be between 1 and 100 inclusive',
265 7
                'Provide a precision within range',
266
                'The TAU constant cannot have a precision higher than the constant stored (100)'
267 7
            );
268
        }
269
270
        if (!is_null($precision)) {
271
            return self::make(self::IMMUTABLE, self::TAU, $precision)->truncateToPrecision($precision);
272
        } else {
273
            return self::make(self::IMMUTABLE, self::TAU, 100);
274
        }
275
    }
276 6
277
    /**
278
     * @param int|null $precision
279 6
     *
280 1
     * @return NumberInterface
281 1
     * @throws IntegrityConstraint
282 1
     */
283 1
    public static function make2Pi($precision = null)
284
    {
285
        return self::makeTau($precision);
286
    }
287 6
288 1
    /**
289
     * @param int|null $precision
290 6
     *
291
     * @throws IntegrityConstraint
292
     * @return NumberInterface
293
     */
294
    public static function makeE($precision = null)
295
    {
296
297
        if (!is_null($precision) && ($precision > 100 || $precision < 1)) {
298
            throw new IntegrityConstraint(
299
                '$precision must be between 1 and 100 inclusive',
300
                'Provide a precision within range',
301 1
                'The E constant cannot have a precision higher than the constant stored (100)'
302
            );
303
        }
304 1
305 1
        if (!is_null($precision)) {
306 1
            return self::make(self::IMMUTABLE, self::E, $precision)->truncateToPrecision($precision);
307 1
        } else {
308 1
            return self::make(self::IMMUTABLE, self::E, 100);
309
        }
310
311
    }
312 1
313 1
    /**
314
     * @param int|null $precision
315 1
     *
316
     * @throws IntegrityConstraint
317
     * @return NumberInterface
318
     */
319
    public static function makeGoldenRatio($precision = null)
320
    {
321
322
        if (!is_null($precision) && ($precision > 100 || $precision < 1)) {
323
            throw new IntegrityConstraint(
324
                '$precision must be between 1 and 100 inclusive',
325
                'Provide a precision within range',
326 2
                'The Golden Ratio constant cannot have a precision higher than the constant stored (100)'
327
            );
328
        }
329 2
330 1
        if (!is_null($precision)) {
331 1
            return self::make(self::IMMUTABLE, self::GOLDEN_RATIO, $precision)->truncateToPrecision($precision);
332 1
        } else {
333 1
            return self::make(self::IMMUTABLE, self::GOLDEN_RATIO, 100);
334
        }
335
336
    }
337 2
338 1
    /**
339
     * @param int|null $precision
340 2
     *
341
     * @throws IntegrityConstraint
342
     * @return NumberInterface
343
     */
344
    public static function makeNaturalLog10($precision = null)
345
    {
346
347
        if (!is_null($precision) && ($precision > 100 || $precision < 1)) {
348
            throw new IntegrityConstraint(
349
                '$precision must be between 1 and 100 inclusive',
350 28
                'Provide a precision within range',
351
                'The natural log of 10 constant cannot have a precision higher than the constant stored (100)'
352 28
            );
353
        }
354
355
        if (!is_null($precision)) {
356
            return self::make(self::IMMUTABLE, self::LN_10, $precision)->truncateToPrecision($precision);
357
        } else {
358
            return self::make(self::IMMUTABLE, self::LN_10, 100);
359
        }
360 30
361
    }
362 30
363
    /**
364
     * @param int|null $precision
365
     *
366
     * @return ImmutableDecimal
367
     * @throws IntegrityConstraint
368
     */
369
    public static function makeOne($precision = null)
370
    {
371
        return self::make(self::IMMUTABLE, 1, $precision);
372
    }
373
374
    /**
375
     * @param int|null $precision
376
     *
377
     * @return ImmutableDecimal
378
     * @throws IntegrityConstraint
379
     */
380
    public static function makeZero($precision = null)
381
    {
382
        return self::make(self::IMMUTABLE, 0, $precision);
383
    }
384
385
}