1<?php
2
3namespace PhpOffice\PhpSpreadsheet\Shared\Trend;
4
5class ExponentialBestFit extends BestFit
6{
7    /**
8     * Algorithm type to use for best-fit
9     * (Name of this Trend class).
10     *
11     * @var string
12     */
13    protected $bestFitType = 'exponential';
14
15    /**
16     * Return the Y-Value for a specified value of X.
17     *
18     * @param float $xValue X-Value
19     *
20     * @return float Y-Value
21     */
22    public function getValueOfYForX($xValue)
23    {
24        return $this->getIntersect() * pow($this->getSlope(), ($xValue - $this->xOffset));
25    }
26
27    /**
28     * Return the X-Value for a specified value of Y.
29     *
30     * @param float $yValue Y-Value
31     *
32     * @return float X-Value
33     */
34    public function getValueOfXForY($yValue)
35    {
36        return log(($yValue + $this->yOffset) / $this->getIntersect()) / log($this->getSlope());
37    }
38
39    /**
40     * Return the Equation of the best-fit line.
41     *
42     * @param int $dp Number of places of decimal precision to display
43     *
44     * @return string
45     */
46    public function getEquation($dp = 0)
47    {
48        $slope = $this->getSlope($dp);
49        $intersect = $this->getIntersect($dp);
50
51        return 'Y = ' . $intersect . ' * ' . $slope . '^X';
52    }
53
54    /**
55     * Return the Slope of the line.
56     *
57     * @param int $dp Number of places of decimal precision to display
58     *
59     * @return float
60     */
61    public function getSlope($dp = 0)
62    {
63        if ($dp != 0) {
64            return round(exp($this->slope), $dp);
65        }
66
67        return exp($this->slope);
68    }
69
70    /**
71     * Return the Value of X where it intersects Y = 0.
72     *
73     * @param int $dp Number of places of decimal precision to display
74     *
75     * @return float
76     */
77    public function getIntersect($dp = 0)
78    {
79        if ($dp != 0) {
80            return round(exp($this->intersect), $dp);
81        }
82
83        return exp($this->intersect);
84    }
85
86    /**
87     * Execute the regression and calculate the goodness of fit for a set of X and Y data values.
88     *
89     * @param float[] $yValues The set of Y-values for this regression
90     * @param float[] $xValues The set of X-values for this regression
91     * @param bool $const
92     */
93    private function exponentialRegression($yValues, $xValues, $const)
94    {
95        foreach ($yValues as &$value) {
96            if ($value < 0.0) {
97                $value = 0 - log(abs($value));
98            } elseif ($value > 0.0) {
99                $value = log($value);
100            }
101        }
102        unset($value);
103
104        $this->leastSquareFit($yValues, $xValues, $const);
105    }
106
107    /**
108     * Define the regression and calculate the goodness of fit for a set of X and Y data values.
109     *
110     * @param float[] $yValues The set of Y-values for this regression
111     * @param float[] $xValues The set of X-values for this regression
112     * @param bool $const
113     */
114    public function __construct($yValues, $xValues = [], $const = true)
115    {
116        parent::__construct($yValues, $xValues);
117
118        if (!$this->error) {
119            $this->exponentialRegression($yValues, $xValues, $const);
120        }
121    }
122}
123