Failed Conditions
Pull Request — dev (#50)
by Jordan
09:06 queued 04:26
created

SeriesProvider::maclaurinSeries()   B

Complexity

Conditions 10
Paths 37

Size

Total Lines 80
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 10.1685

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 44
nc 37
nop 8
dl 0
loc 80
ccs 37
cts 42
cp 0.881
crap 10.1685
rs 7.6666
c 1
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Samsara\Fermat\Provider;
4
5
use ReflectionException;
6
use Samsara\Exceptions\UsageError\IntegrityConstraint;
7
use Samsara\Exceptions\UsageError\OptionalExit;
8
use Samsara\Fermat\Numbers;
9
use Samsara\Fermat\Types\Base\Interfaces\Numbers\SimpleNumberInterface;
10
use Samsara\Fermat\Values\ImmutableDecimal;
11
12
class SeriesProvider
13
{
14
15
    /**
16
     * Creates a series that evaluates the following:
17
     *
18
     * SUM[$startTerm -> infinity](
19
     *  $numerator($n) × $input^$exponent($n)
20
     *  --------------------------------
21
     *          $denominator($n)
22
     * )
23
     *
24
     * Where $n is the current term number, starting at $startTerm, and increasing by 1 each loop; where $numerator,
25
     * $exponent, and $denominator are callables that take the term number (as an int) as their only input, and give the
26
     * value of that section at that term number; and where $input is the x value being considered for the series.
27
     *
28
     * The function continues adding terms until a term has MORE leading zeros than the $precision setting. (That is,
29
     * until it adds zero to the total when considering significant digits.)
30
     *
31
     * @param SimpleNumberInterface $input
32
     * @param callable $numerator
33
     * @param callable $exponent
34
     * @param callable $denominator
35
     * @param int $startTermAt
36
     * @param int $precision
37
     * @param int $consecutiveDivergeLimit
38
     * @param int $totalDivergeLimit
39
     *
40
     * @return ImmutableDecimal
41
     * @throws IntegrityConstraint
42
     * @throws OptionalExit
43
     * @throws ReflectionException
44
     */
45 36
    public static function maclaurinSeries(
46
        SimpleNumberInterface $input, // x value in series
47
        callable $numerator, // a function determining what the sign (+/-) is at the nth term
48
        callable $exponent, // a function determining the exponent of x at the nth term
49
        callable $denominator, // a function determining the denominator at the nth term
50
        int $startTermAt = 0,
51
        int $precision = 10,
52
        int $consecutiveDivergeLimit = 5,
53
        int $totalDivergeLimit = 10): ImmutableDecimal
54
    {
55
56 36
        ++$precision;
57
58 36
        $sum = Numbers::makeZero($precision);
59 36
        $value = Numbers::make(Numbers::IMMUTABLE, $input->getValue(), $precision);
60
61 36
        $continue = true;
62 36
        $termNumber = $startTermAt;
63
64 36
        $adjustmentOfZero = 0;
65 36
        $prevDiff = Numbers::makeZero($precision);
66 36
        $prevSum = $sum;
67 36
        $divergeCount = -1;
68 36
        $persistentDivergeCount = -1;
69 36
        $currentPrecision = 0;
70
71 36
        while ($continue) {
72 36
            $term = Numbers::makeOne($precision);
73
74
            try {
75 36
                $exTerm = $value->pow($exponent($termNumber));
76 36
                $term = $term->multiply($exTerm);
77 36
                $term = $term->divide($denominator($termNumber));
0 ignored issues
show
Bug introduced by
The method divide() does not exist on Samsara\Fermat\Types\Bas...tes\CoordinateInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...tes\CoordinateInterface such as Samsara\Fermat\Types\ComplexNumber or Samsara\Fermat\Types\ComplexNumber. ( Ignorable by Annotation )

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

77
                /** @scrutinizer ignore-call */ 
78
                $term = $term->divide($denominator($termNumber));
Loading history...
Bug introduced by
The method divide() 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

77
                /** @scrutinizer ignore-call */ 
78
                $term = $term->divide($denominator($termNumber));

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...
78 36
                $term = $term->multiply($numerator($termNumber));
0 ignored issues
show
Bug introduced by
The method multiply() does not exist on Samsara\Fermat\Types\Bas...tes\CoordinateInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...tes\CoordinateInterface such as Samsara\Fermat\Types\ComplexNumber or Samsara\Fermat\Types\ComplexNumber. ( Ignorable by Annotation )

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

78
                /** @scrutinizer ignore-call */ 
79
                $term = $term->multiply($numerator($termNumber));
Loading history...
Bug introduced by
The method multiply() 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

78
                /** @scrutinizer ignore-call */ 
79
                $term = $term->multiply($numerator($termNumber));

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...
79
            } catch (IntegrityConstraint $constraint) {
80
                return $sum->truncateToPrecision($currentPrecision+1);
81
            }
82
83
            /** @var ImmutableDecimal $term */
84 36
            if ($term->numberOfLeadingZeros() >= $precision && !$term->isWhole()) {
85 29
                $continue = false;
86
            }
87
88 36
            $currentPrecision = $term->numberOfLeadingZeros();
89
90 36
            if ($term->isEqual(0)) {
91 9
                $adjustmentOfZero++;
92
            } else {
93 36
                $adjustmentOfZero = 0;
94
            }
95
96 36
            if ($adjustmentOfZero > 15) {
97 9
                $continue = false;
98
            }
99
100
            /** @var ImmutableDecimal $sum */
101 36
            $sum = $sum->add($term);
102 36
            $currDiff = $sum->subtract($prevSum)->abs();
103
104 36
            if ($prevDiff->isLessThan($currDiff)) {
105 36
                $divergeCount++;
106 36
                $persistentDivergeCount++;
107
            } else {
108 36
                $divergeCount = 0;
109
            }
110
111 36
            if ($divergeCount === $consecutiveDivergeLimit || $persistentDivergeCount === $totalDivergeLimit) {
112
                throw new OptionalExit(
113
                    'Series appear to be diverging. Current diverge count: '.$divergeCount.' | Persistent diverge count: '.$persistentDivergeCount,
114
                    'A call was made to SeriesProvider::maclaurinSeries() that seems to be diverging. Exiting the loop.'
115
                );
116
            }
117
118 36
            $prevDiff = $currDiff;
119 36
            $prevSum = $sum;
120
121 36
            $termNumber++;
122
        }
123
124 36
        return $sum->roundToPrecision($precision);
125
126
    }
127
    
128
}