Passed
Push — master ( a94b8a...621c3c )
by Jordan
21:05 queued 14:22
created

ConstantProvider::makeLn1p1()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 4.0023

Importance

Changes 0
Metric Value
cc 4
eloc 18
nc 2
nop 1
dl 0
loc 31
ccs 18
cts 19
cp 0.9474
crap 4.0023
rs 9.6666
c 0
b 0
f 0
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
    private static DecimalInterface $ln1p1;
26
27
    /**
28
     * @param int $digits
29
     * @return string
30
     * @throws IntegrityConstraint
31
     * @throws MissingPackage
32
     */
33 5
    public static function makePi(int $digits): string
34
    {
35
36 5
        if (isset(self::$pi) && self::$pi->numberOfDecimalDigits() >= $digits) {
37 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

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

96
            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...
97
        }
98
99 2
        $internalScale = $digits + 3;
100
101 2
        $one = Numbers::makeOne($internalScale+5)->setMode(CalcMode::Precision);
102 2
        $denominator = Numbers::make(Numbers::MUTABLE, '1', $internalScale)->setMode(CalcMode::Precision);
103 2
        $e = Numbers::make(NUmbers::MUTABLE, '2', $internalScale)->setMode(CalcMode::Precision);
104 2
        $n = Numbers::make(Numbers::MUTABLE, '2', $internalScale)->setMode(CalcMode::Precision);
105
106 2
        $continue = true;
107
108 2
        while ($continue) {
109 2
            $denominator->multiply($n);
110 2
            $n->add($one);
111 2
            $term = $one->divide($denominator);
112
113 2
            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

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

120
        /** @scrutinizer ignore-call */ 
121
        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\ImmutableFraction. ( Ignorable by Annotation )

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

120
        /** @scrutinizer ignore-call */ 
121
        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...
121
122 2
        return $e->truncateToScale($digits)->getValue(NumberBase::Ten);
123
124
    }
125
126
    /**
127
     * The lnScale() implementation is very efficient, so this is probably our best bet for computing more digits of
128
     * ln(10) to provide.
129
     *
130
     * @param int $digits
131
     * @return string
132
     * @throws IntegrityConstraint
133
     */
134 1
    public static function makeLn10(int $digits): string
135
    {
136
137 1
        if (isset(self::$ln10) && self::$ln10->numberOfDecimalDigits() >= $digits) {
138
            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

138
            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...
139
        }
140
141 1
        $ln10 = Numbers::make(Numbers::IMMUTABLE, 10, $digits+2)->setMode(CalcMode::Precision);
142 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

142
        /** @scrutinizer ignore-call */ 
143
        $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

142
        /** @scrutinizer ignore-call */ 
143
        $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...
143
144 1
        self::$ln10 = $ln10;
145
146 1
        return $ln10->truncateToScale($digits)->getValue(NumberBase::Ten);
147
148
    }
149
150
    /**
151
     * The lnScale() implementation is very efficient, so this is probably our best bet for computing more digits of
152
     * ln(10) to provide.
153
     *
154
     * @param int $digits
155
     * @return string
156
     * @throws IntegrityConstraint
157
     */
158 2
    public static function makeLn2(int $digits): string
159
    {
160
161 2
        if (isset(self::$ln2) && self::$ln2->numberOfDecimalDigits() >= $digits) {
162
            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

162
            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...
163
        }
164
165 2
        $twoThirds = Numbers::make(Numbers::IMMUTABLE, str_pad('0.', $digits+3, '6'));
166 2
        $one = Numbers::makeOne($digits+3);
167 2
        $two = Numbers::make(Numbers::IMMUTABLE, 2, $digits+3);
168 2
        $nine = Numbers::make(Numbers::IMMUTABLE, 9, $digits+3);
169 2
        $sum = Numbers::makeZero($digits+3);
170 2
        $k = 0;
171
172
        do {
173
174 2
            $diff = $one->divide($one->add($two->multiply($k))->multiply($nine->pow($k)), $digits+3)->truncate($digits+2);
0 ignored issues
show
Bug introduced by
The method truncate() 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

174
            $diff = $one->divide($one->add($two->multiply($k))->multiply($nine->pow($k)), $digits+3)->/** @scrutinizer ignore-call */ truncate($digits+2);

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...
175
176 2
            $sum = $sum->add($diff);
177
178 2
            $k++;
179
180 2
        } while (!$diff->isEqual(0));
181
182 2
        $ln2 = $twoThirds->multiply($sum);
183 2
        $ln2 = $ln2->truncateToScale($digits);
0 ignored issues
show
Bug introduced by
The method truncateToScale() 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

183
        /** @scrutinizer ignore-call */ 
184
        $ln2 = $ln2->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\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

183
        /** @scrutinizer ignore-call */ 
184
        $ln2 = $ln2->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\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

183
        /** @scrutinizer ignore-call */ 
184
        $ln2 = $ln2->truncateToScale($digits);
Loading history...
184
185 2
        self::$ln2 = $ln2;
186
187 2
        return $ln2->getValue(NumberBase::Ten);
188
189
    }
190
191 6
    public static function makeLn1p1(int $digits): string
192
    {
193
194 6
        if (isset(self::$ln1p1) && self::$ln1p1->numberOfDecimalDigits() >= $digits) {
195 3
            return self::$ln1p1->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

195
            return self::$ln1p1->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...
196
        }
197
198 6
        $one = Numbers::makeOne($digits+3);
199 6
        $two = Numbers::make(Numbers::IMMUTABLE, 2, $digits+3);
200 6
        $twentyOne = Numbers::make(Numbers::IMMUTABLE, 21, $digits+3);
201 6
        $fourFortyOne = Numbers::make(Numbers::IMMUTABLE, 441, $digits+3);
202 6
        $twoDivTwentyOne = $two->divide($twentyOne);
203 6
        $sum = Numbers::makeZero($digits+3);
204 6
        $k = 0;
205
206
        do {
207
208 6
            $diff = $one->divide($one->add($two->multiply($k))->multiply($fourFortyOne->pow($k)), $digits+3)->truncate($digits+2);
209
210 6
            $sum = $sum->add($diff);
211
212 6
            $k++;
213
214 6
        } while (!$diff->isEqual(0));
215
216 6
        $ln1p1 = $twoDivTwentyOne->multiply($sum);
217 6
        $ln1p1 = $ln1p1->truncateToScale($digits);
218
219 6
        self::$ln1p1 = $ln1p1;
220
221 6
        return $ln1p1->getValue(NumberBase::Ten);
222
223
    }
224
225
}