Completed
Push — develop ( 2922a1...cfa1fe )
by Adrien
24:40
created

Statistical::MINIF()   C

Complexity

Conditions 7
Paths 14

Size

Total Lines 25
Code Lines 15

Duplication

Lines 25
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 15
nc 14
nop 3
dl 25
loc 25
rs 6.7272
c 1
b 0
f 0
ccs 0
cts 22
cp 0
crap 56
1
<?php
2
3
namespace PhpOffice\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 = \PhpOffice\PhpSpreadsheet\Calculation::wrapResult(strtoupper($arg));
860
            }
861
            $testCondition = '=' . $arg . $condition;
862
            if (\PhpOffice\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
     * @return    float
886
     */
887
    public static function BETADIST($value, $alpha, $beta, $rMin = 0, $rMax = 1)
888
    {
889
        $value = Functions::flattenSingleValue($value);
890
        $alpha = Functions::flattenSingleValue($alpha);
891
        $beta = Functions::flattenSingleValue($beta);
892
        $rMin = Functions::flattenSingleValue($rMin);
893
        $rMax = Functions::flattenSingleValue($rMax);
894
895
        if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
896
            if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) {
897
                return Functions::NAN();
898
            }
899
            if ($rMin > $rMax) {
900
                $tmp = $rMin;
901
                $rMin = $rMax;
902
                $rMax = $tmp;
903
            }
904
            $value -= $rMin;
905
            $value /= ($rMax - $rMin);
906
907
            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<PhpOffice\PhpSpre...et\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<PhpOffice\PhpSpre...et\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<PhpOffice\PhpSpre...et\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...
908
        }
909
910
        return Functions::VALUE();
911
    }
912
913
    /**
914
     * BETAINV
915
     *
916
     * Returns the inverse of the beta distribution.
917
     *
918
     * @param    float        $probability    Probability at which you want to evaluate the distribution
919
     * @param    float        $alpha            Parameter to the distribution
920
     * @param    float        $beta            Parameter to the distribution
921
     * @param    float        $rMin            Minimum value
922
     * @param    float        $rMax            Maximum value
923
     * @return    float
924
     */
925
    public static function BETAINV($probability, $alpha, $beta, $rMin = 0, $rMax = 1)
926
    {
927
        $probability = Functions::flattenSingleValue($probability);
928
        $alpha = Functions::flattenSingleValue($alpha);
929
        $beta = Functions::flattenSingleValue($beta);
930
        $rMin = Functions::flattenSingleValue($rMin);
931
        $rMax = Functions::flattenSingleValue($rMax);
932
933
        if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
934 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...
935
                return Functions::NAN();
936
            }
937
            if ($rMin > $rMax) {
938
                $tmp = $rMin;
939
                $rMin = $rMax;
940
                $rMax = $tmp;
941
            }
942
            $a = 0;
943
            $b = 2;
944
945
            $i = 0;
946
            while ((($b - $a) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
947
                $guess = ($a + $b) / 2;
948
                $result = self::BETADIST($guess, $alpha, $beta);
949
                if (($result == $probability) || ($result == 0)) {
950
                    $b = $a;
951
                } elseif ($result > $probability) {
952
                    $b = $guess;
953
                } else {
954
                    $a = $guess;
955
                }
956
            }
957
            if ($i == MAX_ITERATIONS) {
958
                return Functions::NA();
959
            }
960
961
            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...
962
        }
963
964
        return Functions::VALUE();
965
    }
966
967
    /**
968
     * BINOMDIST
969
     *
970
     * Returns the individual term binomial distribution probability. Use BINOMDIST in problems with
971
     *        a fixed number of tests or trials, when the outcomes of any trial are only success or failure,
972
     *        when trials are independent, and when the probability of success is constant throughout the
973
     *        experiment. For example, BINOMDIST can calculate the probability that two of the next three
974
     *        babies born are male.
975
     *
976
     * @param    float        $value            Number of successes in trials
977
     * @param    float        $trials            Number of trials
978
     * @param    float        $probability    Probability of success on each trial
979
     * @param    bool        $cumulative
980
     * @return    float
981
     *
982
     * @todo    Cumulative distribution function
983
     */
984
    public static function BINOMDIST($value, $trials, $probability, $cumulative)
985
    {
986
        $value = floor(Functions::flattenSingleValue($value));
987
        $trials = floor(Functions::flattenSingleValue($trials));
988
        $probability = Functions::flattenSingleValue($probability);
989
990
        if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) {
991
            if (($value < 0) || ($value > $trials)) {
992
                return Functions::NAN();
993
            }
994
            if (($probability < 0) || ($probability > 1)) {
995
                return Functions::NAN();
996
            }
997
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
998
                if ($cumulative) {
999
                    $summer = 0;
1000
                    for ($i = 0; $i <= $value; ++$i) {
1001
                        $summer += MathTrig::COMBIN($trials, $i) * pow($probability, $i) * pow(1 - $probability, $trials - $i);
1002
                    }
1003
1004
                    return $summer;
1005
                } else {
1006
                    return MathTrig::COMBIN($trials, $value) * pow($probability, $value) * pow(1 - $probability, $trials - $value);
1007
                }
1008
            }
1009
        }
1010
1011
        return Functions::VALUE();
1012
    }
1013
1014
    /**
1015
     * CHIDIST
1016
     *
1017
     * Returns the one-tailed probability of the chi-squared distribution.
1018
     *
1019
     * @param    float        $value            Value for the function
1020
     * @param    float        $degrees        degrees of freedom
1021
     * @return    float
1022
     */
1023
    public static function CHIDIST($value, $degrees)
1024
    {
1025
        $value = Functions::flattenSingleValue($value);
1026
        $degrees = floor(Functions::flattenSingleValue($degrees));
1027
1028
        if ((is_numeric($value)) && (is_numeric($degrees))) {
1029
            if ($degrees < 1) {
1030
                return Functions::NAN();
1031
            }
1032
            if ($value < 0) {
1033
                if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1034
                    return 1;
1035
                }
1036
1037
                return Functions::NAN();
1038
            }
1039
1040
            return 1 - (self::incompleteGamma($degrees / 2, $value / 2) / self::gamma($degrees / 2));
1041
        }
1042
1043
        return Functions::VALUE();
1044
    }
1045
1046
    /**
1047
     * CHIINV
1048
     *
1049
     * Returns the one-tailed probability of the chi-squared distribution.
1050
     *
1051
     * @param    float        $probability    Probability for the function
1052
     * @param    float        $degrees        degrees of freedom
1053
     * @return    float
1054
     */
1055 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...
1056
    {
1057
        $probability = Functions::flattenSingleValue($probability);
1058
        $degrees = floor(Functions::flattenSingleValue($degrees));
1059
1060
        if ((is_numeric($probability)) && (is_numeric($degrees))) {
1061
            $xLo = 100;
1062
            $xHi = 0;
1063
1064
            $x = $xNew = 1;
1065
            $dx = 1;
1066
            $i = 0;
1067
1068
            while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
1069
                // Apply Newton-Raphson step
1070
                $result = self::CHIDIST($x, $degrees);
1071
                $error = $result - $probability;
1072
                if ($error == 0.0) {
1073
                    $dx = 0;
1074
                } elseif ($error < 0.0) {
1075
                    $xLo = $x;
1076
                } else {
1077
                    $xHi = $x;
1078
                }
1079
                // Avoid division by zero
1080
                if ($result != 0.0) {
1081
                    $dx = $error / $result;
1082
                    $xNew = $x - $dx;
1083
                }
1084
                // If the NR fails to converge (which for example may be the
1085
                // case if the initial guess is too rough) we apply a bisection
1086
                // step to determine a more narrow interval around the root.
1087
                if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
1088
                    $xNew = ($xLo + $xHi) / 2;
1089
                    $dx = $xNew - $x;
1090
                }
1091
                $x = $xNew;
1092
            }
1093
            if ($i == MAX_ITERATIONS) {
1094
                return Functions::NA();
1095
            }
1096
1097
            return round($x, 12);
1098
        }
1099
1100
        return Functions::VALUE();
1101
    }
1102
1103
    /**
1104
     * CONFIDENCE
1105
     *
1106
     * Returns the confidence interval for a population mean
1107
     *
1108
     * @param    float        $alpha
1109
     * @param    float        $stdDev        Standard Deviation
1110
     * @param    float        $size
1111
     * @return    float
1112
     */
1113
    public static function CONFIDENCE($alpha, $stdDev, $size)
1114
    {
1115
        $alpha = Functions::flattenSingleValue($alpha);
1116
        $stdDev = Functions::flattenSingleValue($stdDev);
1117
        $size = floor(Functions::flattenSingleValue($size));
1118
1119
        if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) {
1120
            if (($alpha <= 0) || ($alpha >= 1)) {
1121
                return Functions::NAN();
1122
            }
1123
            if (($stdDev <= 0) || ($size < 1)) {
1124
                return Functions::NAN();
1125
            }
1126
1127
            return self::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size);
1128
        }
1129
1130
        return Functions::VALUE();
1131
    }
1132
1133
    /**
1134
     * CORREL
1135
     *
1136
     * Returns covariance, the average of the products of deviations for each data point pair.
1137
     *
1138
     * @param    array of mixed        Data Series Y
1139
     * @param    array of mixed        Data Series X
1140
     * @return    float
1141
     */
1142
    public static function CORREL($yValues, $xValues = null)
1143
    {
1144
        if ((is_null($xValues)) || (!is_array($yValues)) || (!is_array($xValues))) {
1145
            return Functions::VALUE();
1146
        }
1147
        if (!self::checkTrendArrays($yValues, $xValues)) {
1148
            return Functions::VALUE();
1149
        }
1150
        $yValueCount = count($yValues);
1151
        $xValueCount = count($xValues);
1152
1153
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
1154
            return Functions::NA();
1155
        } elseif ($yValueCount == 1) {
1156
            return Functions::DIV0();
1157
        }
1158
1159
        $bestFitLinear = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
1160
1161
        return $bestFitLinear->getCorrelation();
1162
    }
1163
1164
    /**
1165
     * COUNT
1166
     *
1167
     * Counts the number of cells that contain numbers within the list of arguments
1168
     *
1169
     * Excel Function:
1170
     *        COUNT(value1[,value2[, ...]])
1171
     *
1172
     * @category Statistical Functions
1173
     * @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...
1174
     * @return    int
1175
     */
1176
    public static function COUNT()
1177
    {
1178
        $returnValue = 0;
1179
1180
        // Loop through arguments
1181
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
1182
        foreach ($aArgs as $k => $arg) {
1183
            if ((is_bool($arg)) &&
1184
                ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) {
1185
                $arg = (integer) $arg;
1186
            }
1187
            // Is it a numeric value?
1188
            if ((is_numeric($arg)) && (!is_string($arg))) {
1189
                ++$returnValue;
1190
            }
1191
        }
1192
1193
        return $returnValue;
1194
    }
1195
1196
    /**
1197
     * COUNTA
1198
     *
1199
     * Counts the number of cells that are not empty within the list of arguments
1200
     *
1201
     * Excel Function:
1202
     *        COUNTA(value1[,value2[, ...]])
1203
     *
1204
     * @category Statistical Functions
1205
     * @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...
1206
     * @return    int
1207
     */
1208 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...
1209
    {
1210
        $returnValue = 0;
1211
1212
        // Loop through arguments
1213
        $aArgs = Functions::flattenArray(func_get_args());
1214
        foreach ($aArgs as $arg) {
1215
            // Is it a numeric, boolean or string value?
1216
            if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
1217
                ++$returnValue;
1218
            }
1219
        }
1220
1221
        return $returnValue;
1222
    }
1223
1224
    /**
1225
     * COUNTBLANK
1226
     *
1227
     * Counts the number of empty cells within the list of arguments
1228
     *
1229
     * Excel Function:
1230
     *        COUNTBLANK(value1[,value2[, ...]])
1231
     *
1232
     * @category Statistical Functions
1233
     * @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...
1234
     * @return    int
1235
     */
1236 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...
1237
    {
1238
        $returnValue = 0;
1239
1240
        // Loop through arguments
1241
        $aArgs = Functions::flattenArray(func_get_args());
1242
        foreach ($aArgs as $arg) {
1243
            // Is it a blank cell?
1244
            if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) {
1245
                ++$returnValue;
1246
            }
1247
        }
1248
1249
        return $returnValue;
1250
    }
1251
1252
    /**
1253
     * COUNTIF
1254
     *
1255
     * Counts the number of cells that contain numbers within the list of arguments
1256
     *
1257
     * Excel Function:
1258
     *        COUNTIF(value1[,value2[, ...]],condition)
1259
     *
1260
     * @category Statistical Functions
1261
     * @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...
1262
     * @param    string        $condition        The criteria that defines which cells will be counted.
1263
     * @return    int
1264
     */
1265
    public static function COUNTIF($aArgs, $condition)
1266
    {
1267
        $returnValue = 0;
1268
1269
        $aArgs = Functions::flattenArray($aArgs);
1270
        $condition = Functions::ifCondition($condition);
1271
        // Loop through arguments
1272
        foreach ($aArgs as $arg) {
1273
            if (!is_numeric($arg)) {
1274
                $arg = \PhpOffice\PhpSpreadsheet\Calculation::wrapResult(strtoupper($arg));
1275
            }
1276
            $testCondition = '=' . $arg . $condition;
1277
            if (\PhpOffice\PhpSpreadsheet\Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
1278
                // Is it a value within our criteria
1279
                ++$returnValue;
1280
            }
1281
        }
1282
1283
        return $returnValue;
1284
    }
1285
1286
    /**
1287
     * COVAR
1288
     *
1289
     * Returns covariance, the average of the products of deviations for each data point pair.
1290
     *
1291
     * @param    array of mixed        Data Series Y
1292
     * @param    array of mixed        Data Series X
1293
     * @return    float
1294
     */
1295 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...
1296
    {
1297
        if (!self::checkTrendArrays($yValues, $xValues)) {
1298
            return Functions::VALUE();
1299
        }
1300
        $yValueCount = count($yValues);
1301
        $xValueCount = count($xValues);
1302
1303
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
1304
            return Functions::NA();
1305
        } elseif ($yValueCount == 1) {
1306
            return Functions::DIV0();
1307
        }
1308
1309
        $bestFitLinear = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
1310
1311
        return $bestFitLinear->getCovariance();
1312
    }
1313
1314
    /**
1315
     * CRITBINOM
1316
     *
1317
     * Returns the smallest value for which the cumulative binomial distribution is greater
1318
     *        than or equal to a criterion value
1319
     *
1320
     * See http://support.microsoft.com/kb/828117/ for details of the algorithm used
1321
     *
1322
     * @param    float        $trials            number of Bernoulli trials
1323
     * @param    float        $probability    probability of a success on each trial
1324
     * @param    float        $alpha            criterion value
1325
     * @return    int
1326
     *
1327
     * @todo    Warning. This implementation differs from the algorithm detailed on the MS
1328
     *            web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess
1329
     *            This eliminates a potential endless loop error, but may have an adverse affect on the
1330
     *            accuracy of the function (although all my tests have so far returned correct results).
1331
     */
1332
    public static function CRITBINOM($trials, $probability, $alpha)
1333
    {
1334
        $trials = floor(Functions::flattenSingleValue($trials));
1335
        $probability = Functions::flattenSingleValue($probability);
1336
        $alpha = Functions::flattenSingleValue($alpha);
1337
1338
        if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) {
1339
            if ($trials < 0) {
1340
                return Functions::NAN();
1341
            } elseif (($probability < 0) || ($probability > 1)) {
1342
                return Functions::NAN();
1343
            } elseif (($alpha < 0) || ($alpha > 1)) {
1344
                return Functions::NAN();
1345
            } elseif ($alpha <= 0.5) {
1346
                $t = sqrt(log(1 / ($alpha * $alpha)));
1347
                $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));
1348
            } else {
1349
                $t = sqrt(log(1 / pow(1 - $alpha, 2)));
1350
                $trialsApprox = $t - (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t);
1351
            }
1352
            $Guess = floor($trials * $probability + $trialsApprox * sqrt($trials * $probability * (1 - $probability)));
1353
            if ($Guess < 0) {
1354
                $Guess = 0;
1355
            } elseif ($Guess > $trials) {
1356
                $Guess = $trials;
1357
            }
1358
1359
            $TotalUnscaledProbability = $UnscaledPGuess = $UnscaledCumPGuess = 0.0;
1360
            $EssentiallyZero = 10e-12;
1361
1362
            $m = floor($trials * $probability);
1363
            ++$TotalUnscaledProbability;
1364
            if ($m == $Guess) {
1365
                ++$UnscaledPGuess;
1366
            }
1367
            if ($m <= $Guess) {
1368
                ++$UnscaledCumPGuess;
1369
            }
1370
1371
            $PreviousValue = 1;
1372
            $Done = false;
1373
            $k = $m + 1;
1374 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...
1375
                $CurrentValue = $PreviousValue * ($trials - $k + 1) * $probability / ($k * (1 - $probability));
1376
                $TotalUnscaledProbability += $CurrentValue;
1377
                if ($k == $Guess) {
1378
                    $UnscaledPGuess += $CurrentValue;
1379
                }
1380
                if ($k <= $Guess) {
1381
                    $UnscaledCumPGuess += $CurrentValue;
1382
                }
1383
                if ($CurrentValue <= $EssentiallyZero) {
1384
                    $Done = true;
1385
                }
1386
                $PreviousValue = $CurrentValue;
1387
                ++$k;
1388
            }
1389
1390
            $PreviousValue = 1;
1391
            $Done = false;
1392
            $k = $m - 1;
1393 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...
1394
                $CurrentValue = $PreviousValue * $k + 1 * (1 - $probability) / (($trials - $k) * $probability);
1395
                $TotalUnscaledProbability += $CurrentValue;
1396
                if ($k == $Guess) {
1397
                    $UnscaledPGuess += $CurrentValue;
1398
                }
1399
                if ($k <= $Guess) {
1400
                    $UnscaledCumPGuess += $CurrentValue;
1401
                }
1402
                if ($CurrentValue <= $EssentiallyZero) {
1403
                    $Done = true;
1404
                }
1405
                $PreviousValue = $CurrentValue;
1406
                --$k;
1407
            }
1408
1409
            $PGuess = $UnscaledPGuess / $TotalUnscaledProbability;
1410
            $CumPGuess = $UnscaledCumPGuess / $TotalUnscaledProbability;
1411
1412
            $CumPGuessMinus1 = $CumPGuess - 1;
1413
1414
            while (true) {
1415
                if (($CumPGuessMinus1 < $alpha) && ($CumPGuess >= $alpha)) {
1416
                    return $Guess;
1417
                } elseif (($CumPGuessMinus1 < $alpha) && ($CumPGuess < $alpha)) {
1418
                    $PGuessPlus1 = $PGuess * ($trials - $Guess) * $probability / $Guess / (1 - $probability);
1419
                    $CumPGuessMinus1 = $CumPGuess;
1420
                    $CumPGuess = $CumPGuess + $PGuessPlus1;
1421
                    $PGuess = $PGuessPlus1;
1422
                    ++$Guess;
1423
                } elseif (($CumPGuessMinus1 >= $alpha) && ($CumPGuess >= $alpha)) {
1424
                    $PGuessMinus1 = $PGuess * $Guess * (1 - $probability) / ($trials - $Guess + 1) / $probability;
1425
                    $CumPGuess = $CumPGuessMinus1;
1426
                    $CumPGuessMinus1 = $CumPGuessMinus1 - $PGuess;
1427
                    $PGuess = $PGuessMinus1;
1428
                    --$Guess;
1429
                }
1430
            }
1431
        }
1432
1433
        return Functions::VALUE();
1434
    }
1435
1436
    /**
1437
     * DEVSQ
1438
     *
1439
     * Returns the sum of squares of deviations of data points from their sample mean.
1440
     *
1441
     * Excel Function:
1442
     *        DEVSQ(value1[,value2[, ...]])
1443
     *
1444
     * @category Statistical Functions
1445
     * @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...
1446
     * @return    float
1447
     */
1448 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...
1449
    {
1450
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
1451
1452
        // Return value
1453
        $returnValue = null;
1454
1455
        $aMean = self::AVERAGE($aArgs);
1456
        if ($aMean != Functions::DIV0()) {
1457
            $aCount = -1;
1458
            foreach ($aArgs as $k => $arg) {
1459
                // Is it a numeric value?
1460
                if ((is_bool($arg)) &&
1461
                    ((!Functions::isCellValue($k)) ||
1462
                    (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) {
1463
                    $arg = (integer) $arg;
1464
                }
1465
                if ((is_numeric($arg)) && (!is_string($arg))) {
1466
                    if (is_null($returnValue)) {
1467
                        $returnValue = pow(($arg - $aMean), 2);
1468
                    } else {
1469
                        $returnValue += pow(($arg - $aMean), 2);
1470
                    }
1471
                    ++$aCount;
1472
                }
1473
            }
1474
1475
            // Return
1476
            if (is_null($returnValue)) {
1477
                return Functions::NAN();
1478
            } else {
1479
                return $returnValue;
1480
            }
1481
        }
1482
1483
        return self::NA();
0 ignored issues
show
Bug introduced by
The method NA() does not seem to exist on object<PhpOffice\PhpSpre...alculation\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...
1484
    }
1485
1486
    /**
1487
     * EXPONDIST
1488
     *
1489
     *    Returns the exponential distribution. Use EXPONDIST to model the time between events,
1490
     *        such as how long an automated bank teller takes to deliver cash. For example, you can
1491
     *        use EXPONDIST to determine the probability that the process takes at most 1 minute.
1492
     *
1493
     * @param    float        $value            Value of the function
1494
     * @param    float        $lambda            The parameter value
1495
     * @param    bool        $cumulative
1496
     * @return    float
1497
     */
1498
    public static function EXPONDIST($value, $lambda, $cumulative)
1499
    {
1500
        $value = Functions::flattenSingleValue($value);
1501
        $lambda = Functions::flattenSingleValue($lambda);
1502
        $cumulative = Functions::flattenSingleValue($cumulative);
1503
1504
        if ((is_numeric($value)) && (is_numeric($lambda))) {
1505
            if (($value < 0) || ($lambda < 0)) {
1506
                return Functions::NAN();
1507
            }
1508
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
1509
                if ($cumulative) {
1510
                    return 1 - exp(0 - $value * $lambda);
1511
                } else {
1512
                    return $lambda * exp(0 - $value * $lambda);
1513
                }
1514
            }
1515
        }
1516
1517
        return Functions::VALUE();
1518
    }
1519
1520
    /**
1521
     * FISHER
1522
     *
1523
     * Returns the Fisher transformation at x. This transformation produces a function that
1524
     *        is normally distributed rather than skewed. Use this function to perform hypothesis
1525
     *        testing on the correlation coefficient.
1526
     *
1527
     * @param    float        $value
1528
     * @return    float
1529
     */
1530
    public static function FISHER($value)
1531
    {
1532
        $value = Functions::flattenSingleValue($value);
1533
1534
        if (is_numeric($value)) {
1535
            if (($value <= -1) || ($value >= 1)) {
1536
                return Functions::NAN();
1537
            }
1538
1539
            return 0.5 * log((1 + $value) / (1 - $value));
1540
        }
1541
1542
        return Functions::VALUE();
1543
    }
1544
1545
    /**
1546
     * FISHERINV
1547
     *
1548
     * Returns the inverse of the Fisher transformation. Use this transformation when
1549
     *        analyzing correlations between ranges or arrays of data. If y = FISHER(x), then
1550
     *        FISHERINV(y) = x.
1551
     *
1552
     * @param    float        $value
1553
     * @return    float
1554
     */
1555
    public static function FISHERINV($value)
1556
    {
1557
        $value = Functions::flattenSingleValue($value);
1558
1559
        if (is_numeric($value)) {
1560
            return (exp(2 * $value) - 1) / (exp(2 * $value) + 1);
1561
        }
1562
1563
        return Functions::VALUE();
1564
    }
1565
1566
    /**
1567
     * FORECAST
1568
     *
1569
     * Calculates, or predicts, a future value by using existing values. The predicted value is a y-value for a given x-value.
1570
     *
1571
     * @param    float                Value of X for which we want to find Y
1572
     * @param    array of mixed        Data Series Y
1573
     * @param    array of mixed        Data Series X
1574
     * @return    float
1575
     */
1576
    public static function FORECAST($xValue, $yValues, $xValues)
1577
    {
1578
        $xValue = Functions::flattenSingleValue($xValue);
1579
        if (!is_numeric($xValue)) {
1580
            return Functions::VALUE();
1581
        } elseif (!self::checkTrendArrays($yValues, $xValues)) {
1582
            return Functions::VALUE();
1583
        }
1584
        $yValueCount = count($yValues);
1585
        $xValueCount = count($xValues);
1586
1587
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
1588
            return Functions::NA();
1589
        } elseif ($yValueCount == 1) {
1590
            return Functions::DIV0();
1591
        }
1592
1593
        $bestFitLinear = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
1594
1595
        return $bestFitLinear->getValueOfYForX($xValue);
1596
    }
1597
1598
    /**
1599
     * GAMMADIST
1600
     *
1601
     * Returns the gamma distribution.
1602
     *
1603
     * @param    float        $value            Value at which you want to evaluate the distribution
1604
     * @param    float        $a                Parameter to the distribution
1605
     * @param    float        $b                Parameter to the distribution
1606
     * @param    bool        $cumulative
1607
     * @return    float
1608
     */
1609
    public static function GAMMADIST($value, $a, $b, $cumulative)
1610
    {
1611
        $value = Functions::flattenSingleValue($value);
1612
        $a = Functions::flattenSingleValue($a);
1613
        $b = Functions::flattenSingleValue($b);
1614
1615
        if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) {
1616
            if (($value < 0) || ($a <= 0) || ($b <= 0)) {
1617
                return Functions::NAN();
1618
            }
1619
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
1620
                if ($cumulative) {
1621
                    return self::incompleteGamma($a, $value / $b) / self::gamma($a);
1622
                } else {
1623
                    return (1 / (pow($b, $a) * self::gamma($a))) * pow($value, $a - 1) * exp(0 - ($value / $b));
1624
                }
1625
            }
1626
        }
1627
1628
        return Functions::VALUE();
1629
    }
1630
1631
    /**
1632
     * GAMMAINV
1633
     *
1634
     * Returns the inverse of the beta distribution.
1635
     *
1636
     * @param    float        $probability    Probability at which you want to evaluate the distribution
1637
     * @param    float        $alpha            Parameter to the distribution
1638
     * @param    float        $beta            Parameter to the distribution
1639
     * @return    float
1640
     */
1641
    public static function GAMMAINV($probability, $alpha, $beta)
1642
    {
1643
        $probability = Functions::flattenSingleValue($probability);
1644
        $alpha = Functions::flattenSingleValue($alpha);
1645
        $beta = Functions::flattenSingleValue($beta);
1646
1647
        if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) {
1648 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...
1649
                return Functions::NAN();
1650
            }
1651
1652
            $xLo = 0;
1653
            $xHi = $alpha * $beta * 5;
1654
1655
            $x = $xNew = 1;
1656
            $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...
1657
            $dx = 1024;
1658
            $i = 0;
1659
1660
            while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
1661
                // Apply Newton-Raphson step
1662
                $error = self::GAMMADIST($x, $alpha, $beta, true) - $probability;
1663
                if ($error < 0.0) {
1664
                    $xLo = $x;
1665
                } else {
1666
                    $xHi = $x;
1667
                }
1668
                $pdf = self::GAMMADIST($x, $alpha, $beta, false);
1669
                // Avoid division by zero
1670
                if ($pdf != 0.0) {
1671
                    $dx = $error / $pdf;
1672
                    $xNew = $x - $dx;
1673
                }
1674
                // If the NR fails to converge (which for example may be the
1675
                // case if the initial guess is too rough) we apply a bisection
1676
                // step to determine a more narrow interval around the root.
1677
                if (($xNew < $xLo) || ($xNew > $xHi) || ($pdf == 0.0)) {
1678
                    $xNew = ($xLo + $xHi) / 2;
1679
                    $dx = $xNew - $x;
1680
                }
1681
                $x = $xNew;
1682
            }
1683
            if ($i == MAX_ITERATIONS) {
1684
                return Functions::NA();
1685
            }
1686
1687
            return $x;
1688
        }
1689
1690
        return Functions::VALUE();
1691
    }
1692
1693
    /**
1694
     * GAMMALN
1695
     *
1696
     * Returns the natural logarithm of the gamma function.
1697
     *
1698
     * @param    float        $value
1699
     * @return    float
1700
     */
1701 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...
1702
    {
1703
        $value = Functions::flattenSingleValue($value);
1704
1705
        if (is_numeric($value)) {
1706
            if ($value <= 0) {
1707
                return Functions::NAN();
1708
            }
1709
1710
            return log(self::gamma($value));
1711
        }
1712
1713
        return Functions::VALUE();
1714
    }
1715
1716
    /**
1717
     * GEOMEAN
1718
     *
1719
     * Returns the geometric mean of an array or range of positive data. For example, you
1720
     *        can use GEOMEAN to calculate average growth rate given compound interest with
1721
     *        variable rates.
1722
     *
1723
     * Excel Function:
1724
     *        GEOMEAN(value1[,value2[, ...]])
1725
     *
1726
     * @category Statistical Functions
1727
     * @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...
1728
     * @return    float
1729
     */
1730
    public static function GEOMEAN()
1731
    {
1732
        $aArgs = Functions::flattenArray(func_get_args());
1733
1734
        $aMean = MathTrig::PRODUCT($aArgs);
1735
        if (is_numeric($aMean) && ($aMean > 0)) {
1736
            $aCount = self::COUNT($aArgs);
1737
            if (self::MIN($aArgs) > 0) {
1738
                return pow($aMean, (1 / $aCount));
1739
            }
1740
        }
1741
1742
        return Functions::NAN();
1743
    }
1744
1745
    /**
1746
     * GROWTH
1747
     *
1748
     * Returns values along a predicted emponential Trend
1749
     *
1750
     * @param    array of mixed        Data Series Y
1751
     * @param    array of mixed        Data Series X
1752
     * @param    array of mixed        Values of X for which we want to find Y
1753
     * @param    bool                A logical value specifying whether to force the intersect to equal 0.
1754
     * @return    array of float
1755
     */
1756 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...
1757
    {
1758
        $yValues = Functions::flattenArray($yValues);
1759
        $xValues = Functions::flattenArray($xValues);
1760
        $newValues = Functions::flattenArray($newValues);
1761
        $const = (is_null($const)) ? true : (boolean) Functions::flattenSingleValue($const);
1762
1763
        $bestFitExponential = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_EXPONENTIAL, $yValues, $xValues, $const);
1764
        if (empty($newValues)) {
1765
            $newValues = $bestFitExponential->getXValues();
1766
        }
1767
1768
        $returnArray = [];
1769
        foreach ($newValues as $xValue) {
1770
            $returnArray[0][] = $bestFitExponential->getValueOfYForX($xValue);
1771
        }
1772
1773
        return $returnArray;
1774
    }
1775
1776
    /**
1777
     * HARMEAN
1778
     *
1779
     * Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the
1780
     *        arithmetic mean of reciprocals.
1781
     *
1782
     * Excel Function:
1783
     *        HARMEAN(value1[,value2[, ...]])
1784
     *
1785
     * @category Statistical Functions
1786
     * @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...
1787
     * @return    float
1788
     */
1789
    public static function HARMEAN()
1790
    {
1791
        // Return value
1792
        $returnValue = Functions::NA();
1793
1794
        // Loop through arguments
1795
        $aArgs = Functions::flattenArray(func_get_args());
1796
        if (self::MIN($aArgs) < 0) {
1797
            return Functions::NAN();
1798
        }
1799
        $aCount = 0;
1800
        foreach ($aArgs as $arg) {
1801
            // Is it a numeric value?
1802
            if ((is_numeric($arg)) && (!is_string($arg))) {
1803
                if ($arg <= 0) {
1804
                    return Functions::NAN();
1805
                }
1806
                if (is_null($returnValue)) {
1807
                    $returnValue = (1 / $arg);
1808
                } else {
1809
                    $returnValue += (1 / $arg);
1810
                }
1811
                ++$aCount;
1812
            }
1813
        }
1814
1815
        // Return
1816
        if ($aCount > 0) {
1817
            return 1 / ($returnValue / $aCount);
1818
        } else {
1819
            return $returnValue;
1820
        }
1821
    }
1822
1823
    /**
1824
     * HYPGEOMDIST
1825
     *
1826
     * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of
1827
     * sample successes, given the sample size, population successes, and population size.
1828
     *
1829
     * @param    float        $sampleSuccesses        Number of successes in the sample
1830
     * @param    float        $sampleNumber            Size of the sample
1831
     * @param    float        $populationSuccesses    Number of successes in the population
1832
     * @param    float        $populationNumber        Population size
1833
     * @return    float
1834
     */
1835
    public static function HYPGEOMDIST($sampleSuccesses, $sampleNumber, $populationSuccesses, $populationNumber)
1836
    {
1837
        $sampleSuccesses = floor(Functions::flattenSingleValue($sampleSuccesses));
1838
        $sampleNumber = floor(Functions::flattenSingleValue($sampleNumber));
1839
        $populationSuccesses = floor(Functions::flattenSingleValue($populationSuccesses));
1840
        $populationNumber = floor(Functions::flattenSingleValue($populationNumber));
1841
1842
        if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) {
1843
            if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) {
1844
                return Functions::NAN();
1845
            }
1846
            if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) {
1847
                return Functions::NAN();
1848
            }
1849
            if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) {
1850
                return Functions::NAN();
1851
            }
1852
1853
            return MathTrig::COMBIN($populationSuccesses, $sampleSuccesses) *
1854
                   MathTrig::COMBIN($populationNumber - $populationSuccesses, $sampleNumber - $sampleSuccesses) /
1855
                   MathTrig::COMBIN($populationNumber, $sampleNumber);
1856
        }
1857
1858
        return Functions::VALUE();
1859
    }
1860
1861
    /**
1862
     * INTERCEPT
1863
     *
1864
     * Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values.
1865
     *
1866
     * @param    array of mixed        Data Series Y
1867
     * @param    array of mixed        Data Series X
1868
     * @return    float
1869
     */
1870 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...
1871
    {
1872
        if (!self::checkTrendArrays($yValues, $xValues)) {
1873
            return Functions::VALUE();
1874
        }
1875
        $yValueCount = count($yValues);
1876
        $xValueCount = count($xValues);
1877
1878
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
1879
            return Functions::NA();
1880
        } elseif ($yValueCount == 1) {
1881
            return Functions::DIV0();
1882
        }
1883
1884
        $bestFitLinear = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
1885
1886
        return $bestFitLinear->getIntersect();
1887
    }
1888
1889
    /**
1890
     * KURT
1891
     *
1892
     * Returns the kurtosis of a data set. Kurtosis characterizes the relative peakedness
1893
     * or flatness of a distribution compared with the normal distribution. Positive
1894
     * kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a
1895
     * relatively flat distribution.
1896
     *
1897
     * @param    array    Data Series
1898
     * @return    float
1899
     */
1900
    public static function KURT()
1901
    {
1902
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
1903
        $mean = self::AVERAGE($aArgs);
1904
        $stdDev = self::STDEV($aArgs);
1905
1906
        if ($stdDev > 0) {
1907
            $count = $summer = 0;
1908
            // Loop through arguments
1909 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...
1910
                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...
1911
                    (!Functions::isMatrixValue($k))) {
1912
                } else {
1913
                    // Is it a numeric value?
1914
                    if ((is_numeric($arg)) && (!is_string($arg))) {
1915
                        $summer += pow((($arg - $mean) / $stdDev), 4);
1916
                        ++$count;
1917
                    }
1918
                }
1919
            }
1920
1921
            // Return
1922
            if ($count > 3) {
1923
                return $summer * ($count * ($count + 1) / (($count - 1) * ($count - 2) * ($count - 3))) - (3 * pow($count - 1, 2) / (($count - 2) * ($count - 3)));
1924
            }
1925
        }
1926
1927
        return Functions::DIV0();
1928
    }
1929
1930
    /**
1931
     * LARGE
1932
     *
1933
     * Returns the nth largest value in a data set. You can use this function to
1934
     *        select a value based on its relative standing.
1935
     *
1936
     * Excel Function:
1937
     *        LARGE(value1[,value2[, ...]],entry)
1938
     *
1939
     * @category Statistical Functions
1940
     * @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...
1941
     * @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...
1942
     * @return    float
1943
     */
1944 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...
1945
    {
1946
        $aArgs = Functions::flattenArray(func_get_args());
1947
1948
        // Calculate
1949
        $entry = floor(array_pop($aArgs));
1950
1951
        if ((is_numeric($entry)) && (!is_string($entry))) {
1952
            $mArgs = [];
1953
            foreach ($aArgs as $arg) {
1954
                // Is it a numeric value?
1955
                if ((is_numeric($arg)) && (!is_string($arg))) {
1956
                    $mArgs[] = $arg;
1957
                }
1958
            }
1959
            $count = self::COUNT($mArgs);
1960
            $entry = floor(--$entry);
1961
            if (($entry < 0) || ($entry >= $count) || ($count == 0)) {
1962
                return Functions::NAN();
1963
            }
1964
            rsort($mArgs);
1965
1966
            return $mArgs[$entry];
1967
        }
1968
1969
        return Functions::VALUE();
1970
    }
1971
1972
    /**
1973
     * LINEST
1974
     *
1975
     * Calculates the statistics for a line by using the "least squares" method to calculate a straight line that best fits your data,
1976
     *        and then returns an array that describes the line.
1977
     *
1978
     * @param    array of mixed        Data Series Y
1979
     * @param    array of mixed        Data Series X
1980
     * @param    bool                A logical value specifying whether to force the intersect to equal 0.
1981
     * @param    bool                A logical value specifying whether to return additional regression statistics.
1982
     * @return    array
1983
     */
1984
    public static function LINEST($yValues, $xValues = null, $const = true, $stats = false)
1985
    {
1986
        $const = (is_null($const)) ? true : (boolean) Functions::flattenSingleValue($const);
1987
        $stats = (is_null($stats)) ? false : (boolean) Functions::flattenSingleValue($stats);
1988
        if (is_null($xValues)) {
1989
            $xValues = range(1, count(Functions::flattenArray($yValues)));
1990
        }
1991
1992
        if (!self::checkTrendArrays($yValues, $xValues)) {
1993
            return Functions::VALUE();
1994
        }
1995
        $yValueCount = count($yValues);
1996
        $xValueCount = count($xValues);
1997
1998
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
1999
            return Functions::NA();
2000
        } elseif ($yValueCount == 1) {
2001
            return 0;
2002
        }
2003
2004
        $bestFitLinear = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues, $const);
2005 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...
2006
            return [
2007
                [
2008
                    $bestFitLinear->getSlope(),
2009
                    $bestFitLinear->getSlopeSE(),
2010
                    $bestFitLinear->getGoodnessOfFit(),
2011
                    $bestFitLinear->getF(),
2012
                    $bestFitLinear->getSSRegression(),
2013
                ],
2014
                [
2015
                    $bestFitLinear->getIntersect(),
2016
                    $bestFitLinear->getIntersectSE(),
2017
                    $bestFitLinear->getStdevOfResiduals(),
2018
                    $bestFitLinear->getDFResiduals(),
2019
                    $bestFitLinear->getSSResiduals(),
2020
                ],
2021
            ];
2022
        } else {
2023
            return [
2024
                $bestFitLinear->getSlope(),
2025
                $bestFitLinear->getIntersect(),
2026
            ];
2027
        }
2028
    }
2029
2030
    /**
2031
     * LOGEST
2032
     *
2033
     * Calculates an exponential curve that best fits the X and Y data series,
2034
     *        and then returns an array that describes the line.
2035
     *
2036
     * @param    array of mixed        Data Series Y
2037
     * @param    array of mixed        Data Series X
2038
     * @param    bool                A logical value specifying whether to force the intersect to equal 0.
2039
     * @param    bool                A logical value specifying whether to return additional regression statistics.
2040
     * @return    array
2041
     */
2042
    public static function LOGEST($yValues, $xValues = null, $const = true, $stats = false)
2043
    {
2044
        $const = (is_null($const)) ? true : (boolean) Functions::flattenSingleValue($const);
2045
        $stats = (is_null($stats)) ? false : (boolean) Functions::flattenSingleValue($stats);
2046
        if (is_null($xValues)) {
2047
            $xValues = range(1, count(Functions::flattenArray($yValues)));
2048
        }
2049
2050
        if (!self::checkTrendArrays($yValues, $xValues)) {
2051
            return Functions::VALUE();
2052
        }
2053
        $yValueCount = count($yValues);
2054
        $xValueCount = count($xValues);
2055
2056
        foreach ($yValues as $value) {
2057
            if ($value <= 0.0) {
2058
                return Functions::NAN();
2059
            }
2060
        }
2061
2062
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2063
            return Functions::NA();
2064
        } elseif ($yValueCount == 1) {
2065
            return 1;
2066
        }
2067
2068
        $bestFitExponential = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_EXPONENTIAL, $yValues, $xValues, $const);
2069 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...
2070
            return [
2071
                [
2072
                    $bestFitExponential->getSlope(),
2073
                    $bestFitExponential->getSlopeSE(),
2074
                    $bestFitExponential->getGoodnessOfFit(),
2075
                    $bestFitExponential->getF(),
2076
                    $bestFitExponential->getSSRegression(),
2077
                ],
2078
                [
2079
                    $bestFitExponential->getIntersect(),
2080
                    $bestFitExponential->getIntersectSE(),
2081
                    $bestFitExponential->getStdevOfResiduals(),
2082
                    $bestFitExponential->getDFResiduals(),
2083
                    $bestFitExponential->getSSResiduals(),
2084
                ],
2085
            ];
2086
        } else {
2087
            return [
2088
                $bestFitExponential->getSlope(),
2089
                $bestFitExponential->getIntersect(),
2090
            ];
2091
        }
2092
    }
2093
2094
    /**
2095
     * LOGINV
2096
     *
2097
     * Returns the inverse of the normal cumulative distribution
2098
     *
2099
     * @param    float        $probability
2100
     * @param    float        $mean
2101
     * @param    float        $stdDev
2102
     * @return    float
2103
     *
2104
     * @todo    Try implementing P J Acklam's refinement algorithm for greater
2105
     *            accuracy if I can get my head round the mathematics
2106
     *            (as described at) http://home.online.no/~pjacklam/notes/invnorm/
2107
     */
2108 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...
2109
    {
2110
        $probability = Functions::flattenSingleValue($probability);
2111
        $mean = Functions::flattenSingleValue($mean);
2112
        $stdDev = Functions::flattenSingleValue($stdDev);
2113
2114
        if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
2115
            if (($probability < 0) || ($probability > 1) || ($stdDev <= 0)) {
2116
                return Functions::NAN();
2117
            }
2118
2119
            return exp($mean + $stdDev * self::NORMSINV($probability));
2120
        }
2121
2122
        return Functions::VALUE();
2123
    }
2124
2125
    /**
2126
     * LOGNORMDIST
2127
     *
2128
     * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed
2129
     * with parameters mean and standard_dev.
2130
     *
2131
     * @param    float        $value
2132
     * @param    float        $mean
2133
     * @param    float        $stdDev
2134
     * @return    float
2135
     */
2136
    public static function LOGNORMDIST($value, $mean, $stdDev)
2137
    {
2138
        $value = Functions::flattenSingleValue($value);
2139
        $mean = Functions::flattenSingleValue($mean);
2140
        $stdDev = Functions::flattenSingleValue($stdDev);
2141
2142
        if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
2143
            if (($value <= 0) || ($stdDev <= 0)) {
2144
                return Functions::NAN();
2145
            }
2146
2147
            return self::NORMSDIST((log($value) - $mean) / $stdDev);
2148
        }
2149
2150
        return Functions::VALUE();
2151
    }
2152
2153
    /**
2154
     * MAX
2155
     *
2156
     * MAX returns the value of the element of the values passed that has the highest value,
2157
     *        with negative numbers considered smaller than positive numbers.
2158
     *
2159
     * Excel Function:
2160
     *        MAX(value1[,value2[, ...]])
2161
     *
2162
     * @category Statistical Functions
2163
     * @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...
2164
     * @return    float
2165
     */
2166 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...
2167
    {
2168
        $returnValue = null;
2169
2170
        // Loop through arguments
2171
        $aArgs = Functions::flattenArray(func_get_args());
2172
        foreach ($aArgs as $arg) {
2173
            // Is it a numeric value?
2174
            if ((is_numeric($arg)) && (!is_string($arg))) {
2175
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
2176
                    $returnValue = $arg;
2177
                }
2178
            }
2179
        }
2180
2181
        if (is_null($returnValue)) {
2182
            return 0;
2183
        }
2184
2185
        return $returnValue;
2186
    }
2187
2188
    /**
2189
     * MAXA
2190
     *
2191
     * Returns the greatest value in a list of arguments, including numbers, text, and logical values
2192
     *
2193
     * Excel Function:
2194
     *        MAXA(value1[,value2[, ...]])
2195
     *
2196
     * @category Statistical Functions
2197
     * @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...
2198
     * @return    float
2199
     */
2200 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...
2201
    {
2202
        $returnValue = null;
2203
2204
        // Loop through arguments
2205
        $aArgs = Functions::flattenArray(func_get_args());
2206
        foreach ($aArgs as $arg) {
2207
            // Is it a numeric value?
2208
            if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
2209
                if (is_bool($arg)) {
2210
                    $arg = (integer) $arg;
2211
                } elseif (is_string($arg)) {
2212
                    $arg = 0;
2213
                }
2214
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
2215
                    $returnValue = $arg;
2216
                }
2217
            }
2218
        }
2219
2220
        if (is_null($returnValue)) {
2221
            return 0;
2222
        }
2223
2224
        return $returnValue;
2225
    }
2226
2227
    /**
2228
     * MAXIF
2229
     *
2230
     * Counts the maximum value within a range of cells that contain numbers within the list of arguments
2231
     *
2232
     * Excel Function:
2233
     *        MAXIF(value1[,value2[, ...]],condition)
2234
     *
2235
     * @category Mathematical and Trigonometric Functions
2236
     * @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...
2237
     * @param    string        $condition        The criteria that defines which cells will be checked.
2238
     * @return    float
2239
     */
2240 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...
2241
    {
2242
        $returnValue = null;
2243
2244
        $aArgs = Functions::flattenArray($aArgs);
2245
        $sumArgs = Functions::flattenArray($sumArgs);
2246
        if (empty($sumArgs)) {
2247
            $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...
2248
        }
2249
        $condition = Functions::ifCondition($condition);
2250
        // Loop through arguments
2251
        foreach ($aArgs as $key => $arg) {
2252
            if (!is_numeric($arg)) {
2253
                $arg = \PhpOffice\PhpSpreadsheet\Calculation::wrapResult(strtoupper($arg));
2254
            }
2255
            $testCondition = '=' . $arg . $condition;
2256
            if (\PhpOffice\PhpSpreadsheet\Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
2257
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
2258
                    $returnValue = $arg;
2259
                }
2260
            }
2261
        }
2262
2263
        return $returnValue;
2264
    }
2265
2266
    /**
2267
     * MEDIAN
2268
     *
2269
     * Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
2270
     *
2271
     * Excel Function:
2272
     *        MEDIAN(value1[,value2[, ...]])
2273
     *
2274
     * @category Statistical Functions
2275
     * @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...
2276
     * @return    float
2277
     */
2278
    public static function MEDIAN()
2279
    {
2280
        $returnValue = Functions::NAN();
2281
2282
        $mArgs = [];
2283
        // Loop through arguments
2284
        $aArgs = Functions::flattenArray(func_get_args());
2285
        foreach ($aArgs as $arg) {
2286
            // Is it a numeric value?
2287
            if ((is_numeric($arg)) && (!is_string($arg))) {
2288
                $mArgs[] = $arg;
2289
            }
2290
        }
2291
2292
        $mValueCount = count($mArgs);
2293
        if ($mValueCount > 0) {
2294
            sort($mArgs, SORT_NUMERIC);
2295
            $mValueCount = $mValueCount / 2;
2296
            if ($mValueCount == floor($mValueCount)) {
2297
                $returnValue = ($mArgs[$mValueCount--] + $mArgs[$mValueCount]) / 2;
2298
            } else {
2299
                $mValueCount = floor($mValueCount);
2300
                $returnValue = $mArgs[$mValueCount];
2301
            }
2302
        }
2303
2304
        return $returnValue;
2305
    }
2306
2307
    /**
2308
     * MIN
2309
     *
2310
     * MIN returns the value of the element of the values passed that has the smallest value,
2311
     *        with negative numbers considered smaller than positive numbers.
2312
     *
2313
     * Excel Function:
2314
     *        MIN(value1[,value2[, ...]])
2315
     *
2316
     * @category Statistical Functions
2317
     * @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...
2318
     * @return    float
2319
     */
2320 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...
2321
    {
2322
        $returnValue = null;
2323
2324
        // Loop through arguments
2325
        $aArgs = Functions::flattenArray(func_get_args());
2326
        foreach ($aArgs as $arg) {
2327
            // Is it a numeric value?
2328
            if ((is_numeric($arg)) && (!is_string($arg))) {
2329
                if ((is_null($returnValue)) || ($arg < $returnValue)) {
2330
                    $returnValue = $arg;
2331
                }
2332
            }
2333
        }
2334
2335
        if (is_null($returnValue)) {
2336
            return 0;
2337
        }
2338
2339
        return $returnValue;
2340
    }
2341
2342
    /**
2343
     * MINA
2344
     *
2345
     * Returns the smallest value in a list of arguments, including numbers, text, and logical values
2346
     *
2347
     * Excel Function:
2348
     *        MINA(value1[,value2[, ...]])
2349
     *
2350
     * @category Statistical Functions
2351
     * @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...
2352
     * @return    float
2353
     */
2354 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...
2355
    {
2356
        $returnValue = null;
2357
2358
        // Loop through arguments
2359
        $aArgs = Functions::flattenArray(func_get_args());
2360
        foreach ($aArgs as $arg) {
2361
            // Is it a numeric value?
2362
            if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
2363
                if (is_bool($arg)) {
2364
                    $arg = (integer) $arg;
2365
                } elseif (is_string($arg)) {
2366
                    $arg = 0;
2367
                }
2368
                if ((is_null($returnValue)) || ($arg < $returnValue)) {
2369
                    $returnValue = $arg;
2370
                }
2371
            }
2372
        }
2373
2374
        if (is_null($returnValue)) {
2375
            return 0;
2376
        }
2377
2378
        return $returnValue;
2379
    }
2380
2381
    /**
2382
     * MINIF
2383
     *
2384
     * Returns the minimum value within a range of cells that contain numbers within the list of arguments
2385
     *
2386
     * Excel Function:
2387
     *        MINIF(value1[,value2[, ...]],condition)
2388
     *
2389
     * @category Mathematical and Trigonometric Functions
2390
     * @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...
2391
     * @param    string        $condition        The criteria that defines which cells will be checked.
2392
     * @return    float
2393
     */
2394 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...
2395
    {
2396
        $returnValue = null;
2397
2398
        $aArgs = Functions::flattenArray($aArgs);
2399
        $sumArgs = Functions::flattenArray($sumArgs);
2400
        if (empty($sumArgs)) {
2401
            $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...
2402
        }
2403
        $condition = Functions::ifCondition($condition);
2404
        // Loop through arguments
2405
        foreach ($aArgs as $key => $arg) {
2406
            if (!is_numeric($arg)) {
2407
                $arg = \PhpOffice\PhpSpreadsheet\Calculation::wrapResult(strtoupper($arg));
2408
            }
2409
            $testCondition = '=' . $arg . $condition;
2410
            if (\PhpOffice\PhpSpreadsheet\Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
2411
                if ((is_null($returnValue)) || ($arg < $returnValue)) {
2412
                    $returnValue = $arg;
2413
                }
2414
            }
2415
        }
2416
2417
        return $returnValue;
2418
    }
2419
2420
    //
2421
    //    Special variant of array_count_values that isn't limited to strings and integers,
2422
    //        but can work with floating point numbers as values
2423
    //
2424
    private static function modeCalc($data)
2425
    {
2426
        $frequencyArray = [];
2427
        foreach ($data as $datum) {
2428
            $found = false;
2429
            foreach ($frequencyArray as $key => $value) {
2430
                if ((string) $value['value'] == (string) $datum) {
2431
                    ++$frequencyArray[$key]['frequency'];
2432
                    $found = true;
2433
                    break;
2434
                }
2435
            }
2436
            if (!$found) {
2437
                $frequencyArray[] = [
2438
                    'value' => $datum,
2439
                    'frequency' => 1,
2440
                ];
2441
            }
2442
        }
2443
2444
        foreach ($frequencyArray as $key => $value) {
2445
            $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...
2446
            $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...
2447
        }
2448
        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...
2449
2450
        if ($frequencyArray[0]['frequency'] == 1) {
2451
            return Functions::NA();
2452
        }
2453
2454
        return $frequencyArray[0]['value'];
2455
    }
2456
2457
    /**
2458
     * MODE
2459
     *
2460
     * Returns the most frequently occurring, or repetitive, value in an array or range of data
2461
     *
2462
     * Excel Function:
2463
     *        MODE(value1[,value2[, ...]])
2464
     *
2465
     * @category Statistical Functions
2466
     * @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...
2467
     * @return    float
2468
     */
2469
    public static function MODE()
2470
    {
2471
        $returnValue = Functions::NA();
2472
2473
        // Loop through arguments
2474
        $aArgs = Functions::flattenArray(func_get_args());
2475
2476
        $mArgs = [];
2477
        foreach ($aArgs as $arg) {
2478
            // Is it a numeric value?
2479
            if ((is_numeric($arg)) && (!is_string($arg))) {
2480
                $mArgs[] = $arg;
2481
            }
2482
        }
2483
2484
        if (!empty($mArgs)) {
2485
            return self::modeCalc($mArgs);
2486
        }
2487
2488
        return $returnValue;
2489
    }
2490
2491
    /**
2492
     * NEGBINOMDIST
2493
     *
2494
     * Returns the negative binomial distribution. NEGBINOMDIST returns the probability that
2495
     *        there will be number_f failures before the number_s-th success, when the constant
2496
     *        probability of a success is probability_s. This function is similar to the binomial
2497
     *        distribution, except that the number of successes is fixed, and the number of trials is
2498
     *        variable. Like the binomial, trials are assumed to be independent.
2499
     *
2500
     * @param    float        $failures        Number of Failures
2501
     * @param    float        $successes        Threshold number of Successes
2502
     * @param    float        $probability    Probability of success on each trial
2503
     * @return    float
2504
     */
2505
    public static function NEGBINOMDIST($failures, $successes, $probability)
2506
    {
2507
        $failures = floor(Functions::flattenSingleValue($failures));
2508
        $successes = floor(Functions::flattenSingleValue($successes));
2509
        $probability = Functions::flattenSingleValue($probability);
2510
2511
        if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) {
2512
            if (($failures < 0) || ($successes < 1)) {
2513
                return Functions::NAN();
2514
            } elseif (($probability < 0) || ($probability > 1)) {
2515
                return Functions::NAN();
2516
            }
2517
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
2518
                if (($failures + $successes - 1) <= 0) {
2519
                    return Functions::NAN();
2520
                }
2521
            }
2522
2523
            return (MathTrig::COMBIN($failures + $successes - 1, $successes - 1)) * (pow($probability, $successes)) * (pow(1 - $probability, $failures));
2524
        }
2525
2526
        return Functions::VALUE();
2527
    }
2528
2529
    /**
2530
     * NORMDIST
2531
     *
2532
     * Returns the normal distribution for the specified mean and standard deviation. This
2533
     * function has a very wide range of applications in statistics, including hypothesis
2534
     * testing.
2535
     *
2536
     * @param    float        $value
2537
     * @param    float        $mean        Mean Value
2538
     * @param    float        $stdDev        Standard Deviation
2539
     * @param    bool        $cumulative
2540
     * @return    float
2541
     */
2542
    public static function NORMDIST($value, $mean, $stdDev, $cumulative)
2543
    {
2544
        $value = Functions::flattenSingleValue($value);
2545
        $mean = Functions::flattenSingleValue($mean);
2546
        $stdDev = Functions::flattenSingleValue($stdDev);
2547
2548
        if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
2549
            if ($stdDev < 0) {
2550
                return Functions::NAN();
2551
            }
2552
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
2553
                if ($cumulative) {
2554
                    return 0.5 * (1 + Engineering::erfVal(($value - $mean) / ($stdDev * sqrt(2))));
2555
                } else {
2556
                    return (1 / (SQRT2PI * $stdDev)) * exp(0 - (pow($value - $mean, 2) / (2 * ($stdDev * $stdDev))));
2557
                }
2558
            }
2559
        }
2560
2561
        return Functions::VALUE();
2562
    }
2563
2564
    /**
2565
     * NORMINV
2566
     *
2567
     * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation.
2568
     *
2569
     * @param    float        $probability
2570
     * @param    float        $mean        Mean Value
2571
     * @param    float        $stdDev        Standard Deviation
2572
     * @return    float
2573
     */
2574 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...
2575
    {
2576
        $probability = Functions::flattenSingleValue($probability);
2577
        $mean = Functions::flattenSingleValue($mean);
2578
        $stdDev = Functions::flattenSingleValue($stdDev);
2579
2580
        if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
2581
            if (($probability < 0) || ($probability > 1)) {
2582
                return Functions::NAN();
2583
            }
2584
            if ($stdDev < 0) {
2585
                return Functions::NAN();
2586
            }
2587
2588
            return (self::inverseNcdf($probability) * $stdDev) + $mean;
2589
        }
2590
2591
        return Functions::VALUE();
2592
    }
2593
2594
    /**
2595
     * NORMSDIST
2596
     *
2597
     * Returns the standard normal cumulative distribution function. The distribution has
2598
     * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a
2599
     * table of standard normal curve areas.
2600
     *
2601
     * @param    float        $value
2602
     * @return    float
2603
     */
2604
    public static function NORMSDIST($value)
2605
    {
2606
        $value = Functions::flattenSingleValue($value);
2607
2608
        return self::NORMDIST($value, 0, 1, true);
2609
    }
2610
2611
    /**
2612
     * NORMSINV
2613
     *
2614
     * Returns the inverse of the standard normal cumulative distribution
2615
     *
2616
     * @param    float        $value
2617
     * @return    float
2618
     */
2619
    public static function NORMSINV($value)
2620
    {
2621
        return self::NORMINV($value, 0, 1);
2622
    }
2623
2624
    /**
2625
     * PERCENTILE
2626
     *
2627
     * Returns the nth percentile of values in a range..
2628
     *
2629
     * Excel Function:
2630
     *        PERCENTILE(value1[,value2[, ...]],entry)
2631
     *
2632
     * @category Statistical Functions
2633
     * @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...
2634
     * @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...
2635
     * @return    float
2636
     */
2637
    public static function PERCENTILE()
2638
    {
2639
        $aArgs = Functions::flattenArray(func_get_args());
2640
2641
        // Calculate
2642
        $entry = array_pop($aArgs);
2643
2644
        if ((is_numeric($entry)) && (!is_string($entry))) {
2645
            if (($entry < 0) || ($entry > 1)) {
2646
                return Functions::NAN();
2647
            }
2648
            $mArgs = [];
2649
            foreach ($aArgs as $arg) {
2650
                // Is it a numeric value?
2651
                if ((is_numeric($arg)) && (!is_string($arg))) {
2652
                    $mArgs[] = $arg;
2653
                }
2654
            }
2655
            $mValueCount = count($mArgs);
2656
            if ($mValueCount > 0) {
2657
                sort($mArgs);
2658
                $count = self::COUNT($mArgs);
2659
                $index = $entry * ($count - 1);
2660
                $iBase = floor($index);
2661
                if ($index == $iBase) {
2662
                    return $mArgs[$index];
2663
                } else {
2664
                    $iNext = $iBase + 1;
2665
                    $iProportion = $index - $iBase;
2666
2667
                    return $mArgs[$iBase] + (($mArgs[$iNext] - $mArgs[$iBase]) * $iProportion);
2668
                }
2669
            }
2670
        }
2671
2672
        return Functions::VALUE();
2673
    }
2674
2675
    /**
2676
     * PERCENTRANK
2677
     *
2678
     * Returns the rank of a value in a data set as a percentage of the data set.
2679
     *
2680
     * @param    array of number        An array of, or a reference to, a list of numbers.
2681
     * @param    number                The number whose rank you want to find.
2682
     * @param    number                The number of significant digits for the returned percentage value.
2683
     * @return    float
2684
     */
2685
    public static function PERCENTRANK($valueSet, $value, $significance = 3)
2686
    {
2687
        $valueSet = Functions::flattenArray($valueSet);
2688
        $value = Functions::flattenSingleValue($value);
2689
        $significance = (is_null($significance)) ? 3 : (integer) Functions::flattenSingleValue($significance);
2690
2691
        foreach ($valueSet as $key => $valueEntry) {
2692
            if (!is_numeric($valueEntry)) {
2693
                unset($valueSet[$key]);
2694
            }
2695
        }
2696
        sort($valueSet, SORT_NUMERIC);
2697
        $valueCount = count($valueSet);
2698
        if ($valueCount == 0) {
2699
            return Functions::NAN();
2700
        }
2701
2702
        $valueAdjustor = $valueCount - 1;
2703
        if (($value < $valueSet[0]) || ($value > $valueSet[$valueAdjustor])) {
2704
            return Functions::NA();
2705
        }
2706
2707
        $pos = array_search($value, $valueSet);
2708
        if ($pos === false) {
2709
            $pos = 0;
2710
            $testValue = $valueSet[0];
2711
            while ($testValue < $value) {
2712
                $testValue = $valueSet[++$pos];
2713
            }
2714
            --$pos;
2715
            $pos += (($value - $valueSet[$pos]) / ($testValue - $valueSet[$pos]));
2716
        }
2717
2718
        return round($pos / $valueAdjustor, $significance);
2719
    }
2720
2721
    /**
2722
     * PERMUT
2723
     *
2724
     * Returns the number of permutations for a given number of objects that can be
2725
     *        selected from number objects. A permutation is any set or subset of objects or
2726
     *        events where internal order is significant. Permutations are different from
2727
     *        combinations, for which the internal order is not significant. Use this function
2728
     *        for lottery-style probability calculations.
2729
     *
2730
     * @param    int        $numObjs    Number of different objects
2731
     * @param    int        $numInSet    Number of objects in each permutation
2732
     * @return    int        Number of permutations
2733
     */
2734 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...
2735
    {
2736
        $numObjs = Functions::flattenSingleValue($numObjs);
2737
        $numInSet = Functions::flattenSingleValue($numInSet);
2738
2739
        if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
2740
            $numInSet = floor($numInSet);
2741
            if ($numObjs < $numInSet) {
2742
                return Functions::NAN();
2743
            }
2744
2745
            return round(MathTrig::FACT($numObjs) / MathTrig::FACT($numObjs - $numInSet));
2746
        }
2747
2748
        return Functions::VALUE();
2749
    }
2750
2751
    /**
2752
     * POISSON
2753
     *
2754
     * Returns the Poisson distribution. A common application of the Poisson distribution
2755
     * is predicting the number of events over a specific time, such as the number of
2756
     * cars arriving at a toll plaza in 1 minute.
2757
     *
2758
     * @param    float        $value
2759
     * @param    float        $mean        Mean Value
2760
     * @param    bool        $cumulative
2761
     * @return    float
2762
     */
2763
    public static function POISSON($value, $mean, $cumulative)
2764
    {
2765
        $value = Functions::flattenSingleValue($value);
2766
        $mean = Functions::flattenSingleValue($mean);
2767
2768
        if ((is_numeric($value)) && (is_numeric($mean))) {
2769
            if (($value < 0) || ($mean <= 0)) {
2770
                return Functions::NAN();
2771
            }
2772
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
2773
                if ($cumulative) {
2774
                    $summer = 0;
2775
                    for ($i = 0; $i <= floor($value); ++$i) {
2776
                        $summer += pow($mean, $i) / MathTrig::FACT($i);
2777
                    }
2778
2779
                    return exp(0 - $mean) * $summer;
2780
                } else {
2781
                    return (exp(0 - $mean) * pow($mean, $value)) / MathTrig::FACT($value);
2782
                }
2783
            }
2784
        }
2785
2786
        return Functions::VALUE();
2787
    }
2788
2789
    /**
2790
     * QUARTILE
2791
     *
2792
     * Returns the quartile of a data set.
2793
     *
2794
     * Excel Function:
2795
     *        QUARTILE(value1[,value2[, ...]],entry)
2796
     *
2797
     * @category Statistical Functions
2798
     * @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...
2799
     * @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...
2800
     * @return    float
2801
     */
2802
    public static function QUARTILE()
2803
    {
2804
        $aArgs = Functions::flattenArray(func_get_args());
2805
2806
        // Calculate
2807
        $entry = floor(array_pop($aArgs));
2808
2809
        if ((is_numeric($entry)) && (!is_string($entry))) {
2810
            $entry /= 4;
2811
            if (($entry < 0) || ($entry > 1)) {
2812
                return Functions::NAN();
2813
            }
2814
2815
            return self::PERCENTILE($aArgs, $entry);
2816
        }
2817
2818
        return Functions::VALUE();
2819
    }
2820
2821
    /**
2822
     * RANK
2823
     *
2824
     * Returns the rank of a number in a list of numbers.
2825
     *
2826
     * @param    number                The number whose rank you want to find.
2827
     * @param    array of number        An array of, or a reference to, a list of numbers.
2828
     * @param    mixed                Order to sort the values in the value set
2829
     * @return    float
2830
     */
2831
    public static function RANK($value, $valueSet, $order = 0)
2832
    {
2833
        $value = Functions::flattenSingleValue($value);
2834
        $valueSet = Functions::flattenArray($valueSet);
2835
        $order = (is_null($order)) ? 0 : (integer) Functions::flattenSingleValue($order);
2836
2837
        foreach ($valueSet as $key => $valueEntry) {
2838
            if (!is_numeric($valueEntry)) {
2839
                unset($valueSet[$key]);
2840
            }
2841
        }
2842
2843
        if ($order == 0) {
2844
            rsort($valueSet, SORT_NUMERIC);
2845
        } else {
2846
            sort($valueSet, SORT_NUMERIC);
2847
        }
2848
        $pos = array_search($value, $valueSet);
2849
        if ($pos === false) {
2850
            return Functions::NA();
2851
        }
2852
2853
        return ++$pos;
2854
    }
2855
2856
    /**
2857
     * RSQ
2858
     *
2859
     * Returns the square of the Pearson product moment correlation coefficient through data points in known_y's and known_x's.
2860
     *
2861
     * @param    array of mixed        Data Series Y
2862
     * @param    array of mixed        Data Series X
2863
     * @return    float
2864
     */
2865 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...
2866
    {
2867
        if (!self::checkTrendArrays($yValues, $xValues)) {
2868
            return Functions::VALUE();
2869
        }
2870
        $yValueCount = count($yValues);
2871
        $xValueCount = count($xValues);
2872
2873
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2874
            return Functions::NA();
2875
        } elseif ($yValueCount == 1) {
2876
            return Functions::DIV0();
2877
        }
2878
2879
        $bestFitLinear = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
2880
2881
        return $bestFitLinear->getGoodnessOfFit();
2882
    }
2883
2884
    /**
2885
     * SKEW
2886
     *
2887
     * Returns the skewness of a distribution. Skewness characterizes the degree of asymmetry
2888
     * of a distribution around its mean. Positive skewness indicates a distribution with an
2889
     * asymmetric tail extending toward more positive values. Negative skewness indicates a
2890
     * distribution with an asymmetric tail extending toward more negative values.
2891
     *
2892
     * @param    array    Data Series
2893
     * @return    float
2894
     */
2895
    public static function SKEW()
2896
    {
2897
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
2898
        $mean = self::AVERAGE($aArgs);
2899
        $stdDev = self::STDEV($aArgs);
2900
2901
        $count = $summer = 0;
2902
        // Loop through arguments
2903 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...
2904
            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...
2905
                (!Functions::isMatrixValue($k))) {
2906
            } else {
2907
                // Is it a numeric value?
2908
                if ((is_numeric($arg)) && (!is_string($arg))) {
2909
                    $summer += pow((($arg - $mean) / $stdDev), 3);
2910
                    ++$count;
2911
                }
2912
            }
2913
        }
2914
2915
        if ($count > 2) {
2916
            return $summer * ($count / (($count - 1) * ($count - 2)));
2917
        }
2918
2919
        return Functions::DIV0();
2920
    }
2921
2922
    /**
2923
     * SLOPE
2924
     *
2925
     * Returns the slope of the linear regression line through data points in known_y's and known_x's.
2926
     *
2927
     * @param    array of mixed        Data Series Y
2928
     * @param    array of mixed        Data Series X
2929
     * @return    float
2930
     */
2931 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...
2932
    {
2933
        if (!self::checkTrendArrays($yValues, $xValues)) {
2934
            return Functions::VALUE();
2935
        }
2936
        $yValueCount = count($yValues);
2937
        $xValueCount = count($xValues);
2938
2939
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2940
            return Functions::NA();
2941
        } elseif ($yValueCount == 1) {
2942
            return Functions::DIV0();
2943
        }
2944
2945
        $bestFitLinear = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
2946
2947
        return $bestFitLinear->getSlope();
2948
    }
2949
2950
    /**
2951
     * SMALL
2952
     *
2953
     * Returns the nth smallest value in a data set. You can use this function to
2954
     *        select a value based on its relative standing.
2955
     *
2956
     * Excel Function:
2957
     *        SMALL(value1[,value2[, ...]],entry)
2958
     *
2959
     * @category Statistical Functions
2960
     * @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...
2961
     * @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...
2962
     * @return    float
2963
     */
2964 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...
2965
    {
2966
        $aArgs = Functions::flattenArray(func_get_args());
2967
2968
        // Calculate
2969
        $entry = array_pop($aArgs);
2970
2971
        if ((is_numeric($entry)) && (!is_string($entry))) {
2972
            $mArgs = [];
2973
            foreach ($aArgs as $arg) {
2974
                // Is it a numeric value?
2975
                if ((is_numeric($arg)) && (!is_string($arg))) {
2976
                    $mArgs[] = $arg;
2977
                }
2978
            }
2979
            $count = self::COUNT($mArgs);
2980
            $entry = floor(--$entry);
2981
            if (($entry < 0) || ($entry >= $count) || ($count == 0)) {
2982
                return Functions::NAN();
2983
            }
2984
            sort($mArgs);
2985
2986
            return $mArgs[$entry];
2987
        }
2988
2989
        return Functions::VALUE();
2990
    }
2991
2992
    /**
2993
     * STANDARDIZE
2994
     *
2995
     * Returns a normalized value from a distribution characterized by mean and standard_dev.
2996
     *
2997
     * @param    float    $value        Value to normalize
2998
     * @param    float    $mean        Mean Value
2999
     * @param    float    $stdDev        Standard Deviation
3000
     * @return    float    Standardized value
3001
     */
3002 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...
3003
    {
3004
        $value = Functions::flattenSingleValue($value);
3005
        $mean = Functions::flattenSingleValue($mean);
3006
        $stdDev = Functions::flattenSingleValue($stdDev);
3007
3008
        if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
3009
            if ($stdDev <= 0) {
3010
                return Functions::NAN();
3011
            }
3012
3013
            return ($value - $mean) / $stdDev;
3014
        }
3015
3016
        return Functions::VALUE();
3017
    }
3018
3019
    /**
3020
     * STDEV
3021
     *
3022
     * Estimates standard deviation based on a sample. The standard deviation is a measure of how
3023
     *        widely values are dispersed from the average value (the mean).
3024
     *
3025
     * Excel Function:
3026
     *        STDEV(value1[,value2[, ...]])
3027
     *
3028
     * @category Statistical Functions
3029
     * @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...
3030
     * @return    float
3031
     */
3032 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...
3033
    {
3034
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3035
3036
        // Return value
3037
        $returnValue = null;
3038
3039
        $aMean = self::AVERAGE($aArgs);
3040
        if (!is_null($aMean)) {
3041
            $aCount = -1;
3042
            foreach ($aArgs as $k => $arg) {
3043
                if ((is_bool($arg)) &&
3044
                    ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) {
3045
                    $arg = (integer) $arg;
3046
                }
3047
                // Is it a numeric value?
3048
                if ((is_numeric($arg)) && (!is_string($arg))) {
3049
                    if (is_null($returnValue)) {
3050
                        $returnValue = pow(($arg - $aMean), 2);
3051
                    } else {
3052
                        $returnValue += pow(($arg - $aMean), 2);
3053
                    }
3054
                    ++$aCount;
3055
                }
3056
            }
3057
3058
            // Return
3059
            if (($aCount > 0) && ($returnValue >= 0)) {
3060
                return sqrt($returnValue / $aCount);
3061
            }
3062
        }
3063
3064
        return Functions::DIV0();
3065
    }
3066
3067
    /**
3068
     * STDEVA
3069
     *
3070
     * Estimates standard deviation based on a sample, including numbers, text, and logical values
3071
     *
3072
     * Excel Function:
3073
     *        STDEVA(value1[,value2[, ...]])
3074
     *
3075
     * @category Statistical Functions
3076
     * @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...
3077
     * @return    float
3078
     */
3079 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...
3080
    {
3081
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3082
3083
        $returnValue = null;
3084
3085
        $aMean = self::AVERAGEA($aArgs);
3086
        if (!is_null($aMean)) {
3087
            $aCount = -1;
3088
            foreach ($aArgs as $k => $arg) {
3089
                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...
3090
                    (!Functions::isMatrixValue($k))) {
3091
                } else {
3092
                    // Is it a numeric value?
3093
                    if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
3094
                        if (is_bool($arg)) {
3095
                            $arg = (integer) $arg;
3096
                        } elseif (is_string($arg)) {
3097
                            $arg = 0;
3098
                        }
3099
                        if (is_null($returnValue)) {
3100
                            $returnValue = pow(($arg - $aMean), 2);
3101
                        } else {
3102
                            $returnValue += pow(($arg - $aMean), 2);
3103
                        }
3104
                        ++$aCount;
3105
                    }
3106
                }
3107
            }
3108
3109
            if (($aCount > 0) && ($returnValue >= 0)) {
3110
                return sqrt($returnValue / $aCount);
3111
            }
3112
        }
3113
3114
        return Functions::DIV0();
3115
    }
3116
3117
    /**
3118
     * STDEVP
3119
     *
3120
     * Calculates standard deviation based on the entire population
3121
     *
3122
     * Excel Function:
3123
     *        STDEVP(value1[,value2[, ...]])
3124
     *
3125
     * @category Statistical Functions
3126
     * @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...
3127
     * @return    float
3128
     */
3129 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...
3130
    {
3131
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3132
3133
        $returnValue = null;
3134
3135
        $aMean = self::AVERAGE($aArgs);
3136
        if (!is_null($aMean)) {
3137
            $aCount = 0;
3138
            foreach ($aArgs as $k => $arg) {
3139
                if ((is_bool($arg)) &&
3140
                    ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) {
3141
                    $arg = (integer) $arg;
3142
                }
3143
                // Is it a numeric value?
3144
                if ((is_numeric($arg)) && (!is_string($arg))) {
3145
                    if (is_null($returnValue)) {
3146
                        $returnValue = pow(($arg - $aMean), 2);
3147
                    } else {
3148
                        $returnValue += pow(($arg - $aMean), 2);
3149
                    }
3150
                    ++$aCount;
3151
                }
3152
            }
3153
3154
            if (($aCount > 0) && ($returnValue >= 0)) {
3155
                return sqrt($returnValue / $aCount);
3156
            }
3157
        }
3158
3159
        return Functions::DIV0();
3160
    }
3161
3162
    /**
3163
     * STDEVPA
3164
     *
3165
     * Calculates standard deviation based on the entire population, including numbers, text, and logical values
3166
     *
3167
     * Excel Function:
3168
     *        STDEVPA(value1[,value2[, ...]])
3169
     *
3170
     * @category Statistical Functions
3171
     * @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...
3172
     * @return    float
3173
     */
3174 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...
3175
    {
3176
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3177
3178
        $returnValue = null;
3179
3180
        $aMean = self::AVERAGEA($aArgs);
3181
        if (!is_null($aMean)) {
3182
            $aCount = 0;
3183
            foreach ($aArgs as $k => $arg) {
3184
                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...
3185
                    (!Functions::isMatrixValue($k))) {
3186
                } else {
3187
                    // Is it a numeric value?
3188
                    if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
3189
                        if (is_bool($arg)) {
3190
                            $arg = (integer) $arg;
3191
                        } elseif (is_string($arg)) {
3192
                            $arg = 0;
3193
                        }
3194
                        if (is_null($returnValue)) {
3195
                            $returnValue = pow(($arg - $aMean), 2);
3196
                        } else {
3197
                            $returnValue += pow(($arg - $aMean), 2);
3198
                        }
3199
                        ++$aCount;
3200
                    }
3201
                }
3202
            }
3203
3204
            if (($aCount > 0) && ($returnValue >= 0)) {
3205
                return sqrt($returnValue / $aCount);
3206
            }
3207
        }
3208
3209
        return Functions::DIV0();
3210
    }
3211
3212
    /**
3213
     * STEYX
3214
     *
3215
     * Returns the standard error of the predicted y-value for each x in the regression.
3216
     *
3217
     * @param    array of mixed        Data Series Y
3218
     * @param    array of mixed        Data Series X
3219
     * @return    float
3220
     */
3221 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...
3222
    {
3223
        if (!self::checkTrendArrays($yValues, $xValues)) {
3224
            return Functions::VALUE();
3225
        }
3226
        $yValueCount = count($yValues);
3227
        $xValueCount = count($xValues);
3228
3229
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
3230
            return Functions::NA();
3231
        } elseif ($yValueCount == 1) {
3232
            return Functions::DIV0();
3233
        }
3234
3235
        $bestFitLinear = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues);
3236
3237
        return $bestFitLinear->getStdevOfResiduals();
3238
    }
3239
3240
    /**
3241
     * TDIST
3242
     *
3243
     * Returns the probability of Student's T distribution.
3244
     *
3245
     * @param    float        $value            Value for the function
3246
     * @param    float        $degrees        degrees of freedom
3247
     * @param    float        $tails            number of tails (1 or 2)
3248
     * @return    float
3249
     */
3250
    public static function TDIST($value, $degrees, $tails)
3251
    {
3252
        $value = Functions::flattenSingleValue($value);
3253
        $degrees = floor(Functions::flattenSingleValue($degrees));
3254
        $tails = floor(Functions::flattenSingleValue($tails));
3255
3256
        if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) {
3257
            if (($value < 0) || ($degrees < 1) || ($tails < 1) || ($tails > 2)) {
3258
                return Functions::NAN();
3259
            }
3260
            //    tdist, which finds the probability that corresponds to a given value
3261
            //    of t with k degrees of freedom. This algorithm is translated from a
3262
            //    pascal function on p81 of "Statistical Computing in Pascal" by D
3263
            //    Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd:
3264
            //    London). The above Pascal algorithm is itself a translation of the
3265
            //    fortran algoritm "AS 3" by B E Cooper of the Atlas Computer
3266
            //    Laboratory as reported in (among other places) "Applied Statistics
3267
            //    Algorithms", editied by P Griffiths and I D Hill (1985; Ellis
3268
            //    Horwood Ltd.; W. Sussex, England).
3269
            $tterm = $degrees;
3270
            $ttheta = atan2($value, sqrt($tterm));
3271
            $tc = cos($ttheta);
3272
            $ts = sin($ttheta);
3273
            $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...
3274
3275
            if (($degrees % 2) == 1) {
3276
                $ti = 3;
3277
                $tterm = $tc;
3278
            } else {
3279
                $ti = 2;
3280
                $tterm = 1;
3281
            }
3282
3283
            $tsum = $tterm;
3284
            while ($ti < $degrees) {
3285
                $tterm *= $tc * $tc * ($ti - 1) / $ti;
3286
                $tsum += $tterm;
3287
                $ti += 2;
3288
            }
3289
            $tsum *= $ts;
3290
            if (($degrees % 2) == 1) {
3291
                $tsum = M_2DIVPI * ($tsum + $ttheta);
3292
            }
3293
            $tValue = 0.5 * (1 + $tsum);
3294
            if ($tails == 1) {
3295
                return 1 - abs($tValue);
3296
            } else {
3297
                return 1 - abs((1 - $tValue) - $tValue);
3298
            }
3299
        }
3300
3301
        return Functions::VALUE();
3302
    }
3303
3304
    /**
3305
     * TINV
3306
     *
3307
     * Returns the one-tailed probability of the chi-squared distribution.
3308
     *
3309
     * @param    float        $probability    Probability for the function
3310
     * @param    float        $degrees        degrees of freedom
3311
     * @return    float
3312
     */
3313 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...
3314
    {
3315
        $probability = Functions::flattenSingleValue($probability);
3316
        $degrees = floor(Functions::flattenSingleValue($degrees));
3317
3318
        if ((is_numeric($probability)) && (is_numeric($degrees))) {
3319
            $xLo = 100;
3320
            $xHi = 0;
3321
3322
            $x = $xNew = 1;
3323
            $dx = 1;
3324
            $i = 0;
3325
3326
            while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
3327
                // Apply Newton-Raphson step
3328
                $result = self::TDIST($x, $degrees, 2);
3329
                $error = $result - $probability;
3330
                if ($error == 0.0) {
3331
                    $dx = 0;
3332
                } elseif ($error < 0.0) {
3333
                    $xLo = $x;
3334
                } else {
3335
                    $xHi = $x;
3336
                }
3337
                // Avoid division by zero
3338
                if ($result != 0.0) {
3339
                    $dx = $error / $result;
3340
                    $xNew = $x - $dx;
3341
                }
3342
                // If the NR fails to converge (which for example may be the
3343
                // case if the initial guess is too rough) we apply a bisection
3344
                // step to determine a more narrow interval around the root.
3345
                if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
3346
                    $xNew = ($xLo + $xHi) / 2;
3347
                    $dx = $xNew - $x;
3348
                }
3349
                $x = $xNew;
3350
            }
3351
            if ($i == MAX_ITERATIONS) {
3352
                return Functions::NA();
3353
            }
3354
3355
            return round($x, 12);
3356
        }
3357
3358
        return Functions::VALUE();
3359
    }
3360
3361
    /**
3362
     * TREND
3363
     *
3364
     * Returns values along a linear Trend
3365
     *
3366
     * @param    array of mixed        Data Series Y
3367
     * @param    array of mixed        Data Series X
3368
     * @param    array of mixed        Values of X for which we want to find Y
3369
     * @param    bool                A logical value specifying whether to force the intersect to equal 0.
3370
     * @return    array of float
3371
     */
3372 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...
3373
    {
3374
        $yValues = Functions::flattenArray($yValues);
3375
        $xValues = Functions::flattenArray($xValues);
3376
        $newValues = Functions::flattenArray($newValues);
3377
        $const = (is_null($const)) ? true : (boolean) Functions::flattenSingleValue($const);
3378
3379
        $bestFitLinear = \PhpOffice\PhpSpreadsheet\Shared\trend\trend::calculate(\PhpOffice\PhpSpreadsheet\Shared\trend\trend::TREND_LINEAR, $yValues, $xValues, $const);
3380
        if (empty($newValues)) {
3381
            $newValues = $bestFitLinear->getXValues();
3382
        }
3383
3384
        $returnArray = [];
3385
        foreach ($newValues as $xValue) {
3386
            $returnArray[0][] = $bestFitLinear->getValueOfYForX($xValue);
3387
        }
3388
3389
        return $returnArray;
3390
    }
3391
3392
    /**
3393
     * TRIMMEAN
3394
     *
3395
     * Returns the mean of the interior of a data set. TRIMMEAN calculates the mean
3396
     *        taken by excluding a percentage of data points from the top and bottom tails
3397
     *        of a data set.
3398
     *
3399
     * Excel Function:
3400
     *        TRIMEAN(value1[,value2[, ...]], $discard)
3401
     *
3402
     * @category Statistical Functions
3403
     * @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...
3404
     * @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...
3405
     * @return    float
3406
     */
3407
    public static function TRIMMEAN()
3408
    {
3409
        $aArgs = Functions::flattenArray(func_get_args());
3410
3411
        // Calculate
3412
        $percent = array_pop($aArgs);
3413
3414
        if ((is_numeric($percent)) && (!is_string($percent))) {
3415
            if (($percent < 0) || ($percent > 1)) {
3416
                return Functions::NAN();
3417
            }
3418
            $mArgs = [];
3419
            foreach ($aArgs as $arg) {
3420
                // Is it a numeric value?
3421
                if ((is_numeric($arg)) && (!is_string($arg))) {
3422
                    $mArgs[] = $arg;
3423
                }
3424
            }
3425
            $discard = floor(self::COUNT($mArgs) * $percent / 2);
3426
            sort($mArgs);
3427
            for ($i = 0; $i < $discard; ++$i) {
3428
                array_pop($mArgs);
3429
                array_shift($mArgs);
3430
            }
3431
3432
            return self::AVERAGE($mArgs);
3433
        }
3434
3435
        return Functions::VALUE();
3436
    }
3437
3438
    /**
3439
     * VARFunc
3440
     *
3441
     * Estimates variance based on a sample.
3442
     *
3443
     * Excel Function:
3444
     *        VAR(value1[,value2[, ...]])
3445
     *
3446
     * @category Statistical Functions
3447
     * @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...
3448
     * @return    float
3449
     */
3450 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...
3451
    {
3452
        $returnValue = Functions::DIV0();
3453
3454
        $summerA = $summerB = 0;
3455
3456
        // Loop through arguments
3457
        $aArgs = Functions::flattenArray(func_get_args());
3458
        $aCount = 0;
3459
        foreach ($aArgs as $arg) {
3460
            if (is_bool($arg)) {
3461
                $arg = (integer) $arg;
3462
            }
3463
            // Is it a numeric value?
3464
            if ((is_numeric($arg)) && (!is_string($arg))) {
3465
                $summerA += ($arg * $arg);
3466
                $summerB += $arg;
3467
                ++$aCount;
3468
            }
3469
        }
3470
3471
        if ($aCount > 1) {
3472
            $summerA *= $aCount;
3473
            $summerB *= $summerB;
3474
            $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
3475
        }
3476
3477
        return $returnValue;
3478
    }
3479
3480
    /**
3481
     * VARA
3482
     *
3483
     * Estimates variance based on a sample, including numbers, text, and logical values
3484
     *
3485
     * Excel Function:
3486
     *        VARA(value1[,value2[, ...]])
3487
     *
3488
     * @category Statistical Functions
3489
     * @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...
3490
     * @return    float
3491
     */
3492 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...
3493
    {
3494
        $returnValue = Functions::DIV0();
3495
3496
        $summerA = $summerB = 0;
3497
3498
        // Loop through arguments
3499
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3500
        $aCount = 0;
3501
        foreach ($aArgs as $k => $arg) {
3502
            if ((is_string($arg)) &&
3503
                (Functions::isValue($k))) {
3504
                return Functions::VALUE();
3505
            } 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...
3506
                (!Functions::isMatrixValue($k))) {
3507
            } else {
3508
                // Is it a numeric value?
3509
                if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
3510
                    if (is_bool($arg)) {
3511
                        $arg = (integer) $arg;
3512
                    } elseif (is_string($arg)) {
3513
                        $arg = 0;
3514
                    }
3515
                    $summerA += ($arg * $arg);
3516
                    $summerB += $arg;
3517
                    ++$aCount;
3518
                }
3519
            }
3520
        }
3521
3522
        if ($aCount > 1) {
3523
            $summerA *= $aCount;
3524
            $summerB *= $summerB;
3525
            $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
3526
        }
3527
3528
        return $returnValue;
3529
    }
3530
3531
    /**
3532
     * VARP
3533
     *
3534
     * Calculates variance based on the entire population
3535
     *
3536
     * Excel Function:
3537
     *        VARP(value1[,value2[, ...]])
3538
     *
3539
     * @category Statistical Functions
3540
     * @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...
3541
     * @return    float
3542
     */
3543 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...
3544
    {
3545
        // Return value
3546
        $returnValue = Functions::DIV0();
3547
3548
        $summerA = $summerB = 0;
3549
3550
        // Loop through arguments
3551
        $aArgs = Functions::flattenArray(func_get_args());
3552
        $aCount = 0;
3553
        foreach ($aArgs as $arg) {
3554
            if (is_bool($arg)) {
3555
                $arg = (integer) $arg;
3556
            }
3557
            // Is it a numeric value?
3558
            if ((is_numeric($arg)) && (!is_string($arg))) {
3559
                $summerA += ($arg * $arg);
3560
                $summerB += $arg;
3561
                ++$aCount;
3562
            }
3563
        }
3564
3565
        if ($aCount > 0) {
3566
            $summerA *= $aCount;
3567
            $summerB *= $summerB;
3568
            $returnValue = ($summerA - $summerB) / ($aCount * $aCount);
3569
        }
3570
3571
        return $returnValue;
3572
    }
3573
3574
    /**
3575
     * VARPA
3576
     *
3577
     * Calculates variance based on the entire population, including numbers, text, and logical values
3578
     *
3579
     * Excel Function:
3580
     *        VARPA(value1[,value2[, ...]])
3581
     *
3582
     * @category Statistical Functions
3583
     * @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...
3584
     * @return    float
3585
     */
3586 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...
3587
    {
3588
        $returnValue = Functions::DIV0();
3589
3590
        $summerA = $summerB = 0;
3591
3592
        // Loop through arguments
3593
        $aArgs = Functions::flattenArrayIndexed(func_get_args());
3594
        $aCount = 0;
3595
        foreach ($aArgs as $k => $arg) {
3596
            if ((is_string($arg)) &&
3597
                (Functions::isValue($k))) {
3598
                return Functions::VALUE();
3599
            } 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...
3600
                (!Functions::isMatrixValue($k))) {
3601
            } else {
3602
                // Is it a numeric value?
3603
                if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
3604
                    if (is_bool($arg)) {
3605
                        $arg = (integer) $arg;
3606
                    } elseif (is_string($arg)) {
3607
                        $arg = 0;
3608
                    }
3609
                    $summerA += ($arg * $arg);
3610
                    $summerB += $arg;
3611
                    ++$aCount;
3612
                }
3613
            }
3614
        }
3615
3616
        if ($aCount > 0) {
3617
            $summerA *= $aCount;
3618
            $summerB *= $summerB;
3619
            $returnValue = ($summerA - $summerB) / ($aCount * $aCount);
3620
        }
3621
3622
        return $returnValue;
3623
    }
3624
3625
    /**
3626
     * WEIBULL
3627
     *
3628
     * Returns the Weibull distribution. Use this distribution in reliability
3629
     * analysis, such as calculating a device's mean time to failure.
3630
     *
3631
     * @param    float        $value
3632
     * @param    float        $alpha        Alpha Parameter
3633
     * @param    float        $beta        Beta Parameter
3634
     * @param    bool        $cumulative
3635
     * @return    float
3636
     */
3637
    public static function WEIBULL($value, $alpha, $beta, $cumulative)
3638
    {
3639
        $value = Functions::flattenSingleValue($value);
3640
        $alpha = Functions::flattenSingleValue($alpha);
3641
        $beta = Functions::flattenSingleValue($beta);
3642
3643
        if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) {
3644
            if (($value < 0) || ($alpha <= 0) || ($beta <= 0)) {
3645
                return Functions::NAN();
3646
            }
3647
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
3648
                if ($cumulative) {
3649
                    return 1 - exp(0 - pow($value / $beta, $alpha));
3650
                } else {
3651
                    return ($alpha / pow($beta, $alpha)) * pow($value, $alpha - 1) * exp(0 - pow($value / $beta, $alpha));
3652
                }
3653
            }
3654
        }
3655
3656
        return Functions::VALUE();
3657
    }
3658
3659
    /**
3660
     * ZTEST
3661
     *
3662
     * Returns the Weibull distribution. Use this distribution in reliability
3663
     * analysis, such as calculating a device's mean time to failure.
3664
     *
3665
     * @param    float        $dataSet
3666
     * @param    float        $m0        Alpha Parameter
3667
     * @param    float        $sigma    Beta Parameter
3668
     * @return    float
3669
     */
3670
    public static function ZTEST($dataSet, $m0, $sigma = null)
3671
    {
3672
        $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...
3673
        $m0 = Functions::flattenSingleValue($m0);
3674
        $sigma = Functions::flattenSingleValue($sigma);
3675
3676
        if (is_null($sigma)) {
3677
            $sigma = self::STDEV($dataSet);
3678
        }
3679
        $n = count($dataSet);
3680
3681
        return 1 - self::NORMSDIST((self::AVERAGE($dataSet) - $m0) / ($sigma / SQRT($n)));
3682
    }
3683
}
3684