PageRenderTime 26ms CodeModel.GetById 5ms app.highlight 72ms RepoModel.GetById 1ms app.codeStats 2ms

/branches/v1.6.5/Classes/PHPExcel/Calculation/Functions.php

#
PHP | 7142 lines | 4199 code | 675 blank | 2268 comment | 1299 complexity | 78eaacab02c64a14509049ef66dcdc67 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2
   3/**
   4 * PHPExcel
   5 *
   6 * Copyright (c) 2006 - 2009 PHPExcel
   7 *
   8 * This library is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU Lesser General Public
  10 * License as published by the Free Software Foundation; either
  11 * version 2.1 of the License, or (at your option) any later version.
  12 *
  13 * This library is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 * Lesser General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU Lesser General Public
  19 * License along with this library; if not, write to the Free Software
  20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  21 *
  22 * @category   PHPExcel
  23 * @package	PHPExcel_Calculation
  24 * @copyright  Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
  25 * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
  26 * @version	##VERSION##, ##DATE##
  27 */
  28
  29
  30define('EPS', 2.22e-16);
  31define('MAX_VALUE', 1.2e308);
  32define('LOG_GAMMA_X_MAX_VALUE', 2.55e305);
  33define('SQRT2PI', 2.5066282746310005024157652848110452530069867406099);
  34define('XMININ', 2.23e-308);
  35define('MAX_ITERATIONS', 150);
  36define('PRECISION', 8.88E-016);
  37define('EULER', 2.71828182845904523536);
  38
  39$savedPrecision = ini_get('precision');
  40if ($savedPrecision < 15) {
  41	ini_set('precision',15);
  42}
  43
  44
  45/** PHPExcel_Cell */
  46require_once 'PHPExcel/Cell.php';
  47
  48/** PHPExcel_Cell_DataType */
  49require_once 'PHPExcel/Cell/DataType.php';
  50
  51/** PHPExcel_Shared_Date */
  52require_once 'PHPExcel/Shared/Date.php';
  53
  54/** PHPExcel_Shared_Date */
  55require_once 'PHPExcel/Shared/JAMA/Matrix.php';
  56
  57
  58/**
  59 * PHPExcel_Calculation_Functions
  60 *
  61 * @category   PHPExcel
  62 * @package	PHPExcel_Calculation
  63 * @copyright  Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
  64 */
  65class PHPExcel_Calculation_Functions {
  66
  67	/** constants */
  68	const COMPATIBILITY_EXCEL		= 'Excel';
  69	const COMPATIBILITY_GNUMERIC	= 'Gnumeric';
  70	const COMPATIBILITY_OPENOFFICE	= 'OpenOfficeCalc';
  71
  72	const RETURNDATE_PHP_NUMERIC = 'P';
  73	const RETURNDATE_PHP_OBJECT = 'O';
  74	const RETURNDATE_EXCEL = 'E';
  75
  76
  77	/**
  78	 * Compatibility mode to use for error checking and responses
  79	 *
  80	 * @var string
  81	 */
  82	private static $compatibilityMode	= self::COMPATIBILITY_EXCEL;
  83
  84	/**
  85	 * Data Type to use when returning date values
  86	 *
  87	 * @var integer
  88	 */
  89	private static $ReturnDateType	= self::RETURNDATE_PHP_NUMERIC;
  90
  91	/**
  92	 * List of error codes
  93	 *
  94	 * @var array
  95	 */
  96	private static $_errorCodes	= array( 'null'				=> '#NULL!',
  97										 'divisionbyzero'	=> '#DIV/0!',
  98										 'value'			=> '#VALUE!',
  99										 'reference'		=> '#REF!',
 100										 'name'				=> '#NAME?',
 101										 'num'				=> '#NUM!',
 102										 'na'				=> '#N/A',
 103										 'gettingdata'		=> '#GETTING_DATA'
 104									   );
 105
 106
 107	/**
 108	 * Set the Compatibility Mode
 109	 *
 110	 * @param	 string		$compatibilityMode		Compatibility Mode
 111	 * @return	 boolean	(Success or Failure)
 112	 */
 113	public static function setCompatibilityMode($compatibilityMode) {
 114		if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
 115			($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
 116			($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
 117			self::$compatibilityMode = $compatibilityMode;
 118			return True;
 119		}
 120		return False;
 121	}
 122
 123	/**
 124	 * Return the current Compatibility Mode
 125	 *
 126	 * @return	 string		$compatibilityMode		Compatibility Mode
 127	 */
 128	public static function getCompatibilityMode() {
 129		return self::$compatibilityMode;
 130	}
 131
 132	/**
 133	 * Set the Return Date Format (Excel, PHP Serialized or PHP Object)
 134	 *
 135	 * @param	 integer	$returnDateType			Return Date Format
 136	 * @return	 boolean							Success or failure
 137	 */
 138	public static function setReturnDateType($returnDateType) {
 139		if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
 140			($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
 141			($returnDateType == self::RETURNDATE_EXCEL)) {
 142			self::$ReturnDateType = $returnDateType;
 143			return True;
 144		}
 145		return False;
 146	}	//	function setReturnDateType()
 147
 148
 149	/**
 150	 * Return the Return Date Format (Excel, PHP Serialized or PHP Object)
 151	 *
 152	 * @return	 integer	$returnDateType			Return Date Format
 153	 */
 154	public static function getReturnDateType() {
 155		return self::$ReturnDateType;
 156	}	//	function getReturnDateType()
 157
 158
 159	/**
 160	 * DUMMY
 161	 *
 162	 * @return  string	#NAME?
 163	 */
 164	public static function DUMMY() {
 165		return self::$_errorCodes['name'];
 166	}
 167
 168	/**
 169	 * NA
 170	 *
 171	 * @return  string	#N/A!
 172	 */
 173	public static function NA() {
 174		return self::$_errorCodes['na'];
 175	}
 176
 177	/**
 178	 * LOGICAL_AND
 179	 *
 180	 * Returns boolean TRUE if all its arguments are TRUE; returns FALSE if one or more argument is FALSE.
 181	 *
 182	 *	Booleans arguments are treated as True or False as appropriate
 183	 *	Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
 184	 *	If any argument value is a string, or a Null, it is ignored
 185	 *
 186	 *	Quirk of Excel:
 187	 *		String values passed directly to the function rather than through a cell reference
 188	 *			e.g.=AND(1,"A",1)
 189	 *		will return a #VALUE! error, _not_ ignoring the string.
 190	 *		This behaviour is not replicated
 191	 *
 192	 * @param	array of mixed		Data Series
 193	 * @return  boolean
 194	 */
 195	public static function LOGICAL_AND() {
 196		// Return value
 197		$returnValue = True;
 198
 199		// Loop through the arguments
 200		$aArgs = self::flattenArray(func_get_args());
 201		$argCount = 0;
 202		foreach ($aArgs as $arg) {
 203			// Is it a boolean value?
 204			if (is_bool($arg)) {
 205				$returnValue = $returnValue && $arg;
 206				++$argCount;
 207			} elseif ((is_numeric($arg)) && (!is_string($arg))) {
 208				$returnValue = $returnValue && ($arg != 0);
 209				++$argCount;
 210			}
 211		}
 212
 213		// Return
 214		if ($argCount == 0) {
 215			return self::$_errorCodes['value'];
 216		}
 217		return $returnValue;
 218	}
 219
 220	/**
 221	 * LOGICAL_OR
 222	 *
 223	 * Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE.
 224	 *
 225	 *	Booleans arguments are treated as True or False as appropriate
 226	 *	Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
 227	 *	If any argument value is a string, or a Null, it is ignored
 228	 *
 229	 * @param	array of mixed		Data Series
 230	 * @return  boolean
 231	 */
 232	public static function LOGICAL_OR() {
 233		// Return value
 234		$returnValue = False;
 235
 236		// Loop through the arguments
 237		$aArgs = self::flattenArray(func_get_args());
 238		$argCount = 0;
 239		foreach ($aArgs as $arg) {
 240			// Is it a boolean value?
 241			if (is_bool($arg)) {
 242				$returnValue = $returnValue || $arg;
 243				++$argCount;
 244			} elseif ((is_numeric($arg)) && (!is_string($arg))) {
 245				$returnValue = $returnValue || ($arg != 0);
 246				++$argCount;
 247			}
 248		}
 249
 250		// Return
 251		if ($argCount == 0) {
 252			return self::$_errorCodes['value'];
 253		}
 254		return $returnValue;
 255	}
 256
 257	/**
 258	 * LOGICAL_FALSE
 259	 *
 260	 * Returns FALSE.
 261	 *
 262	 * @return  boolean
 263	 */
 264	public static function LOGICAL_FALSE() {
 265		return False;
 266	}
 267
 268	/**
 269	 * LOGICAL_TRUE
 270	 *
 271	 * Returns TRUE.
 272	 *
 273	 * @return  boolean
 274	 */
 275	public static function LOGICAL_TRUE() {
 276		return True;
 277	}
 278
 279	/**
 280	 * ATAN2
 281	 *
 282	 * This function calculates the arc tangent of the two variables x and y. It is similar to
 283	 *		calculating the arc tangent of y / x, except that the signs of both arguments are used
 284	 *		to determine the quadrant of the result.
 285	 * Note that Excel reverses the arguments, so we need to reverse them here before calling the
 286	 *		standard PHP atan() function
 287	 *
 288	 * @param	float	$x		Number
 289	 * @param	float	$y		Number
 290	 * @return  float	Square Root of Number * Pi
 291	 */
 292	public static function REVERSE_ATAN2($x, $y) {
 293		$x	= self::flattenSingleValue($x);
 294		$y	= self::flattenSingleValue($y);
 295
 296		return atan2($y, $x);
 297	}
 298
 299	/**
 300	 * SUM
 301	 *
 302	 * SUM computes the sum of all the values and cells referenced in the argument list.
 303	 *
 304	 * @param	array of mixed		Data Series
 305	 * @return  float
 306	 */
 307	public static function SUM() {
 308		// Return value
 309		$returnValue = 0;
 310
 311		// Loop through the arguments
 312		$aArgs = self::flattenArray(func_get_args());
 313		foreach ($aArgs as $arg) {
 314			// Is it a numeric value?
 315			if ((is_numeric($arg)) && (!is_string($arg))) {
 316				$returnValue += $arg;
 317			}
 318		}
 319
 320		// Return
 321		return $returnValue;
 322	}
 323
 324	/**
 325	 * SUMSQ
 326	 *
 327	 * Returns the sum of the squares of the arguments
 328	 *
 329	 * @param	array of mixed		Data Series
 330	 * @return  float
 331	 */
 332	public static function SUMSQ() {
 333		// Return value
 334		$returnValue = 0;
 335
 336		// Loop trough arguments
 337		$aArgs = self::flattenArray(func_get_args());
 338		foreach ($aArgs as $arg) {
 339			// Is it a numeric value?
 340			if ((is_numeric($arg)) && (!is_string($arg))) {
 341				$returnValue += pow($arg,2);
 342			}
 343		}
 344
 345		// Return
 346		return $returnValue;
 347	}
 348
 349	/**
 350	 * PRODUCT
 351	 *
 352	 * PRODUCT returns the product of all the values and cells referenced in the argument list.
 353	 *
 354	 * @param	array of mixed		Data Series
 355	 * @return  float
 356	 */
 357	public static function PRODUCT() {
 358		// Return value
 359		$returnValue = null;
 360
 361		// Loop trough arguments
 362		$aArgs = self::flattenArray(func_get_args());
 363		foreach ($aArgs as $arg) {
 364			// Is it a numeric value?
 365			if ((is_numeric($arg)) && (!is_string($arg))) {
 366				if (is_null($returnValue)) {
 367					$returnValue = $arg;
 368				} else {
 369					$returnValue *= $arg;
 370				}
 371			}
 372		}
 373
 374		// Return
 375		if (is_null($returnValue)) {
 376			return 0;
 377		}
 378		return $returnValue;
 379	}
 380
 381	/**
 382	 * QUOTIENT
 383	 *
 384	 * QUOTIENT function returns the integer portion of a division.numerator is the divided number
 385	 * and denominator is the divisor.
 386	 *
 387	 * @param	array of mixed		Data Series
 388	 * @return  float
 389	 */
 390	public static function QUOTIENT() {
 391		// Return value
 392		$returnValue = null;
 393
 394		// Loop trough arguments
 395		$aArgs = self::flattenArray(func_get_args());
 396		foreach ($aArgs as $arg) {
 397			// Is it a numeric value?
 398			if ((is_numeric($arg)) && (!is_string($arg))) {
 399				if (is_null($returnValue)) {
 400					if (($returnValue == 0) || ($arg == 0)) {
 401						$returnValue = 0;
 402					} else {
 403						$returnValue = $arg;
 404					}
 405				} else {
 406					if (($returnValue == 0) || ($arg == 0)) {
 407						$returnValue = 0;
 408					} else {
 409						$returnValue /= $arg;
 410					}
 411				}
 412			}
 413		}
 414
 415		// Return
 416		return intval($returnValue);
 417	}
 418
 419	/**
 420	 * MIN
 421	 *
 422	 * MIN returns the value of the element of the values passed that has the smallest value,
 423	 * with negative numbers considered smaller than positive numbers.
 424	 *
 425	 * @param	array of mixed		Data Series
 426	 * @return  float
 427	 */
 428	public static function MIN() {
 429		// Return value
 430		$returnValue = null;
 431
 432		// Loop trough arguments
 433		$aArgs = self::flattenArray(func_get_args());
 434		foreach ($aArgs as $arg) {
 435			// Is it a numeric value?
 436			if ((is_numeric($arg)) && (!is_string($arg))) {
 437				if ((is_null($returnValue)) || ($arg < $returnValue)) {
 438					$returnValue = $arg;
 439				}
 440			}
 441		}
 442
 443		// Return
 444		if(is_null($returnValue)) {
 445			return 0;
 446		}
 447		return $returnValue;
 448	}
 449
 450	/**
 451	 * MINA
 452	 *
 453	 * Returns the smallest value in a list of arguments, including numbers, text, and logical values
 454	 *
 455	 * @param	array of mixed		Data Series
 456	 * @return  float
 457	 */
 458	public static function MINA() {
 459		// Return value
 460		$returnValue = null;
 461
 462		// Loop through arguments
 463		$aArgs = self::flattenArray(func_get_args());
 464		foreach ($aArgs as $arg) {
 465			// Is it a numeric value?
 466			if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
 467				if (is_bool($arg)) {
 468					$arg = (integer) $arg;
 469				} elseif (is_string($arg)) {
 470					$arg = 0;
 471				}
 472				if ((is_null($returnValue)) || ($arg < $returnValue)) {
 473					$returnValue = $arg;
 474				}
 475			}
 476		}
 477
 478		// Return
 479		if(is_null($returnValue)) {
 480			return 0;
 481		}
 482		return $returnValue;
 483	}
 484
 485	/**
 486	 * SMALL
 487	 *
 488	 * Returns the nth smallest value in a data set. You can use this function to
 489	 * select a value based on its relative standing.
 490	 *
 491	 * @param	array of mixed		Data Series
 492	 * @param	float	Entry in the series to return
 493	 * @return	float
 494	 */
 495	public static function SMALL() {
 496		$aArgs = self::flattenArray(func_get_args());
 497
 498		// Calculate
 499		$n = array_pop($aArgs);
 500
 501		if ((is_numeric($n)) && (!is_string($n))) {
 502			$mArgs = array();
 503			foreach ($aArgs as $arg) {
 504				// Is it a numeric value?
 505				if ((is_numeric($arg)) && (!is_string($arg))) {
 506					$mArgs[] = $arg;
 507				}
 508			}
 509			$count = self::COUNT($mArgs);
 510			$n = floor(--$n);
 511			if (($n < 0) || ($n >= $count) || ($count == 0)) {
 512				return self::$_errorCodes['num'];
 513			}
 514			sort($mArgs);
 515			return $mArgs[$n];
 516		}
 517		return self::$_errorCodes['value'];
 518	}
 519
 520	/**
 521	 * MAX
 522	 *
 523	 * MAX returns the value of the element of the values passed that has the highest value,
 524	 * with negative numbers considered smaller than positive numbers.
 525	 *
 526	 * @param	array of mixed		Data Series
 527	 * @return  float
 528	 */
 529	public static function MAX() {
 530		// Return value
 531		$returnValue = null;
 532
 533		// Loop trough arguments
 534		$aArgs = self::flattenArray(func_get_args());
 535		foreach ($aArgs as $arg) {
 536			// Is it a numeric value?
 537			if ((is_numeric($arg)) && (!is_string($arg))) {
 538				if ((is_null($returnValue)) || ($arg > $returnValue)) {
 539					$returnValue = $arg;
 540				}
 541			}
 542		}
 543
 544		// Return
 545		if(is_null($returnValue)) {
 546			return 0;
 547		}
 548		return $returnValue;
 549	}
 550
 551	/**
 552	 * MAXA
 553	 *
 554	 * Returns the greatest value in a list of arguments, including numbers, text, and logical values
 555	 *
 556	 * @param	array of mixed		Data Series
 557	 * @return  float
 558	 */
 559	public static function MAXA() {
 560		// Return value
 561		$returnValue = null;
 562
 563		// Loop through arguments
 564		$aArgs = self::flattenArray(func_get_args());
 565		foreach ($aArgs as $arg) {
 566			// Is it a numeric value?
 567			if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
 568				if (is_bool($arg)) {
 569					$arg = (integer) $arg;
 570				} elseif (is_string($arg)) {
 571					$arg = 0;
 572				}
 573				if ((is_null($returnValue)) || ($arg > $returnValue)) {
 574					$returnValue = $arg;
 575				}
 576			}
 577		}
 578
 579		// Return
 580		if(is_null($returnValue)) {
 581			return 0;
 582		}
 583		return $returnValue;
 584	}
 585
 586	/**
 587	 * LARGE
 588	 *
 589	 * Returns the nth largest value in a data set. You can use this function to
 590	 * select a value based on its relative standing.
 591	 *
 592	 * @param	array of mixed		Data Series
 593	 * @param	float	Entry in the series to return
 594	 * @return	float
 595	 *
 596	 */
 597	public static function LARGE() {
 598		$aArgs = self::flattenArray(func_get_args());
 599
 600		// Calculate
 601		$n = floor(array_pop($aArgs));
 602
 603		if ((is_numeric($n)) && (!is_string($n))) {
 604			$mArgs = array();
 605			foreach ($aArgs as $arg) {
 606				// Is it a numeric value?
 607				if ((is_numeric($arg)) && (!is_string($arg))) {
 608					$mArgs[] = $arg;
 609				}
 610			}
 611			$count = self::COUNT($mArgs);
 612			$n = floor(--$n);
 613			if (($n < 0) || ($n >= $count) || ($count == 0)) {
 614				return self::$_errorCodes['num'];
 615			}
 616			rsort($mArgs);
 617			return $mArgs[$n];
 618		}
 619		return self::$_errorCodes['value'];
 620	}
 621
 622	/**
 623	 * PERCENTILE
 624	 *
 625	 * Returns the nth percentile of values in a range..
 626	 *
 627	 * @param	array of mixed		Data Series
 628	 * @param	float	$entry		Entry in the series to return
 629	 * @return	float
 630	 */
 631	public static function PERCENTILE() {
 632		$aArgs = self::flattenArray(func_get_args());
 633
 634		// Calculate
 635		$entry = array_pop($aArgs);
 636
 637		if ((is_numeric($entry)) && (!is_string($entry))) {
 638			if (($entry < 0) || ($entry > 1)) {
 639				return self::$_errorCodes['num'];
 640			}
 641			$mArgs = array();
 642			foreach ($aArgs as $arg) {
 643				// Is it a numeric value?
 644				if ((is_numeric($arg)) && (!is_string($arg))) {
 645					$mArgs[] = $arg;
 646				}
 647			}
 648			$mValueCount = count($mArgs);
 649			if ($mValueCount > 0) {
 650				sort($mArgs);
 651				$count = self::COUNT($mArgs);
 652				$index = $entry * ($count-1);
 653				$iBase = floor($index);
 654				if ($index == $iBase) {
 655					return $mArgs[$index];
 656				} else {
 657					$iNext = $iBase + 1;
 658					$iProportion = $index - $iBase;
 659					return $mArgs[$iBase] + (($mArgs[$iNext] - $mArgs[$iBase]) * $iProportion) ;
 660				}
 661			}
 662		}
 663		return self::$_errorCodes['value'];
 664	}
 665
 666	/**
 667	 * QUARTILE
 668	 *
 669	 * Returns the quartile of a data set.
 670	 *
 671	 * @param	array of mixed		Data Series
 672	 * @param	float	$entry		Entry in the series to return
 673	 * @return	float
 674	 */
 675	public static function QUARTILE() {
 676		$aArgs = self::flattenArray(func_get_args());
 677
 678		// Calculate
 679		$entry = floor(array_pop($aArgs));
 680
 681		if ((is_numeric($entry)) && (!is_string($entry))) {
 682			$entry /= 4;
 683			if (($entry < 0) || ($entry > 1)) {
 684				return self::$_errorCodes['num'];
 685			}
 686			return self::PERCENTILE($aArgs,$entry);
 687		}
 688		return self::$_errorCodes['value'];
 689	}
 690
 691	/**
 692	 * COUNT
 693	 *
 694	 * Counts the number of cells that contain numbers within the list of arguments
 695	 *
 696	 * @param	array of mixed		Data Series
 697	 * @return  int
 698	 */
 699	public static function COUNT() {
 700		// Return value
 701		$returnValue = 0;
 702
 703		// Loop trough arguments
 704		$aArgs = self::flattenArray(func_get_args());
 705		foreach ($aArgs as $arg) {
 706			if ((is_bool($arg)) && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
 707				$arg = (int) $arg;
 708			}
 709			// Is it a numeric value?
 710			if ((is_numeric($arg)) && (!is_string($arg))) {
 711				++$returnValue;
 712			}
 713		}
 714
 715		// Return
 716		return $returnValue;
 717	}
 718
 719	/**
 720	 * COUNTBLANK
 721	 *
 722	 * Counts the number of empty cells within the list of arguments
 723	 *
 724	 * @param	array of mixed		Data Series
 725	 * @return  int
 726	 */
 727	public static function COUNTBLANK() {
 728		// Return value
 729		$returnValue = 0;
 730
 731		// Loop trough arguments
 732		$aArgs = self::flattenArray(func_get_args());
 733		foreach ($aArgs as $arg) {
 734			// Is it a blank cell?
 735			if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) {
 736				++$returnValue;
 737			}
 738		}
 739
 740		// Return
 741		return $returnValue;
 742	}
 743
 744	/**
 745	 * COUNTA
 746	 *
 747	 * Counts the number of cells that are not empty within the list of arguments
 748	 *
 749	 * @param	array of mixed		Data Series
 750	 * @return  int
 751	 */
 752	public static function COUNTA() {
 753		// Return value
 754		$returnValue = 0;
 755
 756		// Loop through arguments
 757		$aArgs = self::flattenArray(func_get_args());
 758		foreach ($aArgs as $arg) {
 759			// Is it a numeric, boolean or string value?
 760			if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
 761				++$returnValue;
 762			}
 763		}
 764
 765		// Return
 766		return $returnValue;
 767	}
 768
 769	/**
 770	 * AVERAGE
 771	 *
 772	 * Returns the average (arithmetic mean) of the arguments
 773	 *
 774	 * @param	array of mixed		Data Series
 775	 * @return  float
 776	 */
 777	public static function AVERAGE() {
 778		// Return value
 779		$returnValue = 0;
 780
 781		// Loop through arguments
 782		$aArgs = self::flattenArray(func_get_args());
 783		$aCount = 0;
 784		foreach ($aArgs as $arg) {
 785			if ((is_bool($arg))  && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
 786				$arg = (integer) $arg;
 787			}
 788			// Is it a numeric value?
 789			if ((is_numeric($arg)) && (!is_string($arg))) {
 790				if (is_null($returnValue)) {
 791					$returnValue = $arg;
 792				} else {
 793					$returnValue += $arg;
 794				}
 795				++$aCount;
 796			}
 797		}
 798
 799		// Return
 800		if ($aCount > 0) {
 801			return $returnValue / $aCount;
 802		} else {
 803			return self::$_errorCodes['divisionbyzero'];
 804		}
 805	}
 806
 807	/**
 808	 * AVERAGEA
 809	 *
 810	 * Returns the average of its arguments, including numbers, text, and logical values
 811	 *
 812	 * @param	array of mixed		Data Series
 813	 * @return  float
 814	 */
 815	public static function AVERAGEA() {
 816		// Return value
 817		$returnValue = null;
 818
 819		// Loop through arguments
 820		$aArgs = self::flattenArray(func_get_args());
 821		$aCount = 0;
 822		foreach ($aArgs as $arg) {
 823			if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
 824				if (is_bool($arg)) {
 825					$arg = (integer) $arg;
 826				} elseif (is_string($arg)) {
 827					$arg = 0;
 828				}
 829				if (is_null($returnValue)) {
 830					$returnValue = $arg;
 831				} else {
 832					$returnValue += $arg;
 833				}
 834				++$aCount;
 835			}
 836		}
 837
 838		// Return
 839		if ($aCount > 0) {
 840			return $returnValue / $aCount;
 841		} else {
 842			return self::$_errorCodes['divisionbyzero'];
 843		}
 844	}
 845
 846	/**
 847	 * MEDIAN
 848	 *
 849	 * Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
 850	 *
 851	 * @param	array of mixed		Data Series
 852	 * @return  float
 853	 */
 854	public static function MEDIAN() {
 855		// Return value
 856		$returnValue = self::$_errorCodes['num'];
 857
 858		$mArgs = array();
 859		// Loop through arguments
 860		$aArgs = self::flattenArray(func_get_args());
 861		foreach ($aArgs as $arg) {
 862			// Is it a numeric value?
 863			if ((is_numeric($arg)) && (!is_string($arg))) {
 864				$mArgs[] = $arg;
 865			}
 866		}
 867
 868		$mValueCount = count($mArgs);
 869		if ($mValueCount > 0) {
 870			sort($mArgs,SORT_NUMERIC);
 871			$mValueCount = $mValueCount / 2;
 872			if ($mValueCount == floor($mValueCount)) {
 873				$returnValue = ($mArgs[$mValueCount--] + $mArgs[$mValueCount]) / 2;
 874			} else {
 875				$mValueCount == floor($mValueCount);
 876				$returnValue = $mArgs[$mValueCount];
 877			}
 878		}
 879
 880		// Return
 881		return $returnValue;
 882	}
 883
 884	//
 885	//	Special variant of array_count_values that isn't limited to strings and integers,
 886	//		but can work with floating point numbers as values
 887	//
 888	private static function modeCalc($data) {
 889		$frequencyArray = array();
 890		foreach($data as $datum) {
 891			$found = False;
 892			foreach($frequencyArray as $key => $value) {
 893				if ((string)$value['value'] == (string)$datum) {
 894					++$frequencyArray[$key]['frequency'];
 895					$found = True;
 896					break;
 897				}
 898			}
 899			if (!$found) {
 900				$frequencyArray[] = array('value'		=> $datum,
 901										  'frequency'	=>	1 );
 902			}
 903		}
 904
 905		foreach($frequencyArray as $key => $value) {
 906			$frequencyList[$key] = $value['frequency'];
 907			$valueList[$key] = $value['value'];
 908		}
 909		array_multisort($frequencyList, SORT_DESC, $valueList, SORT_ASC, SORT_NUMERIC, $frequencyArray);
 910
 911		if ($frequencyArray[0]['frequency'] == 1) {
 912			return self::NA();
 913		}
 914		return $frequencyArray[0]['value'];
 915	}
 916
 917	/**
 918	 * MODE
 919	 *
 920	 * Returns the most frequently occurring, or repetitive, value in an array or range of data
 921	 *
 922	 * @param	array of mixed		Data Series
 923	 * @return  float
 924	 */
 925	public static function MODE() {
 926		// Return value
 927		$returnValue = self::NA();
 928
 929		// Loop through arguments
 930		$aArgs = self::flattenArray(func_get_args());
 931
 932		$mArgs = array();
 933		foreach ($aArgs as $arg) {
 934			// Is it a numeric value?
 935			if ((is_numeric($arg)) && (!is_string($arg))) {
 936				$mArgs[] = $arg;
 937			}
 938		}
 939
 940		if (count($mArgs) > 0) {
 941			return self::modeCalc($mArgs);
 942		}
 943
 944		// Return
 945		return $returnValue;
 946	}
 947
 948	/**
 949	 * DEVSQ
 950	 *
 951	 * Returns the sum of squares of deviations of data points from their sample mean.
 952	 *
 953	 * @param	array of mixed		Data Series
 954	 * @return  float
 955	 */
 956	public static function DEVSQ() {
 957		// Return value
 958		$returnValue = null;
 959
 960		$aMean = self::AVERAGE(func_get_args());
 961		if (!is_null($aMean)) {
 962			$aArgs = self::flattenArray(func_get_args());
 963
 964			$aCount = -1;
 965			foreach ($aArgs as $arg) {
 966				// Is it a numeric value?
 967				if ((is_bool($arg))  && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
 968					$arg = (int) $arg;
 969				}
 970				if ((is_numeric($arg)) && (!is_string($arg))) {
 971					if (is_null($returnValue)) {
 972						$returnValue = pow(($arg - $aMean),2);
 973					} else {
 974						$returnValue += pow(($arg - $aMean),2);
 975					}
 976					++$aCount;
 977				}
 978			}
 979
 980			// Return
 981			if (is_null($returnValue)) {
 982				return self::$_errorCodes['num'];
 983			} else {
 984				return $returnValue;
 985			}
 986		}
 987		return self::NA();
 988	}
 989
 990	/**
 991	 * AVEDEV
 992	 *
 993	 * Returns the average of the absolute deviations of data points from their mean.
 994	 * AVEDEV is a measure of the variability in a data set.
 995	 *
 996	 * @param	array of mixed		Data Series
 997	 * @return  float
 998	 */
 999	public static function AVEDEV() {
1000		$aArgs = self::flattenArray(func_get_args());
1001
1002		// Return value
1003		$returnValue = null;
1004
1005		$aMean = self::AVERAGE($aArgs);
1006		if ($aMean != self::$_errorCodes['divisionbyzero']) {
1007			$aCount = 0;
1008			foreach ($aArgs as $arg) {
1009				if ((is_bool($arg))  && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
1010					$arg = (integer) $arg;
1011				}
1012				// Is it a numeric value?
1013				if ((is_numeric($arg)) && (!is_string($arg))) {
1014					if (is_null($returnValue)) {
1015						$returnValue = abs($arg - $aMean);
1016					} else {
1017						$returnValue += abs($arg - $aMean);
1018					}
1019					++$aCount;
1020				}
1021			}
1022
1023			// Return
1024			return $returnValue / $aCount ;
1025		}
1026		return self::$_errorCodes['num'];
1027	}
1028
1029	/**
1030	 * GEOMEAN
1031	 *
1032	 * Returns the geometric mean of an array or range of positive data. For example, you
1033	 * can use GEOMEAN to calculate average growth rate given compound interest with
1034	 * variable rates.
1035	 *
1036	 * @param	array of mixed		Data Series
1037	 * @return  float
1038	 */
1039	public static function GEOMEAN() {
1040		$aMean = self::PRODUCT(func_get_args());
1041		if (is_numeric($aMean) && ($aMean > 0)) {
1042			$aArgs = self::flattenArray(func_get_args());
1043			$aCount = self::COUNT($aArgs) ;
1044			if (self::MIN($aArgs) > 0) {
1045				return pow($aMean, (1 / $aCount));
1046			}
1047		}
1048		return self::$_errorCodes['num'];
1049	}
1050
1051	/**
1052	 * HARMEAN
1053	 *
1054	 * Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the
1055	 * arithmetic mean of reciprocals.
1056	 *
1057	 * @param	array of mixed		Data Series
1058	 * @return  float
1059	 */
1060	public static function HARMEAN() {
1061		// Return value
1062		$returnValue = self::NA();
1063
1064		// Loop through arguments
1065		$aArgs = self::flattenArray(func_get_args());
1066		if (self::MIN($aArgs) < 0) {
1067			return self::$_errorCodes['num'];
1068		}
1069		$aCount = 0;
1070		foreach ($aArgs as $arg) {
1071			// Is it a numeric value?
1072			if ((is_numeric($arg)) && (!is_string($arg))) {
1073				if ($arg <= 0) {
1074					return self::$_errorCodes['num'];
1075				}
1076				if (is_null($returnValue)) {
1077					$returnValue = (1 / $arg);
1078				} else {
1079					$returnValue += (1 / $arg);
1080				}
1081				++$aCount;
1082			}
1083		}
1084
1085		// Return
1086		if ($aCount > 0) {
1087			return 1 / ($returnValue / $aCount);
1088		} else {
1089			return $returnValue;
1090		}
1091	}
1092
1093	/**
1094	 * TRIMMEAN
1095	 *
1096	 * Returns the mean of the interior of a data set. TRIMMEAN calculates the mean
1097	 * taken by excluding a percentage of data points from the top and bottom tails
1098	 * of a data set.
1099	 *
1100	 * @param	array of mixed		Data Series
1101	 * @param	float	Percentage to discard
1102	 * @return	float
1103	 */
1104	public static function TRIMMEAN() {
1105		$aArgs = self::flattenArray(func_get_args());
1106
1107		// Calculate
1108		$percent = array_pop($aArgs);
1109
1110		if ((is_numeric($percent)) && (!is_string($percent))) {
1111			if (($percent < 0) || ($percent > 1)) {
1112				return self::$_errorCodes['num'];
1113			}
1114			$mArgs = array();
1115			foreach ($aArgs as $arg) {
1116				// Is it a numeric value?
1117				if ((is_numeric($arg)) && (!is_string($arg))) {
1118					$mArgs[] = $arg;
1119				}
1120			}
1121			$discard = floor(self::COUNT($mArgs) * $percent / 2);
1122			sort($mArgs);
1123			for ($i=0; $i < $discard; ++$i) {
1124				array_pop($mArgs);
1125				array_shift($mArgs);
1126			}
1127			return self::AVERAGE($mArgs);
1128		}
1129		return self::$_errorCodes['value'];
1130	}
1131
1132	/**
1133	 * STDEV
1134	 *
1135	 * Estimates standard deviation based on a sample. The standard deviation is a measure of how
1136	 * widely values are dispersed from the average value (the mean).
1137	 *
1138	 * @param	array of mixed		Data Series
1139	 * @return  float
1140	 */
1141	public static function STDEV() {
1142		// Return value
1143		$returnValue = null;
1144
1145		$aMean = self::AVERAGE(func_get_args());
1146		if (!is_null($aMean)) {
1147			$aArgs = self::flattenArray(func_get_args());
1148
1149			$aCount = -1;
1150			foreach ($aArgs as $arg) {
1151				// Is it a numeric value?
1152				if ((is_numeric($arg)) && (!is_string($arg))) {
1153					if (is_null($returnValue)) {
1154						$returnValue = pow(($arg - $aMean),2);
1155					} else {
1156						$returnValue += pow(($arg - $aMean),2);
1157					}
1158					++$aCount;
1159				}
1160			}
1161
1162			// Return
1163			if (($aCount > 0) && ($returnValue > 0)) {
1164				return sqrt($returnValue / $aCount);
1165			}
1166		}
1167		return self::$_errorCodes['divisionbyzero'];
1168	}
1169
1170	/**
1171	 * STDEVA
1172	 *
1173	 * Estimates standard deviation based on a sample, including numbers, text, and logical values
1174	 *
1175	 * @param	array of mixed		Data Series
1176	 * @return  float
1177	 */
1178	public static function STDEVA() {
1179		// Return value
1180		$returnValue = null;
1181
1182		$aMean = self::AVERAGEA(func_get_args());
1183		if (!is_null($aMean)) {
1184			$aArgs = self::flattenArray(func_get_args());
1185
1186			$aCount = -1;
1187			foreach ($aArgs as $arg) {
1188				// Is it a numeric value?
1189				if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
1190					if (is_bool($arg)) {
1191						$arg = (integer) $arg;
1192					} elseif (is_string($arg)) {
1193						$arg = 0;
1194					}
1195					if (is_null($returnValue)) {
1196						$returnValue = pow(($arg - $aMean),2);
1197					} else {
1198						$returnValue += pow(($arg - $aMean),2);
1199					}
1200					++$aCount;
1201				}
1202			}
1203
1204			// Return
1205			if (($aCount > 0) && ($returnValue > 0)) {
1206				return sqrt($returnValue / $aCount);
1207			}
1208		}
1209		return self::$_errorCodes['divisionbyzero'];
1210	}
1211
1212	/**
1213	 * STDEVP
1214	 *
1215	 * Calculates standard deviation based on the entire population
1216	 *
1217	 * @param	array of mixed		Data Series
1218	 * @return  float
1219	 */
1220	public static function STDEVP() {
1221		// Return value
1222		$returnValue = null;
1223
1224		$aMean = self::AVERAGE(func_get_args());
1225		if (!is_null($aMean)) {
1226			$aArgs = self::flattenArray(func_get_args());
1227
1228			$aCount = 0;
1229			foreach ($aArgs as $arg) {
1230				// Is it a numeric value?
1231				if ((is_numeric($arg)) && (!is_string($arg))) {
1232					if (is_null($returnValue)) {
1233						$returnValue = pow(($arg - $aMean),2);
1234					} else {
1235						$returnValue += pow(($arg - $aMean),2);
1236					}
1237					++$aCount;
1238				}
1239			}
1240
1241			// Return
1242			if (($aCount > 0) && ($returnValue > 0)) {
1243				return sqrt($returnValue / $aCount);
1244			}
1245		}
1246		return self::$_errorCodes['divisionbyzero'];
1247	}
1248
1249	/**
1250	 * STDEVPA
1251	 *
1252	 * Calculates standard deviation based on the entire population, including numbers, text, and logical values
1253	 *
1254	 * @param	array of mixed		Data Series
1255	 * @return  float
1256	 */
1257	public static function STDEVPA() {
1258		// Return value
1259		$returnValue = null;
1260
1261		$aMean = self::AVERAGEA(func_get_args());
1262		if (!is_null($aMean)) {
1263			$aArgs = self::flattenArray(func_get_args());
1264
1265			$aCount = 0;
1266			foreach ($aArgs as $arg) {
1267				// Is it a numeric value?
1268				if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
1269					if (is_bool($arg)) {
1270						$arg = (integer) $arg;
1271					} elseif (is_string($arg)) {
1272						$arg = 0;
1273					}
1274					if (is_null($returnValue)) {
1275						$returnValue = pow(($arg - $aMean),2);
1276					} else {
1277						$returnValue += pow(($arg - $aMean),2);
1278					}
1279					++$aCount;
1280				}
1281			}
1282
1283			// Return
1284			if (($aCount > 0) && ($returnValue > 0)) {
1285				return sqrt($returnValue / $aCount);
1286			}
1287		}
1288		return self::$_errorCodes['divisionbyzero'];
1289	}
1290
1291	/**
1292	 * VARFunc
1293	 *
1294	 * Estimates variance based on a sample.
1295	 *
1296	 * @param	array of mixed		Data Series
1297	 * @return  float
1298	 */
1299	public static function VARFunc() {
1300		// Return value
1301		$returnValue = self::$_errorCodes['divisionbyzero'];
1302
1303		$summerA = $summerB = 0;
1304
1305		// Loop through arguments
1306		$aArgs = self::flattenArray(func_get_args());
1307		$aCount = 0;
1308		foreach ($aArgs as $arg) {
1309			// Is it a numeric value?
1310			if ((is_numeric($arg)) && (!is_string($arg))) {
1311				$summerA += ($arg * $arg);
1312				$summerB += $arg;
1313				++$aCount;
1314			}
1315		}
1316
1317		// Return
1318		if ($aCount > 1) {
1319			$summerA = $summerA * $aCount;
1320			$summerB = ($summerB * $summerB);
1321			$returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
1322		}
1323		return $returnValue;
1324	}
1325
1326	/**
1327	 * VARA
1328	 *
1329	 * Estimates variance based on a sample, including numbers, text, and logical values
1330	 *
1331	 * @param	array of mixed		Data Series
1332	 * @return  float
1333	 */
1334	public static function VARA() {
1335		// Return value
1336		$returnValue = self::$_errorCodes['divisionbyzero'];
1337
1338		$summerA = $summerB = 0;
1339
1340		// Loop through arguments
1341		$aArgs = self::flattenArray(func_get_args());
1342		$aCount = 0;
1343		foreach ($aArgs as $arg) {
1344			// Is it a numeric value?
1345				if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
1346				if (is_bool($arg)) {
1347					$arg = (integer) $arg;
1348				} elseif (is_string($arg)) {
1349					$arg = 0;
1350				}
1351				$summerA += ($arg * $arg);
1352				$summerB += $arg;
1353				++$aCount;
1354			}
1355		}
1356
1357		// Return
1358		if ($aCount > 1) {
1359			$summerA = $summerA * $aCount;
1360			$summerB = ($summerB * $summerB);
1361			$returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
1362		}
1363		return $returnValue;
1364	}
1365
1366	/**
1367	 * VARP
1368	 *
1369	 * Calculates variance based on the entire population
1370	 *
1371	 * @param	array of mixed		Data Series
1372	 * @return  float
1373	 */
1374	public static function VARP() {
1375		// Return value
1376		$returnValue = self::$_errorCodes['divisionbyzero'];
1377
1378		$summerA = $summerB = 0;
1379
1380		// Loop through arguments
1381		$aArgs = self::flattenArray(func_get_args());
1382		$aCount = 0;
1383		foreach ($aArgs as $arg) {
1384			// Is it a numeric value?
1385			if ((is_numeric($arg)) && (!is_string($arg))) {
1386				$summerA += ($arg * $arg);
1387				$summerB += $arg;
1388				++$aCount;
1389			}
1390		}
1391
1392		// Return
1393		if ($aCount > 0) {
1394			$summerA = $summerA * $aCount;
1395			$summerB = ($summerB * $summerB);
1396			$returnValue = ($summerA - $summerB) / ($aCount * $aCount);
1397		}
1398		return $returnValue;
1399	}
1400
1401	/**
1402	 * VARPA
1403	 *
1404	 * Calculates variance based on the entire population, including numbers, text, and logical values
1405	 *
1406	 * @param	array of mixed		Data Series
1407	 * @return  float
1408	 */
1409	public static function VARPA() {
1410		// Return value
1411		$returnValue = self::$_errorCodes['divisionbyzero'];
1412
1413		$summerA = $summerB = 0;
1414
1415		// Loop through arguments
1416		$aArgs = self::flattenArray(func_get_args());
1417		$aCount = 0;
1418		foreach ($aArgs as $arg) {
1419			// Is it a numeric value?
1420			if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
1421				if (is_bool($arg)) {
1422					$arg = (integer) $arg;
1423				} elseif (is_string($arg)) {
1424					$arg = 0;
1425				}
1426				$summerA += ($arg * $arg);
1427				$summerB += $arg;
1428				++$aCount;
1429			}
1430		}
1431
1432		// Return
1433		if ($aCount > 0) {
1434			$summerA = $summerA * $aCount;
1435			$summerB = ($summerB * $summerB);
1436			$returnValue = ($summerA - $summerB) / ($aCount * $aCount);
1437		}
1438		return $returnValue;
1439	}
1440
1441	/**
1442	 * SUBTOTAL
1443	 *
1444	 * Returns a subtotal in a list or database.
1445	 *
1446	 * @param	int		the number 1 to 11 that specifies which function to
1447	 *					use in calculating subtotals within a list.
1448	 * @param	array of mixed		Data Series
1449	 * @return	float
1450	 */
1451	public static function SUBTOTAL() {
1452		$aArgs = self::flattenArray(func_get_args());
1453
1454		// Calculate
1455		$subtotal = array_shift($aArgs);
1456
1457		if ((is_numeric($subtotal)) && (!is_string($subtotal))) {
1458			switch($subtotal) {
1459				case 1	:
1460					return self::AVERAGE($aArgs);
1461					break;
1462				case 2	:
1463					return self::COUNT($aArgs);
1464					break;
1465				case 3	:
1466					return self::COUNTA($aArgs);
1467					break;
1468				case 4	:
1469					return self::MAX($aArgs);
1470					break;
1471				case 5	:
1472					return self::MIN($aArgs);
1473					break;
1474				case 6	:
1475					return self::PRODUCT($aArgs);
1476					break;
1477				case 7	:
1478					return self::STDEV($aArgs);
1479					break;
1480				case 8	:
1481					return self::STDEVP($aArgs);
1482					break;
1483				case 9	:
1484					return self::SUM($aArgs);
1485					break;
1486				case 10	:
1487					return self::VARFunc($aArgs);
1488					break;
1489				case 11	:
1490					return self::VARP($aArgs);
1491					break;
1492			}
1493		}
1494		return self::$_errorCodes['value'];
1495	}
1496
1497	/**
1498	 * SQRTPI
1499	 *
1500	 * Returns the square root of (number * pi).
1501	 *
1502	 * @param	float	$number		Number
1503	 * @return  float	Square Root of Number * Pi
1504	 */
1505	public static function SQRTPI($number) {
1506		$number	= self::flattenSingleValue($number);
1507
1508		if (is_numeric($number)) {
1509			if ($number < 0) {
1510				return self::$_errorCodes['num'];
1511			}
1512			return sqrt($number * pi()) ;
1513		}
1514		return self::$_errorCodes['value'];
1515	}
1516
1517	/**
1518	 * FACT
1519	 *
1520	 * Returns the factorial of a number.
1521	 *
1522	 * @param	float	$factVal	Factorial Value
1523	 * @return  int		Factorial
1524	 */
1525	public static function FACT($factVal) {
1526		$factVal	= self::flattenSingleValue($factVal);
1527
1528		if (is_numeric($factVal)) {
1529			if ($factVal < 0) {
1530				return self::$_errorCodes['num'];
1531			}
1532			$factLoop = floor($factVal);
1533			if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) {
1534				if ($factVal > $factLoop) {
1535					return self::$_errorCodes['num'];
1536				}
1537			}
1538			$factorial = 1;
1539			while ($factLoop > 1) {
1540				$factorial *= $factLoop--;
1541			}
1542			return $factorial ;
1543		}
1544		return self::$_errorCodes['value'];
1545	}
1546
1547	/**
1548	 * FACTDOUBLE
1549	 *
1550	 * Returns the double factorial of a number.
1551	 *
1552	 * @param	float	$factVal	Factorial Value
1553	 * @return  int		Double Factorial
1554	 */
1555	public static function FACTDOUBLE($factVal) {
1556		$factLoop	= floor(self::flattenSingleValue($factVal));
1557
1558		if (is_numeric($factLoop)) {
1559			if ($factVal < 0) {
1560				return self::$_errorCodes['num'];
1561			}
1562			$factorial = 1;
1563			while ($factLoop > 1) {
1564				$factorial *= $factLoop--;
1565				--$factLoop;
1566			}
1567			return $factorial ;
1568		}
1569		return self::$_errorCodes['value'];
1570	}
1571
1572	/**
1573	 * MULTINOMIAL
1574	 *
1575	 * Returns the ratio of the factorial of a sum of values to the product of factorials.
1576	 *
1577	 * @param	array of mixed		Data Series
1578	 * @return  float
1579	 */
1580	public static function MULTINOMIAL() {
1581
1582		// Loop through arguments
1583		$aArgs = self::flattenArray(func_get_args());
1584		$summer = 0;
1585		$divisor = 1;
1586		foreach ($aArgs as $arg) {
1587			// Is it a numeric value?
1588			if (is_numeric($arg)) {
1589				if ($arg < 1) {
1590					return self::$_errorCodes['num'];
1591				}
1592				$summer += floor($arg);
1593				$divisor *= self::FACT($arg);
1594			} else {
1595				return self::$_errorCodes['value'];
1596			}
1597		}
1598
1599		// Return
1600		if ($summer > 0) {
1601			$summer = self::FACT($summer);
1602			return $summer / $divisor;
1603		}
1604		return 0;
1605	}
1606
1607	/**
1608	 * CEILING
1609	 *
1610	 * Returns number rounded up, away from zero, to the nearest multiple of significance.
1611	 *
1612	 * @param	float	$number			Number to round
1613	 * @param	float	$significance	Significance
1614	 * @return  float	Rounded Number
1615	 */
1616	public static function CEILING($number,$significance=null) {
1617		$number			= self::flattenSingleValue($number);
1618		$significance	= self::flattenSingleValue($significance);
1619
1620		if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
1621			$significance = $number/abs($number);
1622		}
1623
1624		if ((is_numeric($number)) && (is_numeric($significance))) {
1625			if (self::SIGN($number) == self::SIGN($significance)) {
1626				if ($significance == 0.0) {
1627					return 0;
1628				}
1629				return ceil($number / $significance) * $significance;
1630			} else {
1631				return self::$_errorCodes['num'];
1632			}
1633		}
1634		return self::$_errorCodes['value'];
1635	}
1636
1637	/**
1638	 * EVEN
1639	 *
1640	 * Returns number rounded up to the nearest even integer.
1641	 *
1642	 * @param	float	$number			Number to round
1643	 * @return  int		Rounded Number
1644	 */
1645	public static function EVEN($number) {
1646		$number	= self::flattenSingleValue($number);
1647
1648		if (is_numeric($number)) {
1649			$significance = 2 * self::SIGN($number);
1650			return self::CEILING($number,$significance);
1651		}
1652		return self::$_errorCodes['value'];
1653	}
1654
1655	/**
1656	 * ODD
1657	 *
1658	 * Returns number rounded up to the nearest odd integer.
1659	 *
1660	 * @param	float	$number			Number to round
1661	 * @return  int		Rounded Number
1662	 */
1663	public static function ODD($number) {
1664		$number	= self::flattenSingleValue($number);
1665
1666		if (is_numeric($number)) {
1667			$significance = self::SIGN($number);
1668			if ($significance == 0) {
1669				return 1;
1670			}
1671			$result = self::CEILING($number,$significance);
1672			if (self::IS_EVEN($result)) {
1673				$result += $significance;
1674			}
1675			return $result;
1676		}
1677		return self::$_errorCodes['value'];
1678	}
1679
1680	/**
1681	 * ROUNDUP
1682	 *
1683	 * Rounds a number up to a specified number of decimal places
1684	 *
1685	 * @param	float	$number			Number to round
1686	 * @param	int		$digits			Number of digits to which you want to round $number
1687	 * @return  float	Rounded Number
1688	 */
1689	public static function ROUNDUP($number,$digits) {
1690		$number	= self::flattenSingleValue($number);
1691		$digits	= self::flattenSingleValue($digits);
1692
1693		if (is_numeric($number)) {
1694			if ((is_numeric($digits)) && ($digits >= 0)) {
1695				$significance = pow(10,$digits);
1696				return ceil($number * $significance) / $significance;
1697			}
1698		}
1699		return self::$_errorCodes['value'];
1700	}
1701
1702	/**
1703	 * ROUNDDOWN
1704	 *
1705	 * Rounds a number down to a specified number of decimal places
1706	 *
1707	 * @param	float	$number			Number to round
1708	 * @param	int		$digits			Number of digits to which you want to round $number
1709	 * @return  float	Rounded Number
1710	 */
1711	public static function ROUNDDOWN($number,$digits) {
1712		$number	= self::flattenSingleValue($number);
1713		$digits	= self::flattenSingleValue($digits);
1714
1715		if (is_numeric($number)) {
1716			if ((is_numeric($digits)) && ($digits >= 0)) {
1717				$significance = pow(10,$digits);
1718				return floor($number * $significance) / $significance;
1719			}
1720		}
1721		return self::$_errorCodes['value'];
1722	}
1723
1724	/**
1725	 * MROUND
1726	 *
1727	 * Rounds a number to the nearest multiple of a specified value
1728	 *
1729	 * @param	float	$number			Number to round
1730	 * @param	int		$multiple		Multiple to which you want to round $number
1731	 * @return  float	Rounded Number
1732	 */
1733	public static function MROUND($number,$multiple) {
1734		$number		= self::flattenSingleValue($number);
1735		$multiple	= self::flattenSingleValue($multiple);
1736
1737		if ((is_numeric($number)) && (is_numeric($multiple))) {
1738			if ((self::SIGN($number)) == (self::SIGN($multiple))) {
1739				$lowerVal = floor($number / $multiple) * $multiple;
1740				$upperVal = ceil($number / $multiple) * $multiple;
1741				$adjustUp = abs($number - $upperVal);
1742				$adjustDown = abs($number - $lowerVal) + PRECISION;
1743				if ($adjustDown < $adjustUp) {
1744					return $lowerVal;
1745				}
1746				return $upperVal;
1747			}
1748			return self::$_errorCodes['num'];
1749		}
1750		return self::$_errorCodes['value'];
1751	}
1752
1753	/**
1754	 * SIGN
1755	 *
1756	 * Determines the sign of a number. Returns 1 if the number is positive, zero (0)
1757	 * if the number is 0, and -1 if the number is negative.
1758	 *
1759	 * @param	float	$number			Number to round
1760	 * @return  int		sign value
1761	 */
1762	public static function SIGN($number) {
1763		$number	= self::flattenSingleValue($number);
1764
1765		if (is_numeric($number)) {
1766			if ($number == 0.0) {
1767				return 0;
1768			}
1769			return $number / abs($number);
1770		}
1771		return self::$_errorCodes['value'];
1772	}
1773
1774	/**
1775	 * FLOOR
1776	 *
1777	 * Rounds number down, toward zero, to the nearest multiple of significance.
1778	 *
1779	 * @param	float	$number			Number to round
1780	 * @param	float	$significance	Significance
1781	 * @return  float	Rounded Number
1782	 */
1783	public static function FLOOR($number,$significance=null) {
1784		$number			= self::flattenSingleValue($number);
1785		$significance	= self::flattenSingleValue($significance);
1786
1787		if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
1788			$significance = $number/abs($number);
1789		}
1790
1791		if ((is_numeric($number)) && (is_numeric($significance))) {
1792			if ((float) $significance == 0.0) {
1793				return self::$_errorCodes['divisionbyzero'];
1794			}
1795			if (self::SIGN($number) == self::SIGN($significance)) {
1796				return floor($number / $significance) * $significance;
1797			} else {
1798				return self::$_errorCodes['num'];
1799			}
1800		}
1801		return self::$_errorCodes['value'];
1802	}
1803
1804	/**
1805	 * PERMUT
1806	 *
1807	 * Returns the number of permutations for a given number of objects that can be
1808	 * selected from number objects. A permutation is any set or subset of objects or
1809	 * events where internal order is significant. Permutations are different from
1810	 * combinations, for which the internal order is not significant. Use this function
1811	 * for lottery-style probability calculations.
1812	 *
1813	 * @param	int		$numObjs	Number of different objects
1814	 * @param	int		$numInSet	Number of objects in each permutation
1815	 * @return  int		Number of permutations
1816	 */
1817	public static function PERMUT($numObjs,$numInSet) {
1818		$numObjs	= self::flattenSingleValue($numObjs);
1819		$numInSet	= self::flattenSingleValue($numInSet);
1820
1821		if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
1822			if ($numObjs < $numInSet) {
1823				return self::$_errorCodes['num'];
1824			}
1825			return self::FACT($numObjs) / self::FACT($numObjs - $numInSet);
1826		}
1827		return self::$_errorCodes['value'];
1828	}
1829
1830	/**
1831	 * COMBIN
1832	 *
1833	 * Returns the number of combinations for a given number of items. Use COMBIN to
1834	 * determine the total possible number of groups for a given number of items.
1835	 *
1836	 * @param	int		$numObjs	Number of different objects
1837	 * @param	int		$numInSet	Number of objects in each combination
1838	 * @return  int		Number of combinations
1839	 */
1840	public static function COMBIN($numObjs,$numInSet) {
1841		$numObjs	= self::flattenSingleValue($numObjs);
1842		$numInSet	= self::flattenSingleValue($numInSet);
1843
1844		if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
1845			if ($numObjs < $numInSet) {
1846				return self::$_errorCodes['num'];
1847			} elseif ($numInSet < 0) {
1848				return self::$_errorCodes['num'];
1849			}
1850			return (self::FACT($numObjs) / self::FACT($numObjs - $numInSet)) / self::FACT($numInSet);
1851		}
1852		return self::$_errorCodes['value'];
1853	}
1854
1855	/**
1856	 * SERIESSUM
1857	 *
1858	 * Returns the sum of a power series
1859	 *
1860	 * @param	float			$x	Input value to the power series
1861	 * @param	float			$n	Initial power to which you want to raise $x
1862	 * @param	float			$m	Step by which to increase $n for each term in the series
1863	 * @param	array of mixed		Data Series
1864	 * @return	float
1865	 */
1866	public static function SERIESSUM() {
1867		// Return value
1868		$returnValue = 0;
1869
1870		// Loop trough arguments
1871		$aArgs = self::flattenArray(func_get_args());
1872
1873		$x = array_shift($aArgs);
1874		$n = array_shift($aArgs);
1875		$m = array_shift($aArgs);
1876
1877		if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) {
1878			// Calculate
1879			$i = 0;
1880			foreach($aArgs as $arg) {
1881				// Is it a numeric value?
1882				if ((is_numeric($arg)) && (!is_string($arg))) {
1883					$returnValue += $arg * pow($x,$n + ($m * $i++));
1884				} else {
1885					return self::$_errorCodes['value'];
1886				}
1887			}
1888			// Return
1889			return $returnValue;
1890		}
1891		return self::$_errorCodes['value'];
1892	}
1893
1894	/**
1895	 * STANDARDIZE
1896	 *
1897	 * Returns a normalized value from a distribution characterized by mean and standard_dev.
1898	 *
1899	 * @param	float	$value		Value to normalize
1900	 * @param	float	$mean		Mean Value
1901	 * @param	float	$stdDev		Standard Deviation
1902	 * @return  float	Standardized value
1903	 */
1904	public static function STANDARDIZE($value,$mean,$stdDev) {
1905		$value	= self::flattenSingleValue($value);
1906		$mean	= self::flattenSingleValue($mean);
1907		$stdDev	= self::flattenSingleValue($stdDev);
1908
1909		if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
1910			if ($stdDev <= 0) {
1911				return self::$_errorCodes['num'];
1912			}
1913			return ($value - $mean) / $stdDev ;
1914		}
1915		return self::$_errorCodes['value'];
1916	}
1917
1918	//
1919	//	Private method to return an array of the factors of the input value
1920	//
1921	private static function factors($value) {
1922		$startVal = floor(sqrt($value));
1923
1924		$factorArray = array();
1925		for ($i = $startVal; $i > 1; --$i) {
1926			if (($value % $i) == 0) {
1927				$factorArray = array_merge($factorArray,self::factors($value / $i));
1928				$factorArray = array_merge($factorArray,self::factors($i));
1929				if ($i <= sqrt($value)) {
1930					break;
1931				}
1932			}
1933		}
1934		if (count($factorArray) > 0) {
1935			rsort($factorArray);
1936			return $factorArray;
1937		} else {
1938			return array((integer) $value);
1939		}
1940	}
1941
1942	/**
1943	 * LCM
1944	 *
1945	 * Returns the lowest common multiplier of a series of numbers
1946	 *
1947	 * @param	$array	Values to calculate the Lowest Common Multiplier
1948	 * @return  int		Lowest Common Multiplier
1949	 */
1950	public static function LCM() {
1951		$aArgs = self::flattenArray(func_get_args());
1952
1953		$returnValue = 1;
1954		$allPoweredFactors = array();
1955		foreach($aArgs as $value) {
1956			if (!is_numeric($value)) {
1957				return self::$_errorCodes['value'];
1958			}
1959			if ($value < 1) {
1960				return self::$_errorCodes['num'];
1961			}
1962			$myFactors = self::factors(floor($value));
1963			$myCountedFactors = array_count_values($myFactors);
1964			$myPoweredFactors = array();
1965			foreach($myCountedFactors as $myCountedFactor => $myCountedPower) {
1966				$myPoweredFactors[$myCountedFactor] = pow($myCountedFactor,$myCountedPower);
1967			}
1968			foreach($myPoweredFactors as $myPoweredValue => $myPoweredFactor) {
1969				if (array_key_exists($myPoweredValue,$allPoweredFactors)) {
1970					if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) {
1971						$allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
1972					}
1973				} else {
1974					$allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
1975				}
1976			}
1977		}
1978		foreach($allPoweredFactors as $allPoweredFactor) {
1979			$returnValue *= (integer) $allPoweredFactor;
1980		}
1981		return $returnValue;
1982	}
1983
1984	/**
1985	 * GCD
1986	 *
1987	 * Returns the greatest common divisor of a series of numbers
1988	 *
1989	 * @param	$array	Values to calculate the Greatest Common Divisor
1990	 * @return  int		Greatest Common Divisor
1991	 */
1992	public static function GCD() {
1993		$aArgs = self::flattenArray(func_get_args());
1994
1995		$returnValue = 1;
1996		$allPoweredFactors = array();
1997		foreach($aArgs as $value) {
1998			if ($value == 0) {
1999				return 0;
2000			}
2001			$myFactors = self::factors($value);
2002			$myCountedFactors = array_count_values($myFactors);
2003			$allValuesFactors[] = $myCountedFactors;
2004		}
2005		$allValuesCount = count($allValuesFactors);
2006		$mergedArray = $allValuesFactors[0];
2007		for ($i=1;$i < $allValuesCount; ++$i) {
2008			$mergedArray = array_intersect_key($mergedArray,$allValuesFactors[$i]);
2009		}
2010		$mergedArrayValues = count($mergedArray);
2011		if ($mergedArrayValues == 0) {
2012			return $returnValue;
2013		} elseif ($mergedArrayValues > 1) {
2014			foreach($mergedArray as $mergedKey => $mergedValue) {
2015				foreach($allValuesFactors as $highestPowerTest) {
2016					foreach($highestPowerTest as $testKey => $testValue) {
2017						if (($testKey == $mergedKey) && ($testValue < $mergedValue)) {
2018							$mergedArray[$mergedKey] = $testValue;
2019							$mergedValue = $testValue;
2020						}
2021					}
2022				}
2023			}
2024
2025			$returnValue = 1;
2026			foreach($mergedArray as $key => $value) {
2027				$returnValue *= pow($key,$value);
2028			}
2029			return $returnValue;
2030		} else {
2031			$keys = array_keys($mergedArray);
2032			$key = $keys[0];
2033			$value = $mergedArray[$key];
2034			foreach($allValuesFactors as $testValue) {
2035				foreach($testValue as $mergedKey => $mergedValue) {
2036					if (($mergedKey == $key) && ($mergedValue < $value)) {
2037						$value = $mergedValue;
2038					}
2039				}
2040			}
2041			return pow($key,$value);
2042		}
2043	}
2044
2045	/**
2046	 * BINOMDIST
2047	 *
2048	 * Returns the individual term binomial distribution probability. Use BINOMDIST in problems with
2049	 * a fixed number of tests or trials, when the outcomes of any trial are only success or failure,
2050	 * when trials are independent, and when the probability of success is constant throughout the
2051	 * experiment. For example, BINOMDIST can calculate the probability that two of the next three
2052	 * ba…

Large files files are truncated, but you can click here to view the full file