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