Completed
Push — develop ( 685e29...09d456 )
by Adrien
14:14
created

Statistical::LINEST()   D

Complexity

Conditions 9
Paths 40

Size

Total Lines 45
Code Lines 30

Duplication

Lines 23
Ratio 51.11 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 30
c 1
b 0
f 0
nc 40
nop 4
dl 23
loc 45
ccs 0
cts 27
cp 0
crap 90
rs 4.909
1
<?php
2
3
namespace PhpSpreadsheet\Calculation;
4
5
/* LOG_GAMMA_X_MAX_VALUE */
6
define('LOG_GAMMA_X_MAX_VALUE', 2.55e305);
7
8
/* XMININ */
9
define('XMININ', 2.23e-308);
10
11
/* EPS */
12
define('EPS', 2.22e-16);
13
14
/* SQRT2PI */
15
define('SQRT2PI', 2.5066282746310005024157652848110452530069867406099);
16
17
/**
18
 * Copyright (c) 2006 - 2016 PhpSpreadsheet
19
 *
20
 * This library is free software; you can redistribute it and/or
21
 * modify it under the terms of the GNU Lesser General Public
22
 * License as published by the Free Software Foundation; either
23
 * version 2.1 of the License, or (at your option) any later version.
24
 *
25
 * This library is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28
 * Lesser General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Lesser General Public
31
 * License along with this library; if not, write to the Free Software
32
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33
 *
34
 * @category    PhpSpreadsheet
35
 * @copyright   Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
36
 * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
37
 * @version     ##VERSION##, ##DATE##
38
 */
39
class Statistical
40
{
41
    private static function checkTrendArrays(&$array1, &$array2)
42
    {
43
        if (!is_array($array1)) {
44
            $array1 = [$array1];
45
        }
46
        if (!is_array($array2)) {
47
            $array2 = [$array2];
48
        }
49
50
        $array1 = Functions::flattenArray($array1);
51
        $array2 = Functions::flattenArray($array2);
52 View Code Duplication
        foreach ($array1 as $key => $value) {
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...
53
            if ((is_bool($value)) || (is_string($value)) || (is_null($value))) {
54
                unset($array1[$key]);
55
                unset($array2[$key]);
56
            }
57
        }
58 View Code Duplication
        foreach ($array2 as $key => $value) {
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...
59
            if ((is_bool($value)) || (is_string($value)) || (is_null($value))) {
60
                unset($array1[$key]);
61
                unset($array2[$key]);
62
            }
63
        }
64
        $array1 = array_merge($array1);
65
        $array2 = array_merge($array2);
66
67
        return true;
68
    }
69
70
    /**
71
     * Beta function.
72
     *
73
     * @author Jaco van Kooten
74
     *
75
     * @param p require p>0
76
     * @param q require q>0
77
     * @return 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
0 ignored issues
show
Documentation introduced by
The doc-type 0 could not be parsed: Unknown type name "0" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
78
     */
79
    private static function beta($p, $q)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
80
    {
81
        if ($p <= 0.0 || $q <= 0.0 || ($p + $q) > LOG_GAMMA_X_MAX_VALUE) {
82
            return 0.0;
83
        } else {
84
            return exp(self::logBeta($p, $q));
85
        }
86
    }
87
88
    /**
89
     * Incomplete beta function
90
     *
91
     * @author Jaco van Kooten
92
     * @author Paul Meagher
93
     *
94
     * The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992).
95
     * @param x require 0<=x<=1
96
     * @param p require p>0
97
     * @param q require q>0
98
     * @return 0 if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow
0 ignored issues
show
Documentation introduced by
The doc-type 0 could not be parsed: Unknown type name "0" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
99
     */
100
    private static function incompleteBeta($x, $p, $q)
101
    {
102
        if ($x <= 0.0) {
103
            return 0.0;
104
        } elseif ($x >= 1.0) {
105
            return 1.0;
106
        } elseif (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) {
107
            return 0.0;
108
        }
109
        $beta_gam = exp((0 - self::logBeta($p, $q)) + $p * log($x) + $q * log(1.0 - $x));
110
        if ($x < ($p + 1.0) / ($p + $q + 2.0)) {
111
            return $beta_gam * self::betaFraction($x, $p, $q) / $p;
112
        } else {
113
            return 1.0 - ($beta_gam * self::betaFraction(1 - $x, $q, $p) / $q);
114
        }
115
    }
116
117
    // Function cache for logBeta function
118
    private static $logBetaCacheP = 0.0;
119
    private static $logBetaCacheQ = 0.0;
120
    private static $logBetaCacheResult = 0.0;
121
122
    /**
123
     * The natural logarithm of the beta function.
124
     *
125
     * @param p require p>0
126
     * @param q require q>0
127
     * @return 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
0 ignored issues
show
Documentation introduced by
The doc-type 0 could not be parsed: Unknown type name "0" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
128
     * @author Jaco van Kooten
129
     */
130
    private static function logBeta($p, $q)
131
    {
132
        if ($p != self::$logBetaCacheP || $q != self::$logBetaCacheQ) {
133
            self::$logBetaCacheP = $p;
134
            self::$logBetaCacheQ = $q;
135
            if (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) {
136
                self::$logBetaCacheResult = 0.0;
137
            } else {
138
                self::$logBetaCacheResult = self::logGamma($p) + self::logGamma($q) - self::logGamma($p + $q);
139
            }
140
        }
141
142
        return self::$logBetaCacheResult;
143
    }
144
145
    /**
146
     * Evaluates of continued fraction part of incomplete beta function.
147
     * Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
148
     * @author Jaco van Kooten
149
     */
150
    private static function betaFraction($x, $p, $q)
151
    {
152
        $c = 1.0;
153
        $sum_pq = $p + $q;
154
        $p_plus = $p + 1.0;
155
        $p_minus = $p - 1.0;
156
        $h = 1.0 - $sum_pq * $x / $p_plus;
157
        if (abs($h) < XMININ) {
158
            $h = XMININ;
159
        }
160
        $h = 1.0 / $h;
161
        $frac = $h;
162
        $m = 1;
163
        $delta = 0.0;
164
        while ($m <= MAX_ITERATIONS && abs($delta - 1.0) > PRECISION) {
165
            $m2 = 2 * $m;
166
            // even index for d
167
            $d = $m * ($q - $m) * $x / (($p_minus + $m2) * ($p + $m2));
168
            $h = 1.0 + $d * $h;
169
            if (abs($h) < XMININ) {
170
                $h = XMININ;
171
            }
172
            $h = 1.0 / $h;
173
            $c = 1.0 + $d / $c;
174
            if (abs($c) < XMININ) {
175
                $c = XMININ;
176
            }
177
            $frac *= $h * $c;
178
            // odd index for d
179
            $d = -($p + $m) * ($sum_pq + $m) * $x / (($p + $m2) * ($p_plus + $m2));
180
            $h = 1.0 + $d * $h;
181
            if (abs($h) < XMININ) {
182
                $h = XMININ;
183
            }
184
            $h = 1.0 / $h;
185
            $c = 1.0 + $d / $c;
186
            if (abs($c) < XMININ) {
187
                $c = XMININ;
188
            }
189
            $delta = $h * $c;
190
            $frac *= $delta;
191
            ++$m;
192
        }
193
194
        return $frac;
195
    }
196
197
/**
198
 * logGamma function
199
 *
200
 * @version 1.1
201
 * @author Jaco van Kooten
202
 *
203
 * Original author was Jaco van Kooten. Ported to PHP by Paul Meagher.
204
 *
205
 * The natural logarithm of the gamma function. <br />
206
 * Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz <br />
207
 * Applied Mathematics Division <br />
208
 * Argonne National Laboratory <br />
209
 * Argonne, IL 60439 <br />
210
 * <p>
211
 * References:
212
 * <ol>
213
 * <li>W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural
214
 *     Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.</li>
215
 * <li>K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.</li>
216
 * <li>Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.</li>
217
 * </ol>
218
 * </p>
219
 * <p>
220
 * From the original documentation:
221
 * </p>
222
 * <p>
223
 * This routine calculates the LOG(GAMMA) function for a positive real argument X.
224
 * Computation is based on an algorithm outlined in references 1 and 2.
225
 * The program uses rational functions that theoretically approximate LOG(GAMMA)
226
 * to at least 18 significant decimal digits. The approximation for X > 12 is from
227
 * reference 3, while approximations for X < 12.0 are similar to those in reference
228
 * 1, but are unpublished. The accuracy achieved depends on the arithmetic system,
229
 * the compiler, the intrinsic functions, and proper selection of the
230
 * machine-dependent constants.
231
 * </p>
232
 * <p>
233
 * Error returns: <br />
234
 * The program returns the value XINF for X .LE. 0.0 or when overflow would occur.
235
 * The computation is believed to be free of underflow and overflow.
236
 * </p>
237
 * @return MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305
238
 */
239
240
    // Function cache for logGamma
241
    private static $logGammaCacheResult = 0.0;
242
    private static $logGammaCacheX = 0.0;
243
244
    private static function logGamma($x)
245
    {
246
        // Log Gamma related constants
247
        static $lg_d1 = -0.5772156649015328605195174;
248
        static $lg_d2 = 0.4227843350984671393993777;
249
        static $lg_d4 = 1.791759469228055000094023;
250
251
        static $lg_p1 = [
252
            4.945235359296727046734888,
253
            201.8112620856775083915565,
254
            2290.838373831346393026739,
255
            11319.67205903380828685045,
256
            28557.24635671635335736389,
257
            38484.96228443793359990269,
258
            26377.48787624195437963534,
259
            7225.813979700288197698961,
260
        ];
261
        static $lg_p2 = [
262
            4.974607845568932035012064,
263
            542.4138599891070494101986,
264
            15506.93864978364947665077,
265
            184793.2904445632425417223,
266
            1088204.76946882876749847,
267
            3338152.967987029735917223,
268
            5106661.678927352456275255,
269
            3074109.054850539556250927,
270
        ];
271
        static $lg_p4 = [
272
            14745.02166059939948905062,
273
            2426813.369486704502836312,
274
            121475557.4045093227939592,
275
            2663432449.630976949898078,
276
            29403789566.34553899906876,
277
            170266573776.5398868392998,
278
            492612579337.743088758812,
279
            560625185622.3951465078242,
280
        ];
281
        static $lg_q1 = [
282
            67.48212550303777196073036,
283
            1113.332393857199323513008,
284
            7738.757056935398733233834,
285
            27639.87074403340708898585,
286
            54993.10206226157329794414,
287
            61611.22180066002127833352,
288
            36351.27591501940507276287,
289
            8785.536302431013170870835,
290
        ];
291
        static $lg_q2 = [
292
            183.0328399370592604055942,
293
            7765.049321445005871323047,
294
            133190.3827966074194402448,
295
            1136705.821321969608938755,
296
            5267964.117437946917577538,
297
            13467014.54311101692290052,
298
            17827365.30353274213975932,
299
            9533095.591844353613395747,
300
        ];
301
        static $lg_q4 = [
302
            2690.530175870899333379843,
303
            639388.5654300092398984238,
304
            41355999.30241388052042842,
305
            1120872109.61614794137657,
306
            14886137286.78813811542398,
307
            101680358627.2438228077304,
308
            341747634550.7377132798597,
309
            446315818741.9713286462081,
310
        ];
311
        static $lg_c = [
312
            -0.001910444077728,
313
            8.4171387781295e-4,
314
            -5.952379913043012e-4,
315
            7.93650793500350248e-4,
316
            -0.002777777777777681622553,
317
            0.08333333333333333331554247,
318
            0.0057083835261,
319
        ];
320
321
        // Rough estimate of the fourth root of logGamma_xBig
322
        static $lg_frtbig = 2.25e76;
323
        static $pnt68 = 0.6796875;
324
325
        if ($x == self::$logGammaCacheX) {
326
            return self::$logGammaCacheResult;
327
        }
328
        $y = $x;
329
        if ($y > 0.0 && $y <= LOG_GAMMA_X_MAX_VALUE) {
330
            if ($y <= EPS) {
331
                $res = -log(y);
332
            } elseif ($y <= 1.5) {
333
                // ---------------------
334
                //    EPS .LT. X .LE. 1.5
335
                // ---------------------
336
                if ($y < $pnt68) {
337
                    $corr = -log($y);
338
                    $xm1 = $y;
339
                } else {
340
                    $corr = 0.0;
341
                    $xm1 = $y - 1.0;
342
                }
343
                if ($y <= 0.5 || $y >= $pnt68) {
344
                    $xden = 1.0;
345
                    $xnum = 0.0;
346
                    for ($i = 0; $i < 8; ++$i) {
347
                        $xnum = $xnum * $xm1 + $lg_p1[$i];
348
                        $xden = $xden * $xm1 + $lg_q1[$i];
349
                    }
350
                    $res = $corr + $xm1 * ($lg_d1 + $xm1 * ($xnum / $xden));
351 View Code Duplication
                } else {
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...
352
                    $xm2 = $y - 1.0;
353
                    $xden = 1.0;
354
                    $xnum = 0.0;
355
                    for ($i = 0; $i < 8; ++$i) {
356
                        $xnum = $xnum * $xm2 + $lg_p2[$i];
357
                        $xden = $xden * $xm2 + $lg_q2[$i];
358
                    }
359
                    $res = $corr + $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden));
360
                }
361 View Code Duplication
            } elseif ($y <= 4.0) {
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...
362
                // ---------------------
363
                //    1.5 .LT. X .LE. 4.0
364
                // ---------------------
365
                $xm2 = $y - 2.0;
366
                $xden = 1.0;
367
                $xnum = 0.0;
368
                for ($i = 0; $i < 8; ++$i) {
369
                    $xnum = $xnum * $xm2 + $lg_p2[$i];
370
                    $xden = $xden * $xm2 + $lg_q2[$i];
371
                }
372
                $res = $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden));
373
            } elseif ($y <= 12.0) {
374
                // ----------------------
375
                //    4.0 .LT. X .LE. 12.0
376
                // ----------------------
377
                $xm4 = $y - 4.0;
378
                $xden = -1.0;
379
                $xnum = 0.0;
380
                for ($i = 0; $i < 8; ++$i) {
381
                    $xnum = $xnum * $xm4 + $lg_p4[$i];
382
                    $xden = $xden * $xm4 + $lg_q4[$i];
383
                }
384
                $res = $lg_d4 + $xm4 * ($xnum / $xden);
385
            } else {
386
                // ---------------------------------
387
                //    Evaluate for argument .GE. 12.0
388
                // ---------------------------------
389
                $res = 0.0;
390
                if ($y <= $lg_frtbig) {
391
                    $res = $lg_c[6];
392
                    $ysq = $y * $y;
393
                    for ($i = 0; $i < 6; ++$i) {
394
                        $res = $res / $ysq + $lg_c[$i];
395
                    }
396
                    $res /= $y;
397
                    $corr = log($y);
398
                    $res = $res + log(SQRT2PI) - 0.5 * $corr;
399
                    $res += $y * ($corr - 1.0);
400
                }
401
            }
402
        } else {
403
            // --------------------------
404
            //    Return for bad arguments
405
            // --------------------------
406
            $res = MAX_VALUE;
407
        }
408
        // ------------------------------
409
        //    Final adjustments and return
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
410
        // ------------------------------
411
        self::$logGammaCacheX = $x;
412
        self::$logGammaCacheResult = $res;
413
414
        return $res;
415
    }
416
417
    //
418
    //    Private implementation of the incomplete Gamma function
419
    //
420
    private static function incompleteGamma($a, $x)
421
    {
422
        static $max = 32;
423
        $summer = 0;
424
        for ($n = 0; $n <= $max; ++$n) {
425
            $divisor = $a;
426
            for ($i = 1; $i <= $n; ++$i) {
427
                $divisor *= ($a + $i);
428
            }
429
            $summer += (pow($x, $n) / $divisor);
430
        }
431
432
        return pow($x, $a) * exp(0 - $x) * $summer;
433
    }
434
435
    //
436
    //    Private implementation of the Gamma function
437
    //
438
    private static function gamma($data)
439
    {
440
        if ($data == 0.0) {
441
            return 0;
442
        }
443
444
        static $p0 = 1.000000000190015;
445
        static $p = [
446
            1 => 76.18009172947146,
447
            2 => -86.50532032941677,
448
            3 => 24.01409824083091,
449
            4 => -1.231739572450155,
450
            5 => 1.208650973866179e-3,
451
            6 => -5.395239384953e-6,
452
        ];
453
454
        $y = $x = $data;
455
        $tmp = $x + 5.5;
456
        $tmp -= ($x + 0.5) * log($tmp);
457
458
        $summer = $p0;
459
        for ($j = 1; $j <= 6; ++$j) {
460
            $summer += ($p[$j] / ++$y);
461
        }
462
463
        return exp(0 - $tmp + log(SQRT2PI * $summer / $x));
464
    }
465
466
    /***************************************************************************
467
     *                                inverse_ncdf.php
468
     *                            -------------------
469
     *    begin                : Friday, January 16, 2004
470
     *    copyright            : (C) 2004 Michael Nickerson
471
     *    email                : [email protected]
472
     *
473
     ***************************************************************************/
474
    private static function inverseNcdf($p)
475
    {
476
        //    Inverse ncdf approximation by Peter J. Acklam, implementation adapted to
477
        //    PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
478
        //    a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html
479
        //    I have not checked the accuracy of this implementation. Be aware that PHP
480
        //    will truncate the coeficcients to 14 digits.
481
482
        //    You have permission to use and distribute this function freely for
483
        //    whatever purpose you want, but please show common courtesy and give credit
484
        //    where credit is due.
485
486
        //    Input paramater is $p - probability - where 0 < p < 1.
487
488
        //    Coefficients in rational approximations
489
        static $a = [
490
            1 => -3.969683028665376e+01,
491
            2 => 2.209460984245205e+02,
492
            3 => -2.759285104469687e+02,
493
            4 => 1.383577518672690e+02,
494
            5 => -3.066479806614716e+01,
495
            6 => 2.506628277459239e+00,
496
        ];
497
498
        static $b = [
499
            1 => -5.447609879822406e+01,
500
            2 => 1.615858368580409e+02,
501
            3 => -1.556989798598866e+02,
502
            4 => 6.680131188771972e+01,
503
            5 => -1.328068155288572e+01,
504
        ];
505
506
        static $c = [
507
            1 => -7.784894002430293e-03,
508
            2 => -3.223964580411365e-01,
509
            3 => -2.400758277161838e+00,
510
            4 => -2.549732539343734e+00,
511
            5 => 4.374664141464968e+00,
512
            6 => 2.938163982698783e+00,
513
        ];
514
515
        static $d = [
516
            1 => 7.784695709041462e-03,
517
            2 => 3.224671290700398e-01,
518
            3 => 2.445134137142996e+00,
519
            4 => 3.754408661907416e+00,
520
        ];
521
522
        //    Define lower and upper region break-points.
523
        $p_low = 0.02425;            //Use lower region approx. below this
524
        $p_high = 1 - $p_low;        //Use upper region approx. above this
525
526
        if (0 < $p && $p < $p_low) {
527
            //    Rational approximation for lower region.
528
            $q = sqrt(-2 * log($p));
529
530
            return ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) /
531
                    (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1);
532
        } elseif ($p_low <= $p && $p <= $p_high) {
533
            //    Rational approximation for central region.
534
            $q = $p - 0.5;
535
            $r = $q * $q;
536
537
            return ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) * $r + $a[6]) * $q /
538
                   ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r + $b[4]) * $r + $b[5]) * $r + 1);
539
        } elseif ($p_high < $p && $p < 1) {
540
            //    Rational approximation for upper region.
541
            $q = sqrt(-2 * log(1 - $p));
542
543
            return -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) /
544
                     (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1);
545
        }
546
        //    If 0 < p < 1, return a null value
547
        return Functions::NULL();
548
    }
549
550
    private static function inverseNcdf2($prob)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
551
    {
552
        //    Approximation of inverse standard normal CDF developed by
553
        //    B. Moro, "The Full Monte," Risk 8(2), Feb 1995, 57-58.
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
554
555
        $a1 = 2.50662823884;
556
        $a2 = -18.61500062529;
557
        $a3 = 41.39119773534;
558
        $a4 = -25.44106049637;
559
560
        $b1 = -8.4735109309;
561
        $b2 = 23.08336743743;
562
        $b3 = -21.06224101826;
563
        $b4 = 3.13082909833;
564
565
        $c1 = 0.337475482272615;
566
        $c2 = 0.976169019091719;
567
        $c3 = 0.160797971491821;
568
        $c4 = 2.76438810333863E-02;
569
        $c5 = 3.8405729373609E-03;
570
        $c6 = 3.951896511919E-04;
571
        $c7 = 3.21767881768E-05;
572
        $c8 = 2.888167364E-07;
573
        $c9 = 3.960315187E-07;
574
575
        $y = $prob - 0.5;
576
        if (abs($y) < 0.42) {
577
            $z = ($y * $y);
578
            $z = $y * ((($a4 * $z + $a3) * $z + $a2) * $z + $a1) / (((($b4 * $z + $b3) * $z + $b2) * $z + $b1) * $z + 1);
579
        } else {
580
            if ($y > 0) {
581
                $z = log(-log(1 - $prob));
582
            } else {
583
                $z = log(-log($prob));
584
            }
585
            $z = $c1 + $z * ($c2 + $z * ($c3 + $z * ($c4 + $z * ($c5 + $z * ($c6 + $z * ($c7 + $z * ($c8 + $z * $c9)))))));
586
            if ($y < 0) {
587
                $z = -$z;
588
            }
589
        }
590
591
        return $z;
592
    }    //    function inverseNcdf2()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
593
594
    private static function inverseNcdf3($p)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
595
    {
596
        //    ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3.
597
        //    Produces the normal deviate Z corresponding to a given lower
598
        //    tail area of P; Z is accurate to about 1 part in 10**16.
599
        //
600
        //    This is a PHP version of the original FORTRAN code that can
601
        //    be found at http://lib.stat.cmu.edu/apstat/
602
        $split1 = 0.425;
0 ignored issues
show
Unused Code introduced by
$split1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
603
        $split2 = 5;
604
        $const1 = 0.180625;
605
        $const2 = 1.6;
606
607
        //    coefficients for p close to 0.5
608
        $a0 = 3.3871328727963666080;
609
        $a1 = 1.3314166789178437745E+2;
610
        $a2 = 1.9715909503065514427E+3;
611
        $a3 = 1.3731693765509461125E+4;
612
        $a4 = 4.5921953931549871457E+4;
613
        $a5 = 6.7265770927008700853E+4;
614
        $a6 = 3.3430575583588128105E+4;
615
        $a7 = 2.5090809287301226727E+3;
616
617
        $b1 = 4.2313330701600911252E+1;
618
        $b2 = 6.8718700749205790830E+2;
619
        $b3 = 5.3941960214247511077E+3;
620
        $b4 = 2.1213794301586595867E+4;
621
        $b5 = 3.9307895800092710610E+4;
622
        $b6 = 2.8729085735721942674E+4;
623
        $b7 = 5.2264952788528545610E+3;
624
625
        //    coefficients for p not close to 0, 0.5 or 1.
626
        $c0 = 1.42343711074968357734;
627
        $c1 = 4.63033784615654529590;
628
        $c2 = 5.76949722146069140550;
629
        $c3 = 3.64784832476320460504;
630
        $c4 = 1.27045825245236838258;
631
        $c5 = 2.41780725177450611770E-1;
632
        $c6 = 2.27238449892691845833E-2;
633
        $c7 = 7.74545014278341407640E-4;
634
635
        $d1 = 2.05319162663775882187;
636
        $d2 = 1.67638483018380384940;
637
        $d3 = 6.89767334985100004550E-1;
638
        $d4 = 1.48103976427480074590E-1;
639
        $d5 = 1.51986665636164571966E-2;
640
        $d6 = 5.47593808499534494600E-4;
641
        $d7 = 1.05075007164441684324E-9;
642
643
        //    coefficients for p near 0 or 1.
644
        $e0 = 6.65790464350110377720;
645
        $e1 = 5.46378491116411436990;
646
        $e2 = 1.78482653991729133580;
647
        $e3 = 2.96560571828504891230E-1;
648
        $e4 = 2.65321895265761230930E-2;
649
        $e5 = 1.24266094738807843860E-3;
650
        $e6 = 2.71155556874348757815E-5;
651
        $e7 = 2.01033439929228813265E-7;
652
653
        $f1 = 5.99832206555887937690E-1;
654
        $f2 = 1.36929880922735805310E-1;
655
        $f3 = 1.48753612908506148525E-2;
656
        $f4 = 7.86869131145613259100E-4;
657
        $f5 = 1.84631831751005468180E-5;
658
        $f6 = 1.42151175831644588870E-7;
659
        $f7 = 2.04426310338993978564E-15;
660
661
        $q = $p - 0.5;
662
663
        //    computation for p close to 0.5
664
        if (abs($q) <= split1) {
665
            $R = $const1 - $q * $q;
666
            $z = $q * ((((((($a7 * $R + $a6) * $R + $a5) * $R + $a4) * $R + $a3) * $R + $a2) * $R + $a1) * $R + $a0) /
667
                      ((((((($b7 * $R + $b6) * $R + $b5) * $R + $b4) * $R + $b3) * $R + $b2) * $R + $b1) * $R + 1);
668
        } else {
669
            if ($q < 0) {
670
                $R = $p;
671
            } else {
672
                $R = 1 - $p;
673
            }
674
            $R = pow(-log($R), 2);
675
676
            //    computation for p not close to 0, 0.5 or 1.
677
            if ($R <= $split2) {
678
                $R = $R - $const2;
679
                $z = ((((((($c7 * $R + $c6) * $R + $c5) * $R + $c4) * $R + $c3) * $R + $c2) * $R + $c1) * $R + $c0) /
680
                     ((((((($d7 * $R + $d6) * $R + $d5) * $R + $d4) * $R + $d3) * $R + $d2) * $R + $d1) * $R + 1);
681
            } else {
682
                //    computation for p near 0 or 1.
683
                $R = $R - $split2;
684
                $z = ((((((($e7 * $R + $e6) * $R + $e5) * $R + $e4) * $R + $e3) * $R + $e2) * $R + $e1) * $R + $e0) /
685
                     ((((((($f7 * $R + $f6) * $R + $f5) * $R + $f4) * $R + $f3) * $R + $f2) * $R + $f1) * $R + 1);
686
            }
687
            if ($q < 0) {
688
                $z = -$z;
689
            }
690
        }
691
692
        return $z;
693
    }
694
695
    /**
696
     * AVEDEV
697
     *
698
     * Returns the average of the absolute deviations of data points from their mean.
699
     * AVEDEV is a measure of the variability in a data set.
700
     *
701
     * Excel Function:
702
     *        AVEDEV(value1[,value2[, ...]])
703
     *
704
     * @category Statistical Functions
705
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
706
     * @return    float
707
     */
708 View Code Duplication
    public static function AVEDEV()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
709
    {
710
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
711
712
        // Return value
713
        $returnValue = null;
714
715
        $aMean = self::AVERAGE($aArgs);
716
        if ($aMean != Functions::DIV0()) {
717
            $aCount = 0;
718
            foreach ($aArgs as $k => $arg) {
719
                if ((is_bool($arg)) &&
720
                    ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) {
721
                    $arg = (integer) $arg;
722
                }
723
                // Is it a numeric value?
724
                if ((is_numeric($arg)) && (!is_string($arg))) {
725
                    if (is_null($returnValue)) {
726
                        $returnValue = abs($arg - $aMean);
727
                    } else {
728
                        $returnValue += abs($arg - $aMean);
729
                    }
730
                    ++$aCount;
731
                }
732
            }
733
734
            // Return
735
            if ($aCount == 0) {
736
                return Functions::DIV0();
737
            }
738
739
            return $returnValue / $aCount;
740
        }
741
742
        return Functions::NAN();
743
    }
744
745
    /**
746
     * AVERAGE
747
     *
748
     * Returns the average (arithmetic mean) of the arguments
749
     *
750
     * Excel Function:
751
     *        AVERAGE(value1[,value2[, ...]])
752
     *
753
     * @category Statistical Functions
754
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
755
     * @return    float
756
     */
757
    public static function AVERAGE()
758
    {
759
        $returnValue = $aCount = 0;
760
761
        // Loop through arguments
762
        foreach (Functions::flattenArrayIndexed(func_get_args()) as $k => $arg) {
763
            if ((is_bool($arg)) &&
764
                ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) {
765
                $arg = (integer) $arg;
766
            }
767
            // Is it a numeric value?
768
            if ((is_numeric($arg)) && (!is_string($arg))) {
769
                if (is_null($returnValue)) {
770
                    $returnValue = $arg;
771
                } else {
772
                    $returnValue += $arg;
773
                }
774
                ++$aCount;
775
            }
776
        }
777
778
        // Return
779
        if ($aCount > 0) {
780
            return $returnValue / $aCount;
781
        } else {
782
            return Functions::DIV0();
783
        }
784
    }
785
786
    /**
787
     * AVERAGEA
788
     *
789
     * Returns the average of its arguments, including numbers, text, and logical values
790
     *
791
     * Excel Function:
792
     *        AVERAGEA(value1[,value2[, ...]])
793
     *
794
     * @category Statistical Functions
795
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
796
     * @return    float
797
     */
798
    public static function AVERAGEA()
799
    {
800
        $returnValue = null;
801
802
        $aCount = 0;
803
        // Loop through arguments
804
        foreach (Functions::flattenArrayIndexed(func_get_args()) as $k => $arg) {
805
            if ((is_bool($arg)) &&
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
806
                (!Functions::isMatrixValue($k))) {
807
            } else {
808
                if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
809
                    if (is_bool($arg)) {
810
                        $arg = (integer) $arg;
811
                    } elseif (is_string($arg)) {
812
                        $arg = 0;
813
                    }
814
                    if (is_null($returnValue)) {
815
                        $returnValue = $arg;
816
                    } else {
817
                        $returnValue += $arg;
818
                    }
819
                    ++$aCount;
820
                }
821
            }
822
        }
823
824
        if ($aCount > 0) {
825
            return $returnValue / $aCount;
826
        } else {
827
            return Functions::DIV0();
828
        }
829
    }
830
831
    /**
832
     * AVERAGEIF
833
     *
834
     * Returns the average value from a range of cells that contain numbers within the list of arguments
835
     *
836
     * Excel Function:
837
     *        AVERAGEIF(value1[,value2[, ...]],condition)
838
     *
839
     * @category Mathematical and Trigonometric Functions
840
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
841
     * @param    string        $condition        The criteria that defines which cells will be checked.
842
     * @param    mixed[]        $averageArgs    Data values
843
     * @return    float
844
     */
845
    public static function AVERAGEIF($aArgs, $condition, $averageArgs = [])
846
    {
847
        $returnValue = 0;
848
849
        $aArgs = Functions::flattenArray($aArgs);
850
        $averageArgs = Functions::flattenArray($averageArgs);
851
        if (empty($averageArgs)) {
852
            $averageArgs = $aArgs;
0 ignored issues
show
Unused Code introduced by
$averageArgs is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
853
        }
854
        $condition = Functions::ifCondition($condition);
855
        // Loop through arguments
856
        $aCount = 0;
857
        foreach ($aArgs as $key => $arg) {
858
            if (!is_numeric($arg)) {
859
                $arg = \PhpSpreadsheet\Calculation::wrapResult(strtoupper($arg));
860
            }
861
            $testCondition = '=' . $arg . $condition;
862
            if (\PhpSpreadsheet\Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
863
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
864
                    $returnValue += $arg;
865
                    ++$aCount;
866
                }
867
            }
868
        }
869
870
        if ($aCount > 0) {
871
            return $returnValue / $aCount;
872
        }
873
874
        return Functions::DIV0();
875
    }
876
877
    /**
878
     * BETADIST
879
     *
880
     * Returns the beta distribution.
881
     *
882
     * @param    float        $value            Value at which you want to evaluate the distribution
883
     * @param    float        $alpha            Parameter to the distribution
884
     * @param    float        $beta            Parameter to the distribution
885
     * @param    bool        $cumulative
0 ignored issues
show
Bug introduced by
There is no parameter named $cumulative. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
886
     * @return    float
887
     */
888
    public static function BETADIST($value, $alpha, $beta, $rMin = 0, $rMax = 1)
889
    {
890
        $value = Functions::flattenSingleValue($value);
891
        $alpha = Functions::flattenSingleValue($alpha);
892
        $beta = Functions::flattenSingleValue($beta);
893
        $rMin = Functions::flattenSingleValue($rMin);
894
        $rMax = Functions::flattenSingleValue($rMax);
895
896
        if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
897
            if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) {
898
                return Functions::NAN();
899
            }
900
            if ($rMin > $rMax) {
901
                $tmp = $rMin;
902
                $rMin = $rMax;
903
                $rMax = $tmp;
904
            }
905
            $value -= $rMin;
906
            $value /= ($rMax - $rMin);
907
908
            return self::incompleteBeta($value, $alpha, $beta);
0 ignored issues
show
Documentation introduced by
$value is of type integer|double, but the function expects a object<PhpSpreadsheet\Calculation\require>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$alpha is of type integer|double|string, but the function expects a object<PhpSpreadsheet\Calculation\require>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$beta is of type integer|double|string, but the function expects a object<PhpSpreadsheet\Calculation\require>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
909
        }
910
911
        return Functions::VALUE();
912
    }
913
914
    /**
915
     * BETAINV
916
     *
917
     * Returns the inverse of the beta distribution.
918
     *
919
     * @param    float        $probability    Probability at which you want to evaluate the distribution
920
     * @param    float        $alpha            Parameter to the distribution
921
     * @param    float        $beta            Parameter to the distribution
922
     * @param    float        $rMin            Minimum value
923
     * @param    float        $rMax            Maximum value
924
     * @param    bool        $cumulative
0 ignored issues
show
Bug introduced by
There is no parameter named $cumulative. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
925
     * @return    float
926
     */
927
    public static function BETAINV($probability, $alpha, $beta, $rMin = 0, $rMax = 1)
928
    {
929
        $probability = Functions::flattenSingleValue($probability);
930
        $alpha = Functions::flattenSingleValue($alpha);
931
        $beta = Functions::flattenSingleValue($beta);
932
        $rMin = Functions::flattenSingleValue($rMin);
933
        $rMax = Functions::flattenSingleValue($rMax);
934
935
        if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
936 View Code Duplication
            if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) {
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...
937
                return Functions::NAN();
938
            }
939
            if ($rMin > $rMax) {
940
                $tmp = $rMin;
941
                $rMin = $rMax;
942
                $rMax = $tmp;
943
            }
944
            $a = 0;
945
            $b = 2;
946
947
            $i = 0;
948
            while ((($b - $a) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
949
                $guess = ($a + $b) / 2;
950
                $result = self::BETADIST($guess, $alpha, $beta);
951
                if (($result == $probability) || ($result == 0)) {
952
                    $b = $a;
953
                } elseif ($result > $probability) {
954
                    $b = $guess;
955
                } else {
956
                    $a = $guess;
957
                }
958
            }
959
            if ($i == MAX_ITERATIONS) {
960
                return Functions::NA();
961
            }
962
963
            return round($rMin + $guess * ($rMax - $rMin), 12);
0 ignored issues
show
Bug introduced by
The variable $guess does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
964
        }
965
966
        return Functions::VALUE();
967
    }
968
969
    /**
970
     * BINOMDIST
971
     *
972
     * Returns the individual term binomial distribution probability. Use BINOMDIST in problems with
973
     *        a fixed number of tests or trials, when the outcomes of any trial are only success or failure,
974
     *        when trials are independent, and when the probability of success is constant throughout the
975
     *        experiment. For example, BINOMDIST can calculate the probability that two of the next three
976
     *        babies born are male.
977
     *
978
     * @param    float        $value            Number of successes in trials
979
     * @param    float        $trials            Number of trials
980
     * @param    float        $probability    Probability of success on each trial
981
     * @param    bool        $cumulative
982
     * @return    float
983
     *
984
     * @todo    Cumulative distribution function
985
     */
986
    public static function BINOMDIST($value, $trials, $probability, $cumulative)
987
    {
988
        $value = floor(Functions::flattenSingleValue($value));
989
        $trials = floor(Functions::flattenSingleValue($trials));
990
        $probability = Functions::flattenSingleValue($probability);
991
992
        if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) {
993
            if (($value < 0) || ($value > $trials)) {
994
                return Functions::NAN();
995
            }
996
            if (($probability < 0) || ($probability > 1)) {
997
                return Functions::NAN();
998
            }
999
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
1000
                if ($cumulative) {
1001
                    $summer = 0;
1002
                    for ($i = 0; $i <= $value; ++$i) {
1003
                        $summer += MathTrig::COMBIN($trials, $i) * pow($probability, $i) * pow(1 - $probability, $trials - $i);
1004
                    }
1005
1006
                    return $summer;
1007
                } else {
1008
                    return MathTrig::COMBIN($trials, $value) * pow($probability, $value) * pow(1 - $probability, $trials - $value);
1009
                }
1010
            }
1011
        }
1012
1013
        return Functions::VALUE();
1014
    }
1015
1016
    /**
1017
     * CHIDIST
1018
     *
1019
     * Returns the one-tailed probability of the chi-squared distribution.
1020
     *
1021
     * @param    float        $value            Value for the function
1022
     * @param    float        $degrees        degrees of freedom
1023
     * @return    float
1024
     */
1025
    public static function CHIDIST($value, $degrees)
1026
    {
1027
        $value = Functions::flattenSingleValue($value);
1028
        $degrees = floor(Functions::flattenSingleValue($degrees));
1029
1030
        if ((is_numeric($value)) && (is_numeric($degrees))) {
1031
            if ($degrees < 1) {
1032
                return Functions::NAN();
1033
            }
1034
            if ($value < 0) {
1035
                if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1036
                    return 1;
1037
                }
1038
1039
                return Functions::NAN();
1040
            }
1041
1042
            return 1 - (self::incompleteGamma($degrees / 2, $value / 2) / self::gamma($degrees / 2));
1043
        }
1044
1045
        return Functions::VALUE();
1046
    }
1047
1048
    /**
1049
     * CHIINV
1050
     *
1051
     * Returns the one-tailed probability of the chi-squared distribution.
1052
     *
1053
     * @param    float        $probability    Probability for the function
1054
     * @param    float        $degrees        degrees of freedom
1055
     * @return    float
1056
     */
1057 View Code Duplication
    public static function CHIINV($probability, $degrees)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1058
    {
1059
        $probability = Functions::flattenSingleValue($probability);
1060
        $degrees = floor(Functions::flattenSingleValue($degrees));
1061
1062
        if ((is_numeric($probability)) && (is_numeric($degrees))) {
1063
            $xLo = 100;
1064
            $xHi = 0;
1065
1066
            $x = $xNew = 1;
1067
            $dx = 1;
1068
            $i = 0;
1069
1070
            while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
1071
                // Apply Newton-Raphson step
1072
                $result = self::CHIDIST($x, $degrees);
1073
                $error = $result - $probability;
1074
                if ($error == 0.0) {
1075
                    $dx = 0;
1076
                } elseif ($error < 0.0) {
1077
                    $xLo = $x;
1078
                } else {
1079
                    $xHi = $x;
1080
                }
1081
                // Avoid division by zero
1082
                if ($result != 0.0) {
1083
                    $dx = $error / $result;
1084
                    $xNew = $x - $dx;
1085
                }
1086
                // If the NR fails to converge (which for example may be the
1087
                // case if the initial guess is too rough) we apply a bisection
1088
                // step to determine a more narrow interval around the root.
1089
                if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
1090
                    $xNew = ($xLo + $xHi) / 2;
1091
                    $dx = $xNew - $x;
1092
                }
1093
                $x = $xNew;
1094
            }
1095
            if ($i == MAX_ITERATIONS) {
1096
                return Functions::NA();
1097
            }
1098
1099
            return round($x, 12);
1100
        }
1101
1102
        return Functions::VALUE();
1103
    }
1104
1105
    /**
1106
     * CONFIDENCE
1107
     *
1108
     * Returns the confidence interval for a population mean
1109
     *
1110
     * @param    float        $alpha
1111
     * @param    float        $stdDev        Standard Deviation
1112
     * @param    float        $size
1113
     * @return    float
1114
     */
1115
    public static function CONFIDENCE($alpha, $stdDev, $size)
1116
    {
1117
        $alpha = Functions::flattenSingleValue($alpha);
1118
        $stdDev = Functions::flattenSingleValue($stdDev);
1119
        $size = floor(Functions::flattenSingleValue($size));
1120
1121
        if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) {
1122
            if (($alpha <= 0) || ($alpha >= 1)) {
1123
                return Functions::NAN();
1124
            }
1125
            if (($stdDev <= 0) || ($size < 1)) {
1126
                return Functions::NAN();
1127
            }
1128
1129
            return self::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size);
1130
        }
1131
1132
        return Functions::VALUE();
1133
    }
1134
1135
    /**
1136
     * CORREL
1137
     *
1138
     * Returns covariance, the average of the products of deviations for each data point pair.
1139
     *
1140
     * @param    array of mixed        Data Series Y
1141
     * @param    array of mixed        Data Series X
1142
     * @return    float
1143
     */
1144
    public static function CORREL($yValues, $xValues = null)
1145
    {
1146
        if ((is_null($xValues)) || (!is_array($yValues)) || (!is_array($xValues))) {
1147
            return Functions::VALUE();
1148
        }
1149
        if (!self::checkTrendArrays($yValues, $xValues)) {
1150
            return Functions::VALUE();
1151
        }
1152
        $yValueCount = count($yValues);
1153
        $xValueCount = count($xValues);
1154
1155
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
1156
            return Functions::NA();
1157
        } elseif ($yValueCount == 1) {
1158
            return Functions::DIV0();
1159
        }
1160
1161
        $bestFitLinear = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
1162
1163
        return $bestFitLinear->getCorrelation();
1164
    }
1165
1166
    /**
1167
     * COUNT
1168
     *
1169
     * Counts the number of cells that contain numbers within the list of arguments
1170
     *
1171
     * Excel Function:
1172
     *        COUNT(value1[,value2[, ...]])
1173
     *
1174
     * @category Statistical Functions
1175
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1176
     * @return    int
1177
     */
1178
    public static function COUNT()
1179
    {
1180
        $returnValue = 0;
1181
1182
        // Loop through arguments
1183
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
1184
        foreach ($aArgs as $k => $arg) {
1185
            if ((is_bool($arg)) &&
1186
                ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) {
1187
                $arg = (integer) $arg;
1188
            }
1189
            // Is it a numeric value?
1190
            if ((is_numeric($arg)) && (!is_string($arg))) {
1191
                ++$returnValue;
1192
            }
1193
        }
1194
1195
        return $returnValue;
1196
    }
1197
1198
    /**
1199
     * COUNTA
1200
     *
1201
     * Counts the number of cells that are not empty within the list of arguments
1202
     *
1203
     * Excel Function:
1204
     *        COUNTA(value1[,value2[, ...]])
1205
     *
1206
     * @category Statistical Functions
1207
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1208
     * @return    int
1209
     */
1210 View Code Duplication
    public static function COUNTA()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1211
    {
1212
        $returnValue = 0;
1213
1214
        // Loop through arguments
1215
        $aArgs = Functions::flattenArray(func_get_args());
1216
        foreach ($aArgs as $arg) {
1217
            // Is it a numeric, boolean or string value?
1218
            if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
1219
                ++$returnValue;
1220
            }
1221
        }
1222
1223
        return $returnValue;
1224
    }
1225
1226
    /**
1227
     * COUNTBLANK
1228
     *
1229
     * Counts the number of empty cells within the list of arguments
1230
     *
1231
     * Excel Function:
1232
     *        COUNTBLANK(value1[,value2[, ...]])
1233
     *
1234
     * @category Statistical Functions
1235
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1236
     * @return    int
1237
     */
1238 View Code Duplication
    public static function COUNTBLANK()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1239
    {
1240
        $returnValue = 0;
1241
1242
        // Loop through arguments
1243
        $aArgs = Functions::flattenArray(func_get_args());
1244
        foreach ($aArgs as $arg) {
1245
            // Is it a blank cell?
1246
            if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) {
1247
                ++$returnValue;
1248
            }
1249
        }
1250
1251
        return $returnValue;
1252
    }
1253
1254
    /**
1255
     * COUNTIF
1256
     *
1257
     * Counts the number of cells that contain numbers within the list of arguments
1258
     *
1259
     * Excel Function:
1260
     *        COUNTIF(value1[,value2[, ...]],condition)
1261
     *
1262
     * @category Statistical Functions
1263
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1264
     * @param    string        $condition        The criteria that defines which cells will be counted.
1265
     * @return    int
1266
     */
1267
    public static function COUNTIF($aArgs, $condition)
1268
    {
1269
        $returnValue = 0;
1270
1271
        $aArgs = Functions::flattenArray($aArgs);
1272
        $condition = Functions::ifCondition($condition);
1273
        // Loop through arguments
1274
        foreach ($aArgs as $arg) {
1275
            if (!is_numeric($arg)) {
1276
                $arg = \PhpSpreadsheet\Calculation::wrapResult(strtoupper($arg));
1277
            }
1278
            $testCondition = '=' . $arg . $condition;
1279
            if (\PhpSpreadsheet\Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
1280
                // Is it a value within our criteria
1281
                ++$returnValue;
1282
            }
1283
        }
1284
1285
        return $returnValue;
1286
    }
1287
1288
    /**
1289
     * COVAR
1290
     *
1291
     * Returns covariance, the average of the products of deviations for each data point pair.
1292
     *
1293
     * @param    array of mixed        Data Series Y
1294
     * @param    array of mixed        Data Series X
1295
     * @return    float
1296
     */
1297 View Code Duplication
    public static function COVAR($yValues, $xValues)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1298
    {
1299
        if (!self::checkTrendArrays($yValues, $xValues)) {
1300
            return Functions::VALUE();
1301
        }
1302
        $yValueCount = count($yValues);
1303
        $xValueCount = count($xValues);
1304
1305
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
1306
            return Functions::NA();
1307
        } elseif ($yValueCount == 1) {
1308
            return Functions::DIV0();
1309
        }
1310
1311
        $bestFitLinear = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
1312
1313
        return $bestFitLinear->getCovariance();
1314
    }
1315
1316
    /**
1317
     * CRITBINOM
1318
     *
1319
     * Returns the smallest value for which the cumulative binomial distribution is greater
1320
     *        than or equal to a criterion value
1321
     *
1322
     * See http://support.microsoft.com/kb/828117/ for details of the algorithm used
1323
     *
1324
     * @param    float        $trials            number of Bernoulli trials
1325
     * @param    float        $probability    probability of a success on each trial
1326
     * @param    float        $alpha            criterion value
1327
     * @return    int
1328
     *
1329
     * @todo    Warning. This implementation differs from the algorithm detailed on the MS
1330
     *            web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess
1331
     *            This eliminates a potential endless loop error, but may have an adverse affect on the
1332
     *            accuracy of the function (although all my tests have so far returned correct results).
1333
     */
1334
    public static function CRITBINOM($trials, $probability, $alpha)
1335
    {
1336
        $trials = floor(Functions::flattenSingleValue($trials));
1337
        $probability = Functions::flattenSingleValue($probability);
1338
        $alpha = Functions::flattenSingleValue($alpha);
1339
1340
        if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) {
1341
            if ($trials < 0) {
1342
                return Functions::NAN();
1343
            } elseif (($probability < 0) || ($probability > 1)) {
1344
                return Functions::NAN();
1345
            } elseif (($alpha < 0) || ($alpha > 1)) {
1346
                return Functions::NAN();
1347
            } elseif ($alpha <= 0.5) {
1348
                $t = sqrt(log(1 / ($alpha * $alpha)));
1349
                $trialsApprox = 0 - ($t + (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t));
1350
            } else {
1351
                $t = sqrt(log(1 / pow(1 - $alpha, 2)));
1352
                $trialsApprox = $t - (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t);
1353
            }
1354
            $Guess = floor($trials * $probability + $trialsApprox * sqrt($trials * $probability * (1 - $probability)));
1355
            if ($Guess < 0) {
1356
                $Guess = 0;
1357
            } elseif ($Guess > $trials) {
1358
                $Guess = $trials;
1359
            }
1360
1361
            $TotalUnscaledProbability = $UnscaledPGuess = $UnscaledCumPGuess = 0.0;
1362
            $EssentiallyZero = 10e-12;
1363
1364
            $m = floor($trials * $probability);
1365
            ++$TotalUnscaledProbability;
1366
            if ($m == $Guess) {
1367
                ++$UnscaledPGuess;
1368
            }
1369
            if ($m <= $Guess) {
1370
                ++$UnscaledCumPGuess;
1371
            }
1372
1373
            $PreviousValue = 1;
1374
            $Done = false;
1375
            $k = $m + 1;
1376 View Code Duplication
            while ((!$Done) && ($k <= $trials)) {
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...
1377
                $CurrentValue = $PreviousValue * ($trials - $k + 1) * $probability / ($k * (1 - $probability));
1378
                $TotalUnscaledProbability += $CurrentValue;
1379
                if ($k == $Guess) {
1380
                    $UnscaledPGuess += $CurrentValue;
1381
                }
1382
                if ($k <= $Guess) {
1383
                    $UnscaledCumPGuess += $CurrentValue;
1384
                }
1385
                if ($CurrentValue <= $EssentiallyZero) {
1386
                    $Done = true;
1387
                }
1388
                $PreviousValue = $CurrentValue;
1389
                ++$k;
1390
            }
1391
1392
            $PreviousValue = 1;
1393
            $Done = false;
1394
            $k = $m - 1;
1395 View Code Duplication
            while ((!$Done) && ($k >= 0)) {
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...
1396
                $CurrentValue = $PreviousValue * $k + 1 * (1 - $probability) / (($trials - $k) * $probability);
1397
                $TotalUnscaledProbability += $CurrentValue;
1398
                if ($k == $Guess) {
1399
                    $UnscaledPGuess += $CurrentValue;
1400
                }
1401
                if ($k <= $Guess) {
1402
                    $UnscaledCumPGuess += $CurrentValue;
1403
                }
1404
                if ($CurrentValue <= $EssentiallyZero) {
1405
                    $Done = true;
1406
                }
1407
                $PreviousValue = $CurrentValue;
1408
                --$k;
1409
            }
1410
1411
            $PGuess = $UnscaledPGuess / $TotalUnscaledProbability;
1412
            $CumPGuess = $UnscaledCumPGuess / $TotalUnscaledProbability;
1413
1414
//            $CumPGuessMinus1 = $CumPGuess - $PGuess;
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1415
            $CumPGuessMinus1 = $CumPGuess - 1;
1416
1417
            while (true) {
1418
                if (($CumPGuessMinus1 < $alpha) && ($CumPGuess >= $alpha)) {
1419
                    return $Guess;
1420
                } elseif (($CumPGuessMinus1 < $alpha) && ($CumPGuess < $alpha)) {
1421
                    $PGuessPlus1 = $PGuess * ($trials - $Guess) * $probability / $Guess / (1 - $probability);
1422
                    $CumPGuessMinus1 = $CumPGuess;
1423
                    $CumPGuess = $CumPGuess + $PGuessPlus1;
1424
                    $PGuess = $PGuessPlus1;
1425
                    ++$Guess;
1426
                } elseif (($CumPGuessMinus1 >= $alpha) && ($CumPGuess >= $alpha)) {
1427
                    $PGuessMinus1 = $PGuess * $Guess * (1 - $probability) / ($trials - $Guess + 1) / $probability;
1428
                    $CumPGuess = $CumPGuessMinus1;
1429
                    $CumPGuessMinus1 = $CumPGuessMinus1 - $PGuess;
1430
                    $PGuess = $PGuessMinus1;
1431
                    --$Guess;
1432
                }
1433
            }
1434
        }
1435
1436
        return Functions::VALUE();
1437
    }
1438
1439
    /**
1440
     * DEVSQ
1441
     *
1442
     * Returns the sum of squares of deviations of data points from their sample mean.
1443
     *
1444
     * Excel Function:
1445
     *        DEVSQ(value1[,value2[, ...]])
1446
     *
1447
     * @category Statistical Functions
1448
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1449
     * @return    float
1450
     */
1451 View Code Duplication
    public static function DEVSQ()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1452
    {
1453
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
1454
1455
        // Return value
1456
        $returnValue = null;
1457
1458
        $aMean = self::AVERAGE($aArgs);
1459
        if ($aMean != Functions::DIV0()) {
1460
            $aCount = -1;
1461
            foreach ($aArgs as $k => $arg) {
1462
                // Is it a numeric value?
1463
                if ((is_bool($arg)) &&
1464
                    ((!Functions::isCellValue($k)) ||
1465
                    (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) {
1466
                    $arg = (integer) $arg;
1467
                }
1468
                if ((is_numeric($arg)) && (!is_string($arg))) {
1469
                    if (is_null($returnValue)) {
1470
                        $returnValue = pow(($arg - $aMean), 2);
1471
                    } else {
1472
                        $returnValue += pow(($arg - $aMean), 2);
1473
                    }
1474
                    ++$aCount;
1475
                }
1476
            }
1477
1478
            // Return
1479
            if (is_null($returnValue)) {
1480
                return Functions::NAN();
1481
            } else {
1482
                return $returnValue;
1483
            }
1484
        }
1485
1486
        return self::NA();
0 ignored issues
show
Bug introduced by
The method NA() does not seem to exist on object<PhpSpreadsheet\Calculation\Statistical>.

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...
1487
    }
1488
1489
    /**
1490
     * EXPONDIST
1491
     *
1492
     *    Returns the exponential distribution. Use EXPONDIST to model the time between events,
1493
     *        such as how long an automated bank teller takes to deliver cash. For example, you can
1494
     *        use EXPONDIST to determine the probability that the process takes at most 1 minute.
1495
     *
1496
     * @param    float        $value            Value of the function
1497
     * @param    float        $lambda            The parameter value
1498
     * @param    bool        $cumulative
1499
     * @return    float
1500
     */
1501
    public static function EXPONDIST($value, $lambda, $cumulative)
1502
    {
1503
        $value = Functions::flattenSingleValue($value);
1504
        $lambda = Functions::flattenSingleValue($lambda);
1505
        $cumulative = Functions::flattenSingleValue($cumulative);
1506
1507
        if ((is_numeric($value)) && (is_numeric($lambda))) {
1508
            if (($value < 0) || ($lambda < 0)) {
1509
                return Functions::NAN();
1510
            }
1511
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
1512
                if ($cumulative) {
1513
                    return 1 - exp(0 - $value * $lambda);
1514
                } else {
1515
                    return $lambda * exp(0 - $value * $lambda);
1516
                }
1517
            }
1518
        }
1519
1520
        return Functions::VALUE();
1521
    }
1522
1523
    /**
1524
     * FISHER
1525
     *
1526
     * Returns the Fisher transformation at x. This transformation produces a function that
1527
     *        is normally distributed rather than skewed. Use this function to perform hypothesis
1528
     *        testing on the correlation coefficient.
1529
     *
1530
     * @param    float        $value
1531
     * @return    float
1532
     */
1533
    public static function FISHER($value)
1534
    {
1535
        $value = Functions::flattenSingleValue($value);
1536
1537
        if (is_numeric($value)) {
1538
            if (($value <= -1) || ($value >= 1)) {
1539
                return Functions::NAN();
1540
            }
1541
1542
            return 0.5 * log((1 + $value) / (1 - $value));
1543
        }
1544
1545
        return Functions::VALUE();
1546
    }
1547
1548
    /**
1549
     * FISHERINV
1550
     *
1551
     * Returns the inverse of the Fisher transformation. Use this transformation when
1552
     *        analyzing correlations between ranges or arrays of data. If y = FISHER(x), then
1553
     *        FISHERINV(y) = x.
1554
     *
1555
     * @param    float        $value
1556
     * @return    float
1557
     */
1558
    public static function FISHERINV($value)
1559
    {
1560
        $value = Functions::flattenSingleValue($value);
1561
1562
        if (is_numeric($value)) {
1563
            return (exp(2 * $value) - 1) / (exp(2 * $value) + 1);
1564
        }
1565
1566
        return Functions::VALUE();
1567
    }
1568
1569
    /**
1570
     * FORECAST
1571
     *
1572
     * Calculates, or predicts, a future value by using existing values. The predicted value is a y-value for a given x-value.
1573
     *
1574
     * @param    float                Value of X for which we want to find Y
1575
     * @param    array of mixed        Data Series Y
1576
     * @param    array of mixed        Data Series X
1577
     * @return    float
1578
     */
1579
    public static function FORECAST($xValue, $yValues, $xValues)
1580
    {
1581
        $xValue = Functions::flattenSingleValue($xValue);
1582
        if (!is_numeric($xValue)) {
1583
            return Functions::VALUE();
1584
        } elseif (!self::checkTrendArrays($yValues, $xValues)) {
1585
            return Functions::VALUE();
1586
        }
1587
        $yValueCount = count($yValues);
1588
        $xValueCount = count($xValues);
1589
1590
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
1591
            return Functions::NA();
1592
        } elseif ($yValueCount == 1) {
1593
            return Functions::DIV0();
1594
        }
1595
1596
        $bestFitLinear = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
1597
1598
        return $bestFitLinear->getValueOfYForX($xValue);
1599
    }
1600
1601
    /**
1602
     * GAMMADIST
1603
     *
1604
     * Returns the gamma distribution.
1605
     *
1606
     * @param    float        $value            Value at which you want to evaluate the distribution
1607
     * @param    float        $a                Parameter to the distribution
1608
     * @param    float        $b                Parameter to the distribution
1609
     * @param    bool        $cumulative
1610
     * @return    float
1611
     */
1612
    public static function GAMMADIST($value, $a, $b, $cumulative)
1613
    {
1614
        $value = Functions::flattenSingleValue($value);
1615
        $a = Functions::flattenSingleValue($a);
1616
        $b = Functions::flattenSingleValue($b);
1617
1618
        if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) {
1619
            if (($value < 0) || ($a <= 0) || ($b <= 0)) {
1620
                return Functions::NAN();
1621
            }
1622
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
1623
                if ($cumulative) {
1624
                    return self::incompleteGamma($a, $value / $b) / self::gamma($a);
1625
                } else {
1626
                    return (1 / (pow($b, $a) * self::gamma($a))) * pow($value, $a - 1) * exp(0 - ($value / $b));
1627
                }
1628
            }
1629
        }
1630
1631
        return Functions::VALUE();
1632
    }
1633
1634
    /**
1635
     * GAMMAINV
1636
     *
1637
     * Returns the inverse of the beta distribution.
1638
     *
1639
     * @param    float        $probability    Probability at which you want to evaluate the distribution
1640
     * @param    float        $alpha            Parameter to the distribution
1641
     * @param    float        $beta            Parameter to the distribution
1642
     * @return    float
1643
     */
1644
    public static function GAMMAINV($probability, $alpha, $beta)
1645
    {
1646
        $probability = Functions::flattenSingleValue($probability);
1647
        $alpha = Functions::flattenSingleValue($alpha);
1648
        $beta = Functions::flattenSingleValue($beta);
1649
1650
        if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) {
1651 View Code Duplication
            if (($alpha <= 0) || ($beta <= 0) || ($probability < 0) || ($probability > 1)) {
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...
1652
                return Functions::NAN();
1653
            }
1654
1655
            $xLo = 0;
1656
            $xHi = $alpha * $beta * 5;
1657
1658
            $x = $xNew = 1;
1659
            $error = $pdf = 0;
0 ignored issues
show
Unused Code introduced by
$pdf is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
Unused Code introduced by
$error is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1660
            $dx = 1024;
1661
            $i = 0;
1662
1663
            while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
1664
                // Apply Newton-Raphson step
1665
                $error = self::GAMMADIST($x, $alpha, $beta, true) - $probability;
1666
                if ($error < 0.0) {
1667
                    $xLo = $x;
1668
                } else {
1669
                    $xHi = $x;
1670
                }
1671
                $pdf = self::GAMMADIST($x, $alpha, $beta, false);
1672
                // Avoid division by zero
1673
                if ($pdf != 0.0) {
1674
                    $dx = $error / $pdf;
1675
                    $xNew = $x - $dx;
1676
                }
1677
                // If the NR fails to converge (which for example may be the
1678
                // case if the initial guess is too rough) we apply a bisection
1679
                // step to determine a more narrow interval around the root.
1680
                if (($xNew < $xLo) || ($xNew > $xHi) || ($pdf == 0.0)) {
1681
                    $xNew = ($xLo + $xHi) / 2;
1682
                    $dx = $xNew - $x;
1683
                }
1684
                $x = $xNew;
1685
            }
1686
            if ($i == MAX_ITERATIONS) {
1687
                return Functions::NA();
1688
            }
1689
1690
            return $x;
1691
        }
1692
1693
        return Functions::VALUE();
1694
    }
1695
1696
    /**
1697
     * GAMMALN
1698
     *
1699
     * Returns the natural logarithm of the gamma function.
1700
     *
1701
     * @param    float        $value
1702
     * @return    float
1703
     */
1704 View Code Duplication
    public static function GAMMALN($value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1705
    {
1706
        $value = Functions::flattenSingleValue($value);
1707
1708
        if (is_numeric($value)) {
1709
            if ($value <= 0) {
1710
                return Functions::NAN();
1711
            }
1712
1713
            return log(self::gamma($value));
1714
        }
1715
1716
        return Functions::VALUE();
1717
    }
1718
1719
    /**
1720
     * GEOMEAN
1721
     *
1722
     * Returns the geometric mean of an array or range of positive data. For example, you
1723
     *        can use GEOMEAN to calculate average growth rate given compound interest with
1724
     *        variable rates.
1725
     *
1726
     * Excel Function:
1727
     *        GEOMEAN(value1[,value2[, ...]])
1728
     *
1729
     * @category Statistical Functions
1730
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1731
     * @return    float
1732
     */
1733
    public static function GEOMEAN()
1734
    {
1735
        $aArgs = Functions::flattenArray(func_get_args());
1736
1737
        $aMean = MathTrig::PRODUCT($aArgs);
1738
        if (is_numeric($aMean) && ($aMean > 0)) {
1739
            $aCount = self::COUNT($aArgs);
1740
            if (self::MIN($aArgs) > 0) {
1741
                return pow($aMean, (1 / $aCount));
1742
            }
1743
        }
1744
1745
        return Functions::NAN();
1746
    }
1747
1748
    /**
1749
     * GROWTH
1750
     *
1751
     * Returns values along a predicted emponential Trend
1752
     *
1753
     * @param    array of mixed        Data Series Y
1754
     * @param    array of mixed        Data Series X
1755
     * @param    array of mixed        Values of X for which we want to find Y
1756
     * @param    bool                A logical value specifying whether to force the intersect to equal 0.
1757
     * @return    array of float
1758
     */
1759 View Code Duplication
    public static function GROWTH($yValues, $xValues = [], $newValues = [], $const = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1760
    {
1761
        $yValues = Functions::flattenArray($yValues);
1762
        $xValues = Functions::flattenArray($xValues);
1763
        $newValues = Functions::flattenArray($newValues);
1764
        $const = (is_null($const)) ? true : (boolean) Functions::flattenSingleValue($const);
1765
1766
        $bestFitExponential = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_EXPONENTIAL, $yValues, $xValues, $const);
1767
        if (empty($newValues)) {
1768
            $newValues = $bestFitExponential->getXValues();
1769
        }
1770
1771
        $returnArray = [];
1772
        foreach ($newValues as $xValue) {
1773
            $returnArray[0][] = $bestFitExponential->getValueOfYForX($xValue);
1774
        }
1775
1776
        return $returnArray;
1777
    }
1778
1779
    /**
1780
     * HARMEAN
1781
     *
1782
     * Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the
1783
     *        arithmetic mean of reciprocals.
1784
     *
1785
     * Excel Function:
1786
     *        HARMEAN(value1[,value2[, ...]])
1787
     *
1788
     * @category Statistical Functions
1789
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1790
     * @return    float
1791
     */
1792
    public static function HARMEAN()
1793
    {
1794
        // Return value
1795
        $returnValue = Functions::NA();
1796
1797
        // Loop through arguments
1798
        $aArgs = Functions::flattenArray(func_get_args());
1799
        if (self::MIN($aArgs) < 0) {
1800
            return Functions::NAN();
1801
        }
1802
        $aCount = 0;
1803
        foreach ($aArgs as $arg) {
1804
            // Is it a numeric value?
1805
            if ((is_numeric($arg)) && (!is_string($arg))) {
1806
                if ($arg <= 0) {
1807
                    return Functions::NAN();
1808
                }
1809
                if (is_null($returnValue)) {
1810
                    $returnValue = (1 / $arg);
1811
                } else {
1812
                    $returnValue += (1 / $arg);
1813
                }
1814
                ++$aCount;
1815
            }
1816
        }
1817
1818
        // Return
1819
        if ($aCount > 0) {
1820
            return 1 / ($returnValue / $aCount);
1821
        } else {
1822
            return $returnValue;
1823
        }
1824
    }
1825
1826
    /**
1827
     * HYPGEOMDIST
1828
     *
1829
     * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of
1830
     * sample successes, given the sample size, population successes, and population size.
1831
     *
1832
     * @param    float        $sampleSuccesses        Number of successes in the sample
1833
     * @param    float        $sampleNumber            Size of the sample
1834
     * @param    float        $populationSuccesses    Number of successes in the population
1835
     * @param    float        $populationNumber        Population size
1836
     * @return    float
1837
     */
1838
    public static function HYPGEOMDIST($sampleSuccesses, $sampleNumber, $populationSuccesses, $populationNumber)
1839
    {
1840
        $sampleSuccesses = floor(Functions::flattenSingleValue($sampleSuccesses));
1841
        $sampleNumber = floor(Functions::flattenSingleValue($sampleNumber));
1842
        $populationSuccesses = floor(Functions::flattenSingleValue($populationSuccesses));
1843
        $populationNumber = floor(Functions::flattenSingleValue($populationNumber));
1844
1845
        if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) {
1846
            if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) {
1847
                return Functions::NAN();
1848
            }
1849
            if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) {
1850
                return Functions::NAN();
1851
            }
1852
            if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) {
1853
                return Functions::NAN();
1854
            }
1855
1856
            return MathTrig::COMBIN($populationSuccesses, $sampleSuccesses) *
1857
                   MathTrig::COMBIN($populationNumber - $populationSuccesses, $sampleNumber - $sampleSuccesses) /
1858
                   MathTrig::COMBIN($populationNumber, $sampleNumber);
1859
        }
1860
1861
        return Functions::VALUE();
1862
    }
1863
1864
    /**
1865
     * INTERCEPT
1866
     *
1867
     * Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values.
1868
     *
1869
     * @param    array of mixed        Data Series Y
1870
     * @param    array of mixed        Data Series X
1871
     * @return    float
1872
     */
1873 View Code Duplication
    public static function INTERCEPT($yValues, $xValues)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1874
    {
1875
        if (!self::checkTrendArrays($yValues, $xValues)) {
1876
            return Functions::VALUE();
1877
        }
1878
        $yValueCount = count($yValues);
1879
        $xValueCount = count($xValues);
1880
1881
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
1882
            return Functions::NA();
1883
        } elseif ($yValueCount == 1) {
1884
            return Functions::DIV0();
1885
        }
1886
1887
        $bestFitLinear = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
1888
1889
        return $bestFitLinear->getIntersect();
1890
    }
1891
1892
    /**
1893
     * KURT
1894
     *
1895
     * Returns the kurtosis of a data set. Kurtosis characterizes the relative peakedness
1896
     * or flatness of a distribution compared with the normal distribution. Positive
1897
     * kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a
1898
     * relatively flat distribution.
1899
     *
1900
     * @param    array    Data Series
1901
     * @return    float
1902
     */
1903
    public static function KURT()
1904
    {
1905
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
1906
        $mean = self::AVERAGE($aArgs);
1907
        $stdDev = self::STDEV($aArgs);
1908
1909
        if ($stdDev > 0) {
1910
            $count = $summer = 0;
1911
            // Loop through arguments
1912 View Code Duplication
            foreach ($aArgs as $k => $arg) {
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...
1913
                if ((is_bool($arg)) &&
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1914
                    (!Functions::isMatrixValue($k))) {
1915
                } else {
1916
                    // Is it a numeric value?
1917
                    if ((is_numeric($arg)) && (!is_string($arg))) {
1918
                        $summer += pow((($arg - $mean) / $stdDev), 4);
1919
                        ++$count;
1920
                    }
1921
                }
1922
            }
1923
1924
            // Return
1925
            if ($count > 3) {
1926
                return $summer * ($count * ($count + 1) / (($count - 1) * ($count - 2) * ($count - 3))) - (3 * pow($count - 1, 2) / (($count - 2) * ($count - 3)));
1927
            }
1928
        }
1929
1930
        return Functions::DIV0();
1931
    }
1932
1933
    /**
1934
     * LARGE
1935
     *
1936
     * Returns the nth largest value in a data set. You can use this function to
1937
     *        select a value based on its relative standing.
1938
     *
1939
     * Excel Function:
1940
     *        LARGE(value1[,value2[, ...]],entry)
1941
     *
1942
     * @category Statistical Functions
1943
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1944
     * @param    int            $entry            Position (ordered from the largest) in the array or range of data to return
0 ignored issues
show
Bug introduced by
There is no parameter named $entry. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1945
     * @return    float
1946
     */
1947 View Code Duplication
    public static function LARGE()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1948
    {
1949
        $aArgs = Functions::flattenArray(func_get_args());
1950
1951
        // Calculate
1952
        $entry = floor(array_pop($aArgs));
1953
1954
        if ((is_numeric($entry)) && (!is_string($entry))) {
1955
            $mArgs = [];
1956
            foreach ($aArgs as $arg) {
1957
                // Is it a numeric value?
1958
                if ((is_numeric($arg)) && (!is_string($arg))) {
1959
                    $mArgs[] = $arg;
1960
                }
1961
            }
1962
            $count = self::COUNT($mArgs);
1963
            $entry = floor(--$entry);
1964
            if (($entry < 0) || ($entry >= $count) || ($count == 0)) {
1965
                return Functions::NAN();
1966
            }
1967
            rsort($mArgs);
1968
1969
            return $mArgs[$entry];
1970
        }
1971
1972
        return Functions::VALUE();
1973
    }
1974
1975
    /**
1976
     * LINEST
1977
     *
1978
     * Calculates the statistics for a line by using the "least squares" method to calculate a straight line that best fits your data,
1979
     *        and then returns an array that describes the line.
1980
     *
1981
     * @param    array of mixed        Data Series Y
1982
     * @param    array of mixed        Data Series X
1983
     * @param    bool                A logical value specifying whether to force the intersect to equal 0.
1984
     * @param    bool                A logical value specifying whether to return additional regression statistics.
1985
     * @return    array
1986
     */
1987
    public static function LINEST($yValues, $xValues = null, $const = true, $stats = false)
1988
    {
1989
        $const = (is_null($const)) ? true : (boolean) Functions::flattenSingleValue($const);
1990
        $stats = (is_null($stats)) ? false : (boolean) Functions::flattenSingleValue($stats);
1991
        if (is_null($xValues)) {
1992
            $xValues = range(1, count(Functions::flattenArray($yValues)));
1993
        }
1994
1995
        if (!self::checkTrendArrays($yValues, $xValues)) {
1996
            return Functions::VALUE();
1997
        }
1998
        $yValueCount = count($yValues);
1999
        $xValueCount = count($xValues);
2000
2001
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2002
            return Functions::NA();
2003
        } elseif ($yValueCount == 1) {
2004
            return 0;
2005
        }
2006
2007
        $bestFitLinear = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues, $const);
2008 View Code Duplication
        if ($stats) {
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...
2009
            return [
2010
                [
2011
                    $bestFitLinear->getSlope(),
2012
                    $bestFitLinear->getSlopeSE(),
2013
                    $bestFitLinear->getGoodnessOfFit(),
2014
                    $bestFitLinear->getF(),
2015
                    $bestFitLinear->getSSRegression(),
2016
                ],
2017
                [
2018
                    $bestFitLinear->getIntersect(),
2019
                    $bestFitLinear->getIntersectSE(),
2020
                    $bestFitLinear->getStdevOfResiduals(),
2021
                    $bestFitLinear->getDFResiduals(),
2022
                    $bestFitLinear->getSSResiduals(),
2023
                ],
2024
            ];
2025
        } else {
2026
            return [
2027
                $bestFitLinear->getSlope(),
2028
                $bestFitLinear->getIntersect(),
2029
            ];
2030
        }
2031
    }
2032
2033
    /**
2034
     * LOGEST
2035
     *
2036
     * Calculates an exponential curve that best fits the X and Y data series,
2037
     *        and then returns an array that describes the line.
2038
     *
2039
     * @param    array of mixed        Data Series Y
2040
     * @param    array of mixed        Data Series X
2041
     * @param    bool                A logical value specifying whether to force the intersect to equal 0.
2042
     * @param    bool                A logical value specifying whether to return additional regression statistics.
2043
     * @return    array
2044
     */
2045
    public static function LOGEST($yValues, $xValues = null, $const = true, $stats = false)
2046
    {
2047
        $const = (is_null($const)) ? true : (boolean) Functions::flattenSingleValue($const);
2048
        $stats = (is_null($stats)) ? false : (boolean) Functions::flattenSingleValue($stats);
2049
        if (is_null($xValues)) {
2050
            $xValues = range(1, count(Functions::flattenArray($yValues)));
2051
        }
2052
2053
        if (!self::checkTrendArrays($yValues, $xValues)) {
2054
            return Functions::VALUE();
2055
        }
2056
        $yValueCount = count($yValues);
2057
        $xValueCount = count($xValues);
2058
2059
        foreach ($yValues as $value) {
2060
            if ($value <= 0.0) {
2061
                return Functions::NAN();
2062
            }
2063
        }
2064
2065
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2066
            return Functions::NA();
2067
        } elseif ($yValueCount == 1) {
2068
            return 1;
2069
        }
2070
2071
        $bestFitExponential = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_EXPONENTIAL, $yValues, $xValues, $const);
2072 View Code Duplication
        if ($stats) {
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...
2073
            return [
2074
                [
2075
                    $bestFitExponential->getSlope(),
2076
                    $bestFitExponential->getSlopeSE(),
2077
                    $bestFitExponential->getGoodnessOfFit(),
2078
                    $bestFitExponential->getF(),
2079
                    $bestFitExponential->getSSRegression(),
2080
                ],
2081
                [
2082
                    $bestFitExponential->getIntersect(),
2083
                    $bestFitExponential->getIntersectSE(),
2084
                    $bestFitExponential->getStdevOfResiduals(),
2085
                    $bestFitExponential->getDFResiduals(),
2086
                    $bestFitExponential->getSSResiduals(),
2087
                ],
2088
            ];
2089
        } else {
2090
            return [
2091
                $bestFitExponential->getSlope(),
2092
                $bestFitExponential->getIntersect(),
2093
            ];
2094
        }
2095
    }
2096
2097
    /**
2098
     * LOGINV
2099
     *
2100
     * Returns the inverse of the normal cumulative distribution
2101
     *
2102
     * @param    float        $probability
2103
     * @param    float        $mean
2104
     * @param    float        $stdDev
2105
     * @return    float
2106
     *
2107
     * @todo    Try implementing P J Acklam's refinement algorithm for greater
2108
     *            accuracy if I can get my head round the mathematics
2109
     *            (as described at) http://home.online.no/~pjacklam/notes/invnorm/
2110
     */
2111 View Code Duplication
    public static function LOGINV($probability, $mean, $stdDev)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2112
    {
2113
        $probability = Functions::flattenSingleValue($probability);
2114
        $mean = Functions::flattenSingleValue($mean);
2115
        $stdDev = Functions::flattenSingleValue($stdDev);
2116
2117
        if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
2118
            if (($probability < 0) || ($probability > 1) || ($stdDev <= 0)) {
2119
                return Functions::NAN();
2120
            }
2121
2122
            return exp($mean + $stdDev * self::NORMSINV($probability));
2123
        }
2124
2125
        return Functions::VALUE();
2126
    }
2127
2128
    /**
2129
     * LOGNORMDIST
2130
     *
2131
     * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed
2132
     * with parameters mean and standard_dev.
2133
     *
2134
     * @param    float        $value
2135
     * @param    float        $mean
2136
     * @param    float        $stdDev
2137
     * @return    float
2138
     */
2139
    public static function LOGNORMDIST($value, $mean, $stdDev)
2140
    {
2141
        $value = Functions::flattenSingleValue($value);
2142
        $mean = Functions::flattenSingleValue($mean);
2143
        $stdDev = Functions::flattenSingleValue($stdDev);
2144
2145
        if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
2146
            if (($value <= 0) || ($stdDev <= 0)) {
2147
                return Functions::NAN();
2148
            }
2149
2150
            return self::NORMSDIST((log($value) - $mean) / $stdDev);
2151
        }
2152
2153
        return Functions::VALUE();
2154
    }
2155
2156
    /**
2157
     * MAX
2158
     *
2159
     * MAX returns the value of the element of the values passed that has the highest value,
2160
     *        with negative numbers considered smaller than positive numbers.
2161
     *
2162
     * Excel Function:
2163
     *        MAX(value1[,value2[, ...]])
2164
     *
2165
     * @category Statistical Functions
2166
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2167
     * @return    float
2168
     */
2169 View Code Duplication
    public static function MAX()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2170
    {
2171
        $returnValue = null;
2172
2173
        // Loop through arguments
2174
        $aArgs = Functions::flattenArray(func_get_args());
2175
        foreach ($aArgs as $arg) {
2176
            // Is it a numeric value?
2177
            if ((is_numeric($arg)) && (!is_string($arg))) {
2178
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
2179
                    $returnValue = $arg;
2180
                }
2181
            }
2182
        }
2183
2184
        if (is_null($returnValue)) {
2185
            return 0;
2186
        }
2187
2188
        return $returnValue;
2189
    }
2190
2191
    /**
2192
     * MAXA
2193
     *
2194
     * Returns the greatest value in a list of arguments, including numbers, text, and logical values
2195
     *
2196
     * Excel Function:
2197
     *        MAXA(value1[,value2[, ...]])
2198
     *
2199
     * @category Statistical Functions
2200
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2201
     * @return    float
2202
     */
2203 View Code Duplication
    public static function MAXA()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2204
    {
2205
        $returnValue = null;
2206
2207
        // Loop through arguments
2208
        $aArgs = Functions::flattenArray(func_get_args());
2209
        foreach ($aArgs as $arg) {
2210
            // Is it a numeric value?
2211
            if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
2212
                if (is_bool($arg)) {
2213
                    $arg = (integer) $arg;
2214
                } elseif (is_string($arg)) {
2215
                    $arg = 0;
2216
                }
2217
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
2218
                    $returnValue = $arg;
2219
                }
2220
            }
2221
        }
2222
2223
        if (is_null($returnValue)) {
2224
            return 0;
2225
        }
2226
2227
        return $returnValue;
2228
    }
2229
2230
    /**
2231
     * MAXIF
2232
     *
2233
     * Counts the maximum value within a range of cells that contain numbers within the list of arguments
2234
     *
2235
     * Excel Function:
2236
     *        MAXIF(value1[,value2[, ...]],condition)
2237
     *
2238
     * @category Mathematical and Trigonometric Functions
2239
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2240
     * @param    string        $condition        The criteria that defines which cells will be checked.
2241
     * @return    float
2242
     */
2243 View Code Duplication
    public static function MAXIF($aArgs, $condition, $sumArgs = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2244
    {
2245
        $returnValue = null;
2246
2247
        $aArgs = Functions::flattenArray($aArgs);
2248
        $sumArgs = Functions::flattenArray($sumArgs);
2249
        if (empty($sumArgs)) {
2250
            $sumArgs = $aArgs;
0 ignored issues
show
Unused Code introduced by
$sumArgs is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2251
        }
2252
        $condition = Functions::ifCondition($condition);
2253
        // Loop through arguments
2254
        foreach ($aArgs as $key => $arg) {
2255
            if (!is_numeric($arg)) {
2256
                $arg = \PhpSpreadsheet\Calculation::wrapResult(strtoupper($arg));
2257
            }
2258
            $testCondition = '=' . $arg . $condition;
2259
            if (\PhpSpreadsheet\Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
2260
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
2261
                    $returnValue = $arg;
2262
                }
2263
            }
2264
        }
2265
2266
        return $returnValue;
2267
    }
2268
2269
    /**
2270
     * MEDIAN
2271
     *
2272
     * Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
2273
     *
2274
     * Excel Function:
2275
     *        MEDIAN(value1[,value2[, ...]])
2276
     *
2277
     * @category Statistical Functions
2278
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2279
     * @return    float
2280
     */
2281
    public static function MEDIAN()
2282
    {
2283
        $returnValue = Functions::NAN();
2284
2285
        $mArgs = [];
2286
        // Loop through arguments
2287
        $aArgs = Functions::flattenArray(func_get_args());
2288
        foreach ($aArgs as $arg) {
2289
            // Is it a numeric value?
2290
            if ((is_numeric($arg)) && (!is_string($arg))) {
2291
                $mArgs[] = $arg;
2292
            }
2293
        }
2294
2295
        $mValueCount = count($mArgs);
2296
        if ($mValueCount > 0) {
2297
            sort($mArgs, SORT_NUMERIC);
2298
            $mValueCount = $mValueCount / 2;
2299
            if ($mValueCount == floor($mValueCount)) {
2300
                $returnValue = ($mArgs[$mValueCount--] + $mArgs[$mValueCount]) / 2;
2301
            } else {
2302
                $mValueCount = floor($mValueCount);
2303
                $returnValue = $mArgs[$mValueCount];
2304
            }
2305
        }
2306
2307
        return $returnValue;
2308
    }
2309
2310
    /**
2311
     * MIN
2312
     *
2313
     * MIN returns the value of the element of the values passed that has the smallest value,
2314
     *        with negative numbers considered smaller than positive numbers.
2315
     *
2316
     * Excel Function:
2317
     *        MIN(value1[,value2[, ...]])
2318
     *
2319
     * @category Statistical Functions
2320
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2321
     * @return    float
2322
     */
2323 View Code Duplication
    public static function MIN()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2324
    {
2325
        $returnValue = null;
2326
2327
        // Loop through arguments
2328
        $aArgs = Functions::flattenArray(func_get_args());
2329
        foreach ($aArgs as $arg) {
2330
            // Is it a numeric value?
2331
            if ((is_numeric($arg)) && (!is_string($arg))) {
2332
                if ((is_null($returnValue)) || ($arg < $returnValue)) {
2333
                    $returnValue = $arg;
2334
                }
2335
            }
2336
        }
2337
2338
        if (is_null($returnValue)) {
2339
            return 0;
2340
        }
2341
2342
        return $returnValue;
2343
    }
2344
2345
    /**
2346
     * MINA
2347
     *
2348
     * Returns the smallest value in a list of arguments, including numbers, text, and logical values
2349
     *
2350
     * Excel Function:
2351
     *        MINA(value1[,value2[, ...]])
2352
     *
2353
     * @category Statistical Functions
2354
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2355
     * @return    float
2356
     */
2357 View Code Duplication
    public static function MINA()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2358
    {
2359
        $returnValue = null;
2360
2361
        // Loop through arguments
2362
        $aArgs = Functions::flattenArray(func_get_args());
2363
        foreach ($aArgs as $arg) {
2364
            // Is it a numeric value?
2365
            if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
2366
                if (is_bool($arg)) {
2367
                    $arg = (integer) $arg;
2368
                } elseif (is_string($arg)) {
2369
                    $arg = 0;
2370
                }
2371
                if ((is_null($returnValue)) || ($arg < $returnValue)) {
2372
                    $returnValue = $arg;
2373
                }
2374
            }
2375
        }
2376
2377
        if (is_null($returnValue)) {
2378
            return 0;
2379
        }
2380
2381
        return $returnValue;
2382
    }
2383
2384
    /**
2385
     * MINIF
2386
     *
2387
     * Returns the minimum value within a range of cells that contain numbers within the list of arguments
2388
     *
2389
     * Excel Function:
2390
     *        MINIF(value1[,value2[, ...]],condition)
2391
     *
2392
     * @category Mathematical and Trigonometric Functions
2393
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2394
     * @param    string        $condition        The criteria that defines which cells will be checked.
2395
     * @return    float
2396
     */
2397 View Code Duplication
    public static function MINIF($aArgs, $condition, $sumArgs = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2398
    {
2399
        $returnValue = null;
2400
2401
        $aArgs = Functions::flattenArray($aArgs);
2402
        $sumArgs = Functions::flattenArray($sumArgs);
2403
        if (empty($sumArgs)) {
2404
            $sumArgs = $aArgs;
0 ignored issues
show
Unused Code introduced by
$sumArgs is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2405
        }
2406
        $condition = Functions::ifCondition($condition);
2407
        // Loop through arguments
2408
        foreach ($aArgs as $key => $arg) {
2409
            if (!is_numeric($arg)) {
2410
                $arg = \PhpSpreadsheet\Calculation::wrapResult(strtoupper($arg));
2411
            }
2412
            $testCondition = '=' . $arg . $condition;
2413
            if (\PhpSpreadsheet\Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
2414
                if ((is_null($returnValue)) || ($arg < $returnValue)) {
2415
                    $returnValue = $arg;
2416
                }
2417
            }
2418
        }
2419
2420
        return $returnValue;
2421
    }
2422
2423
    //
2424
    //    Special variant of array_count_values that isn't limited to strings and integers,
2425
    //        but can work with floating point numbers as values
2426
    //
2427
    private static function modeCalc($data)
2428
    {
2429
        $frequencyArray = [];
2430
        foreach ($data as $datum) {
2431
            $found = false;
2432
            foreach ($frequencyArray as $key => $value) {
2433
                if ((string) $value['value'] == (string) $datum) {
2434
                    ++$frequencyArray[$key]['frequency'];
2435
                    $found = true;
2436
                    break;
2437
                }
2438
            }
2439
            if (!$found) {
2440
                $frequencyArray[] = [
2441
                    'value' => $datum,
2442
                    'frequency' => 1,
2443
                ];
2444
            }
2445
        }
2446
2447
        foreach ($frequencyArray as $key => $value) {
2448
            $frequencyList[$key] = $value['frequency'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$frequencyList was never initialized. Although not strictly required by PHP, it is generally a good practice to add $frequencyList = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2449
            $valueList[$key] = $value['value'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$valueList was never initialized. Although not strictly required by PHP, it is generally a good practice to add $valueList = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2450
        }
2451
        array_multisort($frequencyList, SORT_DESC, $valueList, SORT_ASC, SORT_NUMERIC, $frequencyArray);
0 ignored issues
show
Bug introduced by
The variable $valueList does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2452
2453
        if ($frequencyArray[0]['frequency'] == 1) {
2454
            return Functions::NA();
2455
        }
2456
2457
        return $frequencyArray[0]['value'];
2458
    }
2459
2460
    /**
2461
     * MODE
2462
     *
2463
     * Returns the most frequently occurring, or repetitive, value in an array or range of data
2464
     *
2465
     * Excel Function:
2466
     *        MODE(value1[,value2[, ...]])
2467
     *
2468
     * @category Statistical Functions
2469
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2470
     * @return    float
2471
     */
2472
    public static function MODE()
2473
    {
2474
        $returnValue = Functions::NA();
2475
2476
        // Loop through arguments
2477
        $aArgs = Functions::flattenArray(func_get_args());
2478
2479
        $mArgs = [];
2480
        foreach ($aArgs as $arg) {
2481
            // Is it a numeric value?
2482
            if ((is_numeric($arg)) && (!is_string($arg))) {
2483
                $mArgs[] = $arg;
2484
            }
2485
        }
2486
2487
        if (!empty($mArgs)) {
2488
            return self::modeCalc($mArgs);
2489
        }
2490
2491
        return $returnValue;
2492
    }
2493
2494
    /**
2495
     * NEGBINOMDIST
2496
     *
2497
     * Returns the negative binomial distribution. NEGBINOMDIST returns the probability that
2498
     *        there will be number_f failures before the number_s-th success, when the constant
2499
     *        probability of a success is probability_s. This function is similar to the binomial
2500
     *        distribution, except that the number of successes is fixed, and the number of trials is
2501
     *        variable. Like the binomial, trials are assumed to be independent.
2502
     *
2503
     * @param    float        $failures        Number of Failures
2504
     * @param    float        $successes        Threshold number of Successes
2505
     * @param    float        $probability    Probability of success on each trial
2506
     * @return    float
2507
     */
2508
    public static function NEGBINOMDIST($failures, $successes, $probability)
2509
    {
2510
        $failures = floor(Functions::flattenSingleValue($failures));
2511
        $successes = floor(Functions::flattenSingleValue($successes));
2512
        $probability = Functions::flattenSingleValue($probability);
2513
2514
        if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) {
2515
            if (($failures < 0) || ($successes < 1)) {
2516
                return Functions::NAN();
2517
            } elseif (($probability < 0) || ($probability > 1)) {
2518
                return Functions::NAN();
2519
            }
2520
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
2521
                if (($failures + $successes - 1) <= 0) {
2522
                    return Functions::NAN();
2523
                }
2524
            }
2525
2526
            return (MathTrig::COMBIN($failures + $successes - 1, $successes - 1)) * (pow($probability, $successes)) * (pow(1 - $probability, $failures));
2527
        }
2528
2529
        return Functions::VALUE();
2530
    }
2531
2532
    /**
2533
     * NORMDIST
2534
     *
2535
     * Returns the normal distribution for the specified mean and standard deviation. This
2536
     * function has a very wide range of applications in statistics, including hypothesis
2537
     * testing.
2538
     *
2539
     * @param    float        $value
2540
     * @param    float        $mean        Mean Value
2541
     * @param    float        $stdDev        Standard Deviation
2542
     * @param    bool        $cumulative
2543
     * @return    float
2544
     */
2545
    public static function NORMDIST($value, $mean, $stdDev, $cumulative)
2546
    {
2547
        $value = Functions::flattenSingleValue($value);
2548
        $mean = Functions::flattenSingleValue($mean);
2549
        $stdDev = Functions::flattenSingleValue($stdDev);
2550
2551
        if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
2552
            if ($stdDev < 0) {
2553
                return Functions::NAN();
2554
            }
2555
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
2556
                if ($cumulative) {
2557
                    return 0.5 * (1 + Engineering::erfVal(($value - $mean) / ($stdDev * sqrt(2))));
2558
                } else {
2559
                    return (1 / (SQRT2PI * $stdDev)) * exp(0 - (pow($value - $mean, 2) / (2 * ($stdDev * $stdDev))));
2560
                }
2561
            }
2562
        }
2563
2564
        return Functions::VALUE();
2565
    }
2566
2567
    /**
2568
     * NORMINV
2569
     *
2570
     * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation.
2571
     *
2572
     * @param    float        $value
0 ignored issues
show
Bug introduced by
There is no parameter named $value. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2573
     * @param    float        $mean        Mean Value
2574
     * @param    float        $stdDev        Standard Deviation
2575
     * @return    float
2576
     */
2577 View Code Duplication
    public static function NORMINV($probability, $mean, $stdDev)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2578
    {
2579
        $probability = Functions::flattenSingleValue($probability);
2580
        $mean = Functions::flattenSingleValue($mean);
2581
        $stdDev = Functions::flattenSingleValue($stdDev);
2582
2583
        if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
2584
            if (($probability < 0) || ($probability > 1)) {
2585
                return Functions::NAN();
2586
            }
2587
            if ($stdDev < 0) {
2588
                return Functions::NAN();
2589
            }
2590
2591
            return (self::inverseNcdf($probability) * $stdDev) + $mean;
2592
        }
2593
2594
        return Functions::VALUE();
2595
    }
2596
2597
    /**
2598
     * NORMSDIST
2599
     *
2600
     * Returns the standard normal cumulative distribution function. The distribution has
2601
     * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a
2602
     * table of standard normal curve areas.
2603
     *
2604
     * @param    float        $value
2605
     * @return    float
2606
     */
2607
    public static function NORMSDIST($value)
2608
    {
2609
        $value = Functions::flattenSingleValue($value);
2610
2611
        return self::NORMDIST($value, 0, 1, true);
2612
    }
2613
2614
    /**
2615
     * NORMSINV
2616
     *
2617
     * Returns the inverse of the standard normal cumulative distribution
2618
     *
2619
     * @param    float        $value
2620
     * @return    float
2621
     */
2622
    public static function NORMSINV($value)
2623
    {
2624
        return self::NORMINV($value, 0, 1);
2625
    }
2626
2627
    /**
2628
     * PERCENTILE
2629
     *
2630
     * Returns the nth percentile of values in a range..
2631
     *
2632
     * Excel Function:
2633
     *        PERCENTILE(value1[,value2[, ...]],entry)
2634
     *
2635
     * @category Statistical Functions
2636
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2637
     * @param    float        $entry            Percentile value in the range 0..1, inclusive.
0 ignored issues
show
Bug introduced by
There is no parameter named $entry. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2638
     * @return    float
2639
     */
2640
    public static function PERCENTILE()
2641
    {
2642
        $aArgs = Functions::flattenArray(func_get_args());
2643
2644
        // Calculate
2645
        $entry = array_pop($aArgs);
2646
2647
        if ((is_numeric($entry)) && (!is_string($entry))) {
2648
            if (($entry < 0) || ($entry > 1)) {
2649
                return Functions::NAN();
2650
            }
2651
            $mArgs = [];
2652
            foreach ($aArgs as $arg) {
2653
                // Is it a numeric value?
2654
                if ((is_numeric($arg)) && (!is_string($arg))) {
2655
                    $mArgs[] = $arg;
2656
                }
2657
            }
2658
            $mValueCount = count($mArgs);
2659
            if ($mValueCount > 0) {
2660
                sort($mArgs);
2661
                $count = self::COUNT($mArgs);
2662
                $index = $entry * ($count - 1);
2663
                $iBase = floor($index);
2664
                if ($index == $iBase) {
2665
                    return $mArgs[$index];
2666
                } else {
2667
                    $iNext = $iBase + 1;
2668
                    $iProportion = $index - $iBase;
2669
2670
                    return $mArgs[$iBase] + (($mArgs[$iNext] - $mArgs[$iBase]) * $iProportion);
2671
                }
2672
            }
2673
        }
2674
2675
        return Functions::VALUE();
2676
    }
2677
2678
    /**
2679
     * PERCENTRANK
2680
     *
2681
     * Returns the rank of a value in a data set as a percentage of the data set.
2682
     *
2683
     * @param    array of number        An array of, or a reference to, a list of numbers.
2684
     * @param    number                The number whose rank you want to find.
2685
     * @param    number                The number of significant digits for the returned percentage value.
2686
     * @return    float
2687
     */
2688
    public static function PERCENTRANK($valueSet, $value, $significance = 3)
2689
    {
2690
        $valueSet = Functions::flattenArray($valueSet);
2691
        $value = Functions::flattenSingleValue($value);
2692
        $significance = (is_null($significance)) ? 3 : (integer) Functions::flattenSingleValue($significance);
2693
2694
        foreach ($valueSet as $key => $valueEntry) {
2695
            if (!is_numeric($valueEntry)) {
2696
                unset($valueSet[$key]);
2697
            }
2698
        }
2699
        sort($valueSet, SORT_NUMERIC);
2700
        $valueCount = count($valueSet);
2701
        if ($valueCount == 0) {
2702
            return Functions::NAN();
2703
        }
2704
2705
        $valueAdjustor = $valueCount - 1;
2706
        if (($value < $valueSet[0]) || ($value > $valueSet[$valueAdjustor])) {
2707
            return Functions::NA();
2708
        }
2709
2710
        $pos = array_search($value, $valueSet);
2711
        if ($pos === false) {
2712
            $pos = 0;
2713
            $testValue = $valueSet[0];
2714
            while ($testValue < $value) {
2715
                $testValue = $valueSet[++$pos];
2716
            }
2717
            --$pos;
2718
            $pos += (($value - $valueSet[$pos]) / ($testValue - $valueSet[$pos]));
2719
        }
2720
2721
        return round($pos / $valueAdjustor, $significance);
2722
    }
2723
2724
    /**
2725
     * PERMUT
2726
     *
2727
     * Returns the number of permutations for a given number of objects that can be
2728
     *        selected from number objects. A permutation is any set or subset of objects or
2729
     *        events where internal order is significant. Permutations are different from
2730
     *        combinations, for which the internal order is not significant. Use this function
2731
     *        for lottery-style probability calculations.
2732
     *
2733
     * @param    int        $numObjs    Number of different objects
2734
     * @param    int        $numInSet    Number of objects in each permutation
2735
     * @return    int        Number of permutations
2736
     */
2737 View Code Duplication
    public static function PERMUT($numObjs, $numInSet)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2738
    {
2739
        $numObjs = Functions::flattenSingleValue($numObjs);
2740
        $numInSet = Functions::flattenSingleValue($numInSet);
2741
2742
        if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
2743
            $numInSet = floor($numInSet);
2744
            if ($numObjs < $numInSet) {
2745
                return Functions::NAN();
2746
            }
2747
2748
            return round(MathTrig::FACT($numObjs) / MathTrig::FACT($numObjs - $numInSet));
2749
        }
2750
2751
        return Functions::VALUE();
2752
    }
2753
2754
    /**
2755
     * POISSON
2756
     *
2757
     * Returns the Poisson distribution. A common application of the Poisson distribution
2758
     * is predicting the number of events over a specific time, such as the number of
2759
     * cars arriving at a toll plaza in 1 minute.
2760
     *
2761
     * @param    float        $value
2762
     * @param    float        $mean        Mean Value
2763
     * @param    bool        $cumulative
2764
     * @return    float
2765
     */
2766
    public static function POISSON($value, $mean, $cumulative)
2767
    {
2768
        $value = Functions::flattenSingleValue($value);
2769
        $mean = Functions::flattenSingleValue($mean);
2770
2771
        if ((is_numeric($value)) && (is_numeric($mean))) {
2772
            if (($value < 0) || ($mean <= 0)) {
2773
                return Functions::NAN();
2774
            }
2775
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
2776
                if ($cumulative) {
2777
                    $summer = 0;
2778
                    for ($i = 0; $i <= floor($value); ++$i) {
2779
                        $summer += pow($mean, $i) / MathTrig::FACT($i);
2780
                    }
2781
2782
                    return exp(0 - $mean) * $summer;
2783
                } else {
2784
                    return (exp(0 - $mean) * pow($mean, $value)) / MathTrig::FACT($value);
2785
                }
2786
            }
2787
        }
2788
2789
        return Functions::VALUE();
2790
    }
2791
2792
    /**
2793
     * QUARTILE
2794
     *
2795
     * Returns the quartile of a data set.
2796
     *
2797
     * Excel Function:
2798
     *        QUARTILE(value1[,value2[, ...]],entry)
2799
     *
2800
     * @category Statistical Functions
2801
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2802
     * @param    int            $entry            Quartile value in the range 1..3, inclusive.
0 ignored issues
show
Bug introduced by
There is no parameter named $entry. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2803
     * @return    float
2804
     */
2805
    public static function QUARTILE()
2806
    {
2807
        $aArgs = Functions::flattenArray(func_get_args());
2808
2809
        // Calculate
2810
        $entry = floor(array_pop($aArgs));
2811
2812
        if ((is_numeric($entry)) && (!is_string($entry))) {
2813
            $entry /= 4;
2814
            if (($entry < 0) || ($entry > 1)) {
2815
                return Functions::NAN();
2816
            }
2817
2818
            return self::PERCENTILE($aArgs, $entry);
2819
        }
2820
2821
        return Functions::VALUE();
2822
    }
2823
2824
    /**
2825
     * RANK
2826
     *
2827
     * Returns the rank of a number in a list of numbers.
2828
     *
2829
     * @param    number                The number whose rank you want to find.
2830
     * @param    array of number        An array of, or a reference to, a list of numbers.
2831
     * @param    mixed                Order to sort the values in the value set
2832
     * @return    float
2833
     */
2834
    public static function RANK($value, $valueSet, $order = 0)
2835
    {
2836
        $value = Functions::flattenSingleValue($value);
2837
        $valueSet = Functions::flattenArray($valueSet);
2838
        $order = (is_null($order)) ? 0 : (integer) Functions::flattenSingleValue($order);
2839
2840
        foreach ($valueSet as $key => $valueEntry) {
2841
            if (!is_numeric($valueEntry)) {
2842
                unset($valueSet[$key]);
2843
            }
2844
        }
2845
2846
        if ($order == 0) {
2847
            rsort($valueSet, SORT_NUMERIC);
2848
        } else {
2849
            sort($valueSet, SORT_NUMERIC);
2850
        }
2851
        $pos = array_search($value, $valueSet);
2852
        if ($pos === false) {
2853
            return Functions::NA();
2854
        }
2855
2856
        return ++$pos;
2857
    }
2858
2859
    /**
2860
     * RSQ
2861
     *
2862
     * Returns the square of the Pearson product moment correlation coefficient through data points in known_y's and known_x's.
2863
     *
2864
     * @param    array of mixed        Data Series Y
2865
     * @param    array of mixed        Data Series X
2866
     * @return    float
2867
     */
2868 View Code Duplication
    public static function RSQ($yValues, $xValues)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2869
    {
2870
        if (!self::checkTrendArrays($yValues, $xValues)) {
2871
            return Functions::VALUE();
2872
        }
2873
        $yValueCount = count($yValues);
2874
        $xValueCount = count($xValues);
2875
2876
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2877
            return Functions::NA();
2878
        } elseif ($yValueCount == 1) {
2879
            return Functions::DIV0();
2880
        }
2881
2882
        $bestFitLinear = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
2883
2884
        return $bestFitLinear->getGoodnessOfFit();
2885
    }
2886
2887
    /**
2888
     * SKEW
2889
     *
2890
     * Returns the skewness of a distribution. Skewness characterizes the degree of asymmetry
2891
     * of a distribution around its mean. Positive skewness indicates a distribution with an
2892
     * asymmetric tail extending toward more positive values. Negative skewness indicates a
2893
     * distribution with an asymmetric tail extending toward more negative values.
2894
     *
2895
     * @param    array    Data Series
2896
     * @return    float
2897
     */
2898
    public static function SKEW()
2899
    {
2900
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
2901
        $mean = self::AVERAGE($aArgs);
2902
        $stdDev = self::STDEV($aArgs);
2903
2904
        $count = $summer = 0;
2905
        // Loop through arguments
2906 View Code Duplication
        foreach ($aArgs as $k => $arg) {
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...
2907
            if ((is_bool($arg)) &&
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
2908
                (!Functions::isMatrixValue($k))) {
2909
            } else {
2910
                // Is it a numeric value?
2911
                if ((is_numeric($arg)) && (!is_string($arg))) {
2912
                    $summer += pow((($arg - $mean) / $stdDev), 3);
2913
                    ++$count;
2914
                }
2915
            }
2916
        }
2917
2918
        if ($count > 2) {
2919
            return $summer * ($count / (($count - 1) * ($count - 2)));
2920
        }
2921
2922
        return Functions::DIV0();
2923
    }
2924
2925
    /**
2926
     * SLOPE
2927
     *
2928
     * Returns the slope of the linear regression line through data points in known_y's and known_x's.
2929
     *
2930
     * @param    array of mixed        Data Series Y
2931
     * @param    array of mixed        Data Series X
2932
     * @return    float
2933
     */
2934 View Code Duplication
    public static function SLOPE($yValues, $xValues)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2935
    {
2936
        if (!self::checkTrendArrays($yValues, $xValues)) {
2937
            return Functions::VALUE();
2938
        }
2939
        $yValueCount = count($yValues);
2940
        $xValueCount = count($xValues);
2941
2942
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2943
            return Functions::NA();
2944
        } elseif ($yValueCount == 1) {
2945
            return Functions::DIV0();
2946
        }
2947
2948
        $bestFitLinear = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
2949
2950
        return $bestFitLinear->getSlope();
2951
    }
2952
2953
    /**
2954
     * SMALL
2955
     *
2956
     * Returns the nth smallest value in a data set. You can use this function to
2957
     *        select a value based on its relative standing.
2958
     *
2959
     * Excel Function:
2960
     *        SMALL(value1[,value2[, ...]],entry)
2961
     *
2962
     * @category Statistical Functions
2963
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2964
     * @param    int            $entry            Position (ordered from the smallest) in the array or range of data to return
0 ignored issues
show
Bug introduced by
There is no parameter named $entry. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2965
     * @return    float
2966
     */
2967 View Code Duplication
    public static function SMALL()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2968
    {
2969
        $aArgs = Functions::flattenArray(func_get_args());
2970
2971
        // Calculate
2972
        $entry = array_pop($aArgs);
2973
2974
        if ((is_numeric($entry)) && (!is_string($entry))) {
2975
            $mArgs = [];
2976
            foreach ($aArgs as $arg) {
2977
                // Is it a numeric value?
2978
                if ((is_numeric($arg)) && (!is_string($arg))) {
2979
                    $mArgs[] = $arg;
2980
                }
2981
            }
2982
            $count = self::COUNT($mArgs);
2983
            $entry = floor(--$entry);
2984
            if (($entry < 0) || ($entry >= $count) || ($count == 0)) {
2985
                return Functions::NAN();
2986
            }
2987
            sort($mArgs);
2988
2989
            return $mArgs[$entry];
2990
        }
2991
2992
        return Functions::VALUE();
2993
    }
2994
2995
    /**
2996
     * STANDARDIZE
2997
     *
2998
     * Returns a normalized value from a distribution characterized by mean and standard_dev.
2999
     *
3000
     * @param    float    $value        Value to normalize
3001
     * @param    float    $mean        Mean Value
3002
     * @param    float    $stdDev        Standard Deviation
3003
     * @return    float    Standardized value
3004
     */
3005 View Code Duplication
    public static function STANDARDIZE($value, $mean, $stdDev)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3006
    {
3007
        $value = Functions::flattenSingleValue($value);
3008
        $mean = Functions::flattenSingleValue($mean);
3009
        $stdDev = Functions::flattenSingleValue($stdDev);
3010
3011
        if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
3012
            if ($stdDev <= 0) {
3013
                return Functions::NAN();
3014
            }
3015
3016
            return ($value - $mean) / $stdDev;
3017
        }
3018
3019
        return Functions::VALUE();
3020
    }
3021
3022
    /**
3023
     * STDEV
3024
     *
3025
     * Estimates standard deviation based on a sample. The standard deviation is a measure of how
3026
     *        widely values are dispersed from the average value (the mean).
3027
     *
3028
     * Excel Function:
3029
     *        STDEV(value1[,value2[, ...]])
3030
     *
3031
     * @category Statistical Functions
3032
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3033
     * @return    float
3034
     */
3035 View Code Duplication
    public static function STDEV()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3036
    {
3037
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3038
3039
        // Return value
3040
        $returnValue = null;
3041
3042
        $aMean = self::AVERAGE($aArgs);
3043
        if (!is_null($aMean)) {
3044
            $aCount = -1;
3045
            foreach ($aArgs as $k => $arg) {
3046
                if ((is_bool($arg)) &&
3047
                    ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) {
3048
                    $arg = (integer) $arg;
3049
                }
3050
                // Is it a numeric value?
3051
                if ((is_numeric($arg)) && (!is_string($arg))) {
3052
                    if (is_null($returnValue)) {
3053
                        $returnValue = pow(($arg - $aMean), 2);
3054
                    } else {
3055
                        $returnValue += pow(($arg - $aMean), 2);
3056
                    }
3057
                    ++$aCount;
3058
                }
3059
            }
3060
3061
            // Return
3062
            if (($aCount > 0) && ($returnValue >= 0)) {
3063
                return sqrt($returnValue / $aCount);
3064
            }
3065
        }
3066
3067
        return Functions::DIV0();
3068
    }
3069
3070
    /**
3071
     * STDEVA
3072
     *
3073
     * Estimates standard deviation based on a sample, including numbers, text, and logical values
3074
     *
3075
     * Excel Function:
3076
     *        STDEVA(value1[,value2[, ...]])
3077
     *
3078
     * @category Statistical Functions
3079
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3080
     * @return    float
3081
     */
3082 View Code Duplication
    public static function STDEVA()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3083
    {
3084
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3085
3086
        $returnValue = null;
3087
3088
        $aMean = self::AVERAGEA($aArgs);
3089
        if (!is_null($aMean)) {
3090
            $aCount = -1;
3091
            foreach ($aArgs as $k => $arg) {
3092
                if ((is_bool($arg)) &&
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3093
                    (!Functions::isMatrixValue($k))) {
3094
                } else {
3095
                    // Is it a numeric value?
3096
                    if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
3097
                        if (is_bool($arg)) {
3098
                            $arg = (integer) $arg;
3099
                        } elseif (is_string($arg)) {
3100
                            $arg = 0;
3101
                        }
3102
                        if (is_null($returnValue)) {
3103
                            $returnValue = pow(($arg - $aMean), 2);
3104
                        } else {
3105
                            $returnValue += pow(($arg - $aMean), 2);
3106
                        }
3107
                        ++$aCount;
3108
                    }
3109
                }
3110
            }
3111
3112
            if (($aCount > 0) && ($returnValue >= 0)) {
3113
                return sqrt($returnValue / $aCount);
3114
            }
3115
        }
3116
3117
        return Functions::DIV0();
3118
    }
3119
3120
    /**
3121
     * STDEVP
3122
     *
3123
     * Calculates standard deviation based on the entire population
3124
     *
3125
     * Excel Function:
3126
     *        STDEVP(value1[,value2[, ...]])
3127
     *
3128
     * @category Statistical Functions
3129
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3130
     * @return    float
3131
     */
3132 View Code Duplication
    public static function STDEVP()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3133
    {
3134
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3135
3136
        $returnValue = null;
3137
3138
        $aMean = self::AVERAGE($aArgs);
3139
        if (!is_null($aMean)) {
3140
            $aCount = 0;
3141
            foreach ($aArgs as $k => $arg) {
3142
                if ((is_bool($arg)) &&
3143
                    ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) {
3144
                    $arg = (integer) $arg;
3145
                }
3146
                // Is it a numeric value?
3147
                if ((is_numeric($arg)) && (!is_string($arg))) {
3148
                    if (is_null($returnValue)) {
3149
                        $returnValue = pow(($arg - $aMean), 2);
3150
                    } else {
3151
                        $returnValue += pow(($arg - $aMean), 2);
3152
                    }
3153
                    ++$aCount;
3154
                }
3155
            }
3156
3157
            if (($aCount > 0) && ($returnValue >= 0)) {
3158
                return sqrt($returnValue / $aCount);
3159
            }
3160
        }
3161
3162
        return Functions::DIV0();
3163
    }
3164
3165
    /**
3166
     * STDEVPA
3167
     *
3168
     * Calculates standard deviation based on the entire population, including numbers, text, and logical values
3169
     *
3170
     * Excel Function:
3171
     *        STDEVPA(value1[,value2[, ...]])
3172
     *
3173
     * @category Statistical Functions
3174
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3175
     * @return    float
3176
     */
3177 View Code Duplication
    public static function STDEVPA()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3178
    {
3179
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3180
3181
        $returnValue = null;
3182
3183
        $aMean = self::AVERAGEA($aArgs);
3184
        if (!is_null($aMean)) {
3185
            $aCount = 0;
3186
            foreach ($aArgs as $k => $arg) {
3187
                if ((is_bool($arg)) &&
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3188
                    (!Functions::isMatrixValue($k))) {
3189
                } else {
3190
                    // Is it a numeric value?
3191
                    if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
3192
                        if (is_bool($arg)) {
3193
                            $arg = (integer) $arg;
3194
                        } elseif (is_string($arg)) {
3195
                            $arg = 0;
3196
                        }
3197
                        if (is_null($returnValue)) {
3198
                            $returnValue = pow(($arg - $aMean), 2);
3199
                        } else {
3200
                            $returnValue += pow(($arg - $aMean), 2);
3201
                        }
3202
                        ++$aCount;
3203
                    }
3204
                }
3205
            }
3206
3207
            if (($aCount > 0) && ($returnValue >= 0)) {
3208
                return sqrt($returnValue / $aCount);
3209
            }
3210
        }
3211
3212
        return Functions::DIV0();
3213
    }
3214
3215
    /**
3216
     * STEYX
3217
     *
3218
     * Returns the standard error of the predicted y-value for each x in the regression.
3219
     *
3220
     * @param    array of mixed        Data Series Y
3221
     * @param    array of mixed        Data Series X
3222
     * @return    float
3223
     */
3224 View Code Duplication
    public static function STEYX($yValues, $xValues)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3225
    {
3226
        if (!self::checkTrendArrays($yValues, $xValues)) {
3227
            return Functions::VALUE();
3228
        }
3229
        $yValueCount = count($yValues);
3230
        $xValueCount = count($xValues);
3231
3232
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
3233
            return Functions::NA();
3234
        } elseif ($yValueCount == 1) {
3235
            return Functions::DIV0();
3236
        }
3237
3238
        $bestFitLinear = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
3239
3240
        return $bestFitLinear->getStdevOfResiduals();
3241
    }
3242
3243
    /**
3244
     * TDIST
3245
     *
3246
     * Returns the probability of Student's T distribution.
3247
     *
3248
     * @param    float        $value            Value for the function
3249
     * @param    float        $degrees        degrees of freedom
3250
     * @param    float        $tails            number of tails (1 or 2)
3251
     * @return    float
3252
     */
3253
    public static function TDIST($value, $degrees, $tails)
3254
    {
3255
        $value = Functions::flattenSingleValue($value);
3256
        $degrees = floor(Functions::flattenSingleValue($degrees));
3257
        $tails = floor(Functions::flattenSingleValue($tails));
3258
3259
        if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) {
3260
            if (($value < 0) || ($degrees < 1) || ($tails < 1) || ($tails > 2)) {
3261
                return Functions::NAN();
3262
            }
3263
            //    tdist, which finds the probability that corresponds to a given value
3264
            //    of t with k degrees of freedom. This algorithm is translated from a
3265
            //    pascal function on p81 of "Statistical Computing in Pascal" by D
3266
            //    Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd:
3267
            //    London). The above Pascal algorithm is itself a translation of the
3268
            //    fortran algoritm "AS 3" by B E Cooper of the Atlas Computer
3269
            //    Laboratory as reported in (among other places) "Applied Statistics
3270
            //    Algorithms", editied by P Griffiths and I D Hill (1985; Ellis
3271
            //    Horwood Ltd.; W. Sussex, England).
3272
            $tterm = $degrees;
3273
            $ttheta = atan2($value, sqrt($tterm));
3274
            $tc = cos($ttheta);
3275
            $ts = sin($ttheta);
3276
            $tsum = 0;
0 ignored issues
show
Unused Code introduced by
$tsum is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
3277
3278
            if (($degrees % 2) == 1) {
3279
                $ti = 3;
3280
                $tterm = $tc;
3281
            } else {
3282
                $ti = 2;
3283
                $tterm = 1;
3284
            }
3285
3286
            $tsum = $tterm;
3287
            while ($ti < $degrees) {
3288
                $tterm *= $tc * $tc * ($ti - 1) / $ti;
3289
                $tsum += $tterm;
3290
                $ti += 2;
3291
            }
3292
            $tsum *= $ts;
3293
            if (($degrees % 2) == 1) {
3294
                $tsum = M_2DIVPI * ($tsum + $ttheta);
3295
            }
3296
            $tValue = 0.5 * (1 + $tsum);
3297
            if ($tails == 1) {
3298
                return 1 - abs($tValue);
3299
            } else {
3300
                return 1 - abs((1 - $tValue) - $tValue);
3301
            }
3302
        }
3303
3304
        return Functions::VALUE();
3305
    }
3306
3307
    /**
3308
     * TINV
3309
     *
3310
     * Returns the one-tailed probability of the chi-squared distribution.
3311
     *
3312
     * @param    float        $probability    Probability for the function
3313
     * @param    float        $degrees        degrees of freedom
3314
     * @return    float
3315
     */
3316 View Code Duplication
    public static function TINV($probability, $degrees)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3317
    {
3318
        $probability = Functions::flattenSingleValue($probability);
3319
        $degrees = floor(Functions::flattenSingleValue($degrees));
3320
3321
        if ((is_numeric($probability)) && (is_numeric($degrees))) {
3322
            $xLo = 100;
3323
            $xHi = 0;
3324
3325
            $x = $xNew = 1;
3326
            $dx = 1;
3327
            $i = 0;
3328
3329
            while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
3330
                // Apply Newton-Raphson step
3331
                $result = self::TDIST($x, $degrees, 2);
3332
                $error = $result - $probability;
3333
                if ($error == 0.0) {
3334
                    $dx = 0;
3335
                } elseif ($error < 0.0) {
3336
                    $xLo = $x;
3337
                } else {
3338
                    $xHi = $x;
3339
                }
3340
                // Avoid division by zero
3341
                if ($result != 0.0) {
3342
                    $dx = $error / $result;
3343
                    $xNew = $x - $dx;
3344
                }
3345
                // If the NR fails to converge (which for example may be the
3346
                // case if the initial guess is too rough) we apply a bisection
3347
                // step to determine a more narrow interval around the root.
3348
                if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
3349
                    $xNew = ($xLo + $xHi) / 2;
3350
                    $dx = $xNew - $x;
3351
                }
3352
                $x = $xNew;
3353
            }
3354
            if ($i == MAX_ITERATIONS) {
3355
                return Functions::NA();
3356
            }
3357
3358
            return round($x, 12);
3359
        }
3360
3361
        return Functions::VALUE();
3362
    }
3363
3364
    /**
3365
     * TREND
3366
     *
3367
     * Returns values along a linear Trend
3368
     *
3369
     * @param    array of mixed        Data Series Y
3370
     * @param    array of mixed        Data Series X
3371
     * @param    array of mixed        Values of X for which we want to find Y
3372
     * @param    bool                A logical value specifying whether to force the intersect to equal 0.
3373
     * @return    array of float
3374
     */
3375 View Code Duplication
    public static function TREND($yValues, $xValues = [], $newValues = [], $const = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3376
    {
3377
        $yValues = Functions::flattenArray($yValues);
3378
        $xValues = Functions::flattenArray($xValues);
3379
        $newValues = Functions::flattenArray($newValues);
3380
        $const = (is_null($const)) ? true : (boolean) Functions::flattenSingleValue($const);
3381
3382
        $bestFitLinear = \PhpSpreadsheet\Shared\trend\trend::calculate(\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues, $const);
3383
        if (empty($newValues)) {
3384
            $newValues = $bestFitLinear->getXValues();
3385
        }
3386
3387
        $returnArray = [];
3388
        foreach ($newValues as $xValue) {
3389
            $returnArray[0][] = $bestFitLinear->getValueOfYForX($xValue);
3390
        }
3391
3392
        return $returnArray;
3393
    }
3394
3395
    /**
3396
     * TRIMMEAN
3397
     *
3398
     * Returns the mean of the interior of a data set. TRIMMEAN calculates the mean
3399
     *        taken by excluding a percentage of data points from the top and bottom tails
3400
     *        of a data set.
3401
     *
3402
     * Excel Function:
3403
     *        TRIMEAN(value1[,value2[, ...]], $discard)
3404
     *
3405
     * @category Statistical Functions
3406
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3407
     * @param    float        $discard        Percentage to discard
0 ignored issues
show
Bug introduced by
There is no parameter named $discard. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3408
     * @return    float
3409
     */
3410
    public static function TRIMMEAN()
3411
    {
3412
        $aArgs = Functions::flattenArray(func_get_args());
3413
3414
        // Calculate
3415
        $percent = array_pop($aArgs);
3416
3417
        if ((is_numeric($percent)) && (!is_string($percent))) {
3418
            if (($percent < 0) || ($percent > 1)) {
3419
                return Functions::NAN();
3420
            }
3421
            $mArgs = [];
3422
            foreach ($aArgs as $arg) {
3423
                // Is it a numeric value?
3424
                if ((is_numeric($arg)) && (!is_string($arg))) {
3425
                    $mArgs[] = $arg;
3426
                }
3427
            }
3428
            $discard = floor(self::COUNT($mArgs) * $percent / 2);
3429
            sort($mArgs);
3430
            for ($i = 0; $i < $discard; ++$i) {
3431
                array_pop($mArgs);
3432
                array_shift($mArgs);
3433
            }
3434
3435
            return self::AVERAGE($mArgs);
3436
        }
3437
3438
        return Functions::VALUE();
3439
    }
3440
3441
    /**
3442
     * VARFunc
3443
     *
3444
     * Estimates variance based on a sample.
3445
     *
3446
     * Excel Function:
3447
     *        VAR(value1[,value2[, ...]])
3448
     *
3449
     * @category Statistical Functions
3450
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3451
     * @return    float
3452
     */
3453 View Code Duplication
    public static function VARFunc()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3454
    {
3455
        $returnValue = Functions::DIV0();
3456
3457
        $summerA = $summerB = 0;
3458
3459
        // Loop through arguments
3460
        $aArgs = Functions::flattenArray(func_get_args());
3461
        $aCount = 0;
3462
        foreach ($aArgs as $arg) {
3463
            if (is_bool($arg)) {
3464
                $arg = (integer) $arg;
3465
            }
3466
            // Is it a numeric value?
3467
            if ((is_numeric($arg)) && (!is_string($arg))) {
3468
                $summerA += ($arg * $arg);
3469
                $summerB += $arg;
3470
                ++$aCount;
3471
            }
3472
        }
3473
3474
        if ($aCount > 1) {
3475
            $summerA *= $aCount;
3476
            $summerB *= $summerB;
3477
            $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
3478
        }
3479
3480
        return $returnValue;
3481
    }
3482
3483
    /**
3484
     * VARA
3485
     *
3486
     * Estimates variance based on a sample, including numbers, text, and logical values
3487
     *
3488
     * Excel Function:
3489
     *        VARA(value1[,value2[, ...]])
3490
     *
3491
     * @category Statistical Functions
3492
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3493
     * @return    float
3494
     */
3495 View Code Duplication
    public static function VARA()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3496
    {
3497
        $returnValue = Functions::DIV0();
3498
3499
        $summerA = $summerB = 0;
3500
3501
        // Loop through arguments
3502
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3503
        $aCount = 0;
3504
        foreach ($aArgs as $k => $arg) {
3505
            if ((is_string($arg)) &&
3506
                (Functions::isValue($k))) {
3507
                return Functions::VALUE();
3508
            } elseif ((is_string($arg)) &&
0 ignored issues
show
Unused Code introduced by
This elseif statement is empty, and could be removed.

This check looks for the bodies of elseif statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These elseif bodies can be removed. If you have an empty elseif but statements in the else branch, consider inverting the condition.

Loading history...
3509
                (!Functions::isMatrixValue($k))) {
3510
            } else {
3511
                // Is it a numeric value?
3512
                if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
3513
                    if (is_bool($arg)) {
3514
                        $arg = (integer) $arg;
3515
                    } elseif (is_string($arg)) {
3516
                        $arg = 0;
3517
                    }
3518
                    $summerA += ($arg * $arg);
3519
                    $summerB += $arg;
3520
                    ++$aCount;
3521
                }
3522
            }
3523
        }
3524
3525
        if ($aCount > 1) {
3526
            $summerA *= $aCount;
3527
            $summerB *= $summerB;
3528
            $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
3529
        }
3530
3531
        return $returnValue;
3532
    }
3533
3534
    /**
3535
     * VARP
3536
     *
3537
     * Calculates variance based on the entire population
3538
     *
3539
     * Excel Function:
3540
     *        VARP(value1[,value2[, ...]])
3541
     *
3542
     * @category Statistical Functions
3543
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3544
     * @return    float
3545
     */
3546 View Code Duplication
    public static function VARP()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3547
    {
3548
        // Return value
3549
        $returnValue = Functions::DIV0();
3550
3551
        $summerA = $summerB = 0;
3552
3553
        // Loop through arguments
3554
        $aArgs = Functions::flattenArray(func_get_args());
3555
        $aCount = 0;
3556
        foreach ($aArgs as $arg) {
3557
            if (is_bool($arg)) {
3558
                $arg = (integer) $arg;
3559
            }
3560
            // Is it a numeric value?
3561
            if ((is_numeric($arg)) && (!is_string($arg))) {
3562
                $summerA += ($arg * $arg);
3563
                $summerB += $arg;
3564
                ++$aCount;
3565
            }
3566
        }
3567
3568
        if ($aCount > 0) {
3569
            $summerA *= $aCount;
3570
            $summerB *= $summerB;
3571
            $returnValue = ($summerA - $summerB) / ($aCount * $aCount);
3572
        }
3573
3574
        return $returnValue;
3575
    }
3576
3577
    /**
3578
     * VARPA
3579
     *
3580
     * Calculates variance based on the entire population, including numbers, text, and logical values
3581
     *
3582
     * Excel Function:
3583
     *        VARPA(value1[,value2[, ...]])
3584
     *
3585
     * @category Statistical Functions
3586
     * @param    mixed        $arg,...        Data values
0 ignored issues
show
Bug introduced by
There is no parameter named $arg,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3587
     * @return    float
3588
     */
3589 View Code Duplication
    public static function VARPA()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
3590
    {
3591
        $returnValue = Functions::DIV0();
3592
3593
        $summerA = $summerB = 0;
3594
3595
        // Loop through arguments
3596
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3597
        $aCount = 0;
3598
        foreach ($aArgs as $k => $arg) {
3599
            if ((is_string($arg)) &&
3600
                (Functions::isValue($k))) {
3601
                return Functions::VALUE();
3602
            } elseif ((is_string($arg)) &&
0 ignored issues
show
Unused Code introduced by
This elseif statement is empty, and could be removed.

This check looks for the bodies of elseif statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These elseif bodies can be removed. If you have an empty elseif but statements in the else branch, consider inverting the condition.

Loading history...
3603
                (!Functions::isMatrixValue($k))) {
3604
            } else {
3605
                // Is it a numeric value?
3606
                if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
3607
                    if (is_bool($arg)) {
3608
                        $arg = (integer) $arg;
3609
                    } elseif (is_string($arg)) {
3610
                        $arg = 0;
3611
                    }
3612
                    $summerA += ($arg * $arg);
3613
                    $summerB += $arg;
3614
                    ++$aCount;
3615
                }
3616
            }
3617
        }
3618
3619
        if ($aCount > 0) {
3620
            $summerA *= $aCount;
3621
            $summerB *= $summerB;
3622
            $returnValue = ($summerA - $summerB) / ($aCount * $aCount);
3623
        }
3624
3625
        return $returnValue;
3626
    }
3627
3628
    /**
3629
     * WEIBULL
3630
     *
3631
     * Returns the Weibull distribution. Use this distribution in reliability
3632
     * analysis, such as calculating a device's mean time to failure.
3633
     *
3634
     * @param    float        $value
3635
     * @param    float        $alpha        Alpha Parameter
3636
     * @param    float        $beta        Beta Parameter
3637
     * @param    bool        $cumulative
3638
     * @return    float
3639
     */
3640
    public static function WEIBULL($value, $alpha, $beta, $cumulative)
3641
    {
3642
        $value = Functions::flattenSingleValue($value);
3643
        $alpha = Functions::flattenSingleValue($alpha);
3644
        $beta = Functions::flattenSingleValue($beta);
3645
3646
        if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) {
3647
            if (($value < 0) || ($alpha <= 0) || ($beta <= 0)) {
3648
                return Functions::NAN();
3649
            }
3650
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
3651
                if ($cumulative) {
3652
                    return 1 - exp(0 - pow($value / $beta, $alpha));
3653
                } else {
3654
                    return ($alpha / pow($beta, $alpha)) * pow($value, $alpha - 1) * exp(0 - pow($value / $beta, $alpha));
3655
                }
3656
            }
3657
        }
3658
3659
        return Functions::VALUE();
3660
    }
3661
3662
    /**
3663
     * ZTEST
3664
     *
3665
     * Returns the Weibull distribution. Use this distribution in reliability
3666
     * analysis, such as calculating a device's mean time to failure.
3667
     *
3668
     * @param    float        $dataSet
3669
     * @param    float        $m0        Alpha Parameter
3670
     * @param    float        $sigma    Beta Parameter
3671
     * @param    bool        $cumulative
0 ignored issues
show
Bug introduced by
There is no parameter named $cumulative. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3672
     * @return    float
3673
     */
3674
    public static function ZTEST($dataSet, $m0, $sigma = null)
3675
    {
3676
        $dataSet = Functions::flattenArrayIndexed($dataSet);
0 ignored issues
show
Documentation introduced by
$dataSet is of type double, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
3677
        $m0 = Functions::flattenSingleValue($m0);
3678
        $sigma = Functions::flattenSingleValue($sigma);
3679
3680
        if (is_null($sigma)) {
3681
            $sigma = self::STDEV($dataSet);
3682
        }
3683
        $n = count($dataSet);
3684
3685
        return 1 - self::NORMSDIST((self::AVERAGE($dataSet) - $m0) / ($sigma / SQRT($n)));
3686
    }
3687
}
3688