Completed
Push — dev ( 98ee05...c6e1e9 )
by Jordan
02:07
created

SeriesProvider::maclaurinSeries()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 34
Code Lines 21

Duplication

Lines 15
Ratio 44.12 %

Importance

Changes 0
Metric Value
dl 15
loc 34
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 21
nc 3
nop 6
1
<?php
2
3
namespace Samsara\Fermat\Provider;
4
5
use Samsara\Fermat\Numbers;
6
use Samsara\Fermat\Types\Base\NumberInterface;
7
8
class SeriesProvider
9
{
10
11
    /**
12
     * Creates a series that evaluates the following:
13
     *
14
     * SUM[$startTerm -> infinity](
15
     *  $numerator($n) × $input^$exponent($n)
16
     *  --------------------------------
17
     *          $denominator($n)
18
     * )
19
     *
20
     * Where $n is the current term number, starting at $startTerm, and increasing by 1 each loop; where $numerator,
21
     * $exponent, and $denominator are callables that take the term number (as an int) as their only input, and give the
22
     * value of that section at that term number; and where $input is the x value being considered for the series.
23
     *
24
     * The function continues adding terms until a term has MORE leading zeros than the $precision setting. (That is,
25
     * until it adds zero to the total when considering significant digits.)
26
     *
27
     * @param NumberInterface $input
28
     * @param callable        $numerator
29
     * @param callable        $exponent
30
     * @param callable        $denominator
31
     * @param int             $startTermAt
32
     * @param int             $precision
33
     *
34
     * @return NumberInterface
35
     */
36
    public static function maclaurinSeries(
37
        NumberInterface $input, // x value in series
38
        callable $numerator, // a function determining what the sign (+/-) at the nth term
39
        callable $exponent, // a function determining the exponent of x at the nth term
40
        callable $denominator, // a function determining the denominator at the nth term
41
        $startTermAt = 0,
42
        $precision = 10)
43
    {
44
45
        $x = Numbers::makeZero();
46
        $value = Numbers::make(Numbers::IMMUTABLE, $input->getValue());
47
48
        $continue = true;
49
        $termNumber = $startTermAt;
50
51 View Code Duplication
        while ($continue) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
52
            $term = Numbers::makeOne();
53
54
            $term = $term->multiply($value->pow($exponent($termNumber)))
55
                ->divide($denominator($termNumber))
56
                ->multiply($numerator($termNumber));
57
58
            if ($term->numberOfLeadingZeros() >= $precision) {
59
                $continue = false;
60
            }
61
62
            $x = $x->add($term);
63
64
            $termNumber++;
65
        }
66
67
        return $x->roundToPrecision($precision);
68
69
    }
70
71
    public static function genericTwoPartSeries(
72
        callable $part1,
73
        callable $part2,
74
        callable $exponent,
75
        $startTermAt = 0,
76
        $precision = 10)
77
    {
78
79
        $x = Numbers::makeZero();
80
81
        $continue = true;
82
        $termNumber = $startTermAt;
83
84 View Code Duplication
        while ($continue) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
85
            $term = Numbers::makeOne();
86
87
            $term = $term->multiply($part2($termNumber))->pow($exponent($termNumber))
88
                ->multiply($part1($termNumber));
89
90
            if ($term->numberOfLeadingZeros() >= $precision) {
91
                $continue = false;
92
            }
93
94
            $x = $x->add($term);
95
96
            $termNumber++;
97
        }
98
99
        return $x->roundToPrecision($precision);
100
101
    }
102
    
103
}