Passed
Push — master ( c50f33...e75397 )
by Jordan
04:38 queued 12s
created

ConstantProvider   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Test Coverage

Coverage 84.48%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 59
c 1
b 0
f 1
dl 0
loc 152
ccs 49
cts 58
cp 0.8448
rs 10
wmc 17

4 Methods

Rating   Name   Duplication   Size   Complexity  
A makeE() 0 31 6
A makeLn2() 0 13 3
A makePi() 0 41 5
A makeLn10() 0 13 3
1
<?php
2
3
4
namespace Samsara\Fermat\Provider;
5
6
7
use Samsara\Exceptions\SystemError\PlatformError\MissingPackage;
8
use Samsara\Exceptions\UsageError\IntegrityConstraint;
9
use Samsara\Fermat\Enums\CalcMode;
10
use Samsara\Fermat\Enums\NumberBase;
11
use Samsara\Fermat\Numbers;
12
use Samsara\Fermat\Types\Base\Interfaces\Numbers\DecimalInterface;
13
use Samsara\Fermat\Values\ImmutableDecimal;
14
15
/**
16
 *
17
 */
18
class ConstantProvider
19
{
20
21
    private static DecimalInterface $pi;
22
    private static DecimalInterface $e;
23
    private static DecimalInterface $ln10;
24
    private static DecimalInterface $ln2;
25
26
    /**
27
     * @param int $digits
28
     * @return string
29
     * @throws IntegrityConstraint
30
     * @throws MissingPackage
31
     */
32 5
    public static function makePi(int $digits): string
33
    {
34
35 5
        if (isset(self::$pi) && self::$pi->numberOfDecimalDigits() >= $digits) {
36 2
            return self::$pi->truncateToScale($digits)->getValue(NumberBase::Ten);
0 ignored issues
show
Unused Code introduced by
The call to Samsara\Fermat\Types\Bas...erInterface::getValue() has too many arguments starting with Samsara\Fermat\Enums\NumberBase::Ten. ( Ignorable by Annotation )

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

36
            return self::$pi->truncateToScale($digits)->/** @scrutinizer ignore-call */ getValue(NumberBase::Ten);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
37
        }
38
39 5
        $internalScale = $digits + 10;
40
41 5
        $C = Numbers::make(Numbers::IMMUTABLE, '10005', $internalScale)->setMode(CalcMode::Precision)->sqrt($internalScale)->multiply(426880);
42 5
        $M = Numbers::make(Numbers::IMMUTABLE, '1', $internalScale)->setMode(CalcMode::Precision);
43 5
        $L = Numbers::make(Numbers::IMMUTABLE, '13591409', $internalScale)->setMode(CalcMode::Precision);
44 5
        $K = Numbers::make(Numbers::IMMUTABLE, '6', $internalScale)->setMode(CalcMode::Precision);
45 5
        $X = Numbers::make(Numbers::IMMUTABLE, '1')->setMode(CalcMode::Precision);
46 5
        $sum = Numbers::make(Numbers::MUTABLE,'0', $internalScale + 2)->setMode(CalcMode::Precision);
47 5
        $termNum = 0;
48 5
        $one = Numbers::makeOne($internalScale)->setMode(CalcMode::Precision);
49
50 5
        $continue = true;
51
52 5
        while ($continue) {
53 5
            $term = $M->multiply($L)->divide($X);
54
55 5
            if ($termNum > $internalScale) {
56 5
                $continue = false;
57
            }
58
59 5
            $sum->add($term);
60
61 5
            $M = $M->multiply($K->pow(3)->subtract($K->multiply(16))->divide($one->add($termNum)->pow(3), $internalScale));
62 5
            $L = $L->add(545140134);
63 5
            $X = $X->multiply('-262537412640768000');
64 5
            $K = $K->add(12);
65 5
            $termNum++;
66
        }
67
68 5
        $pi = $C->divide($sum, $internalScale);
69
70 5
        self::$pi = $pi->truncateToScale($digits);
71
72 5
        return $pi->truncateToScale($digits)->getValue(NumberBase::Ten);
73
74
    }
75
76
    /**
77
     * Consider also: sum [0 -> INF] { (2n + 2) / (2n + 1)! }
78
     *
79
     * This converges faster (though it's unclear if the calculation is actually faster), and can be represented by this
80
     * set of Fermat calls:
81
     *
82
     * SequenceProvider::nthEvenNumber($n + 1)->divide(SequenceProvider::nthOddNumber($n)->factorial());
83
     *
84
     * Perhaps by substituting the nthOddNumber()->factorial() call with something tracked locally, the performance can
85
     * be improved. Current performance is acceptable even out past 200 digits.
86
     *
87
     * @param int $digits
88
     * @return string
89
     * @throws IntegrityConstraint
90
     */
91 3
    public static function makeE(int $digits): string
92
    {
93
94 3
        if (isset(self::$e) && self::$e->numberOfDecimalDigits() >= $digits) {
95
            return self::$e->truncateToScale($digits)->getValue(NumberBase::Ten);
0 ignored issues
show
Unused Code introduced by
The call to Samsara\Fermat\Types\Bas...erInterface::getValue() has too many arguments starting with Samsara\Fermat\Enums\NumberBase::Ten. ( Ignorable by Annotation )

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

95
            return self::$e->truncateToScale($digits)->/** @scrutinizer ignore-call */ getValue(NumberBase::Ten);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
96
        }
97
98 3
        $internalScale = $digits + 3;
99
100 3
        $one = Numbers::makeOne($internalScale+5)->setMode(CalcMode::Precision);
101 3
        $denominator = Numbers::make(Numbers::MUTABLE, '1', $internalScale)->setMode(CalcMode::Precision);
102 3
        $e = Numbers::make(NUmbers::MUTABLE, '2', $internalScale)->setMode(CalcMode::Precision);
103 3
        $n = Numbers::make(Numbers::MUTABLE, '2', $internalScale)->setMode(CalcMode::Precision);
104
105 3
        $continue = true;
106
107 3
        while ($continue) {
108 3
            $denominator->multiply($n);
109 3
            $n->add($one);
110 3
            $term = $one->divide($denominator);
111
112 3
            if ($term->numberOfLeadingZeros() > $internalScale || $term->isEqual(0)) {
0 ignored issues
show
Bug introduced by
The method numberOfLeadingZeros() does not exist on Samsara\Fermat\Types\Fraction. ( Ignorable by Annotation )

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

112
            if ($term->/** @scrutinizer ignore-call */ numberOfLeadingZeros() > $internalScale || $term->isEqual(0)) {

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...
113 3
                $continue = false;
114
            }
115
116 3
            $e->add($term);
117
        }
118
119 3
        self::$e = $e->truncateToScale($digits);
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

119
        /** @scrutinizer ignore-call */ 
120
        self::$e = $e->truncateToScale($digits);

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

119
        /** @scrutinizer ignore-call */ 
120
        self::$e = $e->truncateToScale($digits);

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...
120
121 3
        return $e->truncateToScale($digits)->getValue(NumberBase::Ten);
122
123
    }
124
125
    /**
126
     * The lnScale() implementation is very efficient, so this is probably our best bet for computing more digits of
127
     * ln(10) to provide.
128
     *
129
     * @param int $digits
130
     * @return string
131
     * @throws IntegrityConstraint
132
     */
133 1
    public static function makeLn10(int $digits): string
134
    {
135
136 1
        if (isset(self::$ln10) && self::$ln10->numberOfDecimalDigits() >= $digits) {
137
            return self::$ln10->truncateToScale($digits)->getValue(NumberBase::Ten);
0 ignored issues
show
Unused Code introduced by
The call to Samsara\Fermat\Types\Bas...erInterface::getValue() has too many arguments starting with Samsara\Fermat\Enums\NumberBase::Ten. ( Ignorable by Annotation )

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

137
            return self::$ln10->truncateToScale($digits)->/** @scrutinizer ignore-call */ getValue(NumberBase::Ten);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
138
        }
139
140 1
        $ln10 = Numbers::make(Numbers::IMMUTABLE, 10, $digits+2)->setMode(CalcMode::Precision);
141 1
        $ln10 = $ln10->ln();
0 ignored issues
show
Bug introduced by
The method ln() 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

141
        /** @scrutinizer ignore-call */ 
142
        $ln10 = $ln10->ln();

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

141
        /** @scrutinizer ignore-call */ 
142
        $ln10 = $ln10->ln();

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...
142
143 1
        self::$ln10 = $ln10;
144
145 1
        return $ln10->truncateToScale($digits)->getValue(NumberBase::Ten);
146
147
    }
148
149
    /**
150
     * The lnScale() implementation is very efficient, so this is probably our best bet for computing more digits of
151
     * ln(10) to provide.
152
     *
153
     * @param int $digits
154
     * @return string
155
     * @throws IntegrityConstraint
156
     */
157
    public static function makeLn2(int $digits): string
158
    {
159
160
        if (isset(self::$ln2) && self::$ln2->numberOfDecimalDigits() >= $digits) {
161
            return self::$ln2->truncateToScale($digits)->getValue(NumberBase::Ten);
0 ignored issues
show
Unused Code introduced by
The call to Samsara\Fermat\Types\Bas...erInterface::getValue() has too many arguments starting with Samsara\Fermat\Enums\NumberBase::Ten. ( Ignorable by Annotation )

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

161
            return self::$ln2->truncateToScale($digits)->/** @scrutinizer ignore-call */ getValue(NumberBase::Ten);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
162
        }
163
164
        $ln2 = Numbers::make(Numbers::IMMUTABLE, 2, $digits+2)->setMode(CalcMode::Precision);
165
        $ln2 = $ln2->ln();
166
167
        self::$ln2 = $ln2;
168
169
        return $ln2->truncateToScale($digits)->getValue(NumberBase::Ten);
170
171
    }
172
173
}