Numbers::makeNaturalLog2()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
dl 0
loc 20
ccs 8
cts 8
cp 1
crap 4
rs 9.9332
c 0
b 0
f 0
eloc 10
nc 4
nop 1
1
<?php
2
3
namespace Samsara\Fermat\Core;
4
5
use Samsara\Exceptions\UsageError\IntegrityConstraint;
6
use Samsara\Fermat\Core\Enums\NumberBase;
7
use Samsara\Fermat\Core\Provider\ConstantProvider;
8
use Samsara\Fermat\Core\Types\Base\Interfaces\Numbers\DecimalInterface;
9
use Samsara\Fermat\Core\Types\Base\Interfaces\Numbers\FractionInterface;
10
use Samsara\Fermat\Core\Types\Base\Interfaces\Numbers\NumberInterface;
0 ignored issues
show
Bug introduced by
The type Samsara\Fermat\Core\Type...Numbers\NumberInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use Samsara\Fermat\Core\Values\ImmutableFraction;
12
use Samsara\Fermat\Core\Values\ImmutableDecimal;
13
use Samsara\Fermat\Core\Values\MutableFraction;
14
use Samsara\Fermat\Core\Values\MutableDecimal;
15
16
/**
17
 * This class contains useful factory methods to create various numbers, verify the
18
 * class of a given number, and generally handle all of the formatting necessary to
19
 * satisfy the various constructors of valid value objects.
20
 *
21
 * @package Samsara\Fermat\Core
22
 */
23
class Numbers
24
{
25
26
    public const MUTABLE = MutableDecimal::class;
27
    public const IMMUTABLE = ImmutableDecimal::class;
28
    public const MUTABLE_FRACTION = MutableFraction::class;
29
    public const IMMUTABLE_FRACTION = ImmutableFraction::class;
30
    /* 105 digits after decimal, which is going to be overkill in almost all places */
31
    public const PI = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679';
32
    /* Tau (2pi) to 100 digits */
33
    public const TAU = '6.2831853071795864769252867665590057683943387987502116419498891846156328125724179972560696506842341359';
34
    /* Euler's Number to 100 digits */
35
    public const E = '2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427';
36
    /* Golden Ratio to 100 digits */
37
    public const GOLDEN_RATIO = '1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137';
38
    /* Natural log of 10 to 100 digits */
39
    public const LN_10 = '2.302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298';
40
    /* Natural log of 2 to 100 digits */
41
    public const LN_2 = '0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687';
42
    /* The value of i^i */
43
    public const I_POW_I = '0.2078795763507619085469556198349787700338778416317696080751358830554198772854821397886002778654260353';
44
45
    /**
46
     * This class will make and return an instance of a concrete value.
47
     *
48
     * The main reason for this class is that you can pass an unknown value instance as the
49
     * $type parameter and it will behave as if you passed the FQCN.
50
     *
51
     * @param mixed         $type   An instance of FQCN for any Fermat value class.
52
     * @param mixed         $value  Any value which is valid for the constructor which will be called.
53
     * @param int|null      $scale  The scale setting the created instance should have.
54
     * @param NumberBase    $base   The base to create the number in. Note, this is not the same as the base of $value, which is always base-10
55
     *
56
     * @return ImmutableDecimal|MutableDecimal|ImmutableFraction|MutableFraction|NumberInterface|FractionInterface
57
     * @throws IntegrityConstraint
58
     */
59 3827
    public static function make(mixed $type, mixed $value, ?int $scale = null, NumberBase $base = NumberBase::Ten)
60
    {
61
62 3827
        if (is_object($type)) {
63 694
            $type = get_class($type);
64
        }
65
66 3827
        if ($type === static::IMMUTABLE) {
67 3827
            return new ImmutableDecimal(trim($value), $scale, $base, true);
68
        }
69
70 922
        if ($type === static::MUTABLE) {
71 710
            return new MutableDecimal(trim($value), $scale, $base, true);
72
        }
73
74 214
        if ($type === static::IMMUTABLE_FRACTION) {
75 210
            return self::makeFractionFromString($type, $value, $base);
76
        }
77
78 6
        if ($type === static::MUTABLE_FRACTION) {
79 6
            return self::makeFractionFromString($type, $value, $base);
80
        }
81
82
        throw new IntegrityConstraint(
83
            '$type must be an implemented concrete class that is supported',
84
            'Provide a type that implements NumberInterface or CoordinateInterface (the Numbers class contains constants for the built in ones)',
85
            'The $type argument was not an implementation of NumberInterface or CoordinateInterface'
86
        );
87
    }
88
89
    /**
90
     * @param $type
91
     * @param $value
92
     * @param int|null $scale
93
     * @param NumberBase $base
94
     *
95
     * @return NumberInterface
96
     * @throws IntegrityConstraint
97
     */
98 2
    public static function makeFromBase10($type, $value, ?int $scale = null, NumberBase $base = NumberBase::Ten): NumberInterface
99
    {
100
        /**
101
         * @var ImmutableDecimal|MutableDecimal $number
102
         */
103 2
        $number = self::make($type, $value, $scale);
104
105 2
        return $number->setBase($base);
106
    }
107
108
    /**
109
     * @param string|object $type
110
     * @param int|float|string|array|NumberInterface|DecimalInterface|FractionInterface $value
111
     * @param int|null $scale
112
     * @param NumberBase $base
113
     *
114
     * @return ImmutableDecimal|MutableDecimal|NumberInterface|ImmutableDecimal[]|MutableDecimal[]|NumberInterface[]
115
     * @throws IntegrityConstraint
116
     */
117 3815
    public static function makeOrDont(string|object $type, mixed $value, ?int $scale = null, NumberBase $base = NumberBase::Ten)
118
    {
119
120 3815
        if (is_object($value)) {
121 3763
            if ($value instanceof $type) {
122 3523
                return $value;
123
            }
124
125 902
            if ($value instanceof NumberInterface) {
126 902
                return static::make($type, $value->getValue(NumberBase::Ten), $scale, $base);
127
            }
128 3789
        } elseif (is_array($value)) {
129 300
            $newInput = [];
130
131 300
            foreach ($value as $key => $item) {
132 300
                $newInput[$key] = static::makeOrDont($type, $item, $scale, $base);
133
            }
134
135 300
            return $newInput;
136 3789
        } elseif (is_string($value) || is_int($value) || is_float($value)) {
137 3789
            $isImaginary = str_contains($value, 'i');
138
139 3789
            if (is_numeric($value) || $isImaginary) {
140 3789
                return static::make($type, $value, $scale, $base);
141
            }
142
        }
143
144
        throw new IntegrityConstraint(
145
            '$input must be an int, float, numeric string, or an implementation of NumberInterface',
146
            'Provide any of the MANY valid inputs',
147
            'The $input argument was not numeric or an implementation of NumberInterface. Given value: '.$value
148
        );
149
150
    }
151
152
    /**
153
     * @param string $type
154
     * @param string $value
155
     * @param NumberBase $base
156
     *
157
     * @return FractionInterface
158
     * @throws IntegrityConstraint
159
     */
160 216
    public static function makeFractionFromString(string $type, string $value, NumberBase $base = NumberBase::Ten): FractionInterface
161
    {
162 216
        $parts = explode('/', $value);
163
164 216
        if (count($parts) > 2) {
165
            throw new IntegrityConstraint(
166
                'Only one division symbol (/) can be used',
167
                'Change the calling code to not provide more than one division symbol',
168
                'makeFractionFromString needs either one or zero division symbols in the $value argument; '.$value.' given'
169
            );
170
        }
171
172
        /** @var ImmutableDecimal $numerator */
173 216
        $numerator = self::make(self::IMMUTABLE, trim($parts[0]));
174
        /** @var ImmutableDecimal $denominator */
175 216
        $denominator = isset($parts[1]) ? self::make(self::IMMUTABLE, trim($parts[1])) : self::makeOne();
176
177 216
        if ($type === self::IMMUTABLE_FRACTION) {
178 212
            return new ImmutableFraction($numerator, $denominator, $base);
179
        }
180
181 6
        if ($type === self::MUTABLE_FRACTION) {
182 6
            return new MutableFraction($numerator, $denominator, $base);
183
        }
184
185
        throw new IntegrityConstraint(
186
            'Type must be an implementation of FractionInterface',
187
            'Alter to calling code to use the correct type',
188
            'makeFractionFromString can only make objects which implement the FractionInterface; '.$type.' given'
189
        );
190
    }
191
192
    /**
193
     * @param int|null $scale
194
     *
195
     * @return ImmutableDecimal
196
     * @throws IntegrityConstraint
197
     */
198 1236
    public static function makePi(int $scale = null): ImmutableDecimal
199
    {
200
201 1236
        if (!is_null($scale)) {
202 1144
            if ($scale < 1) {
203 2
                throw new IntegrityConstraint(
204
                    '$scale must be at least 1',
205
                    'Provide a scale within range',
206
                    'The pi constant cannot have a scale less than 1'
207
                );
208
            }
209
210 1144
            if ($scale > 100) {
211 8
                return self::make(self::IMMUTABLE, ConstantProvider::makePi($scale), $scale);
212
            }
213
214 1140
            return self::make(self::IMMUTABLE, self::PI, $scale+1)->truncateToScale($scale);
215
        }
216
217 150
        return self::make(self::IMMUTABLE, self::PI, 100);
218
219
    }
220
221
    /**
222
     * @param null $scale
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $scale is correct as it would always require null to be passed?
Loading history...
223
     *
224
     * @return ImmutableDecimal
225
     * @throws IntegrityConstraint
226
     */
227 1006
    public static function makeTau($scale = null): ImmutableDecimal
228
    {
229 1006
        if (!is_null($scale)) {
0 ignored issues
show
introduced by
The condition is_null($scale) is always true.
Loading history...
230 926
            if ($scale < 1) {
231 2
                throw new IntegrityConstraint(
232
                    '$scale must be at least 1',
233
                    'Provide a scale within range',
234
                    'The E constant cannot have a scale less than 1'
235
                );
236
            }
237
238 926
            if ($scale > 100) {
239 8
                $pi = self::make(self::IMMUTABLE, ConstantProvider::makePi($scale+2), $scale + 2);
240
                /** @var ImmutableDecimal */
241 8
                return $pi->multiply(2)->truncateToScale($scale);
242
            }
243
244 922
            return self::make(self::IMMUTABLE, self::TAU, $scale+1)->truncateToScale($scale);
245
        }
246
247 132
        return self::make(self::IMMUTABLE, self::TAU, 100);
248
    }
249
250
    /**
251
     * @param int|null $scale
252
     *
253
     * @return ImmutableDecimal
254
     * @throws IntegrityConstraint
255
     */
256 730
    public static function make2Pi(int $scale = null): ImmutableDecimal
257
    {
258 730
        return self::makeTau($scale);
0 ignored issues
show
Bug introduced by
It seems like $scale can also be of type integer; however, parameter $scale of Samsara\Fermat\Core\Numbers::makeTau() does only seem to accept null, 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

258
        return self::makeTau(/** @scrutinizer ignore-type */ $scale);
Loading history...
259
    }
260
261
    /**
262
     * @param int|null $scale
263
     *
264
     * @return ImmutableDecimal
265
     * @throws IntegrityConstraint
266
     */
267 124
    public static function makeE(int $scale = null): ImmutableDecimal
268
    {
269
270 124
        if (!is_null($scale)) {
271 122
            if ($scale < 1) {
272 2
                throw new IntegrityConstraint(
273
                    '$scale must be at least 1',
274
                    'Provide a scale within range',
275
                    'The E constant cannot have a scale less than 1'
276
                );
277
            }
278
279 122
            if ($scale > 100) {
280 2
                return self::make(self::IMMUTABLE, ConstantProvider::makeE($scale), $scale);
281
            }
282
283 122
            return self::make(self::IMMUTABLE, self::E, $scale+1)->truncateToScale($scale);
284
        }
285
286 4
        return self::make(self::IMMUTABLE, self::E, 100);
287
288
    }
289
290
    /**
291
     * @param int|null $scale
292
     *
293
     * @return ImmutableDecimal
294
     * @throws IntegrityConstraint
295
     */
296 2
    public static function makeGoldenRatio(?int $scale = null): ImmutableDecimal
297
    {
298
299 2
        if (!is_null($scale)) {
300 2
            if ($scale < 1) {
301 2
                throw new IntegrityConstraint(
302
                    '$scale must be at least 1',
303
                    'Provide a scale within range',
304
                    'The Phi constant (Golden Ratio) cannot have a scale less than 1'
305
                );
306
            }
307
308 2
            if ($scale > 100) {
309 2
                return self::make(self::IMMUTABLE, ConstantProvider::makeGoldenRatio($scale), $scale);
310
            }
311
312 2
            return self::make(self::IMMUTABLE, self::GOLDEN_RATIO, $scale+1)->truncateToScale($scale);
313
        }
314
315 2
        return self::make(self::IMMUTABLE, self::GOLDEN_RATIO, 100);
316
317
    }
318
319
    /**
320
     * @param int|null $scale
321
     *
322
     * @return ImmutableDecimal
323
     * @throws IntegrityConstraint
324
     */
325 32
    public static function makeNaturalLog10(?int $scale = null): ImmutableDecimal
326
    {
327
328 32
        if (!is_null($scale)) {
329 32
            if ($scale < 1) {
330 2
                throw new IntegrityConstraint(
331
                    '$scale must be at least 1',
332
                    'Provide a scale within range',
333
                    'The natural log of 10 constant cannot have a scale less than 1'
334
                );
335
            }
336
337 32
            if ($scale > 100) {
338 2
                return self::make(self::IMMUTABLE, ConstantProvider::makeLn10($scale), $scale);
339
            }
340
341 32
            return self::make(self::IMMUTABLE, self::LN_10, $scale+1)->truncateToScale($scale);
342
        }
343
344 2
        return self::make(self::IMMUTABLE, self::LN_10, 100);
345
346
    }
347
348
    /**
349
     * @param int|null $scale
350
     *
351
     * @return ImmutableDecimal
352
     * @throws IntegrityConstraint
353
     */
354 69
    public static function makeNaturalLog2(?int $scale = null): ImmutableDecimal
355
    {
356
357 69
        if (!is_null($scale)) {
358 69
            if ($scale < 1) {
359 2
                throw new IntegrityConstraint(
360
                    '$scale must be at least 1',
361
                    'Provide a scale within range',
362
                    'The natural log of 10 constant cannot have a scale less than 1'
363
                );
364
            }
365
366 69
            if ($scale > 100) {
367 13
                return self::make(self::IMMUTABLE, ConstantProvider::makeLn2($scale), $scale);
368
            }
369
370 59
            return self::make(self::IMMUTABLE, self::LN_2, $scale+1)->truncateToScale($scale);
371
        }
372
373 2
        return self::make(self::IMMUTABLE, self::LN_2, 100);
374
375
    }
376
377
    /**
378
     * @param int|null $scale
379
     *
380
     * @return ImmutableDecimal
381
     * @throws IntegrityConstraint
382
     */
383 1363
    public static function makeOne(?int $scale = null): ImmutableDecimal
384
    {
385 1363
        return self::make(self::IMMUTABLE, 1, $scale);
386
    }
387
388
    /**
389
     * @param int|null $scale
390
     *
391
     * @return ImmutableDecimal
392
     * @throws IntegrityConstraint
393
     */
394 1220
    public static function makeZero(?int $scale = null): ImmutableDecimal
395
    {
396 1220
        return self::make(self::IMMUTABLE, 0, $scale);
397
    }
398
399
}