~begerega/ihris-chw-sl/trunk

« back to all changes in this revision

Viewing changes to tools/PHPExcel/PHPExcel/Calculation/Statistical.php

  • Committer: Ese Egerega
  • Date: 2018-05-03 14:17:04 UTC
  • Revision ID: egerega@gmail.com-20180503141704-3br8dto013rgx65x
Initial import of Sierra Leone  CHW registry

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
/** PHPExcel root directory */
 
4
if (!defined('PHPEXCEL_ROOT')) {
 
5
    /**
 
6
     * @ignore
 
7
     */
 
8
    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
 
9
    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
 
10
}
 
11
 
 
12
 
 
13
require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/trend/trendClass.php';
 
14
 
 
15
 
 
16
/** LOG_GAMMA_X_MAX_VALUE */
 
17
define('LOG_GAMMA_X_MAX_VALUE', 2.55e305);
 
18
 
 
19
/** XMININ */
 
20
define('XMININ', 2.23e-308);
 
21
 
 
22
/** EPS */
 
23
define('EPS', 2.22e-16);
 
24
 
 
25
/** SQRT2PI */
 
26
define('SQRT2PI', 2.5066282746310005024157652848110452530069867406099);
 
27
 
 
28
/**
 
29
 * PHPExcel_Calculation_Statistical
 
30
 *
 
31
 * Copyright (c) 2006 - 2015 PHPExcel
 
32
 *
 
33
 * This library is free software; you can redistribute it and/or
 
34
 * modify it under the terms of the GNU Lesser General Public
 
35
 * License as published by the Free Software Foundation; either
 
36
 * version 2.1 of the License, or (at your option) any later version.
 
37
 *
 
38
 * This library is distributed in the hope that it will be useful,
 
39
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
40
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 
41
 * Lesser General Public License for more details.
 
42
 *
 
43
 * You should have received a copy of the GNU Lesser General Public
 
44
 * License along with this library; if not, write to the Free Software
 
45
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
46
 *
 
47
 * @category    PHPExcel
 
48
 * @package        PHPExcel_Calculation
 
49
 * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
 
50
 * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
 
51
 * @version        ##VERSION##, ##DATE##
 
52
 */
 
53
class PHPExcel_Calculation_Statistical
 
54
{
 
55
    private static function checkTrendArrays(&$array1, &$array2)
 
56
    {
 
57
        if (!is_array($array1)) {
 
58
            $array1 = array($array1);
 
59
        }
 
60
        if (!is_array($array2)) {
 
61
            $array2 = array($array2);
 
62
        }
 
63
 
 
64
        $array1 = PHPExcel_Calculation_Functions::flattenArray($array1);
 
65
        $array2 = PHPExcel_Calculation_Functions::flattenArray($array2);
 
66
        foreach ($array1 as $key => $value) {
 
67
            if ((is_bool($value)) || (is_string($value)) || (is_null($value))) {
 
68
                unset($array1[$key]);
 
69
                unset($array2[$key]);
 
70
            }
 
71
        }
 
72
        foreach ($array2 as $key => $value) {
 
73
            if ((is_bool($value)) || (is_string($value)) || (is_null($value))) {
 
74
                unset($array1[$key]);
 
75
                unset($array2[$key]);
 
76
            }
 
77
        }
 
78
        $array1 = array_merge($array1);
 
79
        $array2 = array_merge($array2);
 
80
 
 
81
        return true;
 
82
    }
 
83
 
 
84
 
 
85
    /**
 
86
     * Beta function.
 
87
     *
 
88
     * @author Jaco van Kooten
 
89
     *
 
90
     * @param p require p>0
 
91
     * @param q require q>0
 
92
     * @return 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
 
93
     */
 
94
    private static function beta($p, $q)
 
95
    {
 
96
        if ($p <= 0.0 || $q <= 0.0 || ($p + $q) > LOG_GAMMA_X_MAX_VALUE) {
 
97
            return 0.0;
 
98
        } else {
 
99
            return exp(self::logBeta($p, $q));
 
100
        }
 
101
    }
 
102
 
 
103
 
 
104
    /**
 
105
     * Incomplete beta function
 
106
     *
 
107
     * @author Jaco van Kooten
 
108
     * @author Paul Meagher
 
109
     *
 
110
     * The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992).
 
111
     * @param x require 0<=x<=1
 
112
     * @param p require p>0
 
113
     * @param q require q>0
 
114
     * @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
 
115
     */
 
116
    private static function incompleteBeta($x, $p, $q)
 
117
    {
 
118
        if ($x <= 0.0) {
 
119
            return 0.0;
 
120
        } elseif ($x >= 1.0) {
 
121
            return 1.0;
 
122
        } elseif (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) {
 
123
            return 0.0;
 
124
        }
 
125
        $beta_gam = exp((0 - self::logBeta($p, $q)) + $p * log($x) + $q * log(1.0 - $x));
 
126
        if ($x < ($p + 1.0) / ($p + $q + 2.0)) {
 
127
            return $beta_gam * self::betaFraction($x, $p, $q) / $p;
 
128
        } else {
 
129
            return 1.0 - ($beta_gam * self::betaFraction(1 - $x, $q, $p) / $q);
 
130
        }
 
131
    }
 
132
 
 
133
 
 
134
    // Function cache for logBeta function
 
135
    private static $logBetaCacheP      = 0.0;
 
136
    private static $logBetaCacheQ      = 0.0;
 
137
    private static $logBetaCacheResult = 0.0;
 
138
 
 
139
    /**
 
140
     * The natural logarithm of the beta function.
 
141
     *
 
142
     * @param p require p>0
 
143
     * @param q require q>0
 
144
     * @return 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
 
145
     * @author Jaco van Kooten
 
146
     */
 
147
    private static function logBeta($p, $q)
 
148
    {
 
149
        if ($p != self::$logBetaCacheP || $q != self::$logBetaCacheQ) {
 
150
            self::$logBetaCacheP = $p;
 
151
            self::$logBetaCacheQ = $q;
 
152
            if (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) {
 
153
                self::$logBetaCacheResult = 0.0;
 
154
            } else {
 
155
                self::$logBetaCacheResult = self::logGamma($p) + self::logGamma($q) - self::logGamma($p + $q);
 
156
            }
 
157
        }
 
158
        return self::$logBetaCacheResult;
 
159
    }
 
160
 
 
161
 
 
162
    /**
 
163
     * Evaluates of continued fraction part of incomplete beta function.
 
164
     * Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
 
165
     * @author Jaco van Kooten
 
166
     */
 
167
    private static function betaFraction($x, $p, $q)
 
168
    {
 
169
        $c = 1.0;
 
170
        $sum_pq = $p + $q;
 
171
        $p_plus = $p + 1.0;
 
172
        $p_minus = $p - 1.0;
 
173
        $h = 1.0 - $sum_pq * $x / $p_plus;
 
174
        if (abs($h) < XMININ) {
 
175
            $h = XMININ;
 
176
        }
 
177
        $h = 1.0 / $h;
 
178
        $frac = $h;
 
179
        $m     = 1;
 
180
        $delta = 0.0;
 
181
        while ($m <= MAX_ITERATIONS && abs($delta-1.0) > PRECISION) {
 
182
            $m2 = 2 * $m;
 
183
            // even index for d
 
184
            $d = $m * ($q - $m) * $x / ( ($p_minus + $m2) * ($p + $m2));
 
185
            $h = 1.0 + $d * $h;
 
186
            if (abs($h) < XMININ) {
 
187
                $h = XMININ;
 
188
            }
 
189
            $h = 1.0 / $h;
 
190
            $c = 1.0 + $d / $c;
 
191
            if (abs($c) < XMININ) {
 
192
                $c = XMININ;
 
193
            }
 
194
            $frac *= $h * $c;
 
195
            // odd index for d
 
196
            $d = -($p + $m) * ($sum_pq + $m) * $x / (($p + $m2) * ($p_plus + $m2));
 
197
            $h = 1.0 + $d * $h;
 
198
            if (abs($h) < XMININ) {
 
199
                $h = XMININ;
 
200
            }
 
201
            $h = 1.0 / $h;
 
202
            $c = 1.0 + $d / $c;
 
203
            if (abs($c) < XMININ) {
 
204
                $c = XMININ;
 
205
            }
 
206
            $delta = $h * $c;
 
207
            $frac *= $delta;
 
208
            ++$m;
 
209
        }
 
210
        return $frac;
 
211
    }
 
212
 
 
213
 
 
214
    /**
 
215
     * logGamma function
 
216
     *
 
217
     * @version 1.1
 
218
     * @author Jaco van Kooten
 
219
     *
 
220
     * Original author was Jaco van Kooten. Ported to PHP by Paul Meagher.
 
221
     *
 
222
     * The natural logarithm of the gamma function. <br />
 
223
     * Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz <br />
 
224
     * Applied Mathematics Division <br />
 
225
     * Argonne National Laboratory <br />
 
226
     * Argonne, IL 60439 <br />
 
227
     * <p>
 
228
     * References:
 
229
     * <ol>
 
230
     * <li>W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural
 
231
     *     Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.</li>
 
232
     * <li>K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.</li>
 
233
     * <li>Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.</li>
 
234
     * </ol>
 
235
     * </p>
 
236
     * <p>
 
237
     * From the original documentation:
 
238
     * </p>
 
239
     * <p>
 
240
     * This routine calculates the LOG(GAMMA) function for a positive real argument X.
 
241
     * Computation is based on an algorithm outlined in references 1 and 2.
 
242
     * The program uses rational functions that theoretically approximate LOG(GAMMA)
 
243
     * to at least 18 significant decimal digits. The approximation for X > 12 is from
 
244
     * reference 3, while approximations for X < 12.0 are similar to those in reference
 
245
     * 1, but are unpublished. The accuracy achieved depends on the arithmetic system,
 
246
     * the compiler, the intrinsic functions, and proper selection of the
 
247
     * machine-dependent constants.
 
248
     * </p>
 
249
     * <p>
 
250
     * Error returns: <br />
 
251
     * The program returns the value XINF for X .LE. 0.0 or when overflow would occur.
 
252
     * The computation is believed to be free of underflow and overflow.
 
253
     * </p>
 
254
     * @return MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305
 
255
     */
 
256
 
 
257
    // Function cache for logGamma
 
258
    private static $logGammaCacheResult = 0.0;
 
259
    private static $logGammaCacheX      = 0.0;
 
260
 
 
261
    private static function logGamma($x)
 
262
    {
 
263
        // Log Gamma related constants
 
264
        static $lg_d1 = -0.5772156649015328605195174;
 
265
        static $lg_d2 = 0.4227843350984671393993777;
 
266
        static $lg_d4 = 1.791759469228055000094023;
 
267
 
 
268
        static $lg_p1 = array(
 
269
            4.945235359296727046734888,
 
270
            201.8112620856775083915565,
 
271
            2290.838373831346393026739,
 
272
            11319.67205903380828685045,
 
273
            28557.24635671635335736389,
 
274
            38484.96228443793359990269,
 
275
            26377.48787624195437963534,
 
276
            7225.813979700288197698961
 
277
        );
 
278
        static $lg_p2 = array(
 
279
            4.974607845568932035012064,
 
280
            542.4138599891070494101986,
 
281
            15506.93864978364947665077,
 
282
            184793.2904445632425417223,
 
283
            1088204.76946882876749847,
 
284
            3338152.967987029735917223,
 
285
            5106661.678927352456275255,
 
286
            3074109.054850539556250927
 
287
        );
 
288
        static $lg_p4 = array(
 
289
            14745.02166059939948905062,
 
290
            2426813.369486704502836312,
 
291
            121475557.4045093227939592,
 
292
            2663432449.630976949898078,
 
293
            29403789566.34553899906876,
 
294
            170266573776.5398868392998,
 
295
            492612579337.743088758812,
 
296
            560625185622.3951465078242
 
297
        );
 
298
        static $lg_q1 = array(
 
299
            67.48212550303777196073036,
 
300
            1113.332393857199323513008,
 
301
            7738.757056935398733233834,
 
302
            27639.87074403340708898585,
 
303
            54993.10206226157329794414,
 
304
            61611.22180066002127833352,
 
305
            36351.27591501940507276287,
 
306
            8785.536302431013170870835
 
307
        );
 
308
        static $lg_q2 = array(
 
309
            183.0328399370592604055942,
 
310
            7765.049321445005871323047,
 
311
            133190.3827966074194402448,
 
312
            1136705.821321969608938755,
 
313
            5267964.117437946917577538,
 
314
            13467014.54311101692290052,
 
315
            17827365.30353274213975932,
 
316
            9533095.591844353613395747
 
317
        );
 
318
        static $lg_q4 = array(
 
319
            2690.530175870899333379843,
 
320
            639388.5654300092398984238,
 
321
            41355999.30241388052042842,
 
322
            1120872109.61614794137657,
 
323
            14886137286.78813811542398,
 
324
            101680358627.2438228077304,
 
325
            341747634550.7377132798597,
 
326
            446315818741.9713286462081
 
327
        );
 
328
        static $lg_c  = array(
 
329
            -0.001910444077728,
 
330
            8.4171387781295e-4,
 
331
            -5.952379913043012e-4,
 
332
            7.93650793500350248e-4,
 
333
            -0.002777777777777681622553,
 
334
            0.08333333333333333331554247,
 
335
            0.0057083835261
 
336
        );
 
337
 
 
338
        // Rough estimate of the fourth root of logGamma_xBig
 
339
        static $lg_frtbig = 2.25e76;
 
340
        static $pnt68     = 0.6796875;
 
341
 
 
342
 
 
343
        if ($x == self::$logGammaCacheX) {
 
344
            return self::$logGammaCacheResult;
 
345
        }
 
346
        $y = $x;
 
347
        if ($y > 0.0 && $y <= LOG_GAMMA_X_MAX_VALUE) {
 
348
            if ($y <= EPS) {
 
349
                $res = -log(y);
 
350
            } elseif ($y <= 1.5) {
 
351
                // ---------------------
 
352
                //    EPS .LT. X .LE. 1.5
 
353
                // ---------------------
 
354
                if ($y < $pnt68) {
 
355
                    $corr = -log($y);
 
356
                    $xm1 = $y;
 
357
                } else {
 
358
                    $corr = 0.0;
 
359
                    $xm1 = $y - 1.0;
 
360
                }
 
361
                if ($y <= 0.5 || $y >= $pnt68) {
 
362
                    $xden = 1.0;
 
363
                    $xnum = 0.0;
 
364
                    for ($i = 0; $i < 8; ++$i) {
 
365
                        $xnum = $xnum * $xm1 + $lg_p1[$i];
 
366
                        $xden = $xden * $xm1 + $lg_q1[$i];
 
367
                    }
 
368
                    $res = $corr + $xm1 * ($lg_d1 + $xm1 * ($xnum / $xden));
 
369
                } else {
 
370
                    $xm2 = $y - 1.0;
 
371
                    $xden = 1.0;
 
372
                    $xnum = 0.0;
 
373
                    for ($i = 0; $i < 8; ++$i) {
 
374
                        $xnum = $xnum * $xm2 + $lg_p2[$i];
 
375
                        $xden = $xden * $xm2 + $lg_q2[$i];
 
376
                    }
 
377
                    $res = $corr + $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden));
 
378
                }
 
379
            } elseif ($y <= 4.0) {
 
380
                // ---------------------
 
381
                //    1.5 .LT. X .LE. 4.0
 
382
                // ---------------------
 
383
                $xm2 = $y - 2.0;
 
384
                $xden = 1.0;
 
385
                $xnum = 0.0;
 
386
                for ($i = 0; $i < 8; ++$i) {
 
387
                    $xnum = $xnum * $xm2 + $lg_p2[$i];
 
388
                    $xden = $xden * $xm2 + $lg_q2[$i];
 
389
                }
 
390
                $res = $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden));
 
391
            } elseif ($y <= 12.0) {
 
392
                // ----------------------
 
393
                //    4.0 .LT. X .LE. 12.0
 
394
                // ----------------------
 
395
                $xm4 = $y - 4.0;
 
396
                $xden = -1.0;
 
397
                $xnum = 0.0;
 
398
                for ($i = 0; $i < 8; ++$i) {
 
399
                    $xnum = $xnum * $xm4 + $lg_p4[$i];
 
400
                    $xden = $xden * $xm4 + $lg_q4[$i];
 
401
                }
 
402
                $res = $lg_d4 + $xm4 * ($xnum / $xden);
 
403
            } else {
 
404
                // ---------------------------------
 
405
                //    Evaluate for argument .GE. 12.0
 
406
                // ---------------------------------
 
407
                $res = 0.0;
 
408
                if ($y <= $lg_frtbig) {
 
409
                    $res = $lg_c[6];
 
410
                    $ysq = $y * $y;
 
411
                    for ($i = 0; $i < 6; ++$i) {
 
412
                        $res = $res / $ysq + $lg_c[$i];
 
413
                    }
 
414
                    $res /= $y;
 
415
                    $corr = log($y);
 
416
                    $res = $res + log(SQRT2PI) - 0.5 * $corr;
 
417
                    $res += $y * ($corr - 1.0);
 
418
                }
 
419
            }
 
420
        } else {
 
421
            // --------------------------
 
422
            //    Return for bad arguments
 
423
            // --------------------------
 
424
            $res = MAX_VALUE;
 
425
        }
 
426
        // ------------------------------
 
427
        //    Final adjustments and return
 
428
        // ------------------------------
 
429
        self::$logGammaCacheX = $x;
 
430
        self::$logGammaCacheResult = $res;
 
431
        return $res;
 
432
    }
 
433
 
 
434
 
 
435
    //
 
436
    //    Private implementation of the incomplete Gamma function
 
437
    //
 
438
    private static function incompleteGamma($a, $x)
 
439
    {
 
440
        static $max = 32;
 
441
        $summer = 0;
 
442
        for ($n=0; $n<=$max; ++$n) {
 
443
            $divisor = $a;
 
444
            for ($i=1; $i<=$n; ++$i) {
 
445
                $divisor *= ($a + $i);
 
446
            }
 
447
            $summer += (pow($x, $n) / $divisor);
 
448
        }
 
449
        return pow($x, $a) * exp(0-$x) * $summer;
 
450
    }
 
451
 
 
452
 
 
453
    //
 
454
    //    Private implementation of the Gamma function
 
455
    //
 
456
    private static function gamma($data)
 
457
    {
 
458
        if ($data == 0.0) {
 
459
            return 0;
 
460
        }
 
461
 
 
462
        static $p0 = 1.000000000190015;
 
463
        static $p = array(
 
464
            1 => 76.18009172947146,
 
465
            2 => -86.50532032941677,
 
466
            3 => 24.01409824083091,
 
467
            4 => -1.231739572450155,
 
468
            5 => 1.208650973866179e-3,
 
469
            6 => -5.395239384953e-6
 
470
        );
 
471
 
 
472
        $y = $x = $data;
 
473
        $tmp = $x + 5.5;
 
474
        $tmp -= ($x + 0.5) * log($tmp);
 
475
 
 
476
        $summer = $p0;
 
477
        for ($j=1; $j<=6; ++$j) {
 
478
            $summer += ($p[$j] / ++$y);
 
479
        }
 
480
        return exp(0 - $tmp + log(SQRT2PI * $summer / $x));
 
481
    }
 
482
 
 
483
 
 
484
    /***************************************************************************
 
485
     *                                inverse_ncdf.php
 
486
     *                            -------------------
 
487
     *    begin                : Friday, January 16, 2004
 
488
     *    copyright            : (C) 2004 Michael Nickerson
 
489
     *    email                : nickersonm@yahoo.com
 
490
     *
 
491
     ***************************************************************************/
 
492
    private static function inverseNcdf($p)
 
493
    {
 
494
        //    Inverse ncdf approximation by Peter J. Acklam, implementation adapted to
 
495
        //    PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
 
496
        //    a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html
 
497
        //    I have not checked the accuracy of this implementation. Be aware that PHP
 
498
        //    will truncate the coeficcients to 14 digits.
 
499
 
 
500
        //    You have permission to use and distribute this function freely for
 
501
        //    whatever purpose you want, but please show common courtesy and give credit
 
502
        //    where credit is due.
 
503
 
 
504
        //    Input paramater is $p - probability - where 0 < p < 1.
 
505
 
 
506
        //    Coefficients in rational approximations
 
507
        static $a = array(
 
508
            1 => -3.969683028665376e+01,
 
509
            2 => 2.209460984245205e+02,
 
510
            3 => -2.759285104469687e+02,
 
511
            4 => 1.383577518672690e+02,
 
512
            5 => -3.066479806614716e+01,
 
513
            6 => 2.506628277459239e+00
 
514
        );
 
515
 
 
516
        static $b = array(
 
517
            1 => -5.447609879822406e+01,
 
518
            2 => 1.615858368580409e+02,
 
519
            3 => -1.556989798598866e+02,
 
520
            4 => 6.680131188771972e+01,
 
521
            5 => -1.328068155288572e+01
 
522
        );
 
523
 
 
524
        static $c = array(
 
525
            1 => -7.784894002430293e-03,
 
526
            2 => -3.223964580411365e-01,
 
527
            3 => -2.400758277161838e+00,
 
528
            4 => -2.549732539343734e+00,
 
529
            5 => 4.374664141464968e+00,
 
530
            6 => 2.938163982698783e+00
 
531
        );
 
532
 
 
533
        static $d = array(
 
534
            1 => 7.784695709041462e-03,
 
535
            2 => 3.224671290700398e-01,
 
536
            3 => 2.445134137142996e+00,
 
537
            4 => 3.754408661907416e+00
 
538
        );
 
539
 
 
540
        //    Define lower and upper region break-points.
 
541
        $p_low = 0.02425;            //Use lower region approx. below this
 
542
        $p_high = 1 - $p_low;        //Use upper region approx. above this
 
543
 
 
544
        if (0 < $p && $p < $p_low) {
 
545
            //    Rational approximation for lower region.
 
546
            $q = sqrt(-2 * log($p));
 
547
            return ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) /
 
548
                    (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1);
 
549
        } elseif ($p_low <= $p && $p <= $p_high) {
 
550
            //    Rational approximation for central region.
 
551
            $q = $p - 0.5;
 
552
            $r = $q * $q;
 
553
            return ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) * $r + $a[6]) * $q /
 
554
                   ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r + $b[4]) * $r + $b[5]) * $r + 1);
 
555
        } elseif ($p_high < $p && $p < 1) {
 
556
            //    Rational approximation for upper region.
 
557
            $q = sqrt(-2 * log(1 - $p));
 
558
            return -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) /
 
559
                     (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1);
 
560
        }
 
561
        //    If 0 < p < 1, return a null value
 
562
        return PHPExcel_Calculation_Functions::NULL();
 
563
    }
 
564
 
 
565
 
 
566
    private static function inverseNcdf2($prob)
 
567
    {
 
568
        //    Approximation of inverse standard normal CDF developed by
 
569
        //    B. Moro, "The Full Monte," Risk 8(2), Feb 1995, 57-58.
 
570
 
 
571
        $a1 = 2.50662823884;
 
572
        $a2 = -18.61500062529;
 
573
        $a3 = 41.39119773534;
 
574
        $a4 = -25.44106049637;
 
575
 
 
576
        $b1 = -8.4735109309;
 
577
        $b2 = 23.08336743743;
 
578
        $b3 = -21.06224101826;
 
579
        $b4 = 3.13082909833;
 
580
 
 
581
        $c1 = 0.337475482272615;
 
582
        $c2 = 0.976169019091719;
 
583
        $c3 = 0.160797971491821;
 
584
        $c4 = 2.76438810333863E-02;
 
585
        $c5 = 3.8405729373609E-03;
 
586
        $c6 = 3.951896511919E-04;
 
587
        $c7 = 3.21767881768E-05;
 
588
        $c8 = 2.888167364E-07;
 
589
        $c9 = 3.960315187E-07;
 
590
 
 
591
        $y = $prob - 0.5;
 
592
        if (abs($y) < 0.42) {
 
593
            $z = ($y * $y);
 
594
            $z = $y * ((($a4 * $z + $a3) * $z + $a2) * $z + $a1) / (((($b4 * $z + $b3) * $z + $b2) * $z + $b1) * $z + 1);
 
595
        } else {
 
596
            if ($y > 0) {
 
597
                $z = log(-log(1 - $prob));
 
598
            } else {
 
599
                $z = log(-log($prob));
 
600
            }
 
601
            $z = $c1 + $z * ($c2 + $z * ($c3 + $z * ($c4 + $z * ($c5 + $z * ($c6 + $z * ($c7 + $z * ($c8 + $z * $c9)))))));
 
602
            if ($y < 0) {
 
603
                $z = -$z;
 
604
            }
 
605
        }
 
606
        return $z;
 
607
    }    //    function inverseNcdf2()
 
608
 
 
609
 
 
610
    private static function inverseNcdf3($p)
 
611
    {
 
612
        //    ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3.
 
613
        //    Produces the normal deviate Z corresponding to a given lower
 
614
        //    tail area of P; Z is accurate to about 1 part in 10**16.
 
615
        //
 
616
        //    This is a PHP version of the original FORTRAN code that can
 
617
        //    be found at http://lib.stat.cmu.edu/apstat/
 
618
        $split1 = 0.425;
 
619
        $split2 = 5;
 
620
        $const1 = 0.180625;
 
621
        $const2 = 1.6;
 
622
 
 
623
        //    coefficients for p close to 0.5
 
624
        $a0 = 3.3871328727963666080;
 
625
        $a1 = 1.3314166789178437745E+2;
 
626
        $a2 = 1.9715909503065514427E+3;
 
627
        $a3 = 1.3731693765509461125E+4;
 
628
        $a4 = 4.5921953931549871457E+4;
 
629
        $a5 = 6.7265770927008700853E+4;
 
630
        $a6 = 3.3430575583588128105E+4;
 
631
        $a7 = 2.5090809287301226727E+3;
 
632
 
 
633
        $b1 = 4.2313330701600911252E+1;
 
634
        $b2 = 6.8718700749205790830E+2;
 
635
        $b3 = 5.3941960214247511077E+3;
 
636
        $b4 = 2.1213794301586595867E+4;
 
637
        $b5 = 3.9307895800092710610E+4;
 
638
        $b6 = 2.8729085735721942674E+4;
 
639
        $b7 = 5.2264952788528545610E+3;
 
640
 
 
641
        //    coefficients for p not close to 0, 0.5 or 1.
 
642
        $c0 = 1.42343711074968357734;
 
643
        $c1 = 4.63033784615654529590;
 
644
        $c2 = 5.76949722146069140550;
 
645
        $c3 = 3.64784832476320460504;
 
646
        $c4 = 1.27045825245236838258;
 
647
        $c5 = 2.41780725177450611770E-1;
 
648
        $c6 = 2.27238449892691845833E-2;
 
649
        $c7 = 7.74545014278341407640E-4;
 
650
 
 
651
        $d1 = 2.05319162663775882187;
 
652
        $d2 = 1.67638483018380384940;
 
653
        $d3 = 6.89767334985100004550E-1;
 
654
        $d4 = 1.48103976427480074590E-1;
 
655
        $d5 = 1.51986665636164571966E-2;
 
656
        $d6 = 5.47593808499534494600E-4;
 
657
        $d7 = 1.05075007164441684324E-9;
 
658
 
 
659
        //    coefficients for p near 0 or 1.
 
660
        $e0 = 6.65790464350110377720;
 
661
        $e1 = 5.46378491116411436990;
 
662
        $e2 = 1.78482653991729133580;
 
663
        $e3 = 2.96560571828504891230E-1;
 
664
        $e4 = 2.65321895265761230930E-2;
 
665
        $e5 = 1.24266094738807843860E-3;
 
666
        $e6 = 2.71155556874348757815E-5;
 
667
        $e7 = 2.01033439929228813265E-7;
 
668
 
 
669
        $f1 = 5.99832206555887937690E-1;
 
670
        $f2 = 1.36929880922735805310E-1;
 
671
        $f3 = 1.48753612908506148525E-2;
 
672
        $f4 = 7.86869131145613259100E-4;
 
673
        $f5 = 1.84631831751005468180E-5;
 
674
        $f6 = 1.42151175831644588870E-7;
 
675
        $f7 = 2.04426310338993978564E-15;
 
676
 
 
677
        $q = $p - 0.5;
 
678
 
 
679
        //    computation for p close to 0.5
 
680
        if (abs($q) <= split1) {
 
681
            $R = $const1 - $q * $q;
 
682
            $z = $q * ((((((($a7 * $R + $a6) * $R + $a5) * $R + $a4) * $R + $a3) * $R + $a2) * $R + $a1) * $R + $a0) /
 
683
                      ((((((($b7 * $R + $b6) * $R + $b5) * $R + $b4) * $R + $b3) * $R + $b2) * $R + $b1) * $R + 1);
 
684
        } else {
 
685
            if ($q < 0) {
 
686
                $R = $p;
 
687
            } else {
 
688
                $R = 1 - $p;
 
689
            }
 
690
            $R = pow(-log($R), 2);
 
691
 
 
692
            //    computation for p not close to 0, 0.5 or 1.
 
693
            if ($R <= $split2) {
 
694
                $R = $R - $const2;
 
695
                $z = ((((((($c7 * $R + $c6) * $R + $c5) * $R + $c4) * $R + $c3) * $R + $c2) * $R + $c1) * $R + $c0) /
 
696
                     ((((((($d7 * $R + $d6) * $R + $d5) * $R + $d4) * $R + $d3) * $R + $d2) * $R + $d1) * $R + 1);
 
697
            } else {
 
698
            //    computation for p near 0 or 1.
 
699
                $R = $R - $split2;
 
700
                $z = ((((((($e7 * $R + $e6) * $R + $e5) * $R + $e4) * $R + $e3) * $R + $e2) * $R + $e1) * $R + $e0) /
 
701
                     ((((((($f7 * $R + $f6) * $R + $f5) * $R + $f4) * $R + $f3) * $R + $f2) * $R + $f1) * $R + 1);
 
702
            }
 
703
            if ($q < 0) {
 
704
                $z = -$z;
 
705
            }
 
706
        }
 
707
        return $z;
 
708
    }
 
709
 
 
710
 
 
711
    /**
 
712
     * AVEDEV
 
713
     *
 
714
     * Returns the average of the absolute deviations of data points from their mean.
 
715
     * AVEDEV is a measure of the variability in a data set.
 
716
     *
 
717
     * Excel Function:
 
718
     *        AVEDEV(value1[,value2[, ...]])
 
719
     *
 
720
     * @access    public
 
721
     * @category Statistical Functions
 
722
     * @param    mixed        $arg,...        Data values
 
723
     * @return    float
 
724
     */
 
725
    public static function AVEDEV()
 
726
    {
 
727
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
728
 
 
729
        // Return value
 
730
        $returnValue = null;
 
731
 
 
732
        $aMean = self::AVERAGE($aArgs);
 
733
        if ($aMean != PHPExcel_Calculation_Functions::DIV0()) {
 
734
            $aCount = 0;
 
735
            foreach ($aArgs as $k => $arg) {
 
736
                if ((is_bool($arg)) &&
 
737
                    ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
 
738
                    $arg = (integer) $arg;
 
739
                }
 
740
                // Is it a numeric value?
 
741
                if ((is_numeric($arg)) && (!is_string($arg))) {
 
742
                    if (is_null($returnValue)) {
 
743
                        $returnValue = abs($arg - $aMean);
 
744
                    } else {
 
745
                        $returnValue += abs($arg - $aMean);
 
746
                    }
 
747
                    ++$aCount;
 
748
                }
 
749
            }
 
750
 
 
751
            // Return
 
752
            if ($aCount == 0) {
 
753
                return PHPExcel_Calculation_Functions::DIV0();
 
754
            }
 
755
            return $returnValue / $aCount;
 
756
        }
 
757
        return PHPExcel_Calculation_Functions::NaN();
 
758
    }
 
759
 
 
760
 
 
761
    /**
 
762
     * AVERAGE
 
763
     *
 
764
     * Returns the average (arithmetic mean) of the arguments
 
765
     *
 
766
     * Excel Function:
 
767
     *        AVERAGE(value1[,value2[, ...]])
 
768
     *
 
769
     * @access    public
 
770
     * @category Statistical Functions
 
771
     * @param    mixed        $arg,...        Data values
 
772
     * @return    float
 
773
     */
 
774
    public static function AVERAGE()
 
775
    {
 
776
        $returnValue = $aCount = 0;
 
777
 
 
778
        // Loop through arguments
 
779
        foreach (PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()) as $k => $arg) {
 
780
            if ((is_bool($arg)) &&
 
781
                ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
 
782
                $arg = (integer) $arg;
 
783
            }
 
784
            // Is it a numeric value?
 
785
            if ((is_numeric($arg)) && (!is_string($arg))) {
 
786
                if (is_null($returnValue)) {
 
787
                    $returnValue = $arg;
 
788
                } else {
 
789
                    $returnValue += $arg;
 
790
                }
 
791
                ++$aCount;
 
792
            }
 
793
        }
 
794
 
 
795
        // Return
 
796
        if ($aCount > 0) {
 
797
            return $returnValue / $aCount;
 
798
        } else {
 
799
            return PHPExcel_Calculation_Functions::DIV0();
 
800
        }
 
801
    }
 
802
 
 
803
 
 
804
    /**
 
805
     * AVERAGEA
 
806
     *
 
807
     * Returns the average of its arguments, including numbers, text, and logical values
 
808
     *
 
809
     * Excel Function:
 
810
     *        AVERAGEA(value1[,value2[, ...]])
 
811
     *
 
812
     * @access    public
 
813
     * @category Statistical Functions
 
814
     * @param    mixed        $arg,...        Data values
 
815
     * @return    float
 
816
     */
 
817
    public static function AVERAGEA()
 
818
    {
 
819
        $returnValue = null;
 
820
 
 
821
        $aCount = 0;
 
822
        // Loop through arguments
 
823
        foreach (PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()) as $k => $arg) {
 
824
            if ((is_bool($arg)) &&
 
825
                (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
 
826
            } else {
 
827
                if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
 
828
                    if (is_bool($arg)) {
 
829
                        $arg = (integer) $arg;
 
830
                    } elseif (is_string($arg)) {
 
831
                        $arg = 0;
 
832
                    }
 
833
                    if (is_null($returnValue)) {
 
834
                        $returnValue = $arg;
 
835
                    } else {
 
836
                        $returnValue += $arg;
 
837
                    }
 
838
                    ++$aCount;
 
839
                }
 
840
            }
 
841
        }
 
842
 
 
843
        if ($aCount > 0) {
 
844
            return $returnValue / $aCount;
 
845
        } else {
 
846
            return PHPExcel_Calculation_Functions::DIV0();
 
847
        }
 
848
    }
 
849
 
 
850
 
 
851
    /**
 
852
     * AVERAGEIF
 
853
     *
 
854
     * Returns the average value from a range of cells that contain numbers within the list of arguments
 
855
     *
 
856
     * Excel Function:
 
857
     *        AVERAGEIF(value1[,value2[, ...]],condition)
 
858
     *
 
859
     * @access    public
 
860
     * @category Mathematical and Trigonometric Functions
 
861
     * @param    mixed        $arg,...        Data values
 
862
     * @param    string        $condition        The criteria that defines which cells will be checked.
 
863
     * @param    mixed[]        $averageArgs    Data values
 
864
     * @return    float
 
865
     */
 
866
    public static function AVERAGEIF($aArgs, $condition, $averageArgs = array())
 
867
    {
 
868
        $returnValue = 0;
 
869
 
 
870
        $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs);
 
871
        $averageArgs = PHPExcel_Calculation_Functions::flattenArray($averageArgs);
 
872
        if (empty($averageArgs)) {
 
873
            $averageArgs = $aArgs;
 
874
        }
 
875
        $condition = PHPExcel_Calculation_Functions::ifCondition($condition);
 
876
        // Loop through arguments
 
877
        $aCount = 0;
 
878
        foreach ($aArgs as $key => $arg) {
 
879
            if (!is_numeric($arg)) {
 
880
                $arg = PHPExcel_Calculation::wrapResult(strtoupper($arg));
 
881
            }
 
882
            $testCondition = '='.$arg.$condition;
 
883
            if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
 
884
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
 
885
                    $returnValue += $arg;
 
886
                    ++$aCount;
 
887
                }
 
888
            }
 
889
        }
 
890
 
 
891
        if ($aCount > 0) {
 
892
            return $returnValue / $aCount;
 
893
        }
 
894
        return PHPExcel_Calculation_Functions::DIV0();
 
895
    }
 
896
 
 
897
 
 
898
    /**
 
899
     * BETADIST
 
900
     *
 
901
     * Returns the beta distribution.
 
902
     *
 
903
     * @param    float        $value            Value at which you want to evaluate the distribution
 
904
     * @param    float        $alpha            Parameter to the distribution
 
905
     * @param    float        $beta            Parameter to the distribution
 
906
     * @param    boolean        $cumulative
 
907
     * @return    float
 
908
     *
 
909
     */
 
910
    public static function BETADIST($value, $alpha, $beta, $rMin = 0, $rMax = 1)
 
911
    {
 
912
        $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
913
        $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
 
914
        $beta  = PHPExcel_Calculation_Functions::flattenSingleValue($beta);
 
915
        $rMin  = PHPExcel_Calculation_Functions::flattenSingleValue($rMin);
 
916
        $rMax  = PHPExcel_Calculation_Functions::flattenSingleValue($rMax);
 
917
 
 
918
        if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
 
919
            if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) {
 
920
                return PHPExcel_Calculation_Functions::NaN();
 
921
            }
 
922
            if ($rMin > $rMax) {
 
923
                $tmp = $rMin;
 
924
                $rMin = $rMax;
 
925
                $rMax = $tmp;
 
926
            }
 
927
            $value -= $rMin;
 
928
            $value /= ($rMax - $rMin);
 
929
            return self::incompleteBeta($value, $alpha, $beta);
 
930
        }
 
931
        return PHPExcel_Calculation_Functions::VALUE();
 
932
    }
 
933
 
 
934
 
 
935
    /**
 
936
     * BETAINV
 
937
     *
 
938
     * Returns the inverse of the beta distribution.
 
939
     *
 
940
     * @param    float        $probability    Probability at which you want to evaluate the distribution
 
941
     * @param    float        $alpha            Parameter to the distribution
 
942
     * @param    float        $beta            Parameter to the distribution
 
943
     * @param    float        $rMin            Minimum value
 
944
     * @param    float        $rMax            Maximum value
 
945
     * @param    boolean        $cumulative
 
946
     * @return    float
 
947
     *
 
948
     */
 
949
    public static function BETAINV($probability, $alpha, $beta, $rMin = 0, $rMax = 1)
 
950
    {
 
951
        $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
 
952
        $alpha       = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
 
953
        $beta        = PHPExcel_Calculation_Functions::flattenSingleValue($beta);
 
954
        $rMin        = PHPExcel_Calculation_Functions::flattenSingleValue($rMin);
 
955
        $rMax        = PHPExcel_Calculation_Functions::flattenSingleValue($rMax);
 
956
 
 
957
        if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
 
958
            if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) {
 
959
                return PHPExcel_Calculation_Functions::NaN();
 
960
            }
 
961
            if ($rMin > $rMax) {
 
962
                $tmp = $rMin;
 
963
                $rMin = $rMax;
 
964
                $rMax = $tmp;
 
965
            }
 
966
            $a = 0;
 
967
            $b = 2;
 
968
 
 
969
            $i = 0;
 
970
            while ((($b - $a) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
 
971
                $guess = ($a + $b) / 2;
 
972
                $result = self::BETADIST($guess, $alpha, $beta);
 
973
                if (($result == $probability) || ($result == 0)) {
 
974
                    $b = $a;
 
975
                } elseif ($result > $probability) {
 
976
                    $b = $guess;
 
977
                } else {
 
978
                    $a = $guess;
 
979
                }
 
980
            }
 
981
            if ($i == MAX_ITERATIONS) {
 
982
                return PHPExcel_Calculation_Functions::NA();
 
983
            }
 
984
            return round($rMin + $guess * ($rMax - $rMin), 12);
 
985
        }
 
986
        return PHPExcel_Calculation_Functions::VALUE();
 
987
    }
 
988
 
 
989
 
 
990
    /**
 
991
     * BINOMDIST
 
992
     *
 
993
     * Returns the individual term binomial distribution probability. Use BINOMDIST in problems with
 
994
     *        a fixed number of tests or trials, when the outcomes of any trial are only success or failure,
 
995
     *        when trials are independent, and when the probability of success is constant throughout the
 
996
     *        experiment. For example, BINOMDIST can calculate the probability that two of the next three
 
997
     *        babies born are male.
 
998
     *
 
999
     * @param    float        $value            Number of successes in trials
 
1000
     * @param    float        $trials            Number of trials
 
1001
     * @param    float        $probability    Probability of success on each trial
 
1002
     * @param    boolean        $cumulative
 
1003
     * @return    float
 
1004
     *
 
1005
     * @todo    Cumulative distribution function
 
1006
     *
 
1007
     */
 
1008
    public static function BINOMDIST($value, $trials, $probability, $cumulative)
 
1009
    {
 
1010
        $value       = floor(PHPExcel_Calculation_Functions::flattenSingleValue($value));
 
1011
        $trials      = floor(PHPExcel_Calculation_Functions::flattenSingleValue($trials));
 
1012
        $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
 
1013
 
 
1014
        if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) {
 
1015
            if (($value < 0) || ($value > $trials)) {
 
1016
                return PHPExcel_Calculation_Functions::NaN();
 
1017
            }
 
1018
            if (($probability < 0) || ($probability > 1)) {
 
1019
                return PHPExcel_Calculation_Functions::NaN();
 
1020
            }
 
1021
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
 
1022
                if ($cumulative) {
 
1023
                    $summer = 0;
 
1024
                    for ($i = 0; $i <= $value; ++$i) {
 
1025
                        $summer += PHPExcel_Calculation_MathTrig::COMBIN($trials, $i) * pow($probability, $i) * pow(1 - $probability, $trials - $i);
 
1026
                    }
 
1027
                    return $summer;
 
1028
                } else {
 
1029
                    return PHPExcel_Calculation_MathTrig::COMBIN($trials, $value) * pow($probability, $value) * pow(1 - $probability, $trials - $value) ;
 
1030
                }
 
1031
            }
 
1032
        }
 
1033
        return PHPExcel_Calculation_Functions::VALUE();
 
1034
    }
 
1035
 
 
1036
 
 
1037
    /**
 
1038
     * CHIDIST
 
1039
     *
 
1040
     * Returns the one-tailed probability of the chi-squared distribution.
 
1041
     *
 
1042
     * @param    float        $value            Value for the function
 
1043
     * @param    float        $degrees        degrees of freedom
 
1044
     * @return    float
 
1045
     */
 
1046
    public static function CHIDIST($value, $degrees)
 
1047
    {
 
1048
        $value   = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
1049
        $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees));
 
1050
 
 
1051
        if ((is_numeric($value)) && (is_numeric($degrees))) {
 
1052
            if ($degrees < 1) {
 
1053
                return PHPExcel_Calculation_Functions::NaN();
 
1054
            }
 
1055
            if ($value < 0) {
 
1056
                if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
 
1057
                    return 1;
 
1058
                }
 
1059
                return PHPExcel_Calculation_Functions::NaN();
 
1060
            }
 
1061
            return 1 - (self::incompleteGamma($degrees/2, $value/2) / self::gamma($degrees/2));
 
1062
        }
 
1063
        return PHPExcel_Calculation_Functions::VALUE();
 
1064
    }
 
1065
 
 
1066
 
 
1067
    /**
 
1068
     * CHIINV
 
1069
     *
 
1070
     * Returns the one-tailed probability of the chi-squared distribution.
 
1071
     *
 
1072
     * @param    float        $probability    Probability for the function
 
1073
     * @param    float        $degrees        degrees of freedom
 
1074
     * @return    float
 
1075
     */
 
1076
    public static function CHIINV($probability, $degrees)
 
1077
    {
 
1078
        $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
 
1079
        $degrees     = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees));
 
1080
 
 
1081
        if ((is_numeric($probability)) && (is_numeric($degrees))) {
 
1082
            $xLo = 100;
 
1083
            $xHi = 0;
 
1084
 
 
1085
            $x = $xNew = 1;
 
1086
            $dx    = 1;
 
1087
            $i = 0;
 
1088
 
 
1089
            while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
 
1090
                // Apply Newton-Raphson step
 
1091
                $result = self::CHIDIST($x, $degrees);
 
1092
                $error = $result - $probability;
 
1093
                if ($error == 0.0) {
 
1094
                    $dx = 0;
 
1095
                } elseif ($error < 0.0) {
 
1096
                    $xLo = $x;
 
1097
                } else {
 
1098
                    $xHi = $x;
 
1099
                }
 
1100
                // Avoid division by zero
 
1101
                if ($result != 0.0) {
 
1102
                    $dx = $error / $result;
 
1103
                    $xNew = $x - $dx;
 
1104
                }
 
1105
                // If the NR fails to converge (which for example may be the
 
1106
                // case if the initial guess is too rough) we apply a bisection
 
1107
                // step to determine a more narrow interval around the root.
 
1108
                if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
 
1109
                    $xNew = ($xLo + $xHi) / 2;
 
1110
                    $dx = $xNew - $x;
 
1111
                }
 
1112
                $x = $xNew;
 
1113
            }
 
1114
            if ($i == MAX_ITERATIONS) {
 
1115
                return PHPExcel_Calculation_Functions::NA();
 
1116
            }
 
1117
            return round($x, 12);
 
1118
        }
 
1119
        return PHPExcel_Calculation_Functions::VALUE();
 
1120
    }
 
1121
 
 
1122
 
 
1123
    /**
 
1124
     * CONFIDENCE
 
1125
     *
 
1126
     * Returns the confidence interval for a population mean
 
1127
     *
 
1128
     * @param    float        $alpha
 
1129
     * @param    float        $stdDev        Standard Deviation
 
1130
     * @param    float        $size
 
1131
     * @return    float
 
1132
     *
 
1133
     */
 
1134
    public static function CONFIDENCE($alpha, $stdDev, $size)
 
1135
    {
 
1136
        $alpha  = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
 
1137
        $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
 
1138
        $size   = floor(PHPExcel_Calculation_Functions::flattenSingleValue($size));
 
1139
 
 
1140
        if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) {
 
1141
            if (($alpha <= 0) || ($alpha >= 1)) {
 
1142
                return PHPExcel_Calculation_Functions::NaN();
 
1143
            }
 
1144
            if (($stdDev <= 0) || ($size < 1)) {
 
1145
                return PHPExcel_Calculation_Functions::NaN();
 
1146
            }
 
1147
            return self::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size);
 
1148
        }
 
1149
        return PHPExcel_Calculation_Functions::VALUE();
 
1150
    }
 
1151
 
 
1152
 
 
1153
    /**
 
1154
     * CORREL
 
1155
     *
 
1156
     * Returns covariance, the average of the products of deviations for each data point pair.
 
1157
     *
 
1158
     * @param    array of mixed        Data Series Y
 
1159
     * @param    array of mixed        Data Series X
 
1160
     * @return    float
 
1161
     */
 
1162
    public static function CORREL($yValues, $xValues = null)
 
1163
    {
 
1164
        if ((is_null($xValues)) || (!is_array($yValues)) || (!is_array($xValues))) {
 
1165
            return PHPExcel_Calculation_Functions::VALUE();
 
1166
        }
 
1167
        if (!self::checkTrendArrays($yValues, $xValues)) {
 
1168
            return PHPExcel_Calculation_Functions::VALUE();
 
1169
        }
 
1170
        $yValueCount = count($yValues);
 
1171
        $xValueCount = count($xValues);
 
1172
 
 
1173
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
 
1174
            return PHPExcel_Calculation_Functions::NA();
 
1175
        } elseif ($yValueCount == 1) {
 
1176
            return PHPExcel_Calculation_Functions::DIV0();
 
1177
        }
 
1178
 
 
1179
        $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
 
1180
        return $bestFitLinear->getCorrelation();
 
1181
    }
 
1182
 
 
1183
 
 
1184
    /**
 
1185
     * COUNT
 
1186
     *
 
1187
     * Counts the number of cells that contain numbers within the list of arguments
 
1188
     *
 
1189
     * Excel Function:
 
1190
     *        COUNT(value1[,value2[, ...]])
 
1191
     *
 
1192
     * @access    public
 
1193
     * @category Statistical Functions
 
1194
     * @param    mixed        $arg,...        Data values
 
1195
     * @return    int
 
1196
     */
 
1197
    public static function COUNT()
 
1198
    {
 
1199
        $returnValue = 0;
 
1200
 
 
1201
        // Loop through arguments
 
1202
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
1203
        foreach ($aArgs as $k => $arg) {
 
1204
            if ((is_bool($arg)) &&
 
1205
                ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
 
1206
                $arg = (integer) $arg;
 
1207
            }
 
1208
            // Is it a numeric value?
 
1209
            if ((is_numeric($arg)) && (!is_string($arg))) {
 
1210
                ++$returnValue;
 
1211
            }
 
1212
        }
 
1213
 
 
1214
        return $returnValue;
 
1215
    }
 
1216
 
 
1217
 
 
1218
    /**
 
1219
     * COUNTA
 
1220
     *
 
1221
     * Counts the number of cells that are not empty within the list of arguments
 
1222
     *
 
1223
     * Excel Function:
 
1224
     *        COUNTA(value1[,value2[, ...]])
 
1225
     *
 
1226
     * @access    public
 
1227
     * @category Statistical Functions
 
1228
     * @param    mixed        $arg,...        Data values
 
1229
     * @return    int
 
1230
     */
 
1231
    public static function COUNTA()
 
1232
    {
 
1233
        $returnValue = 0;
 
1234
 
 
1235
        // Loop through arguments
 
1236
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
1237
        foreach ($aArgs as $arg) {
 
1238
            // Is it a numeric, boolean or string value?
 
1239
            if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
 
1240
                ++$returnValue;
 
1241
            }
 
1242
        }
 
1243
 
 
1244
        return $returnValue;
 
1245
    }
 
1246
 
 
1247
 
 
1248
    /**
 
1249
     * COUNTBLANK
 
1250
     *
 
1251
     * Counts the number of empty cells within the list of arguments
 
1252
     *
 
1253
     * Excel Function:
 
1254
     *        COUNTBLANK(value1[,value2[, ...]])
 
1255
     *
 
1256
     * @access    public
 
1257
     * @category Statistical Functions
 
1258
     * @param    mixed        $arg,...        Data values
 
1259
     * @return    int
 
1260
     */
 
1261
    public static function COUNTBLANK()
 
1262
    {
 
1263
        $returnValue = 0;
 
1264
 
 
1265
        // Loop through arguments
 
1266
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
1267
        foreach ($aArgs as $arg) {
 
1268
            // Is it a blank cell?
 
1269
            if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) {
 
1270
                ++$returnValue;
 
1271
            }
 
1272
        }
 
1273
 
 
1274
        return $returnValue;
 
1275
    }
 
1276
 
 
1277
 
 
1278
    /**
 
1279
     * COUNTIF
 
1280
     *
 
1281
     * Counts the number of cells that contain numbers within the list of arguments
 
1282
     *
 
1283
     * Excel Function:
 
1284
     *        COUNTIF(value1[,value2[, ...]],condition)
 
1285
     *
 
1286
     * @access    public
 
1287
     * @category Statistical Functions
 
1288
     * @param    mixed        $arg,...        Data values
 
1289
     * @param    string        $condition        The criteria that defines which cells will be counted.
 
1290
     * @return    int
 
1291
     */
 
1292
    public static function COUNTIF($aArgs, $condition)
 
1293
    {
 
1294
        $returnValue = 0;
 
1295
 
 
1296
        $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs);
 
1297
        $condition = PHPExcel_Calculation_Functions::ifCondition($condition);
 
1298
        // Loop through arguments
 
1299
        foreach ($aArgs as $arg) {
 
1300
            if (!is_numeric($arg)) {
 
1301
                $arg = PHPExcel_Calculation::wrapResult(strtoupper($arg));
 
1302
            }
 
1303
            $testCondition = '='.$arg.$condition;
 
1304
            if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
 
1305
                // Is it a value within our criteria
 
1306
                ++$returnValue;
 
1307
            }
 
1308
        }
 
1309
 
 
1310
        return $returnValue;
 
1311
    }
 
1312
 
 
1313
 
 
1314
    /**
 
1315
     * COVAR
 
1316
     *
 
1317
     * Returns covariance, the average of the products of deviations for each data point pair.
 
1318
     *
 
1319
     * @param    array of mixed        Data Series Y
 
1320
     * @param    array of mixed        Data Series X
 
1321
     * @return    float
 
1322
     */
 
1323
    public static function COVAR($yValues, $xValues)
 
1324
    {
 
1325
        if (!self::checkTrendArrays($yValues, $xValues)) {
 
1326
            return PHPExcel_Calculation_Functions::VALUE();
 
1327
        }
 
1328
        $yValueCount = count($yValues);
 
1329
        $xValueCount = count($xValues);
 
1330
 
 
1331
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
 
1332
            return PHPExcel_Calculation_Functions::NA();
 
1333
        } elseif ($yValueCount == 1) {
 
1334
            return PHPExcel_Calculation_Functions::DIV0();
 
1335
        }
 
1336
 
 
1337
        $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
 
1338
        return $bestFitLinear->getCovariance();
 
1339
    }
 
1340
 
 
1341
 
 
1342
    /**
 
1343
     * CRITBINOM
 
1344
     *
 
1345
     * Returns the smallest value for which the cumulative binomial distribution is greater
 
1346
     *        than or equal to a criterion value
 
1347
     *
 
1348
     * See http://support.microsoft.com/kb/828117/ for details of the algorithm used
 
1349
     *
 
1350
     * @param    float        $trials            number of Bernoulli trials
 
1351
     * @param    float        $probability    probability of a success on each trial
 
1352
     * @param    float        $alpha            criterion value
 
1353
     * @return    int
 
1354
     *
 
1355
     * @todo    Warning. This implementation differs from the algorithm detailed on the MS
 
1356
     *            web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess
 
1357
     *            This eliminates a potential endless loop error, but may have an adverse affect on the
 
1358
     *            accuracy of the function (although all my tests have so far returned correct results).
 
1359
     *
 
1360
     */
 
1361
    public static function CRITBINOM($trials, $probability, $alpha)
 
1362
    {
 
1363
        $trials      = floor(PHPExcel_Calculation_Functions::flattenSingleValue($trials));
 
1364
        $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
 
1365
        $alpha       = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
 
1366
 
 
1367
        if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) {
 
1368
            if ($trials < 0) {
 
1369
                return PHPExcel_Calculation_Functions::NaN();
 
1370
            } elseif (($probability < 0) || ($probability > 1)) {
 
1371
                return PHPExcel_Calculation_Functions::NaN();
 
1372
            } elseif (($alpha < 0) || ($alpha > 1)) {
 
1373
                return PHPExcel_Calculation_Functions::NaN();
 
1374
            } elseif ($alpha <= 0.5) {
 
1375
                $t = sqrt(log(1 / ($alpha * $alpha)));
 
1376
                $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));
 
1377
            } else {
 
1378
                $t = sqrt(log(1 / pow(1 - $alpha, 2)));
 
1379
                $trialsApprox = $t - (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t);
 
1380
            }
 
1381
            $Guess = floor($trials * $probability + $trialsApprox * sqrt($trials * $probability * (1 - $probability)));
 
1382
            if ($Guess < 0) {
 
1383
                $Guess = 0;
 
1384
            } elseif ($Guess > $trials) {
 
1385
                $Guess = $trials;
 
1386
            }
 
1387
 
 
1388
            $TotalUnscaledProbability = $UnscaledPGuess = $UnscaledCumPGuess = 0.0;
 
1389
            $EssentiallyZero = 10e-12;
 
1390
 
 
1391
            $m = floor($trials * $probability);
 
1392
            ++$TotalUnscaledProbability;
 
1393
            if ($m == $Guess) {
 
1394
                ++$UnscaledPGuess;
 
1395
            }
 
1396
            if ($m <= $Guess) {
 
1397
                ++$UnscaledCumPGuess;
 
1398
            }
 
1399
 
 
1400
            $PreviousValue = 1;
 
1401
            $Done = false;
 
1402
            $k = $m + 1;
 
1403
            while ((!$Done) && ($k <= $trials)) {
 
1404
                $CurrentValue = $PreviousValue * ($trials - $k + 1) * $probability / ($k * (1 - $probability));
 
1405
                $TotalUnscaledProbability += $CurrentValue;
 
1406
                if ($k == $Guess) {
 
1407
                    $UnscaledPGuess += $CurrentValue;
 
1408
                }
 
1409
                if ($k <= $Guess) {
 
1410
                    $UnscaledCumPGuess += $CurrentValue;
 
1411
                }
 
1412
                if ($CurrentValue <= $EssentiallyZero) {
 
1413
                    $Done = true;
 
1414
                }
 
1415
                $PreviousValue = $CurrentValue;
 
1416
                ++$k;
 
1417
            }
 
1418
 
 
1419
            $PreviousValue = 1;
 
1420
            $Done = false;
 
1421
            $k = $m - 1;
 
1422
            while ((!$Done) && ($k >= 0)) {
 
1423
                $CurrentValue = $PreviousValue * $k + 1 * (1 - $probability) / (($trials - $k) * $probability);
 
1424
                $TotalUnscaledProbability += $CurrentValue;
 
1425
                if ($k == $Guess) {
 
1426
                    $UnscaledPGuess += $CurrentValue;
 
1427
                }
 
1428
                if ($k <= $Guess) {
 
1429
                    $UnscaledCumPGuess += $CurrentValue;
 
1430
                }
 
1431
                if ($CurrentValue <= $EssentiallyZero) {
 
1432
                    $Done = true;
 
1433
                }
 
1434
                $PreviousValue = $CurrentValue;
 
1435
                --$k;
 
1436
            }
 
1437
 
 
1438
            $PGuess = $UnscaledPGuess / $TotalUnscaledProbability;
 
1439
            $CumPGuess = $UnscaledCumPGuess / $TotalUnscaledProbability;
 
1440
 
 
1441
//            $CumPGuessMinus1 = $CumPGuess - $PGuess;
 
1442
            $CumPGuessMinus1 = $CumPGuess - 1;
 
1443
 
 
1444
            while (true) {
 
1445
                if (($CumPGuessMinus1 < $alpha) && ($CumPGuess >= $alpha)) {
 
1446
                    return $Guess;
 
1447
                } elseif (($CumPGuessMinus1 < $alpha) && ($CumPGuess < $alpha)) {
 
1448
                    $PGuessPlus1 = $PGuess * ($trials - $Guess) * $probability / $Guess / (1 - $probability);
 
1449
                    $CumPGuessMinus1 = $CumPGuess;
 
1450
                    $CumPGuess = $CumPGuess + $PGuessPlus1;
 
1451
                    $PGuess = $PGuessPlus1;
 
1452
                    ++$Guess;
 
1453
                } elseif (($CumPGuessMinus1 >= $alpha) && ($CumPGuess >= $alpha)) {
 
1454
                    $PGuessMinus1 = $PGuess * $Guess * (1 - $probability) / ($trials - $Guess + 1) / $probability;
 
1455
                    $CumPGuess = $CumPGuessMinus1;
 
1456
                    $CumPGuessMinus1 = $CumPGuessMinus1 - $PGuess;
 
1457
                    $PGuess = $PGuessMinus1;
 
1458
                    --$Guess;
 
1459
                }
 
1460
            }
 
1461
        }
 
1462
        return PHPExcel_Calculation_Functions::VALUE();
 
1463
    }
 
1464
 
 
1465
 
 
1466
    /**
 
1467
     * DEVSQ
 
1468
     *
 
1469
     * Returns the sum of squares of deviations of data points from their sample mean.
 
1470
     *
 
1471
     * Excel Function:
 
1472
     *        DEVSQ(value1[,value2[, ...]])
 
1473
     *
 
1474
     * @access    public
 
1475
     * @category Statistical Functions
 
1476
     * @param    mixed        $arg,...        Data values
 
1477
     * @return    float
 
1478
     */
 
1479
    public static function DEVSQ()
 
1480
    {
 
1481
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
1482
 
 
1483
        // Return value
 
1484
        $returnValue = null;
 
1485
 
 
1486
        $aMean = self::AVERAGE($aArgs);
 
1487
        if ($aMean != PHPExcel_Calculation_Functions::DIV0()) {
 
1488
            $aCount = -1;
 
1489
            foreach ($aArgs as $k => $arg) {
 
1490
                // Is it a numeric value?
 
1491
                if ((is_bool($arg)) &&
 
1492
                    ((!PHPExcel_Calculation_Functions::isCellValue($k)) ||
 
1493
                    (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
 
1494
                    $arg = (integer) $arg;
 
1495
                }
 
1496
                if ((is_numeric($arg)) && (!is_string($arg))) {
 
1497
                    if (is_null($returnValue)) {
 
1498
                        $returnValue = pow(($arg - $aMean), 2);
 
1499
                    } else {
 
1500
                        $returnValue += pow(($arg - $aMean), 2);
 
1501
                    }
 
1502
                    ++$aCount;
 
1503
                }
 
1504
            }
 
1505
 
 
1506
            // Return
 
1507
            if (is_null($returnValue)) {
 
1508
                return PHPExcel_Calculation_Functions::NaN();
 
1509
            } else {
 
1510
                return $returnValue;
 
1511
            }
 
1512
        }
 
1513
        return self::NA();
 
1514
    }
 
1515
 
 
1516
 
 
1517
    /**
 
1518
     * EXPONDIST
 
1519
     *
 
1520
     *    Returns the exponential distribution. Use EXPONDIST to model the time between events,
 
1521
     *        such as how long an automated bank teller takes to deliver cash. For example, you can
 
1522
     *        use EXPONDIST to determine the probability that the process takes at most 1 minute.
 
1523
     *
 
1524
     * @param    float        $value            Value of the function
 
1525
     * @param    float        $lambda            The parameter value
 
1526
     * @param    boolean        $cumulative
 
1527
     * @return    float
 
1528
     */
 
1529
    public static function EXPONDIST($value, $lambda, $cumulative)
 
1530
    {
 
1531
        $value    = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
1532
        $lambda    = PHPExcel_Calculation_Functions::flattenSingleValue($lambda);
 
1533
        $cumulative    = PHPExcel_Calculation_Functions::flattenSingleValue($cumulative);
 
1534
 
 
1535
        if ((is_numeric($value)) && (is_numeric($lambda))) {
 
1536
            if (($value < 0) || ($lambda < 0)) {
 
1537
                return PHPExcel_Calculation_Functions::NaN();
 
1538
            }
 
1539
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
 
1540
                if ($cumulative) {
 
1541
                    return 1 - exp(0-$value*$lambda);
 
1542
                } else {
 
1543
                    return $lambda * exp(0-$value*$lambda);
 
1544
                }
 
1545
            }
 
1546
        }
 
1547
        return PHPExcel_Calculation_Functions::VALUE();
 
1548
    }
 
1549
 
 
1550
 
 
1551
    /**
 
1552
     * FISHER
 
1553
     *
 
1554
     * Returns the Fisher transformation at x. This transformation produces a function that
 
1555
     *        is normally distributed rather than skewed. Use this function to perform hypothesis
 
1556
     *        testing on the correlation coefficient.
 
1557
     *
 
1558
     * @param    float        $value
 
1559
     * @return    float
 
1560
     */
 
1561
    public static function FISHER($value)
 
1562
    {
 
1563
        $value    = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
1564
 
 
1565
        if (is_numeric($value)) {
 
1566
            if (($value <= -1) || ($value >= 1)) {
 
1567
                return PHPExcel_Calculation_Functions::NaN();
 
1568
            }
 
1569
            return 0.5 * log((1+$value)/(1-$value));
 
1570
        }
 
1571
        return PHPExcel_Calculation_Functions::VALUE();
 
1572
    }
 
1573
 
 
1574
 
 
1575
    /**
 
1576
     * FISHERINV
 
1577
     *
 
1578
     * Returns the inverse of the Fisher transformation. Use this transformation when
 
1579
     *        analyzing correlations between ranges or arrays of data. If y = FISHER(x), then
 
1580
     *        FISHERINV(y) = x.
 
1581
     *
 
1582
     * @param    float        $value
 
1583
     * @return    float
 
1584
     */
 
1585
    public static function FISHERINV($value)
 
1586
    {
 
1587
        $value    = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
1588
 
 
1589
        if (is_numeric($value)) {
 
1590
            return (exp(2 * $value) - 1) / (exp(2 * $value) + 1);
 
1591
        }
 
1592
        return PHPExcel_Calculation_Functions::VALUE();
 
1593
    }
 
1594
 
 
1595
 
 
1596
    /**
 
1597
     * FORECAST
 
1598
     *
 
1599
     * Calculates, or predicts, a future value by using existing values. The predicted value is a y-value for a given x-value.
 
1600
     *
 
1601
     * @param    float                Value of X for which we want to find Y
 
1602
     * @param    array of mixed        Data Series Y
 
1603
     * @param    array of mixed        Data Series X
 
1604
     * @return    float
 
1605
     */
 
1606
    public static function FORECAST($xValue, $yValues, $xValues)
 
1607
    {
 
1608
        $xValue    = PHPExcel_Calculation_Functions::flattenSingleValue($xValue);
 
1609
        if (!is_numeric($xValue)) {
 
1610
            return PHPExcel_Calculation_Functions::VALUE();
 
1611
        } elseif (!self::checkTrendArrays($yValues, $xValues)) {
 
1612
            return PHPExcel_Calculation_Functions::VALUE();
 
1613
        }
 
1614
        $yValueCount = count($yValues);
 
1615
        $xValueCount = count($xValues);
 
1616
 
 
1617
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
 
1618
            return PHPExcel_Calculation_Functions::NA();
 
1619
        } elseif ($yValueCount == 1) {
 
1620
            return PHPExcel_Calculation_Functions::DIV0();
 
1621
        }
 
1622
 
 
1623
        $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
 
1624
        return $bestFitLinear->getValueOfYForX($xValue);
 
1625
    }
 
1626
 
 
1627
 
 
1628
    /**
 
1629
     * GAMMADIST
 
1630
     *
 
1631
     * Returns the gamma distribution.
 
1632
     *
 
1633
     * @param    float        $value            Value at which you want to evaluate the distribution
 
1634
     * @param    float        $a                Parameter to the distribution
 
1635
     * @param    float        $b                Parameter to the distribution
 
1636
     * @param    boolean        $cumulative
 
1637
     * @return    float
 
1638
     *
 
1639
     */
 
1640
    public static function GAMMADIST($value, $a, $b, $cumulative)
 
1641
    {
 
1642
        $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
1643
        $a     = PHPExcel_Calculation_Functions::flattenSingleValue($a);
 
1644
        $b     = PHPExcel_Calculation_Functions::flattenSingleValue($b);
 
1645
 
 
1646
        if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) {
 
1647
            if (($value < 0) || ($a <= 0) || ($b <= 0)) {
 
1648
                return PHPExcel_Calculation_Functions::NaN();
 
1649
            }
 
1650
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
 
1651
                if ($cumulative) {
 
1652
                    return self::incompleteGamma($a, $value / $b) / self::gamma($a);
 
1653
                } else {
 
1654
                    return (1 / (pow($b, $a) * self::gamma($a))) * pow($value, $a-1) * exp(0-($value / $b));
 
1655
                }
 
1656
            }
 
1657
        }
 
1658
        return PHPExcel_Calculation_Functions::VALUE();
 
1659
    }
 
1660
 
 
1661
 
 
1662
    /**
 
1663
     * GAMMAINV
 
1664
     *
 
1665
     * Returns the inverse of the beta distribution.
 
1666
     *
 
1667
     * @param    float        $probability    Probability at which you want to evaluate the distribution
 
1668
     * @param    float        $alpha            Parameter to the distribution
 
1669
     * @param    float        $beta            Parameter to the distribution
 
1670
     * @return    float
 
1671
     *
 
1672
     */
 
1673
    public static function GAMMAINV($probability, $alpha, $beta)
 
1674
    {
 
1675
        $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
 
1676
        $alpha       = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
 
1677
        $beta        = PHPExcel_Calculation_Functions::flattenSingleValue($beta);
 
1678
 
 
1679
        if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) {
 
1680
            if (($alpha <= 0) || ($beta <= 0) || ($probability < 0) || ($probability > 1)) {
 
1681
                return PHPExcel_Calculation_Functions::NaN();
 
1682
            }
 
1683
 
 
1684
            $xLo = 0;
 
1685
            $xHi = $alpha * $beta * 5;
 
1686
 
 
1687
            $x = $xNew = 1;
 
1688
            $error = $pdf = 0;
 
1689
            $dx    = 1024;
 
1690
            $i = 0;
 
1691
 
 
1692
            while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
 
1693
                // Apply Newton-Raphson step
 
1694
                $error = self::GAMMADIST($x, $alpha, $beta, true) - $probability;
 
1695
                if ($error < 0.0) {
 
1696
                    $xLo = $x;
 
1697
                } else {
 
1698
                    $xHi = $x;
 
1699
                }
 
1700
                $pdf = self::GAMMADIST($x, $alpha, $beta, false);
 
1701
                // Avoid division by zero
 
1702
                if ($pdf != 0.0) {
 
1703
                    $dx = $error / $pdf;
 
1704
                    $xNew = $x - $dx;
 
1705
                }
 
1706
                // If the NR fails to converge (which for example may be the
 
1707
                // case if the initial guess is too rough) we apply a bisection
 
1708
                // step to determine a more narrow interval around the root.
 
1709
                if (($xNew < $xLo) || ($xNew > $xHi) || ($pdf == 0.0)) {
 
1710
                    $xNew = ($xLo + $xHi) / 2;
 
1711
                    $dx = $xNew - $x;
 
1712
                }
 
1713
                $x = $xNew;
 
1714
            }
 
1715
            if ($i == MAX_ITERATIONS) {
 
1716
                return PHPExcel_Calculation_Functions::NA();
 
1717
            }
 
1718
            return $x;
 
1719
        }
 
1720
        return PHPExcel_Calculation_Functions::VALUE();
 
1721
    }
 
1722
 
 
1723
 
 
1724
    /**
 
1725
     * GAMMALN
 
1726
     *
 
1727
     * Returns the natural logarithm of the gamma function.
 
1728
     *
 
1729
     * @param    float        $value
 
1730
     * @return    float
 
1731
     */
 
1732
    public static function GAMMALN($value)
 
1733
    {
 
1734
        $value    = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
1735
 
 
1736
        if (is_numeric($value)) {
 
1737
            if ($value <= 0) {
 
1738
                return PHPExcel_Calculation_Functions::NaN();
 
1739
            }
 
1740
            return log(self::gamma($value));
 
1741
        }
 
1742
        return PHPExcel_Calculation_Functions::VALUE();
 
1743
    }
 
1744
 
 
1745
 
 
1746
    /**
 
1747
     * GEOMEAN
 
1748
     *
 
1749
     * Returns the geometric mean of an array or range of positive data. For example, you
 
1750
     *        can use GEOMEAN to calculate average growth rate given compound interest with
 
1751
     *        variable rates.
 
1752
     *
 
1753
     * Excel Function:
 
1754
     *        GEOMEAN(value1[,value2[, ...]])
 
1755
     *
 
1756
     * @access    public
 
1757
     * @category Statistical Functions
 
1758
     * @param    mixed        $arg,...        Data values
 
1759
     * @return    float
 
1760
     */
 
1761
    public static function GEOMEAN()
 
1762
    {
 
1763
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
1764
 
 
1765
        $aMean = PHPExcel_Calculation_MathTrig::PRODUCT($aArgs);
 
1766
        if (is_numeric($aMean) && ($aMean > 0)) {
 
1767
            $aCount = self::COUNT($aArgs) ;
 
1768
            if (self::MIN($aArgs) > 0) {
 
1769
                return pow($aMean, (1 / $aCount));
 
1770
            }
 
1771
        }
 
1772
        return PHPExcel_Calculation_Functions::NaN();
 
1773
    }
 
1774
 
 
1775
 
 
1776
    /**
 
1777
     * GROWTH
 
1778
     *
 
1779
     * Returns values along a predicted emponential trend
 
1780
     *
 
1781
     * @param    array of mixed        Data Series Y
 
1782
     * @param    array of mixed        Data Series X
 
1783
     * @param    array of mixed        Values of X for which we want to find Y
 
1784
     * @param    boolean                A logical value specifying whether to force the intersect to equal 0.
 
1785
     * @return    array of float
 
1786
     */
 
1787
    public static function GROWTH($yValues, $xValues = array(), $newValues = array(), $const = true)
 
1788
    {
 
1789
        $yValues = PHPExcel_Calculation_Functions::flattenArray($yValues);
 
1790
        $xValues = PHPExcel_Calculation_Functions::flattenArray($xValues);
 
1791
        $newValues = PHPExcel_Calculation_Functions::flattenArray($newValues);
 
1792
        $const = (is_null($const)) ? true : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const);
 
1793
 
 
1794
        $bestFitExponential = trendClass::calculate(trendClass::TREND_EXPONENTIAL, $yValues, $xValues, $const);
 
1795
        if (empty($newValues)) {
 
1796
            $newValues = $bestFitExponential->getXValues();
 
1797
        }
 
1798
 
 
1799
        $returnArray = array();
 
1800
        foreach ($newValues as $xValue) {
 
1801
            $returnArray[0][] = $bestFitExponential->getValueOfYForX($xValue);
 
1802
        }
 
1803
 
 
1804
        return $returnArray;
 
1805
    }
 
1806
 
 
1807
 
 
1808
    /**
 
1809
     * HARMEAN
 
1810
     *
 
1811
     * Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the
 
1812
     *        arithmetic mean of reciprocals.
 
1813
     *
 
1814
     * Excel Function:
 
1815
     *        HARMEAN(value1[,value2[, ...]])
 
1816
     *
 
1817
     * @access    public
 
1818
     * @category Statistical Functions
 
1819
     * @param    mixed        $arg,...        Data values
 
1820
     * @return    float
 
1821
     */
 
1822
    public static function HARMEAN()
 
1823
    {
 
1824
        // Return value
 
1825
        $returnValue = PHPExcel_Calculation_Functions::NA();
 
1826
 
 
1827
        // Loop through arguments
 
1828
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
1829
        if (self::MIN($aArgs) < 0) {
 
1830
            return PHPExcel_Calculation_Functions::NaN();
 
1831
        }
 
1832
        $aCount = 0;
 
1833
        foreach ($aArgs as $arg) {
 
1834
            // Is it a numeric value?
 
1835
            if ((is_numeric($arg)) && (!is_string($arg))) {
 
1836
                if ($arg <= 0) {
 
1837
                    return PHPExcel_Calculation_Functions::NaN();
 
1838
                }
 
1839
                if (is_null($returnValue)) {
 
1840
                    $returnValue = (1 / $arg);
 
1841
                } else {
 
1842
                    $returnValue += (1 / $arg);
 
1843
                }
 
1844
                ++$aCount;
 
1845
            }
 
1846
        }
 
1847
 
 
1848
        // Return
 
1849
        if ($aCount > 0) {
 
1850
            return 1 / ($returnValue / $aCount);
 
1851
        } else {
 
1852
            return $returnValue;
 
1853
        }
 
1854
    }
 
1855
 
 
1856
 
 
1857
    /**
 
1858
     * HYPGEOMDIST
 
1859
     *
 
1860
     * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of
 
1861
     * sample successes, given the sample size, population successes, and population size.
 
1862
     *
 
1863
     * @param    float        $sampleSuccesses        Number of successes in the sample
 
1864
     * @param    float        $sampleNumber            Size of the sample
 
1865
     * @param    float        $populationSuccesses    Number of successes in the population
 
1866
     * @param    float        $populationNumber        Population size
 
1867
     * @return    float
 
1868
     *
 
1869
     */
 
1870
    public static function HYPGEOMDIST($sampleSuccesses, $sampleNumber, $populationSuccesses, $populationNumber)
 
1871
    {
 
1872
        $sampleSuccesses     = floor(PHPExcel_Calculation_Functions::flattenSingleValue($sampleSuccesses));
 
1873
        $sampleNumber        = floor(PHPExcel_Calculation_Functions::flattenSingleValue($sampleNumber));
 
1874
        $populationSuccesses = floor(PHPExcel_Calculation_Functions::flattenSingleValue($populationSuccesses));
 
1875
        $populationNumber    = floor(PHPExcel_Calculation_Functions::flattenSingleValue($populationNumber));
 
1876
 
 
1877
        if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) {
 
1878
            if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) {
 
1879
                return PHPExcel_Calculation_Functions::NaN();
 
1880
            }
 
1881
            if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) {
 
1882
                return PHPExcel_Calculation_Functions::NaN();
 
1883
            }
 
1884
            if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) {
 
1885
                return PHPExcel_Calculation_Functions::NaN();
 
1886
            }
 
1887
            return PHPExcel_Calculation_MathTrig::COMBIN($populationSuccesses, $sampleSuccesses) *
 
1888
                   PHPExcel_Calculation_MathTrig::COMBIN($populationNumber - $populationSuccesses, $sampleNumber - $sampleSuccesses) /
 
1889
                   PHPExcel_Calculation_MathTrig::COMBIN($populationNumber, $sampleNumber);
 
1890
        }
 
1891
        return PHPExcel_Calculation_Functions::VALUE();
 
1892
    }
 
1893
 
 
1894
 
 
1895
    /**
 
1896
     * INTERCEPT
 
1897
     *
 
1898
     * Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values.
 
1899
     *
 
1900
     * @param    array of mixed        Data Series Y
 
1901
     * @param    array of mixed        Data Series X
 
1902
     * @return    float
 
1903
     */
 
1904
    public static function INTERCEPT($yValues, $xValues)
 
1905
    {
 
1906
        if (!self::checkTrendArrays($yValues, $xValues)) {
 
1907
            return PHPExcel_Calculation_Functions::VALUE();
 
1908
        }
 
1909
        $yValueCount = count($yValues);
 
1910
        $xValueCount = count($xValues);
 
1911
 
 
1912
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
 
1913
            return PHPExcel_Calculation_Functions::NA();
 
1914
        } elseif ($yValueCount == 1) {
 
1915
            return PHPExcel_Calculation_Functions::DIV0();
 
1916
        }
 
1917
 
 
1918
        $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
 
1919
        return $bestFitLinear->getIntersect();
 
1920
    }
 
1921
 
 
1922
 
 
1923
    /**
 
1924
     * KURT
 
1925
     *
 
1926
     * Returns the kurtosis of a data set. Kurtosis characterizes the relative peakedness
 
1927
     * or flatness of a distribution compared with the normal distribution. Positive
 
1928
     * kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a
 
1929
     * relatively flat distribution.
 
1930
     *
 
1931
     * @param    array    Data Series
 
1932
     * @return    float
 
1933
     */
 
1934
    public static function KURT()
 
1935
    {
 
1936
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
1937
        $mean = self::AVERAGE($aArgs);
 
1938
        $stdDev = self::STDEV($aArgs);
 
1939
 
 
1940
        if ($stdDev > 0) {
 
1941
            $count = $summer = 0;
 
1942
            // Loop through arguments
 
1943
            foreach ($aArgs as $k => $arg) {
 
1944
                if ((is_bool($arg)) &&
 
1945
                    (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
 
1946
                } else {
 
1947
                    // Is it a numeric value?
 
1948
                    if ((is_numeric($arg)) && (!is_string($arg))) {
 
1949
                        $summer += pow((($arg - $mean) / $stdDev), 4);
 
1950
                        ++$count;
 
1951
                    }
 
1952
                }
 
1953
            }
 
1954
 
 
1955
            // Return
 
1956
            if ($count > 3) {
 
1957
                return $summer * ($count * ($count+1) / (($count-1) * ($count-2) * ($count-3))) - (3 * pow($count-1, 2) / (($count-2) * ($count-3)));
 
1958
            }
 
1959
        }
 
1960
        return PHPExcel_Calculation_Functions::DIV0();
 
1961
    }
 
1962
 
 
1963
 
 
1964
    /**
 
1965
     * LARGE
 
1966
     *
 
1967
     * Returns the nth largest value in a data set. You can use this function to
 
1968
     *        select a value based on its relative standing.
 
1969
     *
 
1970
     * Excel Function:
 
1971
     *        LARGE(value1[,value2[, ...]],entry)
 
1972
     *
 
1973
     * @access    public
 
1974
     * @category Statistical Functions
 
1975
     * @param    mixed        $arg,...        Data values
 
1976
     * @param    int            $entry            Position (ordered from the largest) in the array or range of data to return
 
1977
     * @return    float
 
1978
     *
 
1979
     */
 
1980
    public static function LARGE()
 
1981
    {
 
1982
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
1983
 
 
1984
        // Calculate
 
1985
        $entry = floor(array_pop($aArgs));
 
1986
 
 
1987
        if ((is_numeric($entry)) && (!is_string($entry))) {
 
1988
            $mArgs = array();
 
1989
            foreach ($aArgs as $arg) {
 
1990
                // Is it a numeric value?
 
1991
                if ((is_numeric($arg)) && (!is_string($arg))) {
 
1992
                    $mArgs[] = $arg;
 
1993
                }
 
1994
            }
 
1995
            $count = self::COUNT($mArgs);
 
1996
            $entry = floor(--$entry);
 
1997
            if (($entry < 0) || ($entry >= $count) || ($count == 0)) {
 
1998
                return PHPExcel_Calculation_Functions::NaN();
 
1999
            }
 
2000
            rsort($mArgs);
 
2001
            return $mArgs[$entry];
 
2002
        }
 
2003
        return PHPExcel_Calculation_Functions::VALUE();
 
2004
    }
 
2005
 
 
2006
 
 
2007
    /**
 
2008
     * LINEST
 
2009
     *
 
2010
     * Calculates the statistics for a line by using the "least squares" method to calculate a straight line that best fits your data,
 
2011
     *        and then returns an array that describes the line.
 
2012
     *
 
2013
     * @param    array of mixed        Data Series Y
 
2014
     * @param    array of mixed        Data Series X
 
2015
     * @param    boolean                A logical value specifying whether to force the intersect to equal 0.
 
2016
     * @param    boolean                A logical value specifying whether to return additional regression statistics.
 
2017
     * @return    array
 
2018
     */
 
2019
    public static function LINEST($yValues, $xValues = null, $const = true, $stats = false)
 
2020
    {
 
2021
        $const = (is_null($const)) ? true : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const);
 
2022
        $stats = (is_null($stats)) ? false : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($stats);
 
2023
        if (is_null($xValues)) {
 
2024
            $xValues = range(1, count(PHPExcel_Calculation_Functions::flattenArray($yValues)));
 
2025
        }
 
2026
 
 
2027
        if (!self::checkTrendArrays($yValues, $xValues)) {
 
2028
            return PHPExcel_Calculation_Functions::VALUE();
 
2029
        }
 
2030
        $yValueCount = count($yValues);
 
2031
        $xValueCount = count($xValues);
 
2032
 
 
2033
 
 
2034
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
 
2035
            return PHPExcel_Calculation_Functions::NA();
 
2036
        } elseif ($yValueCount == 1) {
 
2037
            return 0;
 
2038
        }
 
2039
 
 
2040
        $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues, $const);
 
2041
        if ($stats) {
 
2042
            return array(
 
2043
                array(
 
2044
                    $bestFitLinear->getSlope(),
 
2045
                    $bestFitLinear->getSlopeSE(),
 
2046
                    $bestFitLinear->getGoodnessOfFit(),
 
2047
                    $bestFitLinear->getF(),
 
2048
                    $bestFitLinear->getSSRegression(),
 
2049
                ),
 
2050
                array(
 
2051
                    $bestFitLinear->getIntersect(),
 
2052
                    $bestFitLinear->getIntersectSE(),
 
2053
                    $bestFitLinear->getStdevOfResiduals(),
 
2054
                    $bestFitLinear->getDFResiduals(),
 
2055
                    $bestFitLinear->getSSResiduals()
 
2056
                )
 
2057
            );
 
2058
        } else {
 
2059
            return array(
 
2060
                $bestFitLinear->getSlope(),
 
2061
                $bestFitLinear->getIntersect()
 
2062
            );
 
2063
        }
 
2064
    }
 
2065
 
 
2066
 
 
2067
    /**
 
2068
     * LOGEST
 
2069
     *
 
2070
     * Calculates an exponential curve that best fits the X and Y data series,
 
2071
     *        and then returns an array that describes the line.
 
2072
     *
 
2073
     * @param    array of mixed        Data Series Y
 
2074
     * @param    array of mixed        Data Series X
 
2075
     * @param    boolean                A logical value specifying whether to force the intersect to equal 0.
 
2076
     * @param    boolean                A logical value specifying whether to return additional regression statistics.
 
2077
     * @return    array
 
2078
     */
 
2079
    public static function LOGEST($yValues, $xValues = null, $const = true, $stats = false)
 
2080
    {
 
2081
        $const = (is_null($const)) ? true : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const);
 
2082
        $stats = (is_null($stats)) ? false : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($stats);
 
2083
        if (is_null($xValues)) {
 
2084
            $xValues = range(1, count(PHPExcel_Calculation_Functions::flattenArray($yValues)));
 
2085
        }
 
2086
 
 
2087
        if (!self::checkTrendArrays($yValues, $xValues)) {
 
2088
            return PHPExcel_Calculation_Functions::VALUE();
 
2089
        }
 
2090
        $yValueCount = count($yValues);
 
2091
        $xValueCount = count($xValues);
 
2092
 
 
2093
        foreach ($yValues as $value) {
 
2094
            if ($value <= 0.0) {
 
2095
                return PHPExcel_Calculation_Functions::NaN();
 
2096
            }
 
2097
        }
 
2098
 
 
2099
 
 
2100
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
 
2101
            return PHPExcel_Calculation_Functions::NA();
 
2102
        } elseif ($yValueCount == 1) {
 
2103
            return 1;
 
2104
        }
 
2105
 
 
2106
        $bestFitExponential = trendClass::calculate(trendClass::TREND_EXPONENTIAL, $yValues, $xValues, $const);
 
2107
        if ($stats) {
 
2108
            return array(
 
2109
                array(
 
2110
                    $bestFitExponential->getSlope(),
 
2111
                    $bestFitExponential->getSlopeSE(),
 
2112
                    $bestFitExponential->getGoodnessOfFit(),
 
2113
                    $bestFitExponential->getF(),
 
2114
                    $bestFitExponential->getSSRegression(),
 
2115
                ),
 
2116
                array(
 
2117
                    $bestFitExponential->getIntersect(),
 
2118
                    $bestFitExponential->getIntersectSE(),
 
2119
                    $bestFitExponential->getStdevOfResiduals(),
 
2120
                    $bestFitExponential->getDFResiduals(),
 
2121
                    $bestFitExponential->getSSResiduals()
 
2122
                )
 
2123
            );
 
2124
        } else {
 
2125
            return array(
 
2126
                $bestFitExponential->getSlope(),
 
2127
                $bestFitExponential->getIntersect()
 
2128
            );
 
2129
        }
 
2130
    }
 
2131
 
 
2132
 
 
2133
    /**
 
2134
     * LOGINV
 
2135
     *
 
2136
     * Returns the inverse of the normal cumulative distribution
 
2137
     *
 
2138
     * @param    float        $probability
 
2139
     * @param    float        $mean
 
2140
     * @param    float        $stdDev
 
2141
     * @return    float
 
2142
     *
 
2143
     * @todo    Try implementing P J Acklam's refinement algorithm for greater
 
2144
     *            accuracy if I can get my head round the mathematics
 
2145
     *            (as described at) http://home.online.no/~pjacklam/notes/invnorm/
 
2146
     */
 
2147
    public static function LOGINV($probability, $mean, $stdDev)
 
2148
    {
 
2149
        $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
 
2150
        $mean        = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
 
2151
        $stdDev      = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
 
2152
 
 
2153
        if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
 
2154
            if (($probability < 0) || ($probability > 1) || ($stdDev <= 0)) {
 
2155
                return PHPExcel_Calculation_Functions::NaN();
 
2156
            }
 
2157
            return exp($mean + $stdDev * self::NORMSINV($probability));
 
2158
        }
 
2159
        return PHPExcel_Calculation_Functions::VALUE();
 
2160
    }
 
2161
 
 
2162
 
 
2163
    /**
 
2164
     * LOGNORMDIST
 
2165
     *
 
2166
     * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed
 
2167
     * with parameters mean and standard_dev.
 
2168
     *
 
2169
     * @param    float        $value
 
2170
     * @param    float        $mean
 
2171
     * @param    float        $stdDev
 
2172
     * @return    float
 
2173
     */
 
2174
    public static function LOGNORMDIST($value, $mean, $stdDev)
 
2175
    {
 
2176
        $value  = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
2177
        $mean   = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
 
2178
        $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
 
2179
 
 
2180
        if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
 
2181
            if (($value <= 0) || ($stdDev <= 0)) {
 
2182
                return PHPExcel_Calculation_Functions::NaN();
 
2183
            }
 
2184
            return self::NORMSDIST((log($value) - $mean) / $stdDev);
 
2185
        }
 
2186
        return PHPExcel_Calculation_Functions::VALUE();
 
2187
    }
 
2188
 
 
2189
 
 
2190
    /**
 
2191
     * MAX
 
2192
     *
 
2193
     * MAX returns the value of the element of the values passed that has the highest value,
 
2194
     *        with negative numbers considered smaller than positive numbers.
 
2195
     *
 
2196
     * Excel Function:
 
2197
     *        MAX(value1[,value2[, ...]])
 
2198
     *
 
2199
     * @access    public
 
2200
     * @category Statistical Functions
 
2201
     * @param    mixed        $arg,...        Data values
 
2202
     * @return    float
 
2203
     */
 
2204
    public static function MAX()
 
2205
    {
 
2206
        $returnValue = null;
 
2207
 
 
2208
        // Loop through arguments
 
2209
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
2210
        foreach ($aArgs as $arg) {
 
2211
            // Is it a numeric value?
 
2212
            if ((is_numeric($arg)) && (!is_string($arg))) {
 
2213
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
 
2214
                    $returnValue = $arg;
 
2215
                }
 
2216
            }
 
2217
        }
 
2218
 
 
2219
        if (is_null($returnValue)) {
 
2220
            return 0;
 
2221
        }
 
2222
        return $returnValue;
 
2223
    }
 
2224
 
 
2225
 
 
2226
    /**
 
2227
     * MAXA
 
2228
     *
 
2229
     * Returns the greatest value in a list of arguments, including numbers, text, and logical values
 
2230
     *
 
2231
     * Excel Function:
 
2232
     *        MAXA(value1[,value2[, ...]])
 
2233
     *
 
2234
     * @access    public
 
2235
     * @category Statistical Functions
 
2236
     * @param    mixed        $arg,...        Data values
 
2237
     * @return    float
 
2238
     */
 
2239
    public static function MAXA()
 
2240
    {
 
2241
        $returnValue = null;
 
2242
 
 
2243
        // Loop through arguments
 
2244
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
2245
        foreach ($aArgs as $arg) {
 
2246
            // Is it a numeric value?
 
2247
            if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
 
2248
                if (is_bool($arg)) {
 
2249
                    $arg = (integer) $arg;
 
2250
                } elseif (is_string($arg)) {
 
2251
                    $arg = 0;
 
2252
                }
 
2253
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
 
2254
                    $returnValue = $arg;
 
2255
                }
 
2256
            }
 
2257
        }
 
2258
 
 
2259
        if (is_null($returnValue)) {
 
2260
            return 0;
 
2261
        }
 
2262
        return $returnValue;
 
2263
    }
 
2264
 
 
2265
 
 
2266
    /**
 
2267
     * MAXIF
 
2268
     *
 
2269
     * Counts the maximum value within a range of cells that contain numbers within the list of arguments
 
2270
     *
 
2271
     * Excel Function:
 
2272
     *        MAXIF(value1[,value2[, ...]],condition)
 
2273
     *
 
2274
     * @access    public
 
2275
     * @category Mathematical and Trigonometric Functions
 
2276
     * @param    mixed        $arg,...        Data values
 
2277
     * @param    string        $condition        The criteria that defines which cells will be checked.
 
2278
     * @return    float
 
2279
     */
 
2280
    public static function MAXIF($aArgs, $condition, $sumArgs = array())
 
2281
    {
 
2282
        $returnValue = null;
 
2283
 
 
2284
        $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs);
 
2285
        $sumArgs = PHPExcel_Calculation_Functions::flattenArray($sumArgs);
 
2286
        if (empty($sumArgs)) {
 
2287
            $sumArgs = $aArgs;
 
2288
        }
 
2289
        $condition = PHPExcel_Calculation_Functions::ifCondition($condition);
 
2290
        // Loop through arguments
 
2291
        foreach ($aArgs as $key => $arg) {
 
2292
            if (!is_numeric($arg)) {
 
2293
                $arg = PHPExcel_Calculation::wrapResult(strtoupper($arg));
 
2294
            }
 
2295
            $testCondition = '='.$arg.$condition;
 
2296
            if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
 
2297
                if ((is_null($returnValue)) || ($arg > $returnValue)) {
 
2298
                    $returnValue = $arg;
 
2299
                }
 
2300
            }
 
2301
        }
 
2302
 
 
2303
        return $returnValue;
 
2304
    }
 
2305
 
 
2306
    /**
 
2307
     * MEDIAN
 
2308
     *
 
2309
     * Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
 
2310
     *
 
2311
     * Excel Function:
 
2312
     *        MEDIAN(value1[,value2[, ...]])
 
2313
     *
 
2314
     * @access    public
 
2315
     * @category Statistical Functions
 
2316
     * @param    mixed        $arg,...        Data values
 
2317
     * @return    float
 
2318
     */
 
2319
    public static function MEDIAN()
 
2320
    {
 
2321
        $returnValue = PHPExcel_Calculation_Functions::NaN();
 
2322
 
 
2323
        $mArgs = array();
 
2324
        // Loop through arguments
 
2325
        $aArgs = PHPExcel_Calculation_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
                $mArgs[] = $arg;
 
2330
            }
 
2331
        }
 
2332
 
 
2333
        $mValueCount = count($mArgs);
 
2334
        if ($mValueCount > 0) {
 
2335
            sort($mArgs, SORT_NUMERIC);
 
2336
            $mValueCount = $mValueCount / 2;
 
2337
            if ($mValueCount == floor($mValueCount)) {
 
2338
                $returnValue = ($mArgs[$mValueCount--] + $mArgs[$mValueCount]) / 2;
 
2339
            } else {
 
2340
                $mValueCount = floor($mValueCount);
 
2341
                $returnValue = $mArgs[$mValueCount];
 
2342
            }
 
2343
        }
 
2344
 
 
2345
        return $returnValue;
 
2346
    }
 
2347
 
 
2348
 
 
2349
    /**
 
2350
     * MIN
 
2351
     *
 
2352
     * MIN returns the value of the element of the values passed that has the smallest value,
 
2353
     *        with negative numbers considered smaller than positive numbers.
 
2354
     *
 
2355
     * Excel Function:
 
2356
     *        MIN(value1[,value2[, ...]])
 
2357
     *
 
2358
     * @access    public
 
2359
     * @category Statistical Functions
 
2360
     * @param    mixed        $arg,...        Data values
 
2361
     * @return    float
 
2362
     */
 
2363
    public static function MIN()
 
2364
    {
 
2365
        $returnValue = null;
 
2366
 
 
2367
        // Loop through arguments
 
2368
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
2369
        foreach ($aArgs as $arg) {
 
2370
            // Is it a numeric value?
 
2371
            if ((is_numeric($arg)) && (!is_string($arg))) {
 
2372
                if ((is_null($returnValue)) || ($arg < $returnValue)) {
 
2373
                    $returnValue = $arg;
 
2374
                }
 
2375
            }
 
2376
        }
 
2377
 
 
2378
        if (is_null($returnValue)) {
 
2379
            return 0;
 
2380
        }
 
2381
        return $returnValue;
 
2382
    }
 
2383
 
 
2384
 
 
2385
    /**
 
2386
     * MINA
 
2387
     *
 
2388
     * Returns the smallest value in a list of arguments, including numbers, text, and logical values
 
2389
     *
 
2390
     * Excel Function:
 
2391
     *        MINA(value1[,value2[, ...]])
 
2392
     *
 
2393
     * @access    public
 
2394
     * @category Statistical Functions
 
2395
     * @param    mixed        $arg,...        Data values
 
2396
     * @return    float
 
2397
     */
 
2398
    public static function MINA()
 
2399
    {
 
2400
        $returnValue = null;
 
2401
 
 
2402
        // Loop through arguments
 
2403
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
2404
        foreach ($aArgs as $arg) {
 
2405
            // Is it a numeric value?
 
2406
            if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
 
2407
                if (is_bool($arg)) {
 
2408
                    $arg = (integer) $arg;
 
2409
                } elseif (is_string($arg)) {
 
2410
                    $arg = 0;
 
2411
                }
 
2412
                if ((is_null($returnValue)) || ($arg < $returnValue)) {
 
2413
                    $returnValue = $arg;
 
2414
                }
 
2415
            }
 
2416
        }
 
2417
 
 
2418
        if (is_null($returnValue)) {
 
2419
            return 0;
 
2420
        }
 
2421
        return $returnValue;
 
2422
    }
 
2423
 
 
2424
 
 
2425
    /**
 
2426
     * MINIF
 
2427
     *
 
2428
     * Returns the minimum value within a range of cells that contain numbers within the list of arguments
 
2429
     *
 
2430
     * Excel Function:
 
2431
     *        MINIF(value1[,value2[, ...]],condition)
 
2432
     *
 
2433
     * @access    public
 
2434
     * @category Mathematical and Trigonometric Functions
 
2435
     * @param    mixed        $arg,...        Data values
 
2436
     * @param    string        $condition        The criteria that defines which cells will be checked.
 
2437
     * @return    float
 
2438
     */
 
2439
    public static function MINIF($aArgs, $condition, $sumArgs = array())
 
2440
    {
 
2441
        $returnValue = null;
 
2442
 
 
2443
        $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs);
 
2444
        $sumArgs = PHPExcel_Calculation_Functions::flattenArray($sumArgs);
 
2445
        if (empty($sumArgs)) {
 
2446
            $sumArgs = $aArgs;
 
2447
        }
 
2448
        $condition = PHPExcel_Calculation_Functions::ifCondition($condition);
 
2449
        // Loop through arguments
 
2450
        foreach ($aArgs as $key => $arg) {
 
2451
            if (!is_numeric($arg)) {
 
2452
                $arg = PHPExcel_Calculation::wrapResult(strtoupper($arg));
 
2453
            }
 
2454
            $testCondition = '='.$arg.$condition;
 
2455
            if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
 
2456
                if ((is_null($returnValue)) || ($arg < $returnValue)) {
 
2457
                    $returnValue = $arg;
 
2458
                }
 
2459
            }
 
2460
        }
 
2461
 
 
2462
        return $returnValue;
 
2463
    }
 
2464
 
 
2465
 
 
2466
    //
 
2467
    //    Special variant of array_count_values that isn't limited to strings and integers,
 
2468
    //        but can work with floating point numbers as values
 
2469
    //
 
2470
    private static function modeCalc($data)
 
2471
    {
 
2472
        $frequencyArray = array();
 
2473
        foreach ($data as $datum) {
 
2474
            $found = false;
 
2475
            foreach ($frequencyArray as $key => $value) {
 
2476
                if ((string) $value['value'] == (string) $datum) {
 
2477
                    ++$frequencyArray[$key]['frequency'];
 
2478
                    $found = true;
 
2479
                    break;
 
2480
                }
 
2481
            }
 
2482
            if (!$found) {
 
2483
                $frequencyArray[] = array(
 
2484
                    'value'     => $datum,
 
2485
                    'frequency' => 1
 
2486
                );
 
2487
            }
 
2488
        }
 
2489
 
 
2490
        foreach ($frequencyArray as $key => $value) {
 
2491
            $frequencyList[$key] = $value['frequency'];
 
2492
            $valueList[$key] = $value['value'];
 
2493
        }
 
2494
        array_multisort($frequencyList, SORT_DESC, $valueList, SORT_ASC, SORT_NUMERIC, $frequencyArray);
 
2495
 
 
2496
        if ($frequencyArray[0]['frequency'] == 1) {
 
2497
            return PHPExcel_Calculation_Functions::NA();
 
2498
        }
 
2499
        return $frequencyArray[0]['value'];
 
2500
    }
 
2501
 
 
2502
 
 
2503
    /**
 
2504
     * MODE
 
2505
     *
 
2506
     * Returns the most frequently occurring, or repetitive, value in an array or range of data
 
2507
     *
 
2508
     * Excel Function:
 
2509
     *        MODE(value1[,value2[, ...]])
 
2510
     *
 
2511
     * @access    public
 
2512
     * @category Statistical Functions
 
2513
     * @param    mixed        $arg,...        Data values
 
2514
     * @return    float
 
2515
     */
 
2516
    public static function MODE()
 
2517
    {
 
2518
        $returnValue = PHPExcel_Calculation_Functions::NA();
 
2519
 
 
2520
        // Loop through arguments
 
2521
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
2522
 
 
2523
        $mArgs = array();
 
2524
        foreach ($aArgs as $arg) {
 
2525
            // Is it a numeric value?
 
2526
            if ((is_numeric($arg)) && (!is_string($arg))) {
 
2527
                $mArgs[] = $arg;
 
2528
            }
 
2529
        }
 
2530
 
 
2531
        if (!empty($mArgs)) {
 
2532
            return self::modeCalc($mArgs);
 
2533
        }
 
2534
 
 
2535
        return $returnValue;
 
2536
    }
 
2537
 
 
2538
 
 
2539
    /**
 
2540
     * NEGBINOMDIST
 
2541
     *
 
2542
     * Returns the negative binomial distribution. NEGBINOMDIST returns the probability that
 
2543
     *        there will be number_f failures before the number_s-th success, when the constant
 
2544
     *        probability of a success is probability_s. This function is similar to the binomial
 
2545
     *        distribution, except that the number of successes is fixed, and the number of trials is
 
2546
     *        variable. Like the binomial, trials are assumed to be independent.
 
2547
     *
 
2548
     * @param    float        $failures        Number of Failures
 
2549
     * @param    float        $successes        Threshold number of Successes
 
2550
     * @param    float        $probability    Probability of success on each trial
 
2551
     * @return    float
 
2552
     *
 
2553
     */
 
2554
    public static function NEGBINOMDIST($failures, $successes, $probability)
 
2555
    {
 
2556
        $failures    = floor(PHPExcel_Calculation_Functions::flattenSingleValue($failures));
 
2557
        $successes   = floor(PHPExcel_Calculation_Functions::flattenSingleValue($successes));
 
2558
        $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
 
2559
 
 
2560
        if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) {
 
2561
            if (($failures < 0) || ($successes < 1)) {
 
2562
                return PHPExcel_Calculation_Functions::NaN();
 
2563
            } elseif (($probability < 0) || ($probability > 1)) {
 
2564
                return PHPExcel_Calculation_Functions::NaN();
 
2565
            }
 
2566
            if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
 
2567
                if (($failures + $successes - 1) <= 0) {
 
2568
                    return PHPExcel_Calculation_Functions::NaN();
 
2569
                }
 
2570
            }
 
2571
            return (PHPExcel_Calculation_MathTrig::COMBIN($failures + $successes - 1, $successes - 1)) * (pow($probability, $successes)) * (pow(1 - $probability, $failures));
 
2572
        }
 
2573
        return PHPExcel_Calculation_Functions::VALUE();
 
2574
    }
 
2575
 
 
2576
 
 
2577
    /**
 
2578
     * NORMDIST
 
2579
     *
 
2580
     * Returns the normal distribution for the specified mean and standard deviation. This
 
2581
     * function has a very wide range of applications in statistics, including hypothesis
 
2582
     * testing.
 
2583
     *
 
2584
     * @param    float        $value
 
2585
     * @param    float        $mean        Mean Value
 
2586
     * @param    float        $stdDev        Standard Deviation
 
2587
     * @param    boolean        $cumulative
 
2588
     * @return    float
 
2589
     *
 
2590
     */
 
2591
    public static function NORMDIST($value, $mean, $stdDev, $cumulative)
 
2592
    {
 
2593
        $value  = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
2594
        $mean   = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
 
2595
        $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
 
2596
 
 
2597
        if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
 
2598
            if ($stdDev < 0) {
 
2599
                return PHPExcel_Calculation_Functions::NaN();
 
2600
            }
 
2601
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
 
2602
                if ($cumulative) {
 
2603
                    return 0.5 * (1 + PHPExcel_Calculation_Engineering::erfVal(($value - $mean) / ($stdDev * sqrt(2))));
 
2604
                } else {
 
2605
                    return (1 / (SQRT2PI * $stdDev)) * exp(0 - (pow($value - $mean, 2) / (2 * ($stdDev * $stdDev))));
 
2606
                }
 
2607
            }
 
2608
        }
 
2609
        return PHPExcel_Calculation_Functions::VALUE();
 
2610
    }
 
2611
 
 
2612
 
 
2613
    /**
 
2614
     * NORMINV
 
2615
     *
 
2616
     * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation.
 
2617
     *
 
2618
     * @param    float        $value
 
2619
     * @param    float        $mean        Mean Value
 
2620
     * @param    float        $stdDev        Standard Deviation
 
2621
     * @return    float
 
2622
     *
 
2623
     */
 
2624
    public static function NORMINV($probability, $mean, $stdDev)
 
2625
    {
 
2626
        $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
 
2627
        $mean        = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
 
2628
        $stdDev      = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
 
2629
 
 
2630
        if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
 
2631
            if (($probability < 0) || ($probability > 1)) {
 
2632
                return PHPExcel_Calculation_Functions::NaN();
 
2633
            }
 
2634
            if ($stdDev < 0) {
 
2635
                return PHPExcel_Calculation_Functions::NaN();
 
2636
            }
 
2637
            return (self::inverseNcdf($probability) * $stdDev) + $mean;
 
2638
        }
 
2639
        return PHPExcel_Calculation_Functions::VALUE();
 
2640
    }
 
2641
 
 
2642
 
 
2643
    /**
 
2644
     * NORMSDIST
 
2645
     *
 
2646
     * Returns the standard normal cumulative distribution function. The distribution has
 
2647
     * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a
 
2648
     * table of standard normal curve areas.
 
2649
     *
 
2650
     * @param    float        $value
 
2651
     * @return    float
 
2652
     */
 
2653
    public static function NORMSDIST($value)
 
2654
    {
 
2655
        $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
2656
 
 
2657
        return self::NORMDIST($value, 0, 1, true);
 
2658
    }
 
2659
 
 
2660
 
 
2661
    /**
 
2662
     * NORMSINV
 
2663
     *
 
2664
     * Returns the inverse of the standard normal cumulative distribution
 
2665
     *
 
2666
     * @param    float        $value
 
2667
     * @return    float
 
2668
     */
 
2669
    public static function NORMSINV($value)
 
2670
    {
 
2671
        return self::NORMINV($value, 0, 1);
 
2672
    }
 
2673
 
 
2674
 
 
2675
    /**
 
2676
     * PERCENTILE
 
2677
     *
 
2678
     * Returns the nth percentile of values in a range..
 
2679
     *
 
2680
     * Excel Function:
 
2681
     *        PERCENTILE(value1[,value2[, ...]],entry)
 
2682
     *
 
2683
     * @access    public
 
2684
     * @category Statistical Functions
 
2685
     * @param    mixed        $arg,...        Data values
 
2686
     * @param    float        $entry            Percentile value in the range 0..1, inclusive.
 
2687
     * @return    float
 
2688
     */
 
2689
    public static function PERCENTILE()
 
2690
    {
 
2691
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
2692
 
 
2693
        // Calculate
 
2694
        $entry = array_pop($aArgs);
 
2695
 
 
2696
        if ((is_numeric($entry)) && (!is_string($entry))) {
 
2697
            if (($entry < 0) || ($entry > 1)) {
 
2698
                return PHPExcel_Calculation_Functions::NaN();
 
2699
            }
 
2700
            $mArgs = array();
 
2701
            foreach ($aArgs as $arg) {
 
2702
                // Is it a numeric value?
 
2703
                if ((is_numeric($arg)) && (!is_string($arg))) {
 
2704
                    $mArgs[] = $arg;
 
2705
                }
 
2706
            }
 
2707
            $mValueCount = count($mArgs);
 
2708
            if ($mValueCount > 0) {
 
2709
                sort($mArgs);
 
2710
                $count = self::COUNT($mArgs);
 
2711
                $index = $entry * ($count-1);
 
2712
                $iBase = floor($index);
 
2713
                if ($index == $iBase) {
 
2714
                    return $mArgs[$index];
 
2715
                } else {
 
2716
                    $iNext = $iBase + 1;
 
2717
                    $iProportion = $index - $iBase;
 
2718
                    return $mArgs[$iBase] + (($mArgs[$iNext] - $mArgs[$iBase]) * $iProportion) ;
 
2719
                }
 
2720
            }
 
2721
        }
 
2722
        return PHPExcel_Calculation_Functions::VALUE();
 
2723
    }
 
2724
 
 
2725
 
 
2726
    /**
 
2727
     * PERCENTRANK
 
2728
     *
 
2729
     * Returns the rank of a value in a data set as a percentage of the data set.
 
2730
     *
 
2731
     * @param    array of number        An array of, or a reference to, a list of numbers.
 
2732
     * @param    number                The number whose rank you want to find.
 
2733
     * @param    number                The number of significant digits for the returned percentage value.
 
2734
     * @return    float
 
2735
     */
 
2736
    public static function PERCENTRANK($valueSet, $value, $significance = 3)
 
2737
    {
 
2738
        $valueSet     = PHPExcel_Calculation_Functions::flattenArray($valueSet);
 
2739
        $value        = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
2740
        $significance = (is_null($significance)) ? 3 : (integer) PHPExcel_Calculation_Functions::flattenSingleValue($significance);
 
2741
 
 
2742
        foreach ($valueSet as $key => $valueEntry) {
 
2743
            if (!is_numeric($valueEntry)) {
 
2744
                unset($valueSet[$key]);
 
2745
            }
 
2746
        }
 
2747
        sort($valueSet, SORT_NUMERIC);
 
2748
        $valueCount = count($valueSet);
 
2749
        if ($valueCount == 0) {
 
2750
            return PHPExcel_Calculation_Functions::NaN();
 
2751
        }
 
2752
 
 
2753
        $valueAdjustor = $valueCount - 1;
 
2754
        if (($value < $valueSet[0]) || ($value > $valueSet[$valueAdjustor])) {
 
2755
            return PHPExcel_Calculation_Functions::NA();
 
2756
        }
 
2757
 
 
2758
        $pos = array_search($value, $valueSet);
 
2759
        if ($pos === false) {
 
2760
            $pos = 0;
 
2761
            $testValue = $valueSet[0];
 
2762
            while ($testValue < $value) {
 
2763
                $testValue = $valueSet[++$pos];
 
2764
            }
 
2765
            --$pos;
 
2766
            $pos += (($value - $valueSet[$pos]) / ($testValue - $valueSet[$pos]));
 
2767
        }
 
2768
 
 
2769
        return round($pos / $valueAdjustor, $significance);
 
2770
    }
 
2771
 
 
2772
 
 
2773
    /**
 
2774
     * PERMUT
 
2775
     *
 
2776
     * Returns the number of permutations for a given number of objects that can be
 
2777
     *        selected from number objects. A permutation is any set or subset of objects or
 
2778
     *        events where internal order is significant. Permutations are different from
 
2779
     *        combinations, for which the internal order is not significant. Use this function
 
2780
     *        for lottery-style probability calculations.
 
2781
     *
 
2782
     * @param    int        $numObjs    Number of different objects
 
2783
     * @param    int        $numInSet    Number of objects in each permutation
 
2784
     * @return    int        Number of permutations
 
2785
     */
 
2786
    public static function PERMUT($numObjs, $numInSet)
 
2787
    {
 
2788
        $numObjs  = PHPExcel_Calculation_Functions::flattenSingleValue($numObjs);
 
2789
        $numInSet = PHPExcel_Calculation_Functions::flattenSingleValue($numInSet);
 
2790
 
 
2791
        if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
 
2792
            $numInSet = floor($numInSet);
 
2793
            if ($numObjs < $numInSet) {
 
2794
                return PHPExcel_Calculation_Functions::NaN();
 
2795
            }
 
2796
            return round(PHPExcel_Calculation_MathTrig::FACT($numObjs) / PHPExcel_Calculation_MathTrig::FACT($numObjs - $numInSet));
 
2797
        }
 
2798
        return PHPExcel_Calculation_Functions::VALUE();
 
2799
    }
 
2800
 
 
2801
 
 
2802
    /**
 
2803
     * POISSON
 
2804
     *
 
2805
     * Returns the Poisson distribution. A common application of the Poisson distribution
 
2806
     * is predicting the number of events over a specific time, such as the number of
 
2807
     * cars arriving at a toll plaza in 1 minute.
 
2808
     *
 
2809
     * @param    float        $value
 
2810
     * @param    float        $mean        Mean Value
 
2811
     * @param    boolean        $cumulative
 
2812
     * @return    float
 
2813
     *
 
2814
     */
 
2815
    public static function POISSON($value, $mean, $cumulative)
 
2816
    {
 
2817
        $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
2818
        $mean  = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
 
2819
 
 
2820
        if ((is_numeric($value)) && (is_numeric($mean))) {
 
2821
            if (($value < 0) || ($mean <= 0)) {
 
2822
                return PHPExcel_Calculation_Functions::NaN();
 
2823
            }
 
2824
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
 
2825
                if ($cumulative) {
 
2826
                    $summer = 0;
 
2827
                    for ($i = 0; $i <= floor($value); ++$i) {
 
2828
                        $summer += pow($mean, $i) / PHPExcel_Calculation_MathTrig::FACT($i);
 
2829
                    }
 
2830
                    return exp(0-$mean) * $summer;
 
2831
                } else {
 
2832
                    return (exp(0-$mean) * pow($mean, $value)) / PHPExcel_Calculation_MathTrig::FACT($value);
 
2833
                }
 
2834
            }
 
2835
        }
 
2836
        return PHPExcel_Calculation_Functions::VALUE();
 
2837
    }
 
2838
 
 
2839
 
 
2840
    /**
 
2841
     * QUARTILE
 
2842
     *
 
2843
     * Returns the quartile of a data set.
 
2844
     *
 
2845
     * Excel Function:
 
2846
     *        QUARTILE(value1[,value2[, ...]],entry)
 
2847
     *
 
2848
     * @access    public
 
2849
     * @category Statistical Functions
 
2850
     * @param    mixed        $arg,...        Data values
 
2851
     * @param    int            $entry            Quartile value in the range 1..3, inclusive.
 
2852
     * @return    float
 
2853
     */
 
2854
    public static function QUARTILE()
 
2855
    {
 
2856
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
2857
 
 
2858
        // Calculate
 
2859
        $entry = floor(array_pop($aArgs));
 
2860
 
 
2861
        if ((is_numeric($entry)) && (!is_string($entry))) {
 
2862
            $entry /= 4;
 
2863
            if (($entry < 0) || ($entry > 1)) {
 
2864
                return PHPExcel_Calculation_Functions::NaN();
 
2865
            }
 
2866
            return self::PERCENTILE($aArgs, $entry);
 
2867
        }
 
2868
        return PHPExcel_Calculation_Functions::VALUE();
 
2869
    }
 
2870
 
 
2871
 
 
2872
    /**
 
2873
     * RANK
 
2874
     *
 
2875
     * Returns the rank of a number in a list of numbers.
 
2876
     *
 
2877
     * @param    number                The number whose rank you want to find.
 
2878
     * @param    array of number        An array of, or a reference to, a list of numbers.
 
2879
     * @param    mixed                Order to sort the values in the value set
 
2880
     * @return    float
 
2881
     */
 
2882
    public static function RANK($value, $valueSet, $order = 0)
 
2883
    {
 
2884
        $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
2885
        $valueSet = PHPExcel_Calculation_Functions::flattenArray($valueSet);
 
2886
        $order = (is_null($order)) ? 0 : (integer) PHPExcel_Calculation_Functions::flattenSingleValue($order);
 
2887
 
 
2888
        foreach ($valueSet as $key => $valueEntry) {
 
2889
            if (!is_numeric($valueEntry)) {
 
2890
                unset($valueSet[$key]);
 
2891
            }
 
2892
        }
 
2893
 
 
2894
        if ($order == 0) {
 
2895
            rsort($valueSet, SORT_NUMERIC);
 
2896
        } else {
 
2897
            sort($valueSet, SORT_NUMERIC);
 
2898
        }
 
2899
        $pos = array_search($value, $valueSet);
 
2900
        if ($pos === false) {
 
2901
            return PHPExcel_Calculation_Functions::NA();
 
2902
        }
 
2903
 
 
2904
        return ++$pos;
 
2905
    }
 
2906
 
 
2907
 
 
2908
    /**
 
2909
     * RSQ
 
2910
     *
 
2911
     * Returns the square of the Pearson product moment correlation coefficient through data points in known_y's and known_x's.
 
2912
     *
 
2913
     * @param    array of mixed        Data Series Y
 
2914
     * @param    array of mixed        Data Series X
 
2915
     * @return    float
 
2916
     */
 
2917
    public static function RSQ($yValues, $xValues)
 
2918
    {
 
2919
        if (!self::checkTrendArrays($yValues, $xValues)) {
 
2920
            return PHPExcel_Calculation_Functions::VALUE();
 
2921
        }
 
2922
        $yValueCount = count($yValues);
 
2923
        $xValueCount = count($xValues);
 
2924
 
 
2925
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
 
2926
            return PHPExcel_Calculation_Functions::NA();
 
2927
        } elseif ($yValueCount == 1) {
 
2928
            return PHPExcel_Calculation_Functions::DIV0();
 
2929
        }
 
2930
 
 
2931
        $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
 
2932
        return $bestFitLinear->getGoodnessOfFit();
 
2933
    }
 
2934
 
 
2935
 
 
2936
    /**
 
2937
     * SKEW
 
2938
     *
 
2939
     * Returns the skewness of a distribution. Skewness characterizes the degree of asymmetry
 
2940
     * of a distribution around its mean. Positive skewness indicates a distribution with an
 
2941
     * asymmetric tail extending toward more positive values. Negative skewness indicates a
 
2942
     * distribution with an asymmetric tail extending toward more negative values.
 
2943
     *
 
2944
     * @param    array    Data Series
 
2945
     * @return    float
 
2946
     */
 
2947
    public static function SKEW()
 
2948
    {
 
2949
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
2950
        $mean = self::AVERAGE($aArgs);
 
2951
        $stdDev = self::STDEV($aArgs);
 
2952
 
 
2953
        $count = $summer = 0;
 
2954
        // Loop through arguments
 
2955
        foreach ($aArgs as $k => $arg) {
 
2956
            if ((is_bool($arg)) &&
 
2957
                (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
 
2958
            } else {
 
2959
                // Is it a numeric value?
 
2960
                if ((is_numeric($arg)) && (!is_string($arg))) {
 
2961
                    $summer += pow((($arg - $mean) / $stdDev), 3);
 
2962
                    ++$count;
 
2963
                }
 
2964
            }
 
2965
        }
 
2966
 
 
2967
        if ($count > 2) {
 
2968
            return $summer * ($count / (($count-1) * ($count-2)));
 
2969
        }
 
2970
        return PHPExcel_Calculation_Functions::DIV0();
 
2971
    }
 
2972
 
 
2973
 
 
2974
    /**
 
2975
     * SLOPE
 
2976
     *
 
2977
     * Returns the slope of the linear regression line through data points in known_y's and known_x's.
 
2978
     *
 
2979
     * @param    array of mixed        Data Series Y
 
2980
     * @param    array of mixed        Data Series X
 
2981
     * @return    float
 
2982
     */
 
2983
    public static function SLOPE($yValues, $xValues)
 
2984
    {
 
2985
        if (!self::checkTrendArrays($yValues, $xValues)) {
 
2986
            return PHPExcel_Calculation_Functions::VALUE();
 
2987
        }
 
2988
        $yValueCount = count($yValues);
 
2989
        $xValueCount = count($xValues);
 
2990
 
 
2991
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
 
2992
            return PHPExcel_Calculation_Functions::NA();
 
2993
        } elseif ($yValueCount == 1) {
 
2994
            return PHPExcel_Calculation_Functions::DIV0();
 
2995
        }
 
2996
 
 
2997
        $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
 
2998
        return $bestFitLinear->getSlope();
 
2999
    }
 
3000
 
 
3001
 
 
3002
    /**
 
3003
     * SMALL
 
3004
     *
 
3005
     * Returns the nth smallest value in a data set. You can use this function to
 
3006
     *        select a value based on its relative standing.
 
3007
     *
 
3008
     * Excel Function:
 
3009
     *        SMALL(value1[,value2[, ...]],entry)
 
3010
     *
 
3011
     * @access    public
 
3012
     * @category Statistical Functions
 
3013
     * @param    mixed        $arg,...        Data values
 
3014
     * @param    int            $entry            Position (ordered from the smallest) in the array or range of data to return
 
3015
     * @return    float
 
3016
     */
 
3017
    public static function SMALL()
 
3018
    {
 
3019
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
3020
 
 
3021
        // Calculate
 
3022
        $entry = array_pop($aArgs);
 
3023
 
 
3024
        if ((is_numeric($entry)) && (!is_string($entry))) {
 
3025
            $mArgs = array();
 
3026
            foreach ($aArgs as $arg) {
 
3027
                // Is it a numeric value?
 
3028
                if ((is_numeric($arg)) && (!is_string($arg))) {
 
3029
                    $mArgs[] = $arg;
 
3030
                }
 
3031
            }
 
3032
            $count = self::COUNT($mArgs);
 
3033
            $entry = floor(--$entry);
 
3034
            if (($entry < 0) || ($entry >= $count) || ($count == 0)) {
 
3035
                return PHPExcel_Calculation_Functions::NaN();
 
3036
            }
 
3037
            sort($mArgs);
 
3038
            return $mArgs[$entry];
 
3039
        }
 
3040
        return PHPExcel_Calculation_Functions::VALUE();
 
3041
    }
 
3042
 
 
3043
 
 
3044
    /**
 
3045
     * STANDARDIZE
 
3046
     *
 
3047
     * Returns a normalized value from a distribution characterized by mean and standard_dev.
 
3048
     *
 
3049
     * @param    float    $value        Value to normalize
 
3050
     * @param    float    $mean        Mean Value
 
3051
     * @param    float    $stdDev        Standard Deviation
 
3052
     * @return    float    Standardized value
 
3053
     */
 
3054
    public static function STANDARDIZE($value, $mean, $stdDev)
 
3055
    {
 
3056
        $value  = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
3057
        $mean   = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
 
3058
        $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
 
3059
 
 
3060
        if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
 
3061
            if ($stdDev <= 0) {
 
3062
                return PHPExcel_Calculation_Functions::NaN();
 
3063
            }
 
3064
            return ($value - $mean) / $stdDev ;
 
3065
        }
 
3066
        return PHPExcel_Calculation_Functions::VALUE();
 
3067
    }
 
3068
 
 
3069
 
 
3070
    /**
 
3071
     * STDEV
 
3072
     *
 
3073
     * Estimates standard deviation based on a sample. The standard deviation is a measure of how
 
3074
     *        widely values are dispersed from the average value (the mean).
 
3075
     *
 
3076
     * Excel Function:
 
3077
     *        STDEV(value1[,value2[, ...]])
 
3078
     *
 
3079
     * @access    public
 
3080
     * @category Statistical Functions
 
3081
     * @param    mixed        $arg,...        Data values
 
3082
     * @return    float
 
3083
     */
 
3084
    public static function STDEV()
 
3085
    {
 
3086
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
3087
 
 
3088
        // Return value
 
3089
        $returnValue = null;
 
3090
 
 
3091
        $aMean = self::AVERAGE($aArgs);
 
3092
        if (!is_null($aMean)) {
 
3093
            $aCount = -1;
 
3094
            foreach ($aArgs as $k => $arg) {
 
3095
                if ((is_bool($arg)) &&
 
3096
                    ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
 
3097
                    $arg = (integer) $arg;
 
3098
                }
 
3099
                // Is it a numeric value?
 
3100
                if ((is_numeric($arg)) && (!is_string($arg))) {
 
3101
                    if (is_null($returnValue)) {
 
3102
                        $returnValue = pow(($arg - $aMean), 2);
 
3103
                    } else {
 
3104
                        $returnValue += pow(($arg - $aMean), 2);
 
3105
                    }
 
3106
                    ++$aCount;
 
3107
                }
 
3108
            }
 
3109
 
 
3110
            // Return
 
3111
            if (($aCount > 0) && ($returnValue >= 0)) {
 
3112
                return sqrt($returnValue / $aCount);
 
3113
            }
 
3114
        }
 
3115
        return PHPExcel_Calculation_Functions::DIV0();
 
3116
    }
 
3117
 
 
3118
 
 
3119
    /**
 
3120
     * STDEVA
 
3121
     *
 
3122
     * Estimates standard deviation based on a sample, including numbers, text, and logical values
 
3123
     *
 
3124
     * Excel Function:
 
3125
     *        STDEVA(value1[,value2[, ...]])
 
3126
     *
 
3127
     * @access    public
 
3128
     * @category Statistical Functions
 
3129
     * @param    mixed        $arg,...        Data values
 
3130
     * @return    float
 
3131
     */
 
3132
    public static function STDEVA()
 
3133
    {
 
3134
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
3135
 
 
3136
        $returnValue = null;
 
3137
 
 
3138
        $aMean = self::AVERAGEA($aArgs);
 
3139
        if (!is_null($aMean)) {
 
3140
            $aCount = -1;
 
3141
            foreach ($aArgs as $k => $arg) {
 
3142
                if ((is_bool($arg)) &&
 
3143
                    (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
 
3144
                } else {
 
3145
                    // Is it a numeric value?
 
3146
                    if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
 
3147
                        if (is_bool($arg)) {
 
3148
                            $arg = (integer) $arg;
 
3149
                        } elseif (is_string($arg)) {
 
3150
                            $arg = 0;
 
3151
                        }
 
3152
                        if (is_null($returnValue)) {
 
3153
                            $returnValue = pow(($arg - $aMean), 2);
 
3154
                        } else {
 
3155
                            $returnValue += pow(($arg - $aMean), 2);
 
3156
                        }
 
3157
                        ++$aCount;
 
3158
                    }
 
3159
                }
 
3160
            }
 
3161
 
 
3162
            if (($aCount > 0) && ($returnValue >= 0)) {
 
3163
                return sqrt($returnValue / $aCount);
 
3164
            }
 
3165
        }
 
3166
        return PHPExcel_Calculation_Functions::DIV0();
 
3167
    }
 
3168
 
 
3169
 
 
3170
    /**
 
3171
     * STDEVP
 
3172
     *
 
3173
     * Calculates standard deviation based on the entire population
 
3174
     *
 
3175
     * Excel Function:
 
3176
     *        STDEVP(value1[,value2[, ...]])
 
3177
     *
 
3178
     * @access    public
 
3179
     * @category Statistical Functions
 
3180
     * @param    mixed        $arg,...        Data values
 
3181
     * @return    float
 
3182
     */
 
3183
    public static function STDEVP()
 
3184
    {
 
3185
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
3186
 
 
3187
        $returnValue = null;
 
3188
 
 
3189
        $aMean = self::AVERAGE($aArgs);
 
3190
        if (!is_null($aMean)) {
 
3191
            $aCount = 0;
 
3192
            foreach ($aArgs as $k => $arg) {
 
3193
                if ((is_bool($arg)) &&
 
3194
                    ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
 
3195
                    $arg = (integer) $arg;
 
3196
                }
 
3197
                // Is it a numeric value?
 
3198
                if ((is_numeric($arg)) && (!is_string($arg))) {
 
3199
                    if (is_null($returnValue)) {
 
3200
                        $returnValue = pow(($arg - $aMean), 2);
 
3201
                    } else {
 
3202
                        $returnValue += pow(($arg - $aMean), 2);
 
3203
                    }
 
3204
                    ++$aCount;
 
3205
                }
 
3206
            }
 
3207
 
 
3208
            if (($aCount > 0) && ($returnValue >= 0)) {
 
3209
                return sqrt($returnValue / $aCount);
 
3210
            }
 
3211
        }
 
3212
        return PHPExcel_Calculation_Functions::DIV0();
 
3213
    }
 
3214
 
 
3215
 
 
3216
    /**
 
3217
     * STDEVPA
 
3218
     *
 
3219
     * Calculates standard deviation based on the entire population, including numbers, text, and logical values
 
3220
     *
 
3221
     * Excel Function:
 
3222
     *        STDEVPA(value1[,value2[, ...]])
 
3223
     *
 
3224
     * @access    public
 
3225
     * @category Statistical Functions
 
3226
     * @param    mixed        $arg,...        Data values
 
3227
     * @return    float
 
3228
     */
 
3229
    public static function STDEVPA()
 
3230
    {
 
3231
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
3232
 
 
3233
        $returnValue = null;
 
3234
 
 
3235
        $aMean = self::AVERAGEA($aArgs);
 
3236
        if (!is_null($aMean)) {
 
3237
            $aCount = 0;
 
3238
            foreach ($aArgs as $k => $arg) {
 
3239
                if ((is_bool($arg)) &&
 
3240
                    (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
 
3241
                } else {
 
3242
                    // Is it a numeric value?
 
3243
                    if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
 
3244
                        if (is_bool($arg)) {
 
3245
                            $arg = (integer) $arg;
 
3246
                        } elseif (is_string($arg)) {
 
3247
                            $arg = 0;
 
3248
                        }
 
3249
                        if (is_null($returnValue)) {
 
3250
                            $returnValue = pow(($arg - $aMean), 2);
 
3251
                        } else {
 
3252
                            $returnValue += pow(($arg - $aMean), 2);
 
3253
                        }
 
3254
                        ++$aCount;
 
3255
                    }
 
3256
                }
 
3257
            }
 
3258
 
 
3259
            if (($aCount > 0) && ($returnValue >= 0)) {
 
3260
                return sqrt($returnValue / $aCount);
 
3261
            }
 
3262
        }
 
3263
        return PHPExcel_Calculation_Functions::DIV0();
 
3264
    }
 
3265
 
 
3266
 
 
3267
    /**
 
3268
     * STEYX
 
3269
     *
 
3270
     * Returns the standard error of the predicted y-value for each x in the regression.
 
3271
     *
 
3272
     * @param    array of mixed        Data Series Y
 
3273
     * @param    array of mixed        Data Series X
 
3274
     * @return    float
 
3275
     */
 
3276
    public static function STEYX($yValues, $xValues)
 
3277
    {
 
3278
        if (!self::checkTrendArrays($yValues, $xValues)) {
 
3279
            return PHPExcel_Calculation_Functions::VALUE();
 
3280
        }
 
3281
        $yValueCount = count($yValues);
 
3282
        $xValueCount = count($xValues);
 
3283
 
 
3284
        if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
 
3285
            return PHPExcel_Calculation_Functions::NA();
 
3286
        } elseif ($yValueCount == 1) {
 
3287
            return PHPExcel_Calculation_Functions::DIV0();
 
3288
        }
 
3289
 
 
3290
        $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
 
3291
        return $bestFitLinear->getStdevOfResiduals();
 
3292
    }
 
3293
 
 
3294
 
 
3295
    /**
 
3296
     * TDIST
 
3297
     *
 
3298
     * Returns the probability of Student's T distribution.
 
3299
     *
 
3300
     * @param    float        $value            Value for the function
 
3301
     * @param    float        $degrees        degrees of freedom
 
3302
     * @param    float        $tails            number of tails (1 or 2)
 
3303
     * @return    float
 
3304
     */
 
3305
    public static function TDIST($value, $degrees, $tails)
 
3306
    {
 
3307
        $value        = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
3308
        $degrees    = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees));
 
3309
        $tails        = floor(PHPExcel_Calculation_Functions::flattenSingleValue($tails));
 
3310
 
 
3311
        if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) {
 
3312
            if (($value < 0) || ($degrees < 1) || ($tails < 1) || ($tails > 2)) {
 
3313
                return PHPExcel_Calculation_Functions::NaN();
 
3314
            }
 
3315
            //    tdist, which finds the probability that corresponds to a given value
 
3316
            //    of t with k degrees of freedom. This algorithm is translated from a
 
3317
            //    pascal function on p81 of "Statistical Computing in Pascal" by D
 
3318
            //    Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd:
 
3319
            //    London). The above Pascal algorithm is itself a translation of the
 
3320
            //    fortran algoritm "AS 3" by B E Cooper of the Atlas Computer
 
3321
            //    Laboratory as reported in (among other places) "Applied Statistics
 
3322
            //    Algorithms", editied by P Griffiths and I D Hill (1985; Ellis
 
3323
            //    Horwood Ltd.; W. Sussex, England).
 
3324
            $tterm = $degrees;
 
3325
            $ttheta = atan2($value, sqrt($tterm));
 
3326
            $tc = cos($ttheta);
 
3327
            $ts = sin($ttheta);
 
3328
            $tsum = 0;
 
3329
 
 
3330
            if (($degrees % 2) == 1) {
 
3331
                $ti = 3;
 
3332
                $tterm = $tc;
 
3333
            } else {
 
3334
                $ti = 2;
 
3335
                $tterm = 1;
 
3336
            }
 
3337
 
 
3338
            $tsum = $tterm;
 
3339
            while ($ti < $degrees) {
 
3340
                $tterm *= $tc * $tc * ($ti - 1) / $ti;
 
3341
                $tsum += $tterm;
 
3342
                $ti += 2;
 
3343
            }
 
3344
            $tsum *= $ts;
 
3345
            if (($degrees % 2) == 1) {
 
3346
                $tsum = M_2DIVPI * ($tsum + $ttheta);
 
3347
            }
 
3348
            $tValue = 0.5 * (1 + $tsum);
 
3349
            if ($tails == 1) {
 
3350
                return 1 - abs($tValue);
 
3351
            } else {
 
3352
                return 1 - abs((1 - $tValue) - $tValue);
 
3353
            }
 
3354
        }
 
3355
        return PHPExcel_Calculation_Functions::VALUE();
 
3356
    }
 
3357
 
 
3358
 
 
3359
    /**
 
3360
     * TINV
 
3361
     *
 
3362
     * Returns the one-tailed probability of the chi-squared distribution.
 
3363
     *
 
3364
     * @param    float        $probability    Probability for the function
 
3365
     * @param    float        $degrees        degrees of freedom
 
3366
     * @return    float
 
3367
     */
 
3368
    public static function TINV($probability, $degrees)
 
3369
    {
 
3370
        $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
 
3371
        $degrees     = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees));
 
3372
 
 
3373
        if ((is_numeric($probability)) && (is_numeric($degrees))) {
 
3374
            $xLo = 100;
 
3375
            $xHi = 0;
 
3376
 
 
3377
            $x = $xNew = 1;
 
3378
            $dx    = 1;
 
3379
            $i = 0;
 
3380
 
 
3381
            while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
 
3382
                // Apply Newton-Raphson step
 
3383
                $result = self::TDIST($x, $degrees, 2);
 
3384
                $error = $result - $probability;
 
3385
                if ($error == 0.0) {
 
3386
                    $dx = 0;
 
3387
                } elseif ($error < 0.0) {
 
3388
                    $xLo = $x;
 
3389
                } else {
 
3390
                    $xHi = $x;
 
3391
                }
 
3392
                // Avoid division by zero
 
3393
                if ($result != 0.0) {
 
3394
                    $dx = $error / $result;
 
3395
                    $xNew = $x - $dx;
 
3396
                }
 
3397
                // If the NR fails to converge (which for example may be the
 
3398
                // case if the initial guess is too rough) we apply a bisection
 
3399
                // step to determine a more narrow interval around the root.
 
3400
                if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
 
3401
                    $xNew = ($xLo + $xHi) / 2;
 
3402
                    $dx = $xNew - $x;
 
3403
                }
 
3404
                $x = $xNew;
 
3405
            }
 
3406
            if ($i == MAX_ITERATIONS) {
 
3407
                return PHPExcel_Calculation_Functions::NA();
 
3408
            }
 
3409
            return round($x, 12);
 
3410
        }
 
3411
        return PHPExcel_Calculation_Functions::VALUE();
 
3412
    }
 
3413
 
 
3414
 
 
3415
    /**
 
3416
     * TREND
 
3417
     *
 
3418
     * Returns values along a linear trend
 
3419
     *
 
3420
     * @param    array of mixed        Data Series Y
 
3421
     * @param    array of mixed        Data Series X
 
3422
     * @param    array of mixed        Values of X for which we want to find Y
 
3423
     * @param    boolean                A logical value specifying whether to force the intersect to equal 0.
 
3424
     * @return    array of float
 
3425
     */
 
3426
    public static function TREND($yValues, $xValues = array(), $newValues = array(), $const = true)
 
3427
    {
 
3428
        $yValues = PHPExcel_Calculation_Functions::flattenArray($yValues);
 
3429
        $xValues = PHPExcel_Calculation_Functions::flattenArray($xValues);
 
3430
        $newValues = PHPExcel_Calculation_Functions::flattenArray($newValues);
 
3431
        $const = (is_null($const)) ? true : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const);
 
3432
 
 
3433
        $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues, $const);
 
3434
        if (empty($newValues)) {
 
3435
            $newValues = $bestFitLinear->getXValues();
 
3436
        }
 
3437
 
 
3438
        $returnArray = array();
 
3439
        foreach ($newValues as $xValue) {
 
3440
            $returnArray[0][] = $bestFitLinear->getValueOfYForX($xValue);
 
3441
        }
 
3442
 
 
3443
        return $returnArray;
 
3444
    }
 
3445
 
 
3446
 
 
3447
    /**
 
3448
     * TRIMMEAN
 
3449
     *
 
3450
     * Returns the mean of the interior of a data set. TRIMMEAN calculates the mean
 
3451
     *        taken by excluding a percentage of data points from the top and bottom tails
 
3452
     *        of a data set.
 
3453
     *
 
3454
     * Excel Function:
 
3455
     *        TRIMEAN(value1[,value2[, ...]], $discard)
 
3456
     *
 
3457
     * @access    public
 
3458
     * @category Statistical Functions
 
3459
     * @param    mixed        $arg,...        Data values
 
3460
     * @param    float        $discard        Percentage to discard
 
3461
     * @return    float
 
3462
     */
 
3463
    public static function TRIMMEAN()
 
3464
    {
 
3465
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
3466
 
 
3467
        // Calculate
 
3468
        $percent = array_pop($aArgs);
 
3469
 
 
3470
        if ((is_numeric($percent)) && (!is_string($percent))) {
 
3471
            if (($percent < 0) || ($percent > 1)) {
 
3472
                return PHPExcel_Calculation_Functions::NaN();
 
3473
            }
 
3474
            $mArgs = array();
 
3475
            foreach ($aArgs as $arg) {
 
3476
                // Is it a numeric value?
 
3477
                if ((is_numeric($arg)) && (!is_string($arg))) {
 
3478
                    $mArgs[] = $arg;
 
3479
                }
 
3480
            }
 
3481
            $discard = floor(self::COUNT($mArgs) * $percent / 2);
 
3482
            sort($mArgs);
 
3483
            for ($i=0; $i < $discard; ++$i) {
 
3484
                array_pop($mArgs);
 
3485
                array_shift($mArgs);
 
3486
            }
 
3487
            return self::AVERAGE($mArgs);
 
3488
        }
 
3489
        return PHPExcel_Calculation_Functions::VALUE();
 
3490
    }
 
3491
 
 
3492
 
 
3493
    /**
 
3494
     * VARFunc
 
3495
     *
 
3496
     * Estimates variance based on a sample.
 
3497
     *
 
3498
     * Excel Function:
 
3499
     *        VAR(value1[,value2[, ...]])
 
3500
     *
 
3501
     * @access    public
 
3502
     * @category Statistical Functions
 
3503
     * @param    mixed        $arg,...        Data values
 
3504
     * @return    float
 
3505
     */
 
3506
    public static function VARFunc()
 
3507
    {
 
3508
        $returnValue = PHPExcel_Calculation_Functions::DIV0();
 
3509
 
 
3510
        $summerA = $summerB = 0;
 
3511
 
 
3512
        // Loop through arguments
 
3513
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
3514
        $aCount = 0;
 
3515
        foreach ($aArgs as $arg) {
 
3516
            if (is_bool($arg)) {
 
3517
                $arg = (integer) $arg;
 
3518
            }
 
3519
            // Is it a numeric value?
 
3520
            if ((is_numeric($arg)) && (!is_string($arg))) {
 
3521
                $summerA += ($arg * $arg);
 
3522
                $summerB += $arg;
 
3523
                ++$aCount;
 
3524
            }
 
3525
        }
 
3526
 
 
3527
        if ($aCount > 1) {
 
3528
            $summerA *= $aCount;
 
3529
            $summerB *= $summerB;
 
3530
            $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
 
3531
        }
 
3532
        return $returnValue;
 
3533
    }
 
3534
 
 
3535
 
 
3536
    /**
 
3537
     * VARA
 
3538
     *
 
3539
     * Estimates variance based on a sample, including numbers, text, and logical values
 
3540
     *
 
3541
     * Excel Function:
 
3542
     *        VARA(value1[,value2[, ...]])
 
3543
     *
 
3544
     * @access    public
 
3545
     * @category Statistical Functions
 
3546
     * @param    mixed        $arg,...        Data values
 
3547
     * @return    float
 
3548
     */
 
3549
    public static function VARA()
 
3550
    {
 
3551
        $returnValue = PHPExcel_Calculation_Functions::DIV0();
 
3552
 
 
3553
        $summerA = $summerB = 0;
 
3554
 
 
3555
        // Loop through arguments
 
3556
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
3557
        $aCount = 0;
 
3558
        foreach ($aArgs as $k => $arg) {
 
3559
            if ((is_string($arg)) &&
 
3560
                (PHPExcel_Calculation_Functions::isValue($k))) {
 
3561
                return PHPExcel_Calculation_Functions::VALUE();
 
3562
            } elseif ((is_string($arg)) &&
 
3563
                (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
 
3564
            } else {
 
3565
                // Is it a numeric value?
 
3566
                if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
 
3567
                    if (is_bool($arg)) {
 
3568
                        $arg = (integer) $arg;
 
3569
                    } elseif (is_string($arg)) {
 
3570
                        $arg = 0;
 
3571
                    }
 
3572
                    $summerA += ($arg * $arg);
 
3573
                    $summerB += $arg;
 
3574
                    ++$aCount;
 
3575
                }
 
3576
            }
 
3577
        }
 
3578
 
 
3579
        if ($aCount > 1) {
 
3580
            $summerA *= $aCount;
 
3581
            $summerB *= $summerB;
 
3582
            $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
 
3583
        }
 
3584
        return $returnValue;
 
3585
    }
 
3586
 
 
3587
 
 
3588
    /**
 
3589
     * VARP
 
3590
     *
 
3591
     * Calculates variance based on the entire population
 
3592
     *
 
3593
     * Excel Function:
 
3594
     *        VARP(value1[,value2[, ...]])
 
3595
     *
 
3596
     * @access    public
 
3597
     * @category Statistical Functions
 
3598
     * @param    mixed        $arg,...        Data values
 
3599
     * @return    float
 
3600
     */
 
3601
    public static function VARP()
 
3602
    {
 
3603
        // Return value
 
3604
        $returnValue = PHPExcel_Calculation_Functions::DIV0();
 
3605
 
 
3606
        $summerA = $summerB = 0;
 
3607
 
 
3608
        // Loop through arguments
 
3609
        $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 
3610
        $aCount = 0;
 
3611
        foreach ($aArgs as $arg) {
 
3612
            if (is_bool($arg)) {
 
3613
                $arg = (integer) $arg;
 
3614
            }
 
3615
            // Is it a numeric value?
 
3616
            if ((is_numeric($arg)) && (!is_string($arg))) {
 
3617
                $summerA += ($arg * $arg);
 
3618
                $summerB += $arg;
 
3619
                ++$aCount;
 
3620
            }
 
3621
        }
 
3622
 
 
3623
        if ($aCount > 0) {
 
3624
            $summerA *= $aCount;
 
3625
            $summerB *= $summerB;
 
3626
            $returnValue = ($summerA - $summerB) / ($aCount * $aCount);
 
3627
        }
 
3628
        return $returnValue;
 
3629
    }
 
3630
 
 
3631
 
 
3632
    /**
 
3633
     * VARPA
 
3634
     *
 
3635
     * Calculates variance based on the entire population, including numbers, text, and logical values
 
3636
     *
 
3637
     * Excel Function:
 
3638
     *        VARPA(value1[,value2[, ...]])
 
3639
     *
 
3640
     * @access    public
 
3641
     * @category Statistical Functions
 
3642
     * @param    mixed        $arg,...        Data values
 
3643
     * @return    float
 
3644
     */
 
3645
    public static function VARPA()
 
3646
    {
 
3647
        $returnValue = PHPExcel_Calculation_Functions::DIV0();
 
3648
 
 
3649
        $summerA = $summerB = 0;
 
3650
 
 
3651
        // Loop through arguments
 
3652
        $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
 
3653
        $aCount = 0;
 
3654
        foreach ($aArgs as $k => $arg) {
 
3655
            if ((is_string($arg)) &&
 
3656
                (PHPExcel_Calculation_Functions::isValue($k))) {
 
3657
                return PHPExcel_Calculation_Functions::VALUE();
 
3658
            } elseif ((is_string($arg)) &&
 
3659
                (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
 
3660
            } else {
 
3661
                // Is it a numeric value?
 
3662
                if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
 
3663
                    if (is_bool($arg)) {
 
3664
                        $arg = (integer) $arg;
 
3665
                    } elseif (is_string($arg)) {
 
3666
                        $arg = 0;
 
3667
                    }
 
3668
                    $summerA += ($arg * $arg);
 
3669
                    $summerB += $arg;
 
3670
                    ++$aCount;
 
3671
                }
 
3672
            }
 
3673
        }
 
3674
 
 
3675
        if ($aCount > 0) {
 
3676
            $summerA *= $aCount;
 
3677
            $summerB *= $summerB;
 
3678
            $returnValue = ($summerA - $summerB) / ($aCount * $aCount);
 
3679
        }
 
3680
        return $returnValue;
 
3681
    }
 
3682
 
 
3683
 
 
3684
    /**
 
3685
     * WEIBULL
 
3686
     *
 
3687
     * Returns the Weibull distribution. Use this distribution in reliability
 
3688
     * analysis, such as calculating a device's mean time to failure.
 
3689
     *
 
3690
     * @param    float        $value
 
3691
     * @param    float        $alpha        Alpha Parameter
 
3692
     * @param    float        $beta        Beta Parameter
 
3693
     * @param    boolean        $cumulative
 
3694
     * @return    float
 
3695
     *
 
3696
     */
 
3697
    public static function WEIBULL($value, $alpha, $beta, $cumulative)
 
3698
    {
 
3699
        $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
3700
        $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
 
3701
        $beta  = PHPExcel_Calculation_Functions::flattenSingleValue($beta);
 
3702
 
 
3703
        if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) {
 
3704
            if (($value < 0) || ($alpha <= 0) || ($beta <= 0)) {
 
3705
                return PHPExcel_Calculation_Functions::NaN();
 
3706
            }
 
3707
            if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
 
3708
                if ($cumulative) {
 
3709
                    return 1 - exp(0 - pow($value / $beta, $alpha));
 
3710
                } else {
 
3711
                    return ($alpha / pow($beta, $alpha)) * pow($value, $alpha - 1) * exp(0 - pow($value / $beta, $alpha));
 
3712
                }
 
3713
            }
 
3714
        }
 
3715
        return PHPExcel_Calculation_Functions::VALUE();
 
3716
    }
 
3717
 
 
3718
 
 
3719
    /**
 
3720
     * ZTEST
 
3721
     *
 
3722
     * Returns the Weibull distribution. Use this distribution in reliability
 
3723
     * analysis, such as calculating a device's mean time to failure.
 
3724
     *
 
3725
     * @param    float        $dataSet
 
3726
     * @param    float        $m0        Alpha Parameter
 
3727
     * @param    float        $sigma    Beta Parameter
 
3728
     * @param    boolean        $cumulative
 
3729
     * @return    float
 
3730
     *
 
3731
     */
 
3732
    public static function ZTEST($dataSet, $m0, $sigma = null)
 
3733
    {
 
3734
        $dataSet = PHPExcel_Calculation_Functions::flattenArrayIndexed($dataSet);
 
3735
        $m0      = PHPExcel_Calculation_Functions::flattenSingleValue($m0);
 
3736
        $sigma   = PHPExcel_Calculation_Functions::flattenSingleValue($sigma);
 
3737
 
 
3738
        if (is_null($sigma)) {
 
3739
            $sigma = self::STDEV($dataSet);
 
3740
        }
 
3741
        $n = count($dataSet);
 
3742
 
 
3743
        return 1 - self::NORMSDIST((self::AVERAGE($dataSet) - $m0) / ($sigma / SQRT($n)));
 
3744
    }
 
3745
}