Failed Conditions
Pull Request — master (#47)
by Jordan
06:42 queued 03:44
created

SequenceProvider::nthEvenNumber()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
c 1
b 0
f 1
nc 1
nop 1
dl 0
loc 6
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
3
namespace Samsara\Fermat\Provider;
4
5
use Samsara\Exceptions\SystemError\LogicalError\IncompatibleObjectState;
6
use Samsara\Exceptions\UsageError\IntegrityConstraint;
7
use Samsara\Fermat\Numbers;
8
use Samsara\Fermat\Types\Base\Interfaces\Numbers\DecimalInterface;
9
use Samsara\Fermat\Types\Base\Interfaces\Numbers\NumberInterface;
10
use Samsara\Fermat\Values\ImmutableDecimal;
11
12
class SequenceProvider
13
{
14
15
    const EULER_ZIGZAG = [
16
        '1',                                                        // 0
17
        '1',                                                        // 1
18
        '1',                                                        // 2
19
        '2',                                                        // 3
20
        '5',                                                        // 4
21
        '16',                                                       // 5
22
        '61',                                                       // 6
23
        '272',                                                      // 7
24
        '1385',                                                     // 8
25
        '7936',                                                     // 9
26
        '50521',                                                    // 10
27
        '353792',                                                   // 11
28
        '2702765',                                                  // 12
29
        '22368256',                                                 // 13
30
        '199360981',                                                // 14
31
        '1903757312',                                               // 15
32
        '19391512145',                                              // 16
33
        '209865342976',                                             // 17
34
        '2404879675441',                                            // 18
35
        '29088885112832',                                           // 19
36
        '370371188237525',                                          // 20
37
        '4951498053124096',                                         // 21
38
        '69348874393137901',                                        // 22
39
        '1015423886506852352',                                      // 23
40
        '15514534163557086905',                                     // 24
41
        '246921480190207983616',                                    // 25
42
        '4087072509293123892361',                                   // 26
43
        '70251601603943959887872',                                  // 27
44
        '1252259641403629865468285',                                // 28
45
        '23119184187809597841473536',                               // 29
46
        '441543893249023104553682821',                              // 30
47
        '8713962757125169296170811392',                             // 31
48
        '177519391579539289436664789665',                           // 32
49
        '3729407703720529571097509625856',                          // 33
50
        '80723299235887898062168247453281',                         // 34
51
        '1798651693450888780071750349094912',                       // 35
52
        '41222060339517702122347079671259045',                      // 36
53
        '970982810785059112379399707952152576',                     // 37
54
        '23489580527043108252017828576198947741',                   // 38
55
        '583203324917310043943191641625494290432',                  // 39
56
        '14851150718114980017877156781405826684425',                // 40
57
        '387635983772083031828014624002175135645696',               // 41
58
        '10364622733519612119397957304745185976310201',             // 42
59
        '283727921907431909304183316295787837183229952',            // 43
60
        '7947579422597592703608040510088070619519273805',           // 44
61
        '227681379129930886488600284336316164603920777216',         // 45
62
        '6667537516685544977435028474773748197524107684661',        // 46
63
        '199500252157859031027160499643195658166340757225472',      // 47
64
        '6096278645568542158691685742876843153976539044435185',     // 48
65
        '190169564657928428175235445073924928592047775873499136',   // 49
66
        '6053285248188621896314383785111649088103498225146815121',  // 50
67
    ];
68
69
    /**
70
     * OEIS: A005408
71
     *
72
     * @param $n
73
     *
74
     * @return DecimalInterface|NumberInterface
75
     * @throws IntegrityConstraint
76
     */
77 20
    public static function nthOddNumber($n)
78
    {
79
80 20
        $n = Numbers::makeOrDont(Numbers::IMMUTABLE, $n, 100);
81
82 20
        return $n->multiply(2)->add(1);
83
84
    }
85
86
    /**
87
     * OEIS: A005843
88
     *
89
     * @param $n
90
     *
91
     * @return DecimalInterface|NumberInterface
92
     * @throws IntegrityConstraint
93
     */
94 17
    public static function nthEvenNumber($n)
95
    {
96
97 17
        $n = Numbers::makeOrDont(Numbers::IMMUTABLE, $n, 100);
98
99 17
        return $n->multiply(2);
100
101
    }
102
103
    /**
104
     * OEIS: A033999
105
     *
106
     * @param $n
107
     *
108
     * @return DecimalInterface|NumberInterface
109
     * @throws IntegrityConstraint
110
     */
111 17
    public static function nthPowerNegativeOne($n)
112
    {
113
114 17
        $negOne = Numbers::makeOrDont(Numbers::IMMUTABLE, -1, 100);
115 17
        $n = Numbers::makeOrDont(Numbers::IMMUTABLE, $n);
116
117 17
        if ($n->modulo(2)->isEqual(0)) {
0 ignored issues
show
Bug introduced by
The method modulo() 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

117
        if ($n->/** @scrutinizer ignore-call */ modulo(2)->isEqual(0)) {
Loading history...
118 17
            return Numbers::makeOne();
119
        } else {
120 17
            return $negOne;
121
        }
122
123
    }
124
125
    /**
126
     * OEIS: A000111
127
     *
128
     * @param $n
129
     *
130
     * @return DecimalInterface|NumberInterface
131
     * @throws IntegrityConstraint
132
     * @throws IncompatibleObjectState
133
     */
134 4
    public static function nthEulerZigzag($n)
135
    {
136
137 4
        $n = Numbers::makeOrDont(Numbers::IMMUTABLE, $n, 100);
138
139 4
        if ($n->isGreaterThan(50)) {
0 ignored issues
show
Bug introduced by
The method isGreaterThan() 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...s\SimpleNumberInterface or Samsara\Fermat\Types\Fraction 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

139
        if ($n->/** @scrutinizer ignore-call */ isGreaterThan(50)) {
Loading history...
140 1
            throw new IntegrityConstraint(
141 1
                '$n cannot be larger than 50',
142 1
                'Limit your use of the Euler Zigzag Sequence to the 50th index',
143 1
                'This library does not support the Euler Zigzag Sequence (OEIS: A000111) beyond E(50)'
144
            );
145
        }
146
147 4
        return Numbers::make(Numbers::IMMUTABLE, static::EULER_ZIGZAG[$n->asInt()], 100);
0 ignored issues
show
Bug introduced by
The method asInt() 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

147
        return Numbers::make(Numbers::IMMUTABLE, static::EULER_ZIGZAG[$n->/** @scrutinizer ignore-call */ asInt()], 100);
Loading history...
148
149
    }
150
151
    /**
152
     * WARNING: This function is VERY unoptimized. Be careful of large m values.
153
     *
154
     * @param $n
155
     *
156
     * @return DecimalInterface|NumberInterface
157
     * @throws IntegrityConstraint
158
     */
159 1
    public static function nthBernoulliNumber($n)
160
    {
161
162 1
        $n = Numbers::makeOrDont(Numbers::IMMUTABLE, $n, 100);
163
164 1
        if ($n->isEqual(0)) {
165 1
            return Numbers::makeOne();
166 1
        } elseif ($n->isEqual(1)) {
167 1
            return Numbers::make(Numbers::IMMUTABLE, '0.5', 100);
168
        }
169
170 1
        if ($n->isGreaterThan(1) && $n->modulo(2)->isEqual(1)) {
171 1
            return Numbers::makeZero();
172
        }
173
174 1
        $b = Numbers::make(Numbers::IMMUTABLE, -1, 100);
175 1
        $two = Numbers::make(Numbers::IMMUTABLE, 2, 100);
176 1
        $four = Numbers::make(Numbers::IMMUTABLE, 4, 100);
177
178 1
        $b = $b->pow($n->divide(2)->floor())
0 ignored issues
show
Bug introduced by
The method floor() does not exist on Samsara\Fermat\Values\ImmutableComplexNumber. ( Ignorable by Annotation )

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

178
        $b = $b->pow($n->divide(2)->/** @scrutinizer ignore-call */ floor())

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

178
        $b = $b->pow($n->divide(2)->/** @scrutinizer ignore-call */ floor())
Loading history...
Bug introduced by
The method floor() 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

178
        $b = $b->pow($n->divide(2)->/** @scrutinizer ignore-call */ floor())

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...
179 1
            ->multiply($n->divide($two->pow($n)->subtract($four->pow($n))))
180 1
            ->multiply(static::nthEulerZigzag($n));
181
182 1
        return $b;
183
184
    }
185
186
    /**
187
     * OEIS: A000045
188
     *
189
     * This uses an implementation of the fast-doubling Karatsuba multiplication algorithm as described by 'Nayuki':
190
     *
191
     * https://www.nayuki.io/page/fast-fibonacci-algorithms
192
     *
193
     * @param $n
194
     * @return ImmutableDecimal
195
     * @throws IntegrityConstraint
196
     */
197 3
    public static function nthFibonacciNumber($n): ImmutableDecimal
198
    {
199 3
        $n = Numbers::makeOrDont(Numbers::IMMUTABLE, $n);
200 3
        if (!$n->isInt()) {
0 ignored issues
show
Bug introduced by
The method isInt() 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\Fraction or Samsara\Fermat\Types\Fraction 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
        if (!$n->/** @scrutinizer ignore-call */ isInt()) {
Loading history...
201 1
            throw new IntegrityConstraint(
202 1
                'Sequences can only have integer term numbers',
203 1
                'Provide a valid term number',
204 1
                'The nthFibonacciNumber function takes the term number as its argument; provide an integer term number'
205
            );
206
        }
207
208 2
        if ($n->isLessThan(0)) {
0 ignored issues
show
Bug introduced by
The method isLessThan() 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...s\SimpleNumberInterface or Samsara\Fermat\Types\Fraction 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

208
        if ($n->/** @scrutinizer ignore-call */ isLessThan(0)) {
Loading history...
209 1
            throw new IntegrityConstraint(
210 1
                'Negative term numbers not valid for Fibonacci Sequence',
211 1
                'Provide a positive term number',
212 1
                'A negative term number for the Fibonacci sequence was requested; provide a positive term number'
213
            );
214
        }
215
216 1
        $fastFib = static::_fib($n);
0 ignored issues
show
Bug introduced by
It seems like $n can also be of type Samsara\Fermat\Values\MutableDecimal; however, parameter $number of Samsara\Fermat\Provider\SequenceProvider::_fib() does only seem to accept Samsara\Fermat\Values\ImmutableDecimal, 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

216
        $fastFib = static::_fib(/** @scrutinizer ignore-type */ $n);
Loading history...
217
218 1
        return $fastFib[0];
219
    }
220
221 1
    private static function _fib(ImmutableDecimal $number): array
222
    {
223 1
        if ($number->isEqual(0)) {
224 1
            return [Numbers::makeZero(), Numbers::makeOne()];
225
        }
226
227
        /**
228
         * @var ImmutableDecimal $a
229
         * @var ImmutableDecimal $b
230
         * @var ImmutableDecimal $prevCall
231
         */
232 1
        $prevCall = $number->divide(2)->floor();
233 1
        list($a, $b) = static::_fib($prevCall);
234 1
        $c = $a->multiply($b->multiply(2)->subtract($a));
235 1
        $d = $a->multiply($a)->add($b->multiply($b));
236 1
        if ($number->modulo(2)->isEqual(0)) {
237 1
            return [$c, $d];
238
        } else {
239 1
            return [$d, $c->add($d)];
240
        }
241
    }
242
243
}