PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.0.3
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.0.3
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpexcel / Classes / PHPExcel / Calculation / Statistical.php

Statistical.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.0.3, at vendor/phpoffice/phpexcel/Classes/PHPExcel/Calculation/Statistical.php

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