ILIAS  Release_4_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
Functions.php
Go to the documentation of this file.
1 <?php
30 define('EPS', 2.22e-16);
31 
33 define('MAX_VALUE', 1.2e308);
34 
36 define('LOG_GAMMA_X_MAX_VALUE', 2.55e305);
37 
39 define('SQRT2PI', 2.5066282746310005024157652848110452530069867406099);
40 
42 define('XMININ', 2.23e-308);
43 
45 define('MAX_ITERATIONS', 150);
46 
48 define('PRECISION', 8.88E-016);
49 
51 define('EULER', 2.71828182845904523536);
52 
53 $savedPrecision = ini_get('precision');
54 if ($savedPrecision < 16) {
55  ini_set('precision',16);
56 }
57 
58 
60 if (!defined('PHPEXCEL_ROOT')) {
64  define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
65 }
66 
68 require_once PHPEXCEL_ROOT . 'PHPExcel/Cell.php';
69 
71 require_once PHPEXCEL_ROOT . 'PHPExcel/Cell/DataType.php';
72 
74 require_once PHPEXCEL_ROOT . 'PHPExcel/Style/NumberFormat.php';
75 
77 require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/Date.php';
78 
80 require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/Matrix.php';
81 require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/trend/trendClass.php';
82 
83 
92 
94  const COMPATIBILITY_EXCEL = 'Excel';
95  const COMPATIBILITY_GNUMERIC = 'Gnumeric';
96  const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
97 
99  const RETURNDATE_PHP_OBJECT = 'O';
100  const RETURNDATE_EXCEL = 'E';
101 
102 
110 
118 
125  private static $_errorCodes = array( 'null' => '#NULL!',
126  'divisionbyzero' => '#DIV/0!',
127  'value' => '#VALUE!',
128  'reference' => '#REF!',
129  'name' => '#NAME?',
130  'num' => '#NUM!',
131  'na' => '#N/A',
132  'gettingdata' => '#GETTING_DATA'
133  );
134 
135 
148  public static function setCompatibilityMode($compatibilityMode) {
149  if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
150  ($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
151  ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
152  self::$compatibilityMode = $compatibilityMode;
153  return True;
154  }
155  return False;
156  } // function setCompatibilityMode()
157 
158 
170  public static function getCompatibilityMode() {
172  } // function getCompatibilityMode()
173 
174 
187  public static function setReturnDateType($returnDateType) {
188  if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
189  ($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
190  ($returnDateType == self::RETURNDATE_EXCEL)) {
191  self::$ReturnDateType = $returnDateType;
192  return True;
193  }
194  return False;
195  } // function setReturnDateType()
196 
197 
209  public static function getReturnDateType() {
210  return self::$ReturnDateType;
211  } // function getReturnDateType()
212 
213 
221  public static function DUMMY() {
222  return '#Not Yet Implemented';
223  } // function DUMMY()
224 
225 
233  public static function NA() {
234  return self::$_errorCodes['na'];
235  } // function NA()
236 
237 
245  public static function NaN() {
246  return self::$_errorCodes['num'];
247  } // function NAN()
248 
249 
257  public static function NAME() {
258  return self::$_errorCodes['name'];
259  } // function NAME()
260 
261 
269  public static function REF() {
270  return self::$_errorCodes['reference'];
271  } // function REF()
272 
273 
295  public static function LOGICAL_AND() {
296  // Return value
297  $returnValue = True;
298 
299  // Loop through the arguments
300  $aArgs = self::flattenArray(func_get_args());
301  $argCount = 0;
302  foreach ($aArgs as $arg) {
303  // Is it a boolean value?
304  if (is_bool($arg)) {
305  $returnValue = $returnValue && $arg;
306  ++$argCount;
307  } elseif ((is_numeric($arg)) && (!is_string($arg))) {
308  $returnValue = $returnValue && ($arg != 0);
309  ++$argCount;
310  } elseif (is_string($arg)) {
311  $arg = strtoupper($arg);
312  if ($arg == 'TRUE') {
313  $arg = 1;
314  } elseif ($arg == 'FALSE') {
315  $arg = 0;
316  } else {
317  return self::$_errorCodes['value'];
318  }
319  $returnValue = $returnValue && ($arg != 0);
320  ++$argCount;
321  }
322  }
323 
324  // Return
325  if ($argCount == 0) {
326  return self::$_errorCodes['value'];
327  }
328  return $returnValue;
329  } // function LOGICAL_AND()
330 
331 
353  public static function LOGICAL_OR() {
354  // Return value
355  $returnValue = False;
356 
357  // Loop through the arguments
358  $aArgs = self::flattenArray(func_get_args());
359  $argCount = 0;
360  foreach ($aArgs as $arg) {
361  // Is it a boolean value?
362  if (is_bool($arg)) {
363  $returnValue = $returnValue || $arg;
364  ++$argCount;
365  } elseif ((is_numeric($arg)) && (!is_string($arg))) {
366  $returnValue = $returnValue || ($arg != 0);
367  ++$argCount;
368  } elseif (is_string($arg)) {
369  $arg = strtoupper($arg);
370  if ($arg == 'TRUE') {
371  $arg = 1;
372  } elseif ($arg == 'FALSE') {
373  $arg = 0;
374  } else {
375  return self::$_errorCodes['value'];
376  }
377  $returnValue = $returnValue || ($arg != 0);
378  ++$argCount;
379  }
380  }
381 
382  // Return
383  if ($argCount == 0) {
384  return self::$_errorCodes['value'];
385  }
386  return $returnValue;
387  } // function LOGICAL_OR()
388 
389 
402  public static function LOGICAL_FALSE() {
403  return False;
404  } // function LOGICAL_FALSE()
405 
406 
419  public static function LOGICAL_TRUE() {
420  return True;
421  } // function LOGICAL_TRUE()
422 
423 
437  public static function LOGICAL_NOT($logical) {
438  return !$logical;
439  } // function LOGICAL_NOT()
440 
441 
472  public static function STATEMENT_IF($condition = true, $returnIfTrue = 0, $returnIfFalse = False) {
473  $condition = self::flattenSingleValue($condition);
474  $returnIfTrue = self::flattenSingleValue($returnIfTrue);
475  $returnIfFalse = self::flattenSingleValue($returnIfFalse);
476  if (is_null($returnIfTrue)) { $returnIfTrue = 0; }
477  if (is_null($returnIfFalse)) { $returnIfFalse = 0; }
478 
479  return ($condition ? $returnIfTrue : $returnIfFalse);
480  } // function STATEMENT_IF()
481 
482 
490  public static function STATEMENT_IFERROR($value = '', $errorpart = '') {
491  return self::STATEMENT_IF(self::IS_ERROR($value), $errorpart, $value);
492  } // function STATEMENT_IFERROR()
493 
494 
517  public static function REVERSE_ATAN2($xCoordinate, $yCoordinate) {
518  $xCoordinate = (float) self::flattenSingleValue($xCoordinate);
519  $yCoordinate = (float) self::flattenSingleValue($yCoordinate);
520 
521  if (($xCoordinate == 0) && ($yCoordinate == 0)) {
522  return self::$_errorCodes['divisionbyzero'];
523  }
524 
525  return atan2($yCoordinate, $xCoordinate);
526  } // function REVERSE_ATAN2()
527 
528 
543  public static function LOG_BASE($number, $base=10) {
544  $number = self::flattenSingleValue($number);
545  $base = self::flattenSingleValue($base);
546 
547  return log($number, $base);
548  } // function LOG_BASE()
549 
550 
564  public static function SUM() {
565  // Return value
566  $returnValue = 0;
567 
568  // Loop through the arguments
569  $aArgs = self::flattenArray(func_get_args());
570  foreach ($aArgs as $arg) {
571  // Is it a numeric value?
572  if ((is_numeric($arg)) && (!is_string($arg))) {
573  $returnValue += $arg;
574  }
575  }
576 
577  // Return
578  return $returnValue;
579  } // function SUM()
580 
581 
595  public static function SUMSQ() {
596  // Return value
597  $returnValue = 0;
598 
599  // Loop trough arguments
600  $aArgs = self::flattenArray(func_get_args());
601  foreach ($aArgs as $arg) {
602  // Is it a numeric value?
603  if ((is_numeric($arg)) && (!is_string($arg))) {
604  $returnValue += pow($arg,2);
605  }
606  }
607 
608  // Return
609  return $returnValue;
610  } // function SUMSQ()
611 
612 
626  public static function PRODUCT() {
627  // Return value
628  $returnValue = null;
629 
630  // Loop trough arguments
631  $aArgs = self::flattenArray(func_get_args());
632  foreach ($aArgs as $arg) {
633  // Is it a numeric value?
634  if ((is_numeric($arg)) && (!is_string($arg))) {
635  if (is_null($returnValue)) {
636  $returnValue = $arg;
637  } else {
638  $returnValue *= $arg;
639  }
640  }
641  }
642 
643  // Return
644  if (is_null($returnValue)) {
645  return 0;
646  }
647  return $returnValue;
648  } // function PRODUCT()
649 
650 
665  public static function QUOTIENT() {
666  // Return value
667  $returnValue = null;
668 
669  // Loop trough arguments
670  $aArgs = self::flattenArray(func_get_args());
671  foreach ($aArgs as $arg) {
672  // Is it a numeric value?
673  if ((is_numeric($arg)) && (!is_string($arg))) {
674  if (is_null($returnValue)) {
675  $returnValue = ($arg == 0) ? 0 : $arg;
676  } else {
677  if (($returnValue == 0) || ($arg == 0)) {
678  $returnValue = 0;
679  } else {
680  $returnValue /= $arg;
681  }
682  }
683  }
684  }
685 
686  // Return
687  return intval($returnValue);
688  } // function QUOTIENT()
689 
690 
705  public static function MIN() {
706  // Return value
707  $returnValue = null;
708 
709  // Loop trough arguments
710  $aArgs = self::flattenArray(func_get_args());
711  foreach ($aArgs as $arg) {
712  // Is it a numeric value?
713  if ((is_numeric($arg)) && (!is_string($arg))) {
714  if ((is_null($returnValue)) || ($arg < $returnValue)) {
715  $returnValue = $arg;
716  }
717  }
718  }
719 
720  // Return
721  if(is_null($returnValue)) {
722  return 0;
723  }
724  return $returnValue;
725  } // function MIN()
726 
727 
741  public static function MINA() {
742  // Return value
743  $returnValue = null;
744 
745  // Loop through arguments
746  $aArgs = self::flattenArray(func_get_args());
747  foreach ($aArgs as $arg) {
748  // Is it a numeric value?
749  if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
750  if (is_bool($arg)) {
751  $arg = (integer) $arg;
752  } elseif (is_string($arg)) {
753  $arg = 0;
754  }
755  if ((is_null($returnValue)) || ($arg < $returnValue)) {
756  $returnValue = $arg;
757  }
758  }
759  }
760 
761  // Return
762  if(is_null($returnValue)) {
763  return 0;
764  }
765  return $returnValue;
766  } // function MINA()
767 
768 
784  public static function SMALL() {
785  $aArgs = self::flattenArray(func_get_args());
786 
787  // Calculate
788  $n = array_pop($aArgs);
789 
790  if ((is_numeric($n)) && (!is_string($n))) {
791  $mArgs = array();
792  foreach ($aArgs as $arg) {
793  // Is it a numeric value?
794  if ((is_numeric($arg)) && (!is_string($arg))) {
795  $mArgs[] = $arg;
796  }
797  }
798  $count = self::COUNT($mArgs);
799  $n = floor(--$n);
800  if (($n < 0) || ($n >= $count) || ($count == 0)) {
801  return self::$_errorCodes['num'];
802  }
803  sort($mArgs);
804  return $mArgs[$n];
805  }
806  return self::$_errorCodes['value'];
807  } // function SMALL()
808 
809 
824  public static function MAX() {
825  // Return value
826  $returnValue = null;
827 
828  // Loop trough arguments
829  $aArgs = self::flattenArray(func_get_args());
830  foreach ($aArgs as $arg) {
831  // Is it a numeric value?
832  if ((is_numeric($arg)) && (!is_string($arg))) {
833  if ((is_null($returnValue)) || ($arg > $returnValue)) {
834  $returnValue = $arg;
835  }
836  }
837  }
838 
839  // Return
840  if(is_null($returnValue)) {
841  return 0;
842  }
843  return $returnValue;
844  } // function MAX()
845 
846 
860  public static function MAXA() {
861  // Return value
862  $returnValue = null;
863 
864  // Loop through arguments
865  $aArgs = self::flattenArray(func_get_args());
866  foreach ($aArgs as $arg) {
867  // Is it a numeric value?
868  if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
869  if (is_bool($arg)) {
870  $arg = (integer) $arg;
871  } elseif (is_string($arg)) {
872  $arg = 0;
873  }
874  if ((is_null($returnValue)) || ($arg > $returnValue)) {
875  $returnValue = $arg;
876  }
877  }
878  }
879 
880  // Return
881  if(is_null($returnValue)) {
882  return 0;
883  }
884  return $returnValue;
885  } // function MAXA()
886 
887 
904  public static function LARGE() {
905  $aArgs = self::flattenArray(func_get_args());
906 
907  // Calculate
908  $n = floor(array_pop($aArgs));
909 
910  if ((is_numeric($n)) && (!is_string($n))) {
911  $mArgs = array();
912  foreach ($aArgs as $arg) {
913  // Is it a numeric value?
914  if ((is_numeric($arg)) && (!is_string($arg))) {
915  $mArgs[] = $arg;
916  }
917  }
918  $count = self::COUNT($mArgs);
919  $n = floor(--$n);
920  if (($n < 0) || ($n >= $count) || ($count == 0)) {
921  return self::$_errorCodes['num'];
922  }
923  rsort($mArgs);
924  return $mArgs[$n];
925  }
926  return self::$_errorCodes['value'];
927  } // function LARGE()
928 
929 
944  public static function PERCENTILE() {
945  $aArgs = self::flattenArray(func_get_args());
946 
947  // Calculate
948  $entry = array_pop($aArgs);
949 
950  if ((is_numeric($entry)) && (!is_string($entry))) {
951  if (($entry < 0) || ($entry > 1)) {
952  return self::$_errorCodes['num'];
953  }
954  $mArgs = array();
955  foreach ($aArgs as $arg) {
956  // Is it a numeric value?
957  if ((is_numeric($arg)) && (!is_string($arg))) {
958  $mArgs[] = $arg;
959  }
960  }
961  $mValueCount = count($mArgs);
962  if ($mValueCount > 0) {
963  sort($mArgs);
964  $count = self::COUNT($mArgs);
965  $index = $entry * ($count-1);
966  $iBase = floor($index);
967  if ($index == $iBase) {
968  return $mArgs[$index];
969  } else {
970  $iNext = $iBase + 1;
971  $iProportion = $index - $iBase;
972  return $mArgs[$iBase] + (($mArgs[$iNext] - $mArgs[$iBase]) * $iProportion) ;
973  }
974  }
975  }
976  return self::$_errorCodes['value'];
977  } // function PERCENTILE()
978 
979 
994  public static function QUARTILE() {
995  $aArgs = self::flattenArray(func_get_args());
996 
997  // Calculate
998  $entry = floor(array_pop($aArgs));
999 
1000  if ((is_numeric($entry)) && (!is_string($entry))) {
1001  $entry /= 4;
1002  if (($entry < 0) || ($entry > 1)) {
1003  return self::$_errorCodes['num'];
1004  }
1005  return self::PERCENTILE($aArgs,$entry);
1006  }
1007  return self::$_errorCodes['value'];
1008  } // function QUARTILE()
1009 
1010 
1024  public static function COUNT() {
1025  // Return value
1026  $returnValue = 0;
1027 
1028  // Loop trough arguments
1029  $aArgs = self::flattenArray(func_get_args());
1030  foreach ($aArgs as $arg) {
1031  if ((is_bool($arg)) && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
1032  $arg = (int) $arg;
1033  }
1034  // Is it a numeric value?
1035  if ((is_numeric($arg)) && (!is_string($arg))) {
1036  ++$returnValue;
1037  }
1038  }
1039 
1040  // Return
1041  return $returnValue;
1042  } // function COUNT()
1043 
1044 
1058  public static function COUNTBLANK() {
1059  // Return value
1060  $returnValue = 0;
1061 
1062  // Loop trough arguments
1063  $aArgs = self::flattenArray(func_get_args());
1064  foreach ($aArgs as $arg) {
1065  // Is it a blank cell?
1066  if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) {
1067  ++$returnValue;
1068  }
1069  }
1070 
1071  // Return
1072  return $returnValue;
1073  } // function COUNTBLANK()
1074 
1075 
1089  public static function COUNTA() {
1090  // Return value
1091  $returnValue = 0;
1092 
1093  // Loop through arguments
1094  $aArgs = self::flattenArray(func_get_args());
1095  foreach ($aArgs as $arg) {
1096  // Is it a numeric, boolean or string value?
1097  if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
1098  ++$returnValue;
1099  }
1100  }
1101 
1102  // Return
1103  return $returnValue;
1104  } // function COUNTA()
1105 
1106 
1121  public static function COUNTIF($aArgs,$condition) {
1122  // Return value
1123  $returnValue = 0;
1124 
1125  $aArgs = self::flattenArray($aArgs);
1126  if (!in_array($condition{0},array('>', '<', '='))) {
1127  if (!is_numeric($condition)) { $condition = PHPExcel_Calculation::_wrapResult(strtoupper($condition)); }
1128  $condition = '='.$condition;
1129  }
1130  // Loop through arguments
1131  foreach ($aArgs as $arg) {
1132  if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); }
1133  $testCondition = '='.$arg.$condition;
1134  if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
1135  // Is it a value within our criteria
1136  ++$returnValue;
1137  }
1138  }
1139 
1140  // Return
1141  return $returnValue;
1142  } // function COUNTIF()
1143 
1144 
1159  public static function SUMIF($aArgs,$condition,$sumArgs = array()) {
1160  // Return value
1161  $returnValue = 0;
1162 
1163  $aArgs = self::flattenArray($aArgs);
1164  $sumArgs = self::flattenArray($sumArgs);
1165  if (count($sumArgs) == 0) {
1166  $sumArgs = $aArgs;
1167  }
1168  if (!in_array($condition{0},array('>', '<', '='))) {
1169  if (!is_numeric($condition)) { $condition = PHPExcel_Calculation::_wrapResult(strtoupper($condition)); }
1170  $condition = '='.$condition;
1171  }
1172  // Loop through arguments
1173  foreach ($aArgs as $key => $arg) {
1174  if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); }
1175  $testCondition = '='.$arg.$condition;
1176  if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
1177  // Is it a value within our criteria
1178  $returnValue += $sumArgs[$key];
1179  }
1180  }
1181 
1182  // Return
1183  return $returnValue;
1184  } // function SUMIF()
1185 
1186 
1200  public static function AVERAGE() {
1201  // Return value
1202  $returnValue = 0;
1203 
1204  // Loop through arguments
1205  $aArgs = self::flattenArray(func_get_args());
1206  $aCount = 0;
1207  foreach ($aArgs as $arg) {
1208  if ((is_bool($arg)) && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
1209  $arg = (integer) $arg;
1210  }
1211  // Is it a numeric value?
1212  if ((is_numeric($arg)) && (!is_string($arg))) {
1213  if (is_null($returnValue)) {
1214  $returnValue = $arg;
1215  } else {
1216  $returnValue += $arg;
1217  }
1218  ++$aCount;
1219  }
1220  }
1221 
1222  // Return
1223  if ($aCount > 0) {
1224  return $returnValue / $aCount;
1225  } else {
1226  return self::$_errorCodes['divisionbyzero'];
1227  }
1228  } // function AVERAGE()
1229 
1230 
1244  public static function AVERAGEA() {
1245  // Return value
1246  $returnValue = null;
1247 
1248  // Loop through arguments
1249  $aArgs = self::flattenArray(func_get_args());
1250  $aCount = 0;
1251  foreach ($aArgs as $arg) {
1252  if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
1253  if (is_bool($arg)) {
1254  $arg = (integer) $arg;
1255  } elseif (is_string($arg)) {
1256  $arg = 0;
1257  }
1258  if (is_null($returnValue)) {
1259  $returnValue = $arg;
1260  } else {
1261  $returnValue += $arg;
1262  }
1263  ++$aCount;
1264  }
1265  }
1266 
1267  // Return
1268  if ($aCount > 0) {
1269  return $returnValue / $aCount;
1270  } else {
1271  return self::$_errorCodes['divisionbyzero'];
1272  }
1273  } // function AVERAGEA()
1274 
1275 
1289  public static function MEDIAN() {
1290  // Return value
1291  $returnValue = self::$_errorCodes['num'];
1292 
1293  $mArgs = array();
1294  // Loop through arguments
1295  $aArgs = self::flattenArray(func_get_args());
1296  foreach ($aArgs as $arg) {
1297  // Is it a numeric value?
1298  if ((is_numeric($arg)) && (!is_string($arg))) {
1299  $mArgs[] = $arg;
1300  }
1301  }
1302 
1303  $mValueCount = count($mArgs);
1304  if ($mValueCount > 0) {
1305  sort($mArgs,SORT_NUMERIC);
1306  $mValueCount = $mValueCount / 2;
1307  if ($mValueCount == floor($mValueCount)) {
1308  $returnValue = ($mArgs[$mValueCount--] + $mArgs[$mValueCount]) / 2;
1309  } else {
1310  $mValueCount == floor($mValueCount);
1311  $returnValue = $mArgs[$mValueCount];
1312  }
1313  }
1314 
1315  // Return
1316  return $returnValue;
1317  } // function MEDIAN()
1318 
1319 
1320  //
1321  // Special variant of array_count_values that isn't limited to strings and integers,
1322  // but can work with floating point numbers as values
1323  //
1324  private static function _modeCalc($data) {
1325  $frequencyArray = array();
1326  foreach($data as $datum) {
1327  $found = False;
1328  foreach($frequencyArray as $key => $value) {
1329  if ((string) $value['value'] == (string) $datum) {
1330  ++$frequencyArray[$key]['frequency'];
1331  $found = True;
1332  break;
1333  }
1334  }
1335  if (!$found) {
1336  $frequencyArray[] = array('value' => $datum,
1337  'frequency' => 1 );
1338  }
1339  }
1340 
1341  foreach($frequencyArray as $key => $value) {
1342  $frequencyList[$key] = $value['frequency'];
1343  $valueList[$key] = $value['value'];
1344  }
1345  array_multisort($frequencyList, SORT_DESC, $valueList, SORT_ASC, SORT_NUMERIC, $frequencyArray);
1346 
1347  if ($frequencyArray[0]['frequency'] == 1) {
1348  return self::NA();
1349  }
1350  return $frequencyArray[0]['value'];
1351  } // function _modeCalc()
1352 
1353 
1367  public static function MODE() {
1368  // Return value
1369  $returnValue = self::NA();
1370 
1371  // Loop through arguments
1372  $aArgs = self::flattenArray(func_get_args());
1373 
1374  $mArgs = array();
1375  foreach ($aArgs as $arg) {
1376  // Is it a numeric value?
1377  if ((is_numeric($arg)) && (!is_string($arg))) {
1378  $mArgs[] = $arg;
1379  }
1380  }
1381 
1382  if (count($mArgs) > 0) {
1383  return self::_modeCalc($mArgs);
1384  }
1385 
1386  // Return
1387  return $returnValue;
1388  } // function MODE()
1389 
1390 
1404  public static function DEVSQ() {
1405  // Return value
1406  $returnValue = null;
1407 
1408  $aMean = self::AVERAGE(func_get_args());
1409  if (!is_null($aMean)) {
1410  $aArgs = self::flattenArray(func_get_args());
1411 
1412  $aCount = -1;
1413  foreach ($aArgs as $arg) {
1414  // Is it a numeric value?
1415  if ((is_bool($arg)) && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
1416  $arg = (int) $arg;
1417  }
1418  if ((is_numeric($arg)) && (!is_string($arg))) {
1419  if (is_null($returnValue)) {
1420  $returnValue = pow(($arg - $aMean),2);
1421  } else {
1422  $returnValue += pow(($arg - $aMean),2);
1423  }
1424  ++$aCount;
1425  }
1426  }
1427 
1428  // Return
1429  if (is_null($returnValue)) {
1430  return self::$_errorCodes['num'];
1431  } else {
1432  return $returnValue;
1433  }
1434  }
1435  return self::NA();
1436  } // function DEVSQ()
1437 
1438 
1453  public static function AVEDEV() {
1454  $aArgs = self::flattenArray(func_get_args());
1455 
1456  // Return value
1457  $returnValue = null;
1458 
1459  $aMean = self::AVERAGE($aArgs);
1460  if ($aMean != self::$_errorCodes['divisionbyzero']) {
1461  $aCount = 0;
1462  foreach ($aArgs as $arg) {
1463  if ((is_bool($arg)) && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
1464  $arg = (integer) $arg;
1465  }
1466  // Is it a numeric value?
1467  if ((is_numeric($arg)) && (!is_string($arg))) {
1468  if (is_null($returnValue)) {
1469  $returnValue = abs($arg - $aMean);
1470  } else {
1471  $returnValue += abs($arg - $aMean);
1472  }
1473  ++$aCount;
1474  }
1475  }
1476 
1477  // Return
1478  return $returnValue / $aCount ;
1479  }
1480  return self::$_errorCodes['num'];
1481  } // function AVEDEV()
1482 
1483 
1499  public static function GEOMEAN() {
1500  $aMean = self::PRODUCT(func_get_args());
1501  if (is_numeric($aMean) && ($aMean > 0)) {
1502  $aArgs = self::flattenArray(func_get_args());
1503  $aCount = self::COUNT($aArgs) ;
1504  if (self::MIN($aArgs) > 0) {
1505  return pow($aMean, (1 / $aCount));
1506  }
1507  }
1508  return self::$_errorCodes['num'];
1509  } // GEOMEAN()
1510 
1511 
1526  public static function HARMEAN() {
1527  // Return value
1528  $returnValue = self::NA();
1529 
1530  // Loop through arguments
1531  $aArgs = self::flattenArray(func_get_args());
1532  if (self::MIN($aArgs) < 0) {
1533  return self::$_errorCodes['num'];
1534  }
1535  $aCount = 0;
1536  foreach ($aArgs as $arg) {
1537  // Is it a numeric value?
1538  if ((is_numeric($arg)) && (!is_string($arg))) {
1539  if ($arg <= 0) {
1540  return self::$_errorCodes['num'];
1541  }
1542  if (is_null($returnValue)) {
1543  $returnValue = (1 / $arg);
1544  } else {
1545  $returnValue += (1 / $arg);
1546  }
1547  ++$aCount;
1548  }
1549  }
1550 
1551  // Return
1552  if ($aCount > 0) {
1553  return 1 / ($returnValue / $aCount);
1554  } else {
1555  return $returnValue;
1556  }
1557  } // function HARMEAN()
1558 
1559 
1576  public static function TRIMMEAN() {
1577  $aArgs = self::flattenArray(func_get_args());
1578 
1579  // Calculate
1580  $percent = array_pop($aArgs);
1581 
1582  if ((is_numeric($percent)) && (!is_string($percent))) {
1583  if (($percent < 0) || ($percent > 1)) {
1584  return self::$_errorCodes['num'];
1585  }
1586  $mArgs = array();
1587  foreach ($aArgs as $arg) {
1588  // Is it a numeric value?
1589  if ((is_numeric($arg)) && (!is_string($arg))) {
1590  $mArgs[] = $arg;
1591  }
1592  }
1593  $discard = floor(self::COUNT($mArgs) * $percent / 2);
1594  sort($mArgs);
1595  for ($i=0; $i < $discard; ++$i) {
1596  array_pop($mArgs);
1597  array_shift($mArgs);
1598  }
1599  return self::AVERAGE($mArgs);
1600  }
1601  return self::$_errorCodes['value'];
1602  } // function TRIMMEAN()
1603 
1604 
1619  public static function STDEV() {
1620  // Return value
1621  $returnValue = null;
1622 
1623  $aMean = self::AVERAGE(func_get_args());
1624  if (!is_null($aMean)) {
1625  $aArgs = self::flattenArray(func_get_args());
1626 
1627  $aCount = -1;
1628  foreach ($aArgs as $arg) {
1629  // Is it a numeric value?
1630  if ((is_numeric($arg)) && (!is_string($arg))) {
1631  if (is_null($returnValue)) {
1632  $returnValue = pow(($arg - $aMean),2);
1633  } else {
1634  $returnValue += pow(($arg - $aMean),2);
1635  }
1636  ++$aCount;
1637  }
1638  }
1639 
1640  // Return
1641  if (($aCount > 0) && ($returnValue > 0)) {
1642  return sqrt($returnValue / $aCount);
1643  }
1644  }
1645  return self::$_errorCodes['divisionbyzero'];
1646  } // function STDEV()
1647 
1648 
1662  public static function STDEVA() {
1663  // Return value
1664  $returnValue = null;
1665 
1666  $aMean = self::AVERAGEA(func_get_args());
1667  if (!is_null($aMean)) {
1668  $aArgs = self::flattenArray(func_get_args());
1669 
1670  $aCount = -1;
1671  foreach ($aArgs as $arg) {
1672  // Is it a numeric value?
1673  if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
1674  if (is_bool($arg)) {
1675  $arg = (integer) $arg;
1676  } elseif (is_string($arg)) {
1677  $arg = 0;
1678  }
1679  if (is_null($returnValue)) {
1680  $returnValue = pow(($arg - $aMean),2);
1681  } else {
1682  $returnValue += pow(($arg - $aMean),2);
1683  }
1684  ++$aCount;
1685  }
1686  }
1687 
1688  // Return
1689  if (($aCount > 0) && ($returnValue > 0)) {
1690  return sqrt($returnValue / $aCount);
1691  }
1692  }
1693  return self::$_errorCodes['divisionbyzero'];
1694  } // function STDEVA()
1695 
1696 
1710  public static function STDEVP() {
1711  // Return value
1712  $returnValue = null;
1713 
1714  $aMean = self::AVERAGE(func_get_args());
1715  if (!is_null($aMean)) {
1716  $aArgs = self::flattenArray(func_get_args());
1717 
1718  $aCount = 0;
1719  foreach ($aArgs as $arg) {
1720  // Is it a numeric value?
1721  if ((is_numeric($arg)) && (!is_string($arg))) {
1722  if (is_null($returnValue)) {
1723  $returnValue = pow(($arg - $aMean),2);
1724  } else {
1725  $returnValue += pow(($arg - $aMean),2);
1726  }
1727  ++$aCount;
1728  }
1729  }
1730 
1731  // Return
1732  if (($aCount > 0) && ($returnValue > 0)) {
1733  return sqrt($returnValue / $aCount);
1734  }
1735  }
1736  return self::$_errorCodes['divisionbyzero'];
1737  } // function STDEVP()
1738 
1739 
1753  public static function STDEVPA() {
1754  // Return value
1755  $returnValue = null;
1756 
1757  $aMean = self::AVERAGEA(func_get_args());
1758  if (!is_null($aMean)) {
1759  $aArgs = self::flattenArray(func_get_args());
1760 
1761  $aCount = 0;
1762  foreach ($aArgs as $arg) {
1763  // Is it a numeric value?
1764  if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
1765  if (is_bool($arg)) {
1766  $arg = (integer) $arg;
1767  } elseif (is_string($arg)) {
1768  $arg = 0;
1769  }
1770  if (is_null($returnValue)) {
1771  $returnValue = pow(($arg - $aMean),2);
1772  } else {
1773  $returnValue += pow(($arg - $aMean),2);
1774  }
1775  ++$aCount;
1776  }
1777  }
1778 
1779  // Return
1780  if (($aCount > 0) && ($returnValue > 0)) {
1781  return sqrt($returnValue / $aCount);
1782  }
1783  }
1784  return self::$_errorCodes['divisionbyzero'];
1785  } // function STDEVPA()
1786 
1787 
1801  public static function VARFunc() {
1802  // Return value
1803  $returnValue = self::$_errorCodes['divisionbyzero'];
1804 
1805  $summerA = $summerB = 0;
1806 
1807  // Loop through arguments
1808  $aArgs = self::flattenArray(func_get_args());
1809  $aCount = 0;
1810  foreach ($aArgs as $arg) {
1811  // Is it a numeric value?
1812  if ((is_numeric($arg)) && (!is_string($arg))) {
1813  $summerA += ($arg * $arg);
1814  $summerB += $arg;
1815  ++$aCount;
1816  }
1817  }
1818 
1819  // Return
1820  if ($aCount > 1) {
1821  $summerA = $summerA * $aCount;
1822  $summerB = ($summerB * $summerB);
1823  $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
1824  }
1825  return $returnValue;
1826  } // function VARFunc()
1827 
1828 
1842  public static function VARA() {
1843  // Return value
1844  $returnValue = self::$_errorCodes['divisionbyzero'];
1845 
1846  $summerA = $summerB = 0;
1847 
1848  // Loop through arguments
1849  $aArgs = self::flattenArray(func_get_args());
1850  $aCount = 0;
1851  foreach ($aArgs as $arg) {
1852  // Is it a numeric value?
1853  if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
1854  if (is_bool($arg)) {
1855  $arg = (integer) $arg;
1856  } elseif (is_string($arg)) {
1857  $arg = 0;
1858  }
1859  $summerA += ($arg * $arg);
1860  $summerB += $arg;
1861  ++$aCount;
1862  }
1863  }
1864 
1865  // Return
1866  if ($aCount > 1) {
1867  $summerA = $summerA * $aCount;
1868  $summerB = ($summerB * $summerB);
1869  $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
1870  }
1871  return $returnValue;
1872  } // function VARA()
1873 
1874 
1888  public static function VARP() {
1889  // Return value
1890  $returnValue = self::$_errorCodes['divisionbyzero'];
1891 
1892  $summerA = $summerB = 0;
1893 
1894  // Loop through arguments
1895  $aArgs = self::flattenArray(func_get_args());
1896  $aCount = 0;
1897  foreach ($aArgs as $arg) {
1898  // Is it a numeric value?
1899  if ((is_numeric($arg)) && (!is_string($arg))) {
1900  $summerA += ($arg * $arg);
1901  $summerB += $arg;
1902  ++$aCount;
1903  }
1904  }
1905 
1906  // Return
1907  if ($aCount > 0) {
1908  $summerA = $summerA * $aCount;
1909  $summerB = ($summerB * $summerB);
1910  $returnValue = ($summerA - $summerB) / ($aCount * $aCount);
1911  }
1912  return $returnValue;
1913  } // function VARP()
1914 
1915 
1929  public static function VARPA() {
1930  // Return value
1931  $returnValue = self::$_errorCodes['divisionbyzero'];
1932 
1933  $summerA = $summerB = 0;
1934 
1935  // Loop through arguments
1936  $aArgs = self::flattenArray(func_get_args());
1937  $aCount = 0;
1938  foreach ($aArgs as $arg) {
1939  // Is it a numeric value?
1940  if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
1941  if (is_bool($arg)) {
1942  $arg = (integer) $arg;
1943  } elseif (is_string($arg)) {
1944  $arg = 0;
1945  }
1946  $summerA += ($arg * $arg);
1947  $summerB += $arg;
1948  ++$aCount;
1949  }
1950  }
1951 
1952  // Return
1953  if ($aCount > 0) {
1954  $summerA = $summerA * $aCount;
1955  $summerB = ($summerB * $summerB);
1956  $returnValue = ($summerA - $summerB) / ($aCount * $aCount);
1957  }
1958  return $returnValue;
1959  } // function VARPA()
1960 
1961 
1972  public static function RANK($value,$valueSet,$order=0) {
1973  $value = self::flattenSingleValue($value);
1974  $valueSet = self::flattenArray($valueSet);
1975  $order = self::flattenSingleValue($order);
1976 
1977  foreach($valueSet as $key => $valueEntry) {
1978  if (!is_numeric($valueEntry)) {
1979  unset($valueSet[$key]);
1980  }
1981  }
1982 
1983  if ($order == 0) {
1984  rsort($valueSet,SORT_NUMERIC);
1985  } else {
1986  sort($valueSet,SORT_NUMERIC);
1987  }
1988  $pos = array_search($value,$valueSet);
1989  if ($pos === False) {
1990  return self::$_errorCodes['na'];
1991  }
1992 
1993  return ++$pos;
1994  } // function RANK()
1995 
1996 
2007  public static function PERCENTRANK($valueSet,$value,$significance=3) {
2008  $valueSet = self::flattenArray($valueSet);
2009  $value = self::flattenSingleValue($value);
2010  $significance = self::flattenSingleValue($significance);
2011 
2012  foreach($valueSet as $key => $valueEntry) {
2013  if (!is_numeric($valueEntry)) {
2014  unset($valueSet[$key]);
2015  }
2016  }
2017  sort($valueSet,SORT_NUMERIC);
2018  $valueCount = count($valueSet);
2019  if ($valueCount == 0) {
2020  return self::$_errorCodes['num'];
2021  }
2022 
2023  $valueAdjustor = $valueCount - 1;
2024  if (($value < $valueSet[0]) || ($value > $valueSet[$valueAdjustor])) {
2025  return self::$_errorCodes['na'];
2026  }
2027 
2028  $pos = array_search($value,$valueSet);
2029  if ($pos === False) {
2030  $pos = 0;
2031  $testValue = $valueSet[0];
2032  while ($testValue < $value) {
2033  $testValue = $valueSet[++$pos];
2034  }
2035  --$pos;
2036  $pos += (($value - $valueSet[$pos]) / ($testValue - $valueSet[$pos]));
2037  }
2038 
2039  return round($pos / $valueAdjustor,$significance);
2040  } // function PERCENTRANK()
2041 
2042 
2043  private static function _checkTrendArray($values) {
2044  foreach($values as $key => $value) {
2045  if ((is_bool($value)) || ((is_string($value)) && (trim($value) == ''))) {
2046  unset($values[$key]);
2047  } elseif (is_string($value)) {
2048  if (is_numeric($value)) {
2049  $values[$key] = (float) $value;
2050  } else {
2051  unset($values[$key]);
2052  }
2053  }
2054  }
2055  return $values;
2056  } // function _checkTrendArray()
2057 
2058 
2068  public static function INTERCEPT($yValues,$xValues) {
2069  $yValues = self::flattenArray($yValues);
2070  $xValues = self::flattenArray($xValues);
2071 
2072  $yValues = self::_checkTrendArray($yValues);
2073  $yValueCount = count($yValues);
2074  $xValues = self::_checkTrendArray($xValues);
2075  $xValueCount = count($xValues);
2076 
2077  if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2078  return self::$_errorCodes['na'];
2079  } elseif ($yValueCount == 1) {
2080  return self::$_errorCodes['divisionbyzero'];
2081  }
2082 
2083  $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
2084  return $bestFitLinear->getIntersect();
2085  } // function INTERCEPT()
2086 
2087 
2097  public static function RSQ($yValues,$xValues) {
2098  $yValues = self::flattenArray($yValues);
2099  $xValues = self::flattenArray($xValues);
2100 
2101  $yValues = self::_checkTrendArray($yValues);
2102  $yValueCount = count($yValues);
2103  $xValues = self::_checkTrendArray($xValues);
2104  $xValueCount = count($xValues);
2105 
2106  if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2107  return self::$_errorCodes['na'];
2108  } elseif ($yValueCount == 1) {
2109  return self::$_errorCodes['divisionbyzero'];
2110  }
2111 
2112  $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
2113  return $bestFitLinear->getGoodnessOfFit();
2114  } // function RSQ()
2115 
2116 
2126  public static function SLOPE($yValues,$xValues) {
2127  $yValues = self::flattenArray($yValues);
2128  $xValues = self::flattenArray($xValues);
2129 
2130  $yValues = self::_checkTrendArray($yValues);
2131  $yValueCount = count($yValues);
2132  $xValues = self::_checkTrendArray($xValues);
2133  $xValueCount = count($xValues);
2134 
2135  if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2136  return self::$_errorCodes['na'];
2137  } elseif ($yValueCount == 1) {
2138  return self::$_errorCodes['divisionbyzero'];
2139  }
2140 
2141  $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
2142  return $bestFitLinear->getSlope();
2143  } // function SLOPE()
2144 
2145 
2155  public static function STEYX($yValues,$xValues) {
2156  $yValues = self::flattenArray($yValues);
2157  $xValues = self::flattenArray($xValues);
2158 
2159  $yValues = self::_checkTrendArray($yValues);
2160  $yValueCount = count($yValues);
2161  $xValues = self::_checkTrendArray($xValues);
2162  $xValueCount = count($xValues);
2163 
2164  if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2165  return self::$_errorCodes['na'];
2166  } elseif ($yValueCount == 1) {
2167  return self::$_errorCodes['divisionbyzero'];
2168  }
2169 
2170  $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
2171  return $bestFitLinear->getStdevOfResiduals();
2172  } // function STEYX()
2173 
2174 
2184  public static function COVAR($yValues,$xValues) {
2185  $yValues = self::flattenArray($yValues);
2186  $xValues = self::flattenArray($xValues);
2187 
2188  $yValues = self::_checkTrendArray($yValues);
2189  $yValueCount = count($yValues);
2190  $xValues = self::_checkTrendArray($xValues);
2191  $xValueCount = count($xValues);
2192 
2193  if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2194  return self::$_errorCodes['na'];
2195  } elseif ($yValueCount == 1) {
2196  return self::$_errorCodes['divisionbyzero'];
2197  }
2198 
2199  $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
2200  return $bestFitLinear->getCovariance();
2201  } // function COVAR()
2202 
2203 
2213  public static function CORREL($yValues,$xValues) {
2214  $yValues = self::flattenArray($yValues);
2215  $xValues = self::flattenArray($xValues);
2216 
2217  $yValues = self::_checkTrendArray($yValues);
2218  $yValueCount = count($yValues);
2219  $xValues = self::_checkTrendArray($xValues);
2220  $xValueCount = count($xValues);
2221 
2222  if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2223  return self::$_errorCodes['na'];
2224  } elseif ($yValueCount == 1) {
2225  return self::$_errorCodes['divisionbyzero'];
2226  }
2227 
2228  $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
2229  return $bestFitLinear->getCorrelation();
2230  } // function CORREL()
2231 
2232 
2245  public static function LINEST($yValues,$xValues,$const=True,$stats=False) {
2246  $yValues = self::flattenArray($yValues);
2247  $xValues = self::flattenArray($xValues);
2248  $const = (boolean) self::flattenSingleValue($const);
2249  $stats = (boolean) self::flattenSingleValue($stats);
2250 
2251  $yValues = self::_checkTrendArray($yValues);
2252  $yValueCount = count($yValues);
2253  $xValues = self::_checkTrendArray($xValues);
2254  $xValueCount = count($xValues);
2255 
2256  if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2257  return self::$_errorCodes['na'];
2258  } elseif ($yValueCount == 1) {
2259  return self::$_errorCodes['divisionbyzero'];
2260  }
2261 
2262  $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const);
2263  if ($stats) {
2264  return array( array( $bestFitLinear->getSlope(),
2265  $bestFitLinear->getSlopeSE(),
2266  $bestFitLinear->getGoodnessOfFit(),
2267  $bestFitLinear->getF(),
2268  $bestFitLinear->getSSRegression(),
2269  ),
2270  array( $bestFitLinear->getIntersect(),
2271  $bestFitLinear->getIntersectSE(),
2272  $bestFitLinear->getStdevOfResiduals(),
2273  $bestFitLinear->getDFResiduals(),
2274  $bestFitLinear->getSSResiduals()
2275  )
2276  );
2277  } else {
2278  return array( $bestFitLinear->getSlope(),
2279  $bestFitLinear->getIntersect()
2280  );
2281  }
2282  } // function LINEST()
2283 
2284 
2297  public static function LOGEST($yValues,$xValues,$const=True,$stats=False) {
2298  $yValues = self::flattenArray($yValues);
2299  $xValues = self::flattenArray($xValues);
2300  $const = (boolean) self::flattenSingleValue($const);
2301  $stats = (boolean) self::flattenSingleValue($stats);
2302 
2303  $yValues = self::_checkTrendArray($yValues);
2304  $yValueCount = count($yValues);
2305  $xValues = self::_checkTrendArray($xValues);
2306  $xValueCount = count($xValues);
2307 
2308  if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2309  return self::$_errorCodes['na'];
2310  } elseif ($yValueCount == 1) {
2311  return self::$_errorCodes['divisionbyzero'];
2312  }
2313 
2314  $bestFitExponential = trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const);
2315  if ($stats) {
2316  return array( array( $bestFitExponential->getSlope(),
2317  $bestFitExponential->getSlopeSE(),
2318  $bestFitExponential->getGoodnessOfFit(),
2319  $bestFitExponential->getF(),
2320  $bestFitExponential->getSSRegression(),
2321  ),
2322  array( $bestFitExponential->getIntersect(),
2323  $bestFitExponential->getIntersectSE(),
2324  $bestFitExponential->getStdevOfResiduals(),
2325  $bestFitExponential->getDFResiduals(),
2326  $bestFitExponential->getSSResiduals()
2327  )
2328  );
2329  } else {
2330  return array( $bestFitExponential->getSlope(),
2331  $bestFitExponential->getIntersect()
2332  );
2333  }
2334  } // function LOGEST()
2335 
2336 
2347  public static function FORECAST($xValue,$yValues,$xValues) {
2348  $xValue = self::flattenSingleValue($xValue);
2349  $yValues = self::flattenArray($yValues);
2350  $xValues = self::flattenArray($xValues);
2351 
2352  if (!is_numeric($xValue)) {
2353  return self::$_errorCodes['value'];
2354  }
2355 
2356  $yValues = self::_checkTrendArray($yValues);
2357  $yValueCount = count($yValues);
2358  $xValues = self::_checkTrendArray($xValues);
2359  $xValueCount = count($xValues);
2360 
2361  if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
2362  return self::$_errorCodes['na'];
2363  } elseif ($yValueCount == 1) {
2364  return self::$_errorCodes['divisionbyzero'];
2365  }
2366 
2367  $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
2368  return $bestFitLinear->getValueOfYForX($xValue);
2369  } // function FORECAST()
2370 
2371 
2383  public static function TREND($yValues,$xValues=array(),$newValues=array(),$const=True) {
2384  $yValues = self::flattenArray($yValues);
2385  $xValues = self::flattenArray($xValues);
2386  $newValues = self::flattenArray($newValues);
2387  $const = (boolean) self::flattenSingleValue($const);
2388 
2389  $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const);
2390  if (count($newValues) == 0) {
2391  $newValues = $bestFitLinear->getXValues();
2392  }
2393 
2394  $returnArray = array();
2395  foreach($newValues as $xValue) {
2396  $returnArray[0][] = $bestFitLinear->getValueOfYForX($xValue);
2397  }
2398 
2399  return $returnArray;
2400  } // function TREND()
2401 
2402 
2414  public static function GROWTH($yValues,$xValues=array(),$newValues=array(),$const=True) {
2415  $yValues = self::flattenArray($yValues);
2416  $xValues = self::flattenArray($xValues);
2417  $newValues = self::flattenArray($newValues);
2418  $const = (boolean) self::flattenSingleValue($const);
2419 
2420  $bestFitExponential = trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const);
2421  if (count($newValues) == 0) {
2422  $newValues = $bestFitExponential->getXValues();
2423  }
2424 
2425  $returnArray = array();
2426  foreach($newValues as $xValue) {
2427  $returnArray[0][] = $bestFitExponential->getValueOfYForX($xValue);
2428  }
2429 
2430  return $returnArray;
2431  } // function GROWTH()
2432 
2433 
2434  private static function _romanCut($num, $n) {
2435  return ($num - ($num % $n ) ) / $n;
2436  } // function _romanCut()
2437 
2438 
2439  public static function ROMAN($aValue, $style=0) {
2440  $aValue = (integer) self::flattenSingleValue($aValue);
2441  if ((!is_numeric($aValue)) || ($aValue < 0) || ($aValue >= 4000)) {
2442  return self::$_errorCodes['value'];
2443  }
2444  if ($aValue == 0) {
2445  return '';
2446  }
2447 
2448  $mill = Array('', 'M', 'MM', 'MMM', 'MMMM', 'MMMMM');
2449  $cent = Array('', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM');
2450  $tens = Array('', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC');
2451  $ones = Array('', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX');
2452 
2453  $roman = '';
2454  while ($aValue > 5999) {
2455  $roman .= 'M';
2456  $aValue -= 1000;
2457  }
2458  $m = self::_romanCut($aValue, 1000); $aValue %= 1000;
2459  $c = self::_romanCut($aValue, 100); $aValue %= 100;
2460  $t = self::_romanCut($aValue, 10); $aValue %= 10;
2461 
2462  return $roman.$mill[$m].$cent[$c].$tens[$t].$ones[$aValue];
2463  } // function ROMAN()
2464 
2465 
2476  public static function SUBTOTAL() {
2477  $aArgs = self::flattenArray(func_get_args());
2478 
2479  // Calculate
2480  $subtotal = array_shift($aArgs);
2481 
2482  if ((is_numeric($subtotal)) && (!is_string($subtotal))) {
2483  switch($subtotal) {
2484  case 1 :
2485  return self::AVERAGE($aArgs);
2486  break;
2487  case 2 :
2488  return self::COUNT($aArgs);
2489  break;
2490  case 3 :
2491  return self::COUNTA($aArgs);
2492  break;
2493  case 4 :
2494  return self::MAX($aArgs);
2495  break;
2496  case 5 :
2497  return self::MIN($aArgs);
2498  break;
2499  case 6 :
2500  return self::PRODUCT($aArgs);
2501  break;
2502  case 7 :
2503  return self::STDEV($aArgs);
2504  break;
2505  case 8 :
2506  return self::STDEVP($aArgs);
2507  break;
2508  case 9 :
2509  return self::SUM($aArgs);
2510  break;
2511  case 10 :
2512  return self::VARFunc($aArgs);
2513  break;
2514  case 11 :
2515  return self::VARP($aArgs);
2516  break;
2517  }
2518  }
2519  return self::$_errorCodes['value'];
2520  } // function SUBTOTAL()
2521 
2522 
2531  public static function SQRTPI($number) {
2532  $number = self::flattenSingleValue($number);
2533 
2534  if (is_numeric($number)) {
2535  if ($number < 0) {
2536  return self::$_errorCodes['num'];
2537  }
2538  return sqrt($number * pi()) ;
2539  }
2540  return self::$_errorCodes['value'];
2541  } // function SQRTPI()
2542 
2543 
2552  public static function FACT($factVal) {
2553  $factVal = self::flattenSingleValue($factVal);
2554 
2555  if (is_numeric($factVal)) {
2556  if ($factVal < 0) {
2557  return self::$_errorCodes['num'];
2558  }
2559  $factLoop = floor($factVal);
2560  if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) {
2561  if ($factVal > $factLoop) {
2562  return self::$_errorCodes['num'];
2563  }
2564  }
2565  $factorial = 1;
2566  while ($factLoop > 1) {
2567  $factorial *= $factLoop--;
2568  }
2569  return $factorial ;
2570  }
2571  return self::$_errorCodes['value'];
2572  } // function FACT()
2573 
2574 
2583  public static function FACTDOUBLE($factVal) {
2584  $factLoop = floor(self::flattenSingleValue($factVal));
2585 
2586  if (is_numeric($factLoop)) {
2587  if ($factVal < 0) {
2588  return self::$_errorCodes['num'];
2589  }
2590  $factorial = 1;
2591  while ($factLoop > 1) {
2592  $factorial *= $factLoop--;
2593  --$factLoop;
2594  }
2595  return $factorial ;
2596  }
2597  return self::$_errorCodes['value'];
2598  } // function FACTDOUBLE()
2599 
2600 
2609  public static function MULTINOMIAL() {
2610  // Loop through arguments
2611  $aArgs = self::flattenArray(func_get_args());
2612  $summer = 0;
2613  $divisor = 1;
2614  foreach ($aArgs as $arg) {
2615  // Is it a numeric value?
2616  if (is_numeric($arg)) {
2617  if ($arg < 1) {
2618  return self::$_errorCodes['num'];
2619  }
2620  $summer += floor($arg);
2621  $divisor *= self::FACT($arg);
2622  } else {
2623  return self::$_errorCodes['value'];
2624  }
2625  }
2626 
2627  // Return
2628  if ($summer > 0) {
2629  $summer = self::FACT($summer);
2630  return $summer / $divisor;
2631  }
2632  return 0;
2633  } // function MULTINOMIAL()
2634 
2635 
2645  public static function CEILING($number,$significance=null) {
2646  $number = self::flattenSingleValue($number);
2647  $significance = self::flattenSingleValue($significance);
2648 
2649  if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
2650  $significance = $number/abs($number);
2651  }
2652 
2653  if ((is_numeric($number)) && (is_numeric($significance))) {
2654  if (self::SIGN($number) == self::SIGN($significance)) {
2655  if ($significance == 0.0) {
2656  return 0;
2657  }
2658  return ceil($number / $significance) * $significance;
2659  } else {
2660  return self::$_errorCodes['num'];
2661  }
2662  }
2663  return self::$_errorCodes['value'];
2664  } // function CEILING()
2665 
2666 
2675  public static function EVEN($number) {
2676  $number = self::flattenSingleValue($number);
2677 
2678  if (is_numeric($number)) {
2679  $significance = 2 * self::SIGN($number);
2680  return self::CEILING($number,$significance);
2681  }
2682  return self::$_errorCodes['value'];
2683  } // function EVEN()
2684 
2685 
2694  public static function ODD($number) {
2695  $number = self::flattenSingleValue($number);
2696 
2697  if (is_numeric($number)) {
2698  $significance = self::SIGN($number);
2699  if ($significance == 0) {
2700  return 1;
2701  }
2702  $result = self::CEILING($number,$significance);
2703  if (self::IS_EVEN($result)) {
2704  $result += $significance;
2705  }
2706  return $result;
2707  }
2708  return self::$_errorCodes['value'];
2709  } // function ODD()
2710 
2711 
2720  public static function INTVALUE($number) {
2721  $number = self::flattenSingleValue($number);
2722 
2723  if (is_numeric($number)) {
2724  return (int) floor($number);
2725  }
2726  return self::$_errorCodes['value'];
2727  } // function INTVALUE()
2728 
2729 
2739  public static function ROUNDUP($number,$digits) {
2740  $number = self::flattenSingleValue($number);
2741  $digits = self::flattenSingleValue($digits);
2742 
2743  if ((is_numeric($number)) && (is_numeric($digits))) {
2744  $significance = pow(10,$digits);
2745  if ($number < 0.0) {
2746  return floor($number * $significance) / $significance;
2747  } else {
2748  return ceil($number * $significance) / $significance;
2749  }
2750  }
2751  return self::$_errorCodes['value'];
2752  } // function ROUNDUP()
2753 
2754 
2764  public static function ROUNDDOWN($number,$digits) {
2765  $number = self::flattenSingleValue($number);
2766  $digits = self::flattenSingleValue($digits);
2767 
2768  if ((is_numeric($number)) && (is_numeric($digits))) {
2769  $significance = pow(10,$digits);
2770  if ($number < 0.0) {
2771  return ceil($number * $significance) / $significance;
2772  } else {
2773  return floor($number * $significance) / $significance;
2774  }
2775  }
2776  return self::$_errorCodes['value'];
2777  } // function ROUNDDOWN()
2778 
2779 
2789  public static function MROUND($number,$multiple) {
2790  $number = self::flattenSingleValue($number);
2791  $multiple = self::flattenSingleValue($multiple);
2792 
2793  if ((is_numeric($number)) && (is_numeric($multiple))) {
2794  if ($multiple == 0) {
2795  return 0;
2796  }
2797  if ((self::SIGN($number)) == (self::SIGN($multiple))) {
2798  $multiplier = 1 / $multiple;
2799  return round($number * $multiplier) / $multiplier;
2800  }
2801  return self::$_errorCodes['num'];
2802  }
2803  return self::$_errorCodes['value'];
2804  } // function MROUND()
2805 
2806 
2816  public static function SIGN($number) {
2817  $number = self::flattenSingleValue($number);
2818 
2819  if (is_numeric($number)) {
2820  if ($number == 0.0) {
2821  return 0;
2822  }
2823  return $number / abs($number);
2824  }
2825  return self::$_errorCodes['value'];
2826  } // function SIGN()
2827 
2828 
2838  public static function FLOOR($number,$significance=null) {
2839  $number = self::flattenSingleValue($number);
2840  $significance = self::flattenSingleValue($significance);
2841 
2842  if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
2843  $significance = $number/abs($number);
2844  }
2845 
2846  if ((is_numeric($number)) && (is_numeric($significance))) {
2847  if ((float) $significance == 0.0) {
2848  return self::$_errorCodes['divisionbyzero'];
2849  }
2850  if (self::SIGN($number) == self::SIGN($significance)) {
2851  return floor($number / $significance) * $significance;
2852  } else {
2853  return self::$_errorCodes['num'];
2854  }
2855  }
2856  return self::$_errorCodes['value'];
2857  } // function FLOOR()
2858 
2859 
2873  public static function PERMUT($numObjs,$numInSet) {
2874  $numObjs = self::flattenSingleValue($numObjs);
2875  $numInSet = self::flattenSingleValue($numInSet);
2876 
2877  if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
2878  if ($numObjs < $numInSet) {
2879  return self::$_errorCodes['num'];
2880  }
2881  return round(self::FACT($numObjs) / self::FACT($numObjs - $numInSet));
2882  }
2883  return self::$_errorCodes['value'];
2884  } // function PERMUT()
2885 
2886 
2897  public static function COMBIN($numObjs,$numInSet) {
2898  $numObjs = self::flattenSingleValue($numObjs);
2899  $numInSet = self::flattenSingleValue($numInSet);
2900 
2901  if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
2902  if ($numObjs < $numInSet) {
2903  return self::$_errorCodes['num'];
2904  } elseif ($numInSet < 0) {
2905  return self::$_errorCodes['num'];
2906  }
2907  return round(self::FACT($numObjs) / self::FACT($numObjs - $numInSet)) / self::FACT($numInSet);
2908  }
2909  return self::$_errorCodes['value'];
2910  } // function COMBIN()
2911 
2912 
2924  public static function SERIESSUM() {
2925  // Return value
2926  $returnValue = 0;
2927 
2928  // Loop trough arguments
2929  $aArgs = self::flattenArray(func_get_args());
2930 
2931  $x = array_shift($aArgs);
2932  $n = array_shift($aArgs);
2933  $m = array_shift($aArgs);
2934 
2935  if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) {
2936  // Calculate
2937  $i = 0;
2938  foreach($aArgs as $arg) {
2939  // Is it a numeric value?
2940  if ((is_numeric($arg)) && (!is_string($arg))) {
2941  $returnValue += $arg * pow($x,$n + ($m * $i++));
2942  } else {
2943  return self::$_errorCodes['value'];
2944  }
2945  }
2946  // Return
2947  return $returnValue;
2948  }
2949  return self::$_errorCodes['value'];
2950  } // function SERIESSUM()
2951 
2952 
2963  public static function STANDARDIZE($value,$mean,$stdDev) {
2964  $value = self::flattenSingleValue($value);
2965  $mean = self::flattenSingleValue($mean);
2966  $stdDev = self::flattenSingleValue($stdDev);
2967 
2968  if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
2969  if ($stdDev <= 0) {
2970  return self::$_errorCodes['num'];
2971  }
2972  return ($value - $mean) / $stdDev ;
2973  }
2974  return self::$_errorCodes['value'];
2975  } // function STANDARDIZE()
2976 
2977 
2978  //
2979  // Private method to return an array of the factors of the input value
2980  //
2981  private static function _factors($value) {
2982  $startVal = floor(sqrt($value));
2983 
2984  $factorArray = array();
2985  for ($i = $startVal; $i > 1; --$i) {
2986  if (($value % $i) == 0) {
2987  $factorArray = array_merge($factorArray,self::_factors($value / $i));
2988  $factorArray = array_merge($factorArray,self::_factors($i));
2989  if ($i <= sqrt($value)) {
2990  break;
2991  }
2992  }
2993  }
2994  if (count($factorArray) > 0) {
2995  rsort($factorArray);
2996  return $factorArray;
2997  } else {
2998  return array((integer) $value);
2999  }
3000  } // function _factors()
3001 
3002 
3011  public static function LCM() {
3012  $aArgs = self::flattenArray(func_get_args());
3013 
3014  $returnValue = 1;
3015  $allPoweredFactors = array();
3016  foreach($aArgs as $value) {
3017  if (!is_numeric($value)) {
3018  return self::$_errorCodes['value'];
3019  }
3020  if ($value == 0) {
3021  return 0;
3022  } elseif ($value < 0) {
3023  return self::$_errorCodes['num'];
3024  }
3025  $myFactors = self::_factors(floor($value));
3026  $myCountedFactors = array_count_values($myFactors);
3027  $myPoweredFactors = array();
3028  foreach($myCountedFactors as $myCountedFactor => $myCountedPower) {
3029  $myPoweredFactors[$myCountedFactor] = pow($myCountedFactor,$myCountedPower);
3030  }
3031  foreach($myPoweredFactors as $myPoweredValue => $myPoweredFactor) {
3032  if (array_key_exists($myPoweredValue,$allPoweredFactors)) {
3033  if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) {
3034  $allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
3035  }
3036  } else {
3037  $allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
3038  }
3039  }
3040  }
3041  foreach($allPoweredFactors as $allPoweredFactor) {
3042  $returnValue *= (integer) $allPoweredFactor;
3043  }
3044  return $returnValue;
3045  } // function LCM()
3046 
3047 
3056  public static function GCD() {
3057  $aArgs = self::flattenArray(func_get_args());
3058 
3059  $returnValue = 1;
3060  $allPoweredFactors = array();
3061  foreach($aArgs as $value) {
3062  if ($value == 0) {
3063  break;
3064  }
3065  $myFactors = self::_factors($value);
3066  $myCountedFactors = array_count_values($myFactors);
3067  $allValuesFactors[] = $myCountedFactors;
3068  }
3069  $allValuesCount = count($allValuesFactors);
3070  $mergedArray = $allValuesFactors[0];
3071  for ($i=1;$i < $allValuesCount; ++$i) {
3072  $mergedArray = array_intersect_key($mergedArray,$allValuesFactors[$i]);
3073  }
3074  $mergedArrayValues = count($mergedArray);
3075  if ($mergedArrayValues == 0) {
3076  return $returnValue;
3077  } elseif ($mergedArrayValues > 1) {
3078  foreach($mergedArray as $mergedKey => $mergedValue) {
3079  foreach($allValuesFactors as $highestPowerTest) {
3080  foreach($highestPowerTest as $testKey => $testValue) {
3081  if (($testKey == $mergedKey) && ($testValue < $mergedValue)) {
3082  $mergedArray[$mergedKey] = $testValue;
3083  $mergedValue = $testValue;
3084  }
3085  }
3086  }
3087  }
3088 
3089  $returnValue = 1;
3090  foreach($mergedArray as $key => $value) {
3091  $returnValue *= pow($key,$value);
3092  }
3093  return $returnValue;
3094  } else {
3095  $keys = array_keys($mergedArray);
3096  $key = $keys[0];
3097  $value = $mergedArray[$key];
3098  foreach($allValuesFactors as $testValue) {
3099  foreach($testValue as $mergedKey => $mergedValue) {
3100  if (($mergedKey == $key) && ($mergedValue < $value)) {
3101  $value = $mergedValue;
3102  }
3103  }
3104  }
3105  return pow($key,$value);
3106  }
3107  } // function GCD()
3108 
3109 
3128  public static function BINOMDIST($value, $trials, $probability, $cumulative) {
3129  $value = floor(self::flattenSingleValue($value));
3130  $trials = floor(self::flattenSingleValue($trials));
3131  $probability = self::flattenSingleValue($probability);
3132 
3133  if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) {
3134  if (($value < 0) || ($value > $trials)) {
3135  return self::$_errorCodes['num'];
3136  }
3137  if (($probability < 0) || ($probability > 1)) {
3138  return self::$_errorCodes['num'];
3139  }
3140  if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
3141  if ($cumulative) {
3142  $summer = 0;
3143  for ($i = 0; $i <= $value; ++$i) {
3144  $summer += self::COMBIN($trials,$i) * pow($probability,$i) * pow(1 - $probability,$trials - $i);
3145  }
3146  return $summer;
3147  } else {
3148  return self::COMBIN($trials,$value) * pow($probability,$value) * pow(1 - $probability,$trials - $value) ;
3149  }
3150  }
3151  }
3152  return self::$_errorCodes['value'];
3153  } // function BINOMDIST()
3154 
3155 
3171  public static function NEGBINOMDIST($failures, $successes, $probability) {
3172  $failures = floor(self::flattenSingleValue($failures));
3173  $successes = floor(self::flattenSingleValue($successes));
3174  $probability = self::flattenSingleValue($probability);
3175 
3176  if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) {
3177  if (($failures < 0) || ($successes < 1)) {
3178  return self::$_errorCodes['num'];
3179  }
3180  if (($probability < 0) || ($probability > 1)) {
3181  return self::$_errorCodes['num'];
3182  }
3183  if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) {
3184  if (($failures + $successes - 1) <= 0) {
3185  return self::$_errorCodes['num'];
3186  }
3187  }
3188  return (self::COMBIN($failures + $successes - 1,$successes - 1)) * (pow($probability,$successes)) * (pow(1 - $probability,$failures)) ;
3189  }
3190  return self::$_errorCodes['value'];
3191  } // function NEGBINOMDIST()
3192 
3193 
3213  public static function CRITBINOM($trials, $probability, $alpha) {
3214  $trials = floor(self::flattenSingleValue($trials));
3215  $probability = self::flattenSingleValue($probability);
3216  $alpha = self::flattenSingleValue($alpha);
3217 
3218  if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) {
3219  if ($trials < 0) {
3220  return self::$_errorCodes['num'];
3221  }
3222  if (($probability < 0) || ($probability > 1)) {
3223  return self::$_errorCodes['num'];
3224  }
3225  if (($alpha < 0) || ($alpha > 1)) {
3226  return self::$_errorCodes['num'];
3227  }
3228  if ($alpha <= 0.5) {
3229  $t = sqrt(log(1 / pow($alpha,2)));
3230  $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));
3231  } else {
3232  $t = sqrt(log(1 / pow(1 - $alpha,2)));
3233  $trialsApprox = $t - (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t);
3234  }
3235  $Guess = floor($trials * $probability + $trialsApprox * sqrt($trials * $probability * (1 - $probability)));
3236  if ($Guess < 0) {
3237  $Guess = 0;
3238  } elseif ($Guess > $trials) {
3239  $Guess = $trials;
3240  }
3241 
3242  $TotalUnscaledProbability = $UnscaledPGuess = $UnscaledCumPGuess = 0.0;
3243  $EssentiallyZero = 10e-12;
3244 
3245  $m = floor($trials * $probability);
3246  ++$TotalUnscaledProbability;
3247  if ($m == $Guess) { ++$UnscaledPGuess; }
3248  if ($m <= $Guess) { ++$UnscaledCumPGuess; }
3249 
3250  $PreviousValue = 1;
3251  $Done = False;
3252  $k = $m + 1;
3253  while ((!$Done) && ($k <= $trials)) {
3254  $CurrentValue = $PreviousValue * ($trials - $k + 1) * $probability / ($k * (1 - $probability));
3255  $TotalUnscaledProbability += $CurrentValue;
3256  if ($k == $Guess) { $UnscaledPGuess += $CurrentValue; }
3257  if ($k <= $Guess) { $UnscaledCumPGuess += $CurrentValue; }
3258  if ($CurrentValue <= $EssentiallyZero) { $Done = True; }
3259  $PreviousValue = $CurrentValue;
3260  ++$k;
3261  }
3262 
3263  $PreviousValue = 1;
3264  $Done = False;
3265  $k = $m - 1;
3266  while ((!$Done) && ($k >= 0)) {
3267  $CurrentValue = $PreviousValue * $k + 1 * (1 - $probability) / (($trials - $k) * $probability);
3268  $TotalUnscaledProbability += $CurrentValue;
3269  if ($k == $Guess) { $UnscaledPGuess += $CurrentValue; }
3270  if ($k <= $Guess) { $UnscaledCumPGuess += $CurrentValue; }
3271  if ($CurrentValue <= $EssentiallyZero) { $Done = True; }
3272  $PreviousValue = $CurrentValue;
3273  --$k;
3274  }
3275 
3276  $PGuess = $UnscaledPGuess / $TotalUnscaledProbability;
3277  $CumPGuess = $UnscaledCumPGuess / $TotalUnscaledProbability;
3278 
3279 // $CumPGuessMinus1 = $CumPGuess - $PGuess;
3280  $CumPGuessMinus1 = $CumPGuess - 1;
3281 
3282  while (True) {
3283  if (($CumPGuessMinus1 < $alpha) && ($CumPGuess >= $alpha)) {
3284  return $Guess;
3285  } elseif (($CumPGuessMinus1 < $alpha) && ($CumPGuess < $alpha)) {
3286  $PGuessPlus1 = $PGuess * ($trials - $Guess) * $probability / $Guess / (1 - $probability);
3287  $CumPGuessMinus1 = $CumPGuess;
3288  $CumPGuess = $CumPGuess + $PGuessPlus1;
3289  $PGuess = $PGuessPlus1;
3290  ++$Guess;
3291  } elseif (($CumPGuessMinus1 >= $alpha) && ($CumPGuess >= $alpha)) {
3292  $PGuessMinus1 = $PGuess * $Guess * (1 - $probability) / ($trials - $Guess + 1) / $probability;
3293  $CumPGuess = $CumPGuessMinus1;
3294  $CumPGuessMinus1 = $CumPGuessMinus1 - $PGuess;
3295  $PGuess = $PGuessMinus1;
3296  --$Guess;
3297  }
3298  }
3299  }
3300  return self::$_errorCodes['value'];
3301  } // function CRITBINOM()
3302 
3303 
3313  public static function CHIDIST($value, $degrees) {
3314  $value = self::flattenSingleValue($value);
3315  $degrees = floor(self::flattenSingleValue($degrees));
3316 
3317  if ((is_numeric($value)) && (is_numeric($degrees))) {
3318  if ($degrees < 1) {
3319  return self::$_errorCodes['num'];
3320  }
3321  if ($value < 0) {
3322  if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) {
3323  return 1;
3324  }
3325  return self::$_errorCodes['num'];
3326  }
3327  return 1 - (self::_incompleteGamma($degrees/2,$value/2) / self::_gamma($degrees/2));
3328  }
3329  return self::$_errorCodes['value'];
3330  } // function CHIDIST()
3331 
3332 
3342  public static function CHIINV($probability, $degrees) {
3343  $probability = self::flattenSingleValue($probability);
3344  $degrees = floor(self::flattenSingleValue($degrees));
3345 
3346  if ((is_numeric($probability)) && (is_numeric($degrees))) {
3347  $xLo = 100;
3348  $xHi = 0;
3349  $maxIteration = 100;
3350 
3351  $x = $xNew = 1;
3352  $dx = 1;
3353  $i = 0;
3354 
3355  while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
3356  // Apply Newton-Raphson step
3357  $result = self::CHIDIST($x, $degrees);
3358  $error = $result - $probability;
3359  if ($error == 0.0) {
3360  $dx = 0;
3361  } elseif ($error < 0.0) {
3362  $xLo = $x;
3363  } else {
3364  $xHi = $x;
3365  }
3366  // Avoid division by zero
3367  if ($result != 0.0) {
3368  $dx = $error / $result;
3369  $xNew = $x - $dx;
3370  }
3371  // If the NR fails to converge (which for example may be the
3372  // case if the initial guess is too rough) we apply a bisection
3373  // step to determine a more narrow interval around the root.
3374  if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
3375  $xNew = ($xLo + $xHi) / 2;
3376  $dx = $xNew - $x;
3377  }
3378  $x = $xNew;
3379  }
3380  if ($i == MAX_ITERATIONS) {
3381  return self::$_errorCodes['na'];
3382  }
3383  return round($x,12);
3384  }
3385  return self::$_errorCodes['value'];
3386  } // function CHIINV()
3387 
3388 
3401  public static function EXPONDIST($value, $lambda, $cumulative) {
3402  $value = self::flattenSingleValue($value);
3403  $lambda = self::flattenSingleValue($lambda);
3404  $cumulative = self::flattenSingleValue($cumulative);
3405 
3406  if ((is_numeric($value)) && (is_numeric($lambda))) {
3407  if (($value < 0) || ($lambda < 0)) {
3408  return self::$_errorCodes['num'];
3409  }
3410  if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
3411  if ($cumulative) {
3412  return 1 - exp(0-$value*$lambda);
3413  } else {
3414  return $lambda * exp(0-$value*$lambda);
3415  }
3416  }
3417  }
3418  return self::$_errorCodes['value'];
3419  } // function EXPONDIST()
3420 
3421 
3432  public static function FISHER($value) {
3433  $value = self::flattenSingleValue($value);
3434 
3435  if (is_numeric($value)) {
3436  if (($value <= -1) || ($value >= 1)) {
3437  return self::$_errorCodes['num'];
3438  }
3439  return 0.5 * log((1+$value)/(1-$value));
3440  }
3441  return self::$_errorCodes['value'];
3442  } // function FISHER()
3443 
3444 
3455  public static function FISHERINV($value) {
3456  $value = self::flattenSingleValue($value);
3457 
3458  if (is_numeric($value)) {
3459  return (exp(2 * $value) - 1) / (exp(2 * $value) + 1);
3460  }
3461  return self::$_errorCodes['value'];
3462  } // function FISHERINV()
3463 
3464 
3465  // Function cache for _logBeta function
3466  private static $_logBetaCache_p = 0.0;
3467  private static $_logBetaCache_q = 0.0;
3468  private static $_logBetaCache_result = 0.0;
3469 
3477  private static function _logBeta($p, $q) {
3478  if ($p != self::$_logBetaCache_p || $q != self::$_logBetaCache_q) {
3479  self::$_logBetaCache_p = $p;
3480  self::$_logBetaCache_q = $q;
3481  if (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) {
3482  self::$_logBetaCache_result = 0.0;
3483  } else {
3484  self::$_logBetaCache_result = self::_logGamma($p) + self::_logGamma($q) - self::_logGamma($p + $q);
3485  }
3486  }
3488  } // function _logBeta()
3489 
3490 
3496  private static function _betaFraction($x, $p, $q) {
3497  $c = 1.0;
3498  $sum_pq = $p + $q;
3499  $p_plus = $p + 1.0;
3500  $p_minus = $p - 1.0;
3501  $h = 1.0 - $sum_pq * $x / $p_plus;
3502  if (abs($h) < XMININ) {
3503  $h = XMININ;
3504  }
3505  $h = 1.0 / $h;
3506  $frac = $h;
3507  $m = 1;
3508  $delta = 0.0;
3509  while ($m <= MAX_ITERATIONS && abs($delta-1.0) > PRECISION ) {
3510  $m2 = 2 * $m;
3511  // even index for d
3512  $d = $m * ($q - $m) * $x / ( ($p_minus + $m2) * ($p + $m2));
3513  $h = 1.0 + $d * $h;
3514  if (abs($h) < XMININ) {
3515  $h = XMININ;
3516  }
3517  $h = 1.0 / $h;
3518  $c = 1.0 + $d / $c;
3519  if (abs($c) < XMININ) {
3520  $c = XMININ;
3521  }
3522  $frac *= $h * $c;
3523  // odd index for d
3524  $d = -($p + $m) * ($sum_pq + $m) * $x / (($p + $m2) * ($p_plus + $m2));
3525  $h = 1.0 + $d * $h;
3526  if (abs($h) < XMININ) {
3527  $h = XMININ;
3528  }
3529  $h = 1.0 / $h;
3530  $c = 1.0 + $d / $c;
3531  if (abs($c) < XMININ) {
3532  $c = XMININ;
3533  }
3534  $delta = $h * $c;
3535  $frac *= $delta;
3536  ++$m;
3537  }
3538  return $frac;
3539  } // function _betaFraction()
3540 
3541 
3585  // Function cache for logGamma
3586  private static $_logGammaCache_result = 0.0;
3587  private static $_logGammaCache_x = 0.0;
3588 
3589  private static function _logGamma($x) {
3590  // Log Gamma related constants
3591  static $lg_d1 = -0.5772156649015328605195174;
3592  static $lg_d2 = 0.4227843350984671393993777;
3593  static $lg_d4 = 1.791759469228055000094023;
3594 
3595  static $lg_p1 = array( 4.945235359296727046734888,
3596  201.8112620856775083915565,
3597  2290.838373831346393026739,
3598  11319.67205903380828685045,
3599  28557.24635671635335736389,
3600  38484.96228443793359990269,
3601  26377.48787624195437963534,
3602  7225.813979700288197698961 );
3603  static $lg_p2 = array( 4.974607845568932035012064,
3604  542.4138599891070494101986,
3605  15506.93864978364947665077,
3606  184793.2904445632425417223,
3607  1088204.76946882876749847,
3608  3338152.967987029735917223,
3609  5106661.678927352456275255,
3610  3074109.054850539556250927 );
3611  static $lg_p4 = array( 14745.02166059939948905062,
3612  2426813.369486704502836312,
3613  121475557.4045093227939592,
3614  2663432449.630976949898078,
3615  29403789566.34553899906876,
3616  170266573776.5398868392998,
3617  492612579337.743088758812,
3618  560625185622.3951465078242 );
3619 
3620  static $lg_q1 = array( 67.48212550303777196073036,
3621  1113.332393857199323513008,
3622  7738.757056935398733233834,
3623  27639.87074403340708898585,
3624  54993.10206226157329794414,
3625  61611.22180066002127833352,
3626  36351.27591501940507276287,
3627  8785.536302431013170870835 );
3628  static $lg_q2 = array( 183.0328399370592604055942,
3629  7765.049321445005871323047,
3630  133190.3827966074194402448,
3631  1136705.821321969608938755,
3632  5267964.117437946917577538,
3633  13467014.54311101692290052,
3634  17827365.30353274213975932,
3635  9533095.591844353613395747 );
3636  static $lg_q4 = array( 2690.530175870899333379843,
3637  639388.5654300092398984238,
3638  41355999.30241388052042842,
3639  1120872109.61614794137657,
3640  14886137286.78813811542398,
3641  101680358627.2438228077304,
3642  341747634550.7377132798597,
3643  446315818741.9713286462081 );
3644 
3645  static $lg_c = array( -0.001910444077728,
3646  8.4171387781295e-4,
3647  -5.952379913043012e-4,
3648  7.93650793500350248e-4,
3649  -0.002777777777777681622553,
3650  0.08333333333333333331554247,
3651  0.0057083835261 );
3652 
3653  // Rough estimate of the fourth root of logGamma_xBig
3654  static $lg_frtbig = 2.25e76;
3655  static $pnt68 = 0.6796875;
3656 
3657 
3658  if ($x == self::$_logGammaCache_x) {
3660  }
3661  $y = $x;
3662  if ($y > 0.0 && $y <= LOG_GAMMA_X_MAX_VALUE) {
3663  if ($y <= EPS) {
3664  $res = -log(y);
3665  } elseif ($y <= 1.5) {
3666  // ---------------------
3667  // EPS .LT. X .LE. 1.5
3668  // ---------------------
3669  if ($y < $pnt68) {
3670  $corr = -log($y);
3671  $xm1 = $y;
3672  } else {
3673  $corr = 0.0;
3674  $xm1 = $y - 1.0;
3675  }
3676  if ($y <= 0.5 || $y >= $pnt68) {
3677  $xden = 1.0;
3678  $xnum = 0.0;
3679  for ($i = 0; $i < 8; ++$i) {
3680  $xnum = $xnum * $xm1 + $lg_p1[$i];
3681  $xden = $xden * $xm1 + $lg_q1[$i];
3682  }
3683  $res = $corr + $xm1 * ($lg_d1 + $xm1 * ($xnum / $xden));
3684  } else {
3685  $xm2 = $y - 1.0;
3686  $xden = 1.0;
3687  $xnum = 0.0;
3688  for ($i = 0; $i < 8; ++$i) {
3689  $xnum = $xnum * $xm2 + $lg_p2[$i];
3690  $xden = $xden * $xm2 + $lg_q2[$i];
3691  }
3692  $res = $corr + $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden));
3693  }
3694  } elseif ($y <= 4.0) {
3695  // ---------------------
3696  // 1.5 .LT. X .LE. 4.0
3697  // ---------------------
3698  $xm2 = $y - 2.0;
3699  $xden = 1.0;
3700  $xnum = 0.0;
3701  for ($i = 0; $i < 8; ++$i) {
3702  $xnum = $xnum * $xm2 + $lg_p2[$i];
3703  $xden = $xden * $xm2 + $lg_q2[$i];
3704  }
3705  $res = $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden));
3706  } elseif ($y <= 12.0) {
3707  // ----------------------
3708  // 4.0 .LT. X .LE. 12.0
3709  // ----------------------
3710  $xm4 = $y - 4.0;
3711  $xden = -1.0;
3712  $xnum = 0.0;
3713  for ($i = 0; $i < 8; ++$i) {
3714  $xnum = $xnum * $xm4 + $lg_p4[$i];
3715  $xden = $xden * $xm4 + $lg_q4[$i];
3716  }
3717  $res = $lg_d4 + $xm4 * ($xnum / $xden);
3718  } else {
3719  // ---------------------------------
3720  // Evaluate for argument .GE. 12.0
3721  // ---------------------------------
3722  $res = 0.0;
3723  if ($y <= $lg_frtbig) {
3724  $res = $lg_c[6];
3725  $ysq = $y * $y;
3726  for ($i = 0; $i < 6; ++$i)
3727  $res = $res / $ysq + $lg_c[$i];
3728  }
3729  $res /= $y;
3730  $corr = log($y);
3731  $res = $res + log(SQRT2PI) - 0.5 * $corr;
3732  $res += $y * ($corr - 1.0);
3733  }
3734  } else {
3735  // --------------------------
3736  // Return for bad arguments
3737  // --------------------------
3738  $res = MAX_VALUE;
3739  }
3740  // ------------------------------
3741  // Final adjustments and return
3742  // ------------------------------
3743  self::$_logGammaCache_x = $x;
3744  self::$_logGammaCache_result = $res;
3745  return $res;
3746  } // function _logGamma()
3747 
3748 
3758  private static function _beta($p, $q) {
3759  if ($p <= 0.0 || $q <= 0.0 || ($p + $q) > LOG_GAMMA_X_MAX_VALUE) {
3760  return 0.0;
3761  } else {
3762  return exp(self::_logBeta($p, $q));
3763  }
3764  } // function _beta()
3765 
3766 
3779  private static function _incompleteBeta($x, $p, $q) {
3780  if ($x <= 0.0) {
3781  return 0.0;
3782  } elseif ($x >= 1.0) {
3783  return 1.0;
3784  } elseif (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) {
3785  return 0.0;
3786  }
3787  $beta_gam = exp((0 - self::_logBeta($p, $q)) + $p * log($x) + $q * log(1.0 - $x));
3788  if ($x < ($p + 1.0) / ($p + $q + 2.0)) {
3789  return $beta_gam * self::_betaFraction($x, $p, $q) / $p;
3790  } else {
3791  return 1.0 - ($beta_gam * self::_betaFraction(1 - $x, $q, $p) / $q);
3792  }
3793  } // function _incompleteBeta()
3794 
3795 
3808  public static function BETADIST($value,$alpha,$beta,$rMin=0,$rMax=1) {
3809  $value = self::flattenSingleValue($value);
3810  $alpha = self::flattenSingleValue($alpha);
3811  $beta = self::flattenSingleValue($beta);
3812  $rMin = self::flattenSingleValue($rMin);
3813  $rMax = self::flattenSingleValue($rMax);
3814 
3815  if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
3816  if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) {
3817  return self::$_errorCodes['num'];
3818  }
3819  if ($rMin > $rMax) {
3820  $tmp = $rMin;
3821  $rMin = $rMax;
3822  $rMax = $tmp;
3823  }
3824  $value -= $rMin;
3825  $value /= ($rMax - $rMin);
3826  return self::_incompleteBeta($value,$alpha,$beta);
3827  }
3828  return self::$_errorCodes['value'];
3829  } // function BETADIST()
3830 
3831 
3844  public static function BETAINV($probability,$alpha,$beta,$rMin=0,$rMax=1) {
3845  $probability = self::flattenSingleValue($probability);
3846  $alpha = self::flattenSingleValue($alpha);
3847  $beta = self::flattenSingleValue($beta);
3848  $rMin = self::flattenSingleValue($rMin);
3849  $rMax = self::flattenSingleValue($rMax);
3850 
3851  if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
3852  if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) {
3853  return self::$_errorCodes['num'];
3854  }
3855  if ($rMin > $rMax) {
3856  $tmp = $rMin;
3857  $rMin = $rMax;
3858  $rMax = $tmp;
3859  }
3860  $a = 0;
3861  $b = 2;
3862  $maxIteration = 100;
3863 
3864  $i = 0;
3865  while ((($b - $a) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
3866  $guess = ($a + $b) / 2;
3867  $result = self::BETADIST($guess, $alpha, $beta);
3868  if (($result == $probability) || ($result == 0)) {
3869  $b = $a;
3870  } elseif ($result > $probability) {
3871  $b = $guess;
3872  } else {
3873  $a = $guess;
3874  }
3875  }
3876  if ($i == MAX_ITERATIONS) {
3877  return self::$_errorCodes['na'];
3878  }
3879  return round($rMin + $guess * ($rMax - $rMin),12);
3880  }
3881  return self::$_errorCodes['value'];
3882  } // function BETAINV()
3883 
3884 
3885  //
3886  // Private implementation of the incomplete Gamma function
3887  //
3888  private static function _incompleteGamma($a,$x) {
3889  static $max = 32;
3890  $summer = 0;
3891  for ($n=0; $n<=$max; ++$n) {
3892  $divisor = $a;
3893  for ($i=1; $i<=$n; ++$i) {
3894  $divisor *= ($a + $i);
3895  }
3896  $summer += (pow($x,$n) / $divisor);
3897  }
3898  return pow($x,$a) * exp(0-$x) * $summer;
3899  } // function _incompleteGamma()
3900 
3901 
3902  //
3903  // Private implementation of the Gamma function
3904  //
3905  private static function _gamma($data) {
3906  if ($data == 0.0) return 0;
3907 
3908  static $p0 = 1.000000000190015;
3909  static $p = array ( 1 => 76.18009172947146,
3910  2 => -86.50532032941677,
3911  3 => 24.01409824083091,
3912  4 => -1.231739572450155,
3913  5 => 1.208650973866179e-3,
3914  6 => -5.395239384953e-6
3915  );
3916 
3917  $y = $x = $data;
3918  $tmp = $x + 5.5;
3919  $tmp -= ($x + 0.5) * log($tmp);
3920 
3921  $summer = $p0;
3922  for ($j=1;$j<=6;++$j) {
3923  $summer += ($p[$j] / ++$y);
3924  }
3925  return exp(0 - $tmp + log(2.5066282746310005 * $summer / $x));
3926  } // function _gamma()
3927 
3928 
3941  public static function GAMMADIST($value,$a,$b,$cumulative) {
3942  $value = self::flattenSingleValue($value);
3943  $a = self::flattenSingleValue($a);
3944  $b = self::flattenSingleValue($b);
3945 
3946  if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) {
3947  if (($value < 0) || ($a <= 0) || ($b <= 0)) {
3948  return self::$_errorCodes['num'];
3949  }
3950  if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
3951  if ($cumulative) {
3952  return self::_incompleteGamma($a,$value / $b) / self::_gamma($a);
3953  } else {
3954  return (1 / (pow($b,$a) * self::_gamma($a))) * pow($value,$a-1) * exp(0-($value / $b));
3955  }
3956  }
3957  }
3958  return self::$_errorCodes['value'];
3959  } // function GAMMADIST()
3960 
3961 
3974  public static function GAMMAINV($probability,$alpha,$beta) {
3975  $probability = self::flattenSingleValue($probability);
3976  $alpha = self::flattenSingleValue($alpha);
3977  $beta = self::flattenSingleValue($beta);
3978 // $rMin = self::flattenSingleValue($rMin);
3979 // $rMax = self::flattenSingleValue($rMax);
3980 
3981  if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) {
3982  if (($alpha <= 0) || ($beta <= 0) || ($probability <= 0) || ($probability > 1)) {
3983  return self::$_errorCodes['num'];
3984  }
3985  $xLo = 0;
3986  $xHi = 100;
3987  $maxIteration = 100;
3988 
3989  $x = $xNew = 1;
3990  $dx = 1;
3991  $i = 0;
3992 
3993  while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
3994  // Apply Newton-Raphson step
3995  $result = self::GAMMADIST($x, $alpha, $beta, True);
3996  $error = $result - $probability;
3997  if ($error == 0.0) {
3998  $dx = 0;
3999  } elseif ($error < 0.0) {
4000  $xLo = $x;
4001  } else {
4002  $xHi = $x;
4003  }
4004  // Avoid division by zero
4005  if ($result != 0.0) {
4006  $dx = $error / $result;
4007  $xNew = $x - $dx;
4008  }
4009  // If the NR fails to converge (which for example may be the
4010  // case if the initial guess is too rough) we apply a bisection
4011  // step to determine a more narrow interval around the root.
4012  if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
4013  $xNew = ($xLo + $xHi) / 2;
4014  $dx = $xNew - $x;
4015  }
4016  $x = $xNew;
4017  }
4018  if ($i == MAX_ITERATIONS) {
4019  return self::$_errorCodes['na'];
4020  }
4021  return round($x,12);
4022  }
4023  return self::$_errorCodes['value'];
4024  } // function GAMMAINV()
4025 
4026 
4035  public static function GAMMALN($value) {
4036  $value = self::flattenSingleValue($value);
4037 
4038  if (is_numeric($value)) {
4039  if ($value <= 0) {
4040  return self::$_errorCodes['num'];
4041  }
4042  return log(self::_gamma($value));
4043  }
4044  return self::$_errorCodes['value'];
4045  } // function GAMMALN()
4046 
4047 
4062  public static function NORMDIST($value, $mean, $stdDev, $cumulative) {
4063  $value = self::flattenSingleValue($value);
4064  $mean = self::flattenSingleValue($mean);
4065  $stdDev = self::flattenSingleValue($stdDev);
4066 
4067  if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
4068  if ($stdDev < 0) {
4069  return self::$_errorCodes['num'];
4070  }
4071  if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
4072  if ($cumulative) {
4073  return 0.5 * (1 + self::_erfVal(($value - $mean) / ($stdDev * sqrt(2))));
4074  } else {
4075  return (1 / (SQRT2PI * $stdDev)) * exp(0 - (pow($value - $mean,2) / (2 * pow($stdDev,2))));
4076  }
4077  }
4078  }
4079  return self::$_errorCodes['value'];
4080  } // function NORMDIST()
4081 
4082 
4093  public static function NORMSDIST($value) {
4094  $value = self::flattenSingleValue($value);
4095 
4096  return self::NORMDIST($value, 0, 1, True);
4097  } // function NORMSDIST()
4098 
4099 
4109  public static function LOGNORMDIST($value, $mean, $stdDev) {
4110  $value = self::flattenSingleValue($value);
4111  $mean = self::flattenSingleValue($mean);
4112  $stdDev = self::flattenSingleValue($stdDev);
4113 
4114  if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
4115  if (($value <= 0) || ($stdDev <= 0)) {
4116  return self::$_errorCodes['num'];
4117  }
4118  return self::NORMSDIST((log($value) - $mean) / $stdDev);
4119  }
4120  return self::$_errorCodes['value'];
4121  } // function LOGNORMDIST()
4122 
4123 
4124  /***************************************************************************
4125  * inverse_ncdf.php
4126  * -------------------
4127  * begin : Friday, January 16, 2004
4128  * copyright : (C) 2004 Michael Nickerson
4129  * email : nickersonm@yahoo.com
4130  *
4131  ***************************************************************************/
4132  private static function _inverse_ncdf($p) {
4133  // Inverse ncdf approximation by Peter J. Acklam, implementation adapted to
4134  // PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
4135  // a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html
4136  // I have not checked the accuracy of this implementation. Be aware that PHP
4137  // will truncate the coeficcients to 14 digits.
4138 
4139  // You have permission to use and distribute this function freely for
4140  // whatever purpose you want, but please show common courtesy and give credit
4141  // where credit is due.
4142 
4143  // Input paramater is $p - probability - where 0 < p < 1.
4144 
4145  // Coefficients in rational approximations
4146  static $a = array( 1 => -3.969683028665376e+01,
4147  2 => 2.209460984245205e+02,
4148  3 => -2.759285104469687e+02,
4149  4 => 1.383577518672690e+02,
4150  5 => -3.066479806614716e+01,
4151  6 => 2.506628277459239e+00
4152  );
4153 
4154  static $b = array( 1 => -5.447609879822406e+01,
4155  2 => 1.615858368580409e+02,
4156  3 => -1.556989798598866e+02,
4157  4 => 6.680131188771972e+01,
4158  5 => -1.328068155288572e+01
4159  );
4160 
4161  static $c = array( 1 => -7.784894002430293e-03,
4162  2 => -3.223964580411365e-01,
4163  3 => -2.400758277161838e+00,
4164  4 => -2.549732539343734e+00,
4165  5 => 4.374664141464968e+00,
4166  6 => 2.938163982698783e+00
4167  );
4168 
4169  static $d = array( 1 => 7.784695709041462e-03,
4170  2 => 3.224671290700398e-01,
4171  3 => 2.445134137142996e+00,
4172  4 => 3.754408661907416e+00
4173  );
4174 
4175  // Define lower and upper region break-points.
4176  $p_low = 0.02425; //Use lower region approx. below this
4177  $p_high = 1 - $p_low; //Use upper region approx. above this
4178 
4179  if (0 < $p && $p < $p_low) {
4180  // Rational approximation for lower region.
4181  $q = sqrt(-2 * log($p));
4182  return ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) /
4183  (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1);
4184  } elseif ($p_low <= $p && $p <= $p_high) {
4185  // Rational approximation for central region.
4186  $q = $p - 0.5;
4187  $r = $q * $q;
4188  return ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) * $r + $a[6]) * $q /
4189  ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r + $b[4]) * $r + $b[5]) * $r + 1);
4190  } elseif ($p_high < $p && $p < 1) {
4191  // Rational approximation for upper region.
4192  $q = sqrt(-2 * log(1 - $p));
4193  return -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) /
4194  (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1);
4195  }
4196  // If 0 < p < 1, return a null value
4197  return self::$_errorCodes['null'];
4198  } // function _inverse_ncdf()
4199 
4200 
4201  private static function _inverse_ncdf2($prob) {
4202  // Approximation of inverse standard normal CDF developed by
4203  // B. Moro, "The Full Monte," Risk 8(2), Feb 1995, 57-58.
4204 
4205  $a1 = 2.50662823884;
4206  $a2 = -18.61500062529;
4207  $a3 = 41.39119773534;
4208  $a4 = -25.44106049637;
4209 
4210  $b1 = -8.4735109309;
4211  $b2 = 23.08336743743;
4212  $b3 = -21.06224101826;
4213  $b4 = 3.13082909833;
4214 
4215  $c1 = 0.337475482272615;
4216  $c2 = 0.976169019091719;
4217  $c3 = 0.160797971491821;
4218  $c4 = 2.76438810333863E-02;
4219  $c5 = 3.8405729373609E-03;
4220  $c6 = 3.951896511919E-04;
4221  $c7 = 3.21767881768E-05;
4222  $c8 = 2.888167364E-07;
4223  $c9 = 3.960315187E-07;
4224 
4225  $y = $prob - 0.5;
4226  if (abs($y) < 0.42) {
4227  $z = pow($y,2);
4228  $z = $y * ((($a4 * $z + $a3) * $z + $a2) * $z + $a1) / (((($b4 * $z + $b3) * $z + $b2) * $z + $b1) * $z + 1);
4229  } else {
4230  if ($y > 0) {
4231  $z = log(-log(1 - $prob));
4232  } else {
4233  $z = log(-log($prob));
4234  }
4235  $z = $c1 + $z * ($c2 + $z * ($c3 + $z * ($c4 + $z * ($c5 + $z * ($c6 + $z * ($c7 + $z * ($c8 + $z * $c9)))))));
4236  if ($y < 0) {
4237  $z = -$z;
4238  }
4239  }
4240  return $z;
4241  } // function _inverse_ncdf2()
4242 
4243 
4244  private static function _inverse_ncdf3($p) {
4245  // ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3.
4246  // Produces the normal deviate Z corresponding to a given lower
4247  // tail area of P; Z is accurate to about 1 part in 10**16.
4248  //
4249  // This is a PHP version of the original FORTRAN code that can
4250  // be found at http://lib.stat.cmu.edu/apstat/
4251  $split1 = 0.425;
4252  $split2 = 5;
4253  $const1 = 0.180625;
4254  $const2 = 1.6;
4255 
4256  // coefficients for p close to 0.5
4257  $a0 = 3.3871328727963666080;
4258  $a1 = 1.3314166789178437745E+2;
4259  $a2 = 1.9715909503065514427E+3;
4260  $a3 = 1.3731693765509461125E+4;
4261  $a4 = 4.5921953931549871457E+4;
4262  $a5 = 6.7265770927008700853E+4;
4263  $a6 = 3.3430575583588128105E+4;
4264  $a7 = 2.5090809287301226727E+3;
4265 
4266  $b1 = 4.2313330701600911252E+1;
4267  $b2 = 6.8718700749205790830E+2;
4268  $b3 = 5.3941960214247511077E+3;
4269  $b4 = 2.1213794301586595867E+4;
4270  $b5 = 3.9307895800092710610E+4;
4271  $b6 = 2.8729085735721942674E+4;
4272  $b7 = 5.2264952788528545610E+3;
4273 
4274  // coefficients for p not close to 0, 0.5 or 1.
4275  $c0 = 1.42343711074968357734;
4276  $c1 = 4.63033784615654529590;
4277  $c2 = 5.76949722146069140550;
4278  $c3 = 3.64784832476320460504;
4279  $c4 = 1.27045825245236838258;
4280  $c5 = 2.41780725177450611770E-1;
4281  $c6 = 2.27238449892691845833E-2;
4282  $c7 = 7.74545014278341407640E-4;
4283 
4284  $d1 = 2.05319162663775882187;
4285  $d2 = 1.67638483018380384940;
4286  $d3 = 6.89767334985100004550E-1;
4287  $d4 = 1.48103976427480074590E-1;
4288  $d5 = 1.51986665636164571966E-2;
4289  $d6 = 5.47593808499534494600E-4;
4290  $d7 = 1.05075007164441684324E-9;
4291 
4292  // coefficients for p near 0 or 1.
4293  $e0 = 6.65790464350110377720;
4294  $e1 = 5.46378491116411436990;
4295  $e2 = 1.78482653991729133580;
4296  $e3 = 2.96560571828504891230E-1;
4297  $e4 = 2.65321895265761230930E-2;
4298  $e5 = 1.24266094738807843860E-3;
4299  $e6 = 2.71155556874348757815E-5;
4300  $e7 = 2.01033439929228813265E-7;
4301 
4302  $f1 = 5.99832206555887937690E-1;
4303  $f2 = 1.36929880922735805310E-1;
4304  $f3 = 1.48753612908506148525E-2;
4305  $f4 = 7.86869131145613259100E-4;
4306  $f5 = 1.84631831751005468180E-5;
4307  $f6 = 1.42151175831644588870E-7;
4308  $f7 = 2.04426310338993978564E-15;
4309 
4310  $q = $p - 0.5;
4311 
4312  // computation for p close to 0.5
4313  if (abs($q) <= split1) {
4314  $R = $const1 - $q * $q;
4315  $z = $q * ((((((($a7 * $R + $a6) * $R + $a5) * $R + $a4) * $R + $a3) * $R + $a2) * $R + $a1) * $R + $a0) /
4316  ((((((($b7 * $R + $b6) * $R + $b5) * $R + $b4) * $R + $b3) * $R + $b2) * $R + $b1) * $R + 1);
4317  } else {
4318  if ($q < 0) {
4319  $R = $p;
4320  } else {
4321  $R = 1 - $p;
4322  }
4323  $R = pow(-log($R),2);
4324 
4325  // computation for p not close to 0, 0.5 or 1.
4326  If ($R <= $split2) {
4327  $R = $R - $const2;
4328  $z = ((((((($c7 * $R + $c6) * $R + $c5) * $R + $c4) * $R + $c3) * $R + $c2) * $R + $c1) * $R + $c0) /
4329  ((((((($d7 * $R + $d6) * $R + $d5) * $R + $d4) * $R + $d3) * $R + $d2) * $R + $d1) * $R + 1);
4330  } else {
4331  // computation for p near 0 or 1.
4332  $R = $R - $split2;
4333  $z = ((((((($e7 * $R + $e6) * $R + $e5) * $R + $e4) * $R + $e3) * $R + $e2) * $R + $e1) * $R + $e0) /
4334  ((((((($f7 * $R + $f6) * $R + $f5) * $R + $f4) * $R + $f3) * $R + $f2) * $R + $f1) * $R + 1);
4335  }
4336  if ($q < 0) {
4337  $z = -$z;
4338  }
4339  }
4340  return $z;
4341  } // function _inverse_ncdf3()
4342 
4343 
4355  public static function NORMINV($probability,$mean,$stdDev) {
4356  $probability = self::flattenSingleValue($probability);
4357  $mean = self::flattenSingleValue($mean);
4358  $stdDev = self::flattenSingleValue($stdDev);
4359 
4360  if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
4361  if (($probability < 0) || ($probability > 1)) {
4362  return self::$_errorCodes['num'];
4363  }
4364  if ($stdDev < 0) {
4365  return self::$_errorCodes['num'];
4366  }
4367  return (self::_inverse_ncdf($probability) * $stdDev) + $mean;
4368  }
4369  return self::$_errorCodes['value'];
4370  } // function NORMINV()
4371 
4372 
4381  public static function NORMSINV($value) {
4382  return self::NORMINV($value, 0, 1);
4383  } // function NORMSINV()
4384 
4385 
4398  public static function LOGINV($probability, $mean, $stdDev) {
4399  $probability = self::flattenSingleValue($probability);
4400  $mean = self::flattenSingleValue($mean);
4401  $stdDev = self::flattenSingleValue($stdDev);
4402 
4403  if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
4404  if (($probability < 0) || ($probability > 1) || ($stdDev <= 0)) {
4405  return self::$_errorCodes['num'];
4406  }
4407  return exp($mean + $stdDev * self::NORMSINV($probability));
4408  }
4409  return self::$_errorCodes['value'];
4410  } // function LOGINV()
4411 
4412 
4426  public static function HYPGEOMDIST($sampleSuccesses, $sampleNumber, $populationSuccesses, $populationNumber) {
4427  $sampleSuccesses = floor(self::flattenSingleValue($sampleSuccesses));
4428  $sampleNumber = floor(self::flattenSingleValue($sampleNumber));
4429  $populationSuccesses = floor(self::flattenSingleValue($populationSuccesses));
4430  $populationNumber = floor(self::flattenSingleValue($populationNumber));
4431 
4432  if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) {
4433  if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) {
4434  return self::$_errorCodes['num'];
4435  }
4436  if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) {
4437  return self::$_errorCodes['num'];
4438  }
4439  if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) {
4440  return self::$_errorCodes['num'];
4441  }
4442  return self::COMBIN($populationSuccesses,$sampleSuccesses) *
4443  self::COMBIN($populationNumber - $populationSuccesses,$sampleNumber - $sampleSuccesses) /
4444  self::COMBIN($populationNumber,$sampleNumber);
4445  }
4446  return self::$_errorCodes['value'];
4447  } // function HYPGEOMDIST()
4448 
4449 
4460  public static function TDIST($value, $degrees, $tails) {
4461  $value = self::flattenSingleValue($value);
4462  $degrees = floor(self::flattenSingleValue($degrees));
4463  $tails = floor(self::flattenSingleValue($tails));
4464 
4465  if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) {
4466  if (($value < 0) || ($degrees < 1) || ($tails < 1) || ($tails > 2)) {
4467  return self::$_errorCodes['num'];
4468  }
4469  // tdist, which finds the probability that corresponds to a given value
4470  // of t with k degrees of freedom. This algorithm is translated from a
4471  // pascal function on p81 of "Statistical Computing in Pascal" by D
4472  // Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd:
4473  // London). The above Pascal algorithm is itself a translation of the
4474  // fortran algoritm "AS 3" by B E Cooper of the Atlas Computer
4475  // Laboratory as reported in (among other places) "Applied Statistics
4476  // Algorithms", editied by P Griffiths and I D Hill (1985; Ellis
4477  // Horwood Ltd.; W. Sussex, England).
4478 // $ta = 2 / pi();
4479  $ta = 0.636619772367581;
4480  $tterm = $degrees;
4481  $ttheta = atan2($value,sqrt($tterm));
4482  $tc = cos($ttheta);
4483  $ts = sin($ttheta);
4484  $tsum = 0;
4485 
4486  if (($degrees % 2) == 1) {
4487  $ti = 3;
4488  $tterm = $tc;
4489  } else {
4490  $ti = 2;
4491  $tterm = 1;
4492  }
4493 
4494  $tsum = $tterm;
4495  while ($ti < $degrees) {
4496  $tterm *= $tc * $tc * ($ti - 1) / $ti;
4497  $tsum += $tterm;
4498  $ti += 2;
4499  }
4500  $tsum *= $ts;
4501  if (($degrees % 2) == 1) { $tsum = $ta * ($tsum + $ttheta); }
4502  $tValue = 0.5 * (1 + $tsum);
4503  if ($tails == 1) {
4504  return 1 - abs($tValue);
4505  } else {
4506  return 1 - abs((1 - $tValue) - $tValue);
4507  }
4508  }
4509  return self::$_errorCodes['value'];
4510  } // function TDIST()
4511 
4512 
4522  public static function TINV($probability, $degrees) {
4523  $probability = self::flattenSingleValue($probability);
4524  $degrees = floor(self::flattenSingleValue($degrees));
4525 
4526  if ((is_numeric($probability)) && (is_numeric($degrees))) {
4527  $xLo = 100;
4528  $xHi = 0;
4529  $maxIteration = 100;
4530 
4531  $x = $xNew = 1;
4532  $dx = 1;
4533  $i = 0;
4534 
4535  while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
4536  // Apply Newton-Raphson step
4537  $result = self::TDIST($x, $degrees, 2);
4538  $error = $result - $probability;
4539  if ($error == 0.0) {
4540  $dx = 0;
4541  } elseif ($error < 0.0) {
4542  $xLo = $x;
4543  } else {
4544  $xHi = $x;
4545  }
4546  // Avoid division by zero
4547  if ($result != 0.0) {
4548  $dx = $error / $result;
4549  $xNew = $x - $dx;
4550  }
4551  // If the NR fails to converge (which for example may be the
4552  // case if the initial guess is too rough) we apply a bisection
4553  // step to determine a more narrow interval around the root.
4554  if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
4555  $xNew = ($xLo + $xHi) / 2;
4556  $dx = $xNew - $x;
4557  }
4558  $x = $xNew;
4559  }
4560  if ($i == MAX_ITERATIONS) {
4561  return self::$_errorCodes['na'];
4562  }
4563  return round($x,12);
4564  }
4565  return self::$_errorCodes['value'];
4566  } // function TINV()
4567 
4568 
4580  public static function CONFIDENCE($alpha,$stdDev,$size) {
4581  $alpha = self::flattenSingleValue($alpha);
4582  $stdDev = self::flattenSingleValue($stdDev);
4583  $size = floor(self::flattenSingleValue($size));
4584 
4585  if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) {
4586  if (($alpha <= 0) || ($alpha >= 1)) {
4587  return self::$_errorCodes['num'];
4588  }
4589  if (($stdDev <= 0) || ($size < 1)) {
4590  return self::$_errorCodes['num'];
4591  }
4592  return self::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size);
4593  }
4594  return self::$_errorCodes['value'];
4595  } // function CONFIDENCE()
4596 
4597 
4611  public static function POISSON($value, $mean, $cumulative) {
4612  $value = self::flattenSingleValue($value);
4613  $mean = self::flattenSingleValue($mean);
4614 
4615  if ((is_numeric($value)) && (is_numeric($mean))) {
4616  if (($value <= 0) || ($mean <= 0)) {
4617  return self::$_errorCodes['num'];
4618  }
4619  if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
4620  if ($cumulative) {
4621  $summer = 0;
4622  for ($i = 0; $i <= floor($value); ++$i) {
4623  $summer += pow($mean,$i) / self::FACT($i);
4624  }
4625  return exp(0-$mean) * $summer;
4626  } else {
4627  return (exp(0-$mean) * pow($mean,$value)) / self::FACT($value);
4628  }
4629  }
4630  }
4631  return self::$_errorCodes['value'];
4632  } // function POISSON()
4633 
4634 
4648  public static function WEIBULL($value, $alpha, $beta, $cumulative) {
4649  $value = self::flattenSingleValue($value);
4650  $alpha = self::flattenSingleValue($alpha);
4651  $beta = self::flattenSingleValue($beta);
4652 
4653  if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) {
4654  if (($value < 0) || ($alpha <= 0) || ($beta <= 0)) {
4655  return self::$_errorCodes['num'];
4656  }
4657  if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
4658  if ($cumulative) {
4659  return 1 - exp(0 - pow($value / $beta,$alpha));
4660  } else {
4661  return ($alpha / pow($beta,$alpha)) * pow($value,$alpha - 1) * exp(0 - pow($value / $beta,$alpha));
4662  }
4663  }
4664  }
4665  return self::$_errorCodes['value'];
4666  } // function WEIBULL()
4667 
4668 
4680  public static function SKEW() {
4681  $aArgs = self::flattenArray(func_get_args());
4682  $mean = self::AVERAGE($aArgs);
4683  $stdDev = self::STDEV($aArgs);
4684 
4685  $count = $summer = 0;
4686  // Loop through arguments
4687  foreach ($aArgs as $arg) {
4688  // Is it a numeric value?
4689  if ((is_numeric($arg)) && (!is_string($arg))) {
4690  $summer += pow((($arg - $mean) / $stdDev),3) ;
4691  ++$count;
4692  }
4693  }
4694 
4695  // Return
4696  if ($count > 2) {
4697  return $summer * ($count / (($count-1) * ($count-2)));
4698  }
4699  return self::$_errorCodes['divisionbyzero'];
4700  } // function SKEW()
4701 
4702 
4714  public static function KURT() {
4715  $aArgs = self::flattenArray(func_get_args());
4716  $mean = self::AVERAGE($aArgs);
4717  $stdDev = self::STDEV($aArgs);
4718 
4719  if ($stdDev > 0) {
4720  $count = $summer = 0;
4721  // Loop through arguments
4722  foreach ($aArgs as $arg) {
4723  // Is it a numeric value?
4724  if ((is_numeric($arg)) && (!is_string($arg))) {
4725  $summer += pow((($arg - $mean) / $stdDev),4) ;
4726  ++$count;
4727  }
4728  }
4729 
4730  // Return
4731  if ($count > 3) {
4732  return $summer * ($count * ($count+1) / (($count-1) * ($count-2) * ($count-3))) - (3 * pow($count-1,2) / (($count-2) * ($count-3)));
4733  }
4734  }
4735  return self::$_errorCodes['divisionbyzero'];
4736  } // function KURT()
4737 
4738 
4746  public static function RAND($min = 0, $max = 0) {
4747  $min = self::flattenSingleValue($min);
4748  $max = self::flattenSingleValue($max);
4749 
4750  if ($min == 0 && $max == 0) {
4751  return (rand(0,10000000)) / 10000000;
4752  } else {
4753  return rand($min, $max);
4754  }
4755  } // function RAND()
4756 
4757 
4765  public static function MOD($a = 1, $b = 1) {
4766  $a = self::flattenSingleValue($a);
4767  $b = self::flattenSingleValue($b);
4768 
4769  return fmod($a,$b);
4770  } // function MOD()
4771 
4772 
4779  public static function CHARACTER($character) {
4780  $character = self::flattenSingleValue($character);
4781 
4782  if (function_exists('mb_convert_encoding')) {
4783  return mb_convert_encoding('&#'.intval($character).';', 'UTF-8', 'HTML-ENTITIES');
4784  } else {
4785  return chr(intval($character));
4786  }
4787  }
4788 
4795  public static function ASCIICODE($characters) {
4796  $characters = self::flattenSingleValue($characters);
4797  if (is_bool($characters)) {
4798  if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) {
4799  $characters = (int) $characters;
4800  } else {
4801  if ($characters) {
4802  $characters = 'True';
4803  } else {
4804  $characters = 'False';
4805  }
4806  }
4807  }
4808 
4809  if ((function_exists('mb_strlen')) && (function_exists('mb_substr'))) {
4810  if (mb_strlen($characters, 'UTF-8') > 0) {
4811  $character = mb_substr($characters, 0, 1, 'UTF-8');
4812  $byteLength = strlen($character);
4813  $xValue = 0;
4814  for ($i = 0; $i < $byteLength; ++$i) {
4815  $xValue = ($xValue * 256) + ord($character{$i});
4816  }
4817  return $xValue;
4818  }
4819  } else {
4820  if (strlen($characters) > 0) {
4821  return ord(substr($characters, 0, 1));
4822  }
4823  }
4824  return self::$_errorCodes['value'];
4825  } // function ASCIICODE()
4826 
4827 
4833  public static function CONCATENATE() {
4834  // Return value
4835  $returnValue = '';
4836 
4837  // Loop trough arguments
4838  $aArgs = self::flattenArray(func_get_args());
4839  foreach ($aArgs as $arg) {
4840  if (is_bool($arg)) {
4841  if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) {
4842  $arg = (int) $arg;
4843  } else {
4844  if ($arg) {
4845  $arg = 'TRUE';
4846  } else {
4847  $arg = 'FALSE';
4848  }
4849  }
4850  }
4851  $returnValue .= $arg;
4852  }
4853 
4854  // Return
4855  return $returnValue;
4856  } // function CONCATENATE()
4857 
4858 
4866  public static function STRINGLENGTH($value = '') {
4867  $value = self::flattenSingleValue($value);
4868 
4869  if (function_exists('mb_strlen')) {
4870  return mb_strlen($value, 'UTF-8');
4871  } else {
4872  return strlen($value);
4873  }
4874  } // function STRINGLENGTH()
4875 
4876 
4885  public static function SEARCHSENSITIVE($needle,$haystack,$offset=1) {
4886  $needle = (string) self::flattenSingleValue($needle);
4887  $haystack = (string) self::flattenSingleValue($haystack);
4888  $offset = self::flattenSingleValue($offset);
4889 
4890  if (($offset > 0) && (strlen($haystack) > $offset)) {
4891  if (function_exists('mb_strpos')) {
4892  $pos = mb_strpos($haystack, $needle, --$offset,'UTF-8');
4893  } else {
4894  $pos = strpos($haystack, $needle, --$offset);
4895  }
4896  if ($pos !== false) {
4897  return ++$pos;
4898  }
4899  }
4900  return self::$_errorCodes['value'];
4901  } // function SEARCHSENSITIVE()
4902 
4903 
4912  public static function SEARCHINSENSITIVE($needle,$haystack,$offset=1) {
4913  $needle = (string) self::flattenSingleValue($needle);
4914  $haystack = (string) self::flattenSingleValue($haystack);
4915  $offset = self::flattenSingleValue($offset);
4916 
4917  if (($offset > 0) && (strlen($haystack) > $offset)) {
4918  if (function_exists('mb_stripos')) {
4919  $pos = mb_stripos($haystack, $needle, --$offset,'UTF-8');
4920  } else {
4921  $pos = stripos($haystack, $needle, --$offset);
4922  }
4923  if ($pos !== false) {
4924  return ++$pos;
4925  }
4926  }
4927  return self::$_errorCodes['value'];
4928  } // function SEARCHINSENSITIVE()
4929 
4930 
4938  public static function LEFT($value = '', $chars = 1) {
4939  $value = self::flattenSingleValue($value);
4940  $chars = self::flattenSingleValue($chars);
4941 
4942  if (function_exists('mb_substr')) {
4943  return mb_substr($value, 0, $chars, 'UTF-8');
4944  } else {
4945  return substr($value, 0, $chars);
4946  }
4947  } // function LEFT()
4948 
4949 
4957  public static function RIGHT($value = '', $chars = 1) {
4958  $value = self::flattenSingleValue($value);
4959  $chars = self::flattenSingleValue($chars);
4960 
4961  if ((function_exists('mb_substr')) && (function_exists('mb_strlen'))) {
4962  return mb_substr($value, mb_strlen($value, 'UTF-8') - $chars, $chars, 'UTF-8');
4963  } else {
4964  return substr($value, strlen($value) - $chars);
4965  }
4966  } // function RIGHT()
4967 
4968 
4977  public static function MID($value = '', $start = 1, $chars = null) {
4978  $value = self::flattenSingleValue($value);
4980  $chars = self::flattenSingleValue($chars);
4981 
4982  if (function_exists('mb_substr')) {
4983  return mb_substr($value, --$start, $chars, 'UTF-8');
4984  } else {
4985  return substr($value, --$start, $chars);
4986  }
4987  } // function MID()
4988 
4989 
4998  public static function REPLACE($oldText = '', $start = 1, $chars = null, $newText) {
4999  $oldText = self::flattenSingleValue($oldText);
5001  $chars = self::flattenSingleValue($chars);
5002  $newText = self::flattenSingleValue($newText);
5003 
5004  $left = self::LEFT($oldText,$start-1);
5005  $right = self::RIGHT($oldText,self::STRINGLENGTH($oldText)-($start+$chars)+1);
5006 
5007  return $left.$newText.$right;
5008  } // function REPLACE()
5009 
5010 
5017  public static function RETURNSTRING($testValue = '') {
5018  $testValue = self::flattenSingleValue($testValue);
5019 
5020  if (is_string($testValue)) {
5021  return $testValue;
5022  }
5023  return Null;
5024  } // function RETURNSTRING()
5025 
5026 
5033  public static function FIXEDFORMAT($value,$decimals=2,$no_commas=false) {
5034  $value = self::flattenSingleValue($value);
5035  $decimals = self::flattenSingleValue($decimals);
5036  $no_commas = self::flattenSingleValue($no_commas);
5037 
5038  $valueResult = round($value,$decimals);
5039  if ($decimals < 0) { $decimals = 0; }
5040  if (!$no_commas) {
5041  $valueResult = number_format($valueResult,$decimals);
5042  }
5043 
5044  return (string) $valueResult;
5045  } // function FIXEDFORMAT()
5046 
5047 
5054  public static function TEXTFORMAT($value,$format) {
5055  $value = self::flattenSingleValue($value);
5056  $format = self::flattenSingleValue($format);
5057 
5058  return (string) PHPExcel_Style_NumberFormat::toFormattedString($value,$format);
5059  } // function TEXTFORMAT()
5060 
5061 
5068  public static function TRIMSPACES($stringValue = '') {
5069  $stringValue = self::flattenSingleValue($stringValue);
5070 
5071  if (is_string($stringValue) || is_numeric($stringValue)) {
5072  return trim(preg_replace('/ +/',' ',$stringValue));
5073  }
5074  return Null;
5075  } // function TRIMSPACES()
5076 
5077 
5078  private static $_invalidChars = Null;
5079 
5086  public static function TRIMNONPRINTABLE($stringValue = '') {
5087  $stringValue = self::flattenSingleValue($stringValue);
5088 
5089  if (self::$_invalidChars == Null) {
5090  self::$_invalidChars = range(chr(0),chr(31));
5091  }
5092 
5093  if (is_string($stringValue) || is_numeric($stringValue)) {
5094  return str_replace(self::$_invalidChars,'',trim($stringValue,"\x00..\x1F"));
5095  }
5096  return Null;
5097  } // function TRIMNONPRINTABLE()
5098 
5099 
5106  public static function ERROR_TYPE($value = '') {
5107  $value = self::flattenSingleValue($value);
5108 
5109  $i = 1;
5110  foreach(self::$_errorCodes as $errorCode) {
5111  if ($value == $errorCode) {
5112  return $i;
5113  }
5114  ++$i;
5115  }
5116  return self::$_errorCodes['na'];
5117  } // function ERROR_TYPE()
5118 
5119 
5126  public static function IS_BLANK($value = null) {
5127  if (!is_null($value)) {
5128  $value = self::flattenSingleValue($value);
5129  }
5130 
5131  return is_null($value);
5132  } // function IS_BLANK()
5133 
5134 
5141  public static function IS_ERR($value = '') {
5142  $value = self::flattenSingleValue($value);
5143 
5144  return self::IS_ERROR($value) && (!self::IS_NA($value));
5145  } // function IS_ERR()
5146 
5147 
5154  public static function IS_ERROR($value = '') {
5155  $value = self::flattenSingleValue($value);
5156 
5157  return in_array($value, array_values(self::$_errorCodes));
5158  } // function IS_ERROR()
5159 
5160 
5167  public static function IS_NA($value = '') {
5168  $value = self::flattenSingleValue($value);
5169 
5170  return ($value === self::$_errorCodes['na']);
5171  } // function IS_NA()
5172 
5173 
5180  public static function IS_EVEN($value = 0) {
5181  $value = self::flattenSingleValue($value);
5182 
5183  if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
5184  return self::$_errorCodes['value'];
5185  }
5186  return ($value % 2 == 0);
5187  } // function IS_EVEN()
5188 
5189 
5196  public static function IS_ODD($value = null) {
5197  $value = self::flattenSingleValue($value);
5198 
5199  if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
5200  return self::$_errorCodes['value'];
5201  }
5202  return (abs($value) % 2 == 1);
5203  } // function IS_ODD()
5204 
5205 
5212  public static function IS_NUMBER($value = 0) {
5213  $value = self::flattenSingleValue($value);
5214 
5215  if (is_string($value)) {
5216  return False;
5217  }
5218  return is_numeric($value);
5219  } // function IS_NUMBER()
5220 
5221 
5228  public static function IS_LOGICAL($value = true) {
5229  $value = self::flattenSingleValue($value);
5230 
5231  return is_bool($value);
5232  } // function IS_LOGICAL()
5233 
5234 
5241  public static function IS_TEXT($value = '') {
5242  $value = self::flattenSingleValue($value);
5243 
5244  return is_string($value);
5245  } // function IS_TEXT()
5246 
5247 
5254  public static function IS_NONTEXT($value = '') {
5255  return !self::IS_TEXT($value);
5256  } // function IS_NONTEXT()
5257 
5258 
5264  public static function VERSION() {
5265  return 'PHPExcel 1.7.0, 2009-08-10';
5266  } // function VERSION()
5267 
5268 
5278  public static function DATE($year = 0, $month = 1, $day = 1) {
5279  $year = (integer) self::flattenSingleValue($year);
5280  $month = (integer) self::flattenSingleValue($month);
5281  $day = (integer) self::flattenSingleValue($day);
5282 
5284  // Validate parameters
5285  if ($year < ($baseYear-1900)) {
5286  return self::$_errorCodes['num'];
5287  }
5288  if ((($baseYear-1900) != 0) && ($year < $baseYear) && ($year >= 1900)) {
5289  return self::$_errorCodes['num'];
5290  }
5291 
5292  if (($year < $baseYear) && ($year >= ($baseYear-1900))) {
5293  $year += 1900;
5294  }
5295 
5296  if ($month < 1) {
5297  // Handle year/month adjustment if month < 1
5298  --$month;
5299  $year += ceil($month / 12) - 1;
5300  $month = 13 - abs($month % 12);
5301  } elseif ($month > 12) {
5302  // Handle year/month adjustment if month > 12
5303  $year += floor($month / 12);
5304  $month = ($month % 12);
5305  }
5306 
5307  // Re-validate the year parameter after adjustments
5308  if (($year < $baseYear) || ($year >= 10000)) {
5309  return self::$_errorCodes['num'];
5310  }
5311 
5312  // Execute function
5313  $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel($year, $month, $day);
5314  switch (self::getReturnDateType()) {
5315  case self::RETURNDATE_EXCEL : return (float) $excelDateValue;
5316  break;
5317  case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
5318  break;
5319  case self::RETURNDATE_PHP_OBJECT : return PHPExcel_Shared_Date::ExcelToPHPObject($excelDateValue);
5320  break;
5321  }
5322  } // function DATE()
5323 
5324 
5334  public static function TIME($hour = 0, $minute = 0, $second = 0) {
5335  $hour = self::flattenSingleValue($hour);
5336  $minute = self::flattenSingleValue($minute);
5337  $second = self::flattenSingleValue($second);
5338 
5339  if ($hour == '') { $hour = 0; }
5340  if ($minute == '') { $minute = 0; }
5341  if ($second == '') { $second = 0; }
5342 
5343  if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) {
5344  return self::$_errorCodes['value'];
5345  }
5346  $hour = (integer) $hour;
5347  $minute = (integer) $minute;
5348  $second = (integer) $second;
5349 
5350  if ($second < 0) {
5351  $minute += floor($second / 60);
5352  $second = 60 - abs($second % 60);
5353  if ($second == 60) { $second = 0; }
5354  } elseif ($second >= 60) {
5355  $minute += floor($second / 60);
5356  $second = $second % 60;
5357  }
5358  if ($minute < 0) {
5359  $hour += floor($minute / 60);
5360  $minute = 60 - abs($minute % 60);
5361  if ($minute == 60) { $minute = 0; }
5362  } elseif ($minute >= 60) {
5363  $hour += floor($minute / 60);
5364  $minute = $minute % 60;
5365  }
5366 
5367  if ($hour > 23) {
5368  $hour = $hour % 24;
5369  } elseif ($hour < 0) {
5370  return self::$_errorCodes['num'];
5371  }
5372 
5373  // Execute function
5374  switch (self::getReturnDateType()) {
5375  case self::RETURNDATE_EXCEL : $date = 0;
5378  $date = 1;
5379  }
5380  return (float) PHPExcel_Shared_Date::FormattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
5381  break;
5382  case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(1970, 1, 1, $hour-1, $minute, $second)); // -2147468400; // -2147472000 + 3600
5383  break;
5384  case self::RETURNDATE_PHP_OBJECT : $dayAdjust = 0;
5385  if ($hour < 0) {
5386  $dayAdjust = floor($hour / 24);
5387  $hour = 24 - abs($hour % 24);
5388  if ($hour == 24) { $hour = 0; }
5389  } elseif ($hour >= 24) {
5390  $dayAdjust = floor($hour / 24);
5391  $hour = $hour % 24;
5392  }
5393  $phpDateObject = new DateTime('1900-01-01 '.$hour.':'.$minute.':'.$second);
5394  if ($dayAdjust != 0) {
5395  $phpDateObject->modify($dayAdjust.' days');
5396  }
5397  return $phpDateObject;
5398  break;
5399  }
5400  } // function TIME()
5401 
5402 
5410  public static function DATEVALUE($dateValue = 1) {
5411  $dateValue = str_replace(array('/','.',' '),array('-','-','-'),self::flattenSingleValue(trim($dateValue,'"')));
5412 
5413  $yearFound = false;
5414  $t1 = explode('-',$dateValue);
5415  foreach($t1 as &$t) {
5416  if ((is_numeric($t)) && (($t > 31) && ($t < 100))) {
5417  if ($yearFound) {
5418  return self::$_errorCodes['value'];
5419  } else {
5420  $t += 1900;
5421  $yearFound = true;
5422  }
5423  }
5424  }
5425  unset($t);
5426  $dateValue = implode('-',$t1);
5427 
5428  $PHPDateArray = date_parse($dateValue);
5429  if (($PHPDateArray === False) || ($PHPDateArray['error_count'] > 0)) {
5430  $testVal1 = strtok($dateValue,'- ');
5431  if ($testVal1 !== False) {
5432  $testVal2 = strtok('- ');
5433  if ($testVal2 !== False) {
5434  $testVal3 = strtok('- ');
5435  if ($testVal3 === False) {
5436  $testVal3 = strftime('%Y');
5437  }
5438  } else {
5439  return self::$_errorCodes['value'];
5440  }
5441  } else {
5442  return self::$_errorCodes['value'];
5443  }
5444  $PHPDateArray = date_parse($testVal1.'-'.$testVal2.'-'.$testVal3);
5445  if (($PHPDateArray === False) || ($PHPDateArray['error_count'] > 0)) {
5446  $PHPDateArray = date_parse($testVal2.'-'.$testVal1.'-'.$testVal3);
5447  if (($PHPDateArray === False) || ($PHPDateArray['error_count'] > 0)) {
5448  return self::$_errorCodes['value'];
5449  }
5450  }
5451  }
5452 
5453  if (($PHPDateArray !== False) && ($PHPDateArray['error_count'] == 0)) {
5454  // Execute function
5455  if ($PHPDateArray['year'] == '') { $PHPDateArray['year'] = strftime('%Y'); }
5456  if ($PHPDateArray['month'] == '') { $PHPDateArray['month'] = strftime('%m'); }
5457  if ($PHPDateArray['day'] == '') { $PHPDateArray['day'] = strftime('%d'); }
5458  $excelDateValue = floor(PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']));
5459 
5460  switch (self::getReturnDateType()) {
5461  case self::RETURNDATE_EXCEL : return (float) $excelDateValue;
5462  break;
5463  case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
5464  break;
5465  case self::RETURNDATE_PHP_OBJECT : return new DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00');
5466  break;
5467  }
5468  }
5469  return self::$_errorCodes['value'];
5470  } // function DATEVALUE()
5471 
5472 
5479  private static function _getDateValue($dateValue) {
5480  if (!is_numeric($dateValue)) {
5481  if ((is_string($dateValue)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
5482  return self::$_errorCodes['value'];
5483  }
5484  if ((is_object($dateValue)) && ($dateValue instanceof PHPExcel_Shared_Date::$dateTimeObjectType)) {
5485  $dateValue = PHPExcel_Shared_Date::PHPToExcel($dateValue);
5486  } else {
5487  $saveReturnDateType = self::getReturnDateType();
5488  self::setReturnDateType(self::RETURNDATE_EXCEL);
5489  $dateValue = self::DATEVALUE($dateValue);
5490  self::setReturnDateType($saveReturnDateType);
5491  }
5492  }
5493  return $dateValue;
5494  } // function _getDateValue()
5495 
5496 
5504  public static function TIMEVALUE($timeValue) {
5505  $timeValue = self::flattenSingleValue($timeValue);
5506 
5507  if ((($PHPDateArray = date_parse($timeValue)) !== False) && ($PHPDateArray['error_count'] == 0)) {
5508  if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) {
5509  $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']);
5510  } else {
5511  $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel(1900,1,1,$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']) - 1;
5512  }
5513 
5514  switch (self::getReturnDateType()) {
5515  case self::RETURNDATE_EXCEL : return (float) $excelDateValue;
5516  break;
5517  case self::RETURNDATE_PHP_NUMERIC : return (integer) $phpDateValue = PHPExcel_Shared_Date::ExcelToPHP($excelDateValue+25569) - 3600;;
5518  break;
5519  case self::RETURNDATE_PHP_OBJECT : return new DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']);
5520  break;
5521  }
5522  }
5523  return self::$_errorCodes['value'];
5524  } // function TIMEVALUE()
5525 
5526 
5533  private static function _getTimeValue($timeValue) {
5534  $saveReturnDateType = self::getReturnDateType();
5535  self::setReturnDateType(self::RETURNDATE_EXCEL);
5536  $timeValue = self::TIMEVALUE($timeValue);
5537  self::setReturnDateType($saveReturnDateType);
5538  return $timeValue;
5539  } // function _getTimeValue()
5540 
5541 
5548  public static function DATETIMENOW() {
5549  $saveTimeZone = date_default_timezone_get();
5550  date_default_timezone_set('UTC');
5551  $retValue = False;
5552  switch (self::getReturnDateType()) {
5553  case self::RETURNDATE_EXCEL : $retValue = (float) PHPExcel_Shared_Date::PHPToExcel(time());
5554  break;
5555  case self::RETURNDATE_PHP_NUMERIC : $retValue = (integer) time();
5556  break;
5557  case self::RETURNDATE_PHP_OBJECT : $retValue = new DateTime();
5558  break;
5559  }
5560  date_default_timezone_set($saveTimeZone);
5561 
5562  return $retValue;
5563  } // function DATETIMENOW()
5564 
5565 
5572  public static function DATENOW() {
5573  $saveTimeZone = date_default_timezone_get();
5574  date_default_timezone_set('UTC');
5575  $retValue = False;
5576  $excelDateTime = floor(PHPExcel_Shared_Date::PHPToExcel(time()));
5577  switch (self::getReturnDateType()) {
5578  case self::RETURNDATE_EXCEL : $retValue = (float) $excelDateTime;
5579  break;
5580  case self::RETURNDATE_PHP_NUMERIC : $retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime) - 3600;
5581  break;
5582  case self::RETURNDATE_PHP_OBJECT : $retValue = PHPExcel_Shared_Date::ExcelToPHPObject($excelDateTime);
5583  break;
5584  }
5585  date_default_timezone_set($saveTimeZone);
5586 
5587  return $retValue;
5588  } // function DATENOW()
5589 
5590 
5591  private static function _isLeapYear($year) {
5592  return ((($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0));
5593  } // function _isLeapYear()
5594 
5595 
5596  private static function _dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, $methodUS) {
5597  if ($startDay == 31) {
5598  --$startDay;
5599  } elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !self::_isLeapYear($startYear))))) {
5600  $startDay = 30;
5601  }
5602  if ($endDay == 31) {
5603  if ($methodUS && $startDay != 30) {
5604  $endDay = 1;
5605  if ($endMonth == 12) {
5606  ++$endYear;
5607  $endMonth = 1;
5608  } else {
5609  ++$endMonth;
5610  }
5611  } else {
5612  $endDay = 30;
5613  }
5614  }
5615 
5616  return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360;
5617  } // function _dateDiff360()
5618 
5619 
5628  public static function DAYS360($startDate = 0, $endDate = 0, $method = false) {
5629  $startDate = self::flattenSingleValue($startDate);
5630  $endDate = self::flattenSingleValue($endDate);
5631 
5632  if (is_string($startDate = self::_getDateValue($startDate))) {
5633  return self::$_errorCodes['value'];
5634  }
5635  if (is_string($endDate = self::_getDateValue($endDate))) {
5636  return self::$_errorCodes['value'];
5637  }
5638 
5639  // Execute function
5640  $PHPStartDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
5641  $startDay = $PHPStartDateObject->format('j');
5642  $startMonth = $PHPStartDateObject->format('n');
5643  $startYear = $PHPStartDateObject->format('Y');
5644 
5645  $PHPEndDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
5646  $endDay = $PHPEndDateObject->format('j');
5647  $endMonth = $PHPEndDateObject->format('n');
5648  $endYear = $PHPEndDateObject->format('Y');
5649 
5650  return self::_dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method);
5651  } // function DAYS360()
5652 
5653 
5662  public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D') {
5663  $startDate = self::flattenSingleValue($startDate);
5664  $endDate = self::flattenSingleValue($endDate);
5665  $unit = strtoupper(self::flattenSingleValue($unit));
5666 
5667  if (is_string($startDate = self::_getDateValue($startDate))) {
5668  return self::$_errorCodes['value'];
5669  }
5670  if (is_string($endDate = self::_getDateValue($endDate))) {
5671  return self::$_errorCodes['value'];
5672  }
5673 
5674  // Validate parameters
5675  if ($startDate >= $endDate) {
5676  return self::$_errorCodes['num'];
5677  }
5678 
5679  // Execute function
5680  $difference = $endDate - $startDate;
5681 
5682  $PHPStartDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
5683  $startDays = $PHPStartDateObject->format('j');
5684  $startMonths = $PHPStartDateObject->format('n');
5685  $startYears = $PHPStartDateObject->format('Y');
5686 
5687  $PHPEndDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
5688  $endDays = $PHPEndDateObject->format('j');
5689  $endMonths = $PHPEndDateObject->format('n');
5690  $endYears = $PHPEndDateObject->format('Y');
5691 
5692  $retVal = self::$_errorCodes['num'];
5693  switch ($unit) {
5694  case 'D':
5695  $retVal = intval($difference);
5696  break;
5697  case 'M':
5698  $retVal = intval($endMonths - $startMonths) + (intval($endYears - $startYears) * 12);
5699  // We're only interested in full months
5700  if ($endDays < $startDays) {
5701  --$retVal;
5702  }
5703  break;
5704  case 'Y':
5705  $retVal = intval($endYears - $startYears);
5706  // We're only interested in full months
5707  if ($endMonths < $startMonths) {
5708  --$retVal;
5709  } elseif (($endMonths == $startMonths) && ($endDays < $startDays)) {
5710  --$retVal;
5711  }
5712  break;
5713  case 'MD':
5714  if ($endDays < $startDays) {
5715  $retVal = $endDays;
5716  $PHPEndDateObject->modify('-'.$endDays.' days');
5717  $adjustDays = $PHPEndDateObject->format('j');
5718  if ($adjustDays > $startDays) {
5719  $retVal += ($adjustDays - $startDays);
5720  }
5721  } else {
5722  $retVal = $endDays - $startDays;
5723  }
5724  break;
5725  case 'YM':
5726  $retVal = abs(intval($endMonths - $startMonths));
5727  // We're only interested in full months
5728  if ($endDays < $startDays) {
5729  --$retVal;
5730  }
5731  break;
5732  case 'YD':
5733  $retVal = intval($difference);
5734  if ($endYears > $startYears) {
5735  while ($endYears > $startYears) {
5736  $PHPEndDateObject->modify('-1 year');
5737  $endYears = $PHPEndDateObject->format('Y');
5738  }
5739  $retVal = abs($PHPEndDateObject->format('z') - $PHPStartDateObject->format('z'));
5740  }
5741  break;
5742  }
5743  return $retVal;
5744  } // function DATEDIF()
5745 
5746 
5764  public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0) {
5765  $startDate = self::flattenSingleValue($startDate);
5766  $endDate = self::flattenSingleValue($endDate);
5768 
5769  if (is_string($startDate = self::_getDateValue($startDate))) {
5770  return self::$_errorCodes['value'];
5771  }
5772  if (is_string($endDate = self::_getDateValue($endDate))) {
5773  return self::$_errorCodes['value'];
5774  }
5775 
5776  if ((is_numeric($method)) && (!is_string($method))) {
5777  switch($method) {
5778  case 0 :
5779  return self::DAYS360($startDate,$endDate) / 360;
5780  break;
5781  case 1 :
5782  $startYear = self::YEAR($startDate);
5783  $endYear = self::YEAR($endDate);
5784  $leapDay = 0;
5785  if (self::_isLeapYear($startYear) || self::_isLeapYear($endYear)) {
5786  $leapDay = 1;
5787  }
5788  return self::DATEDIF($startDate,$endDate) / (365 + $leapDay);
5789  break;
5790  case 2 :
5791  return self::DATEDIF($startDate,$endDate) / 360;
5792  break;
5793  case 3 :
5794  return self::DATEDIF($startDate,$endDate) / 365;
5795  break;
5796  case 4 :
5797  return self::DAYS360($startDate,$endDate,True) / 360;
5798  break;
5799  }
5800  }
5801  return self::$_errorCodes['value'];
5802  } // function YEARFRAC()
5803 
5804 
5813  public static function NETWORKDAYS($startDate,$endDate) {
5814  // Flush the mandatory start and end date that are referenced in the function definition
5815  $dateArgs = self::flattenArray(func_get_args());
5816  array_shift($dateArgs);
5817  array_shift($dateArgs);
5818 
5819  // Validate the start and end dates
5820  if (is_string($startDate = $sDate = self::_getDateValue($startDate))) {
5821  return self::$_errorCodes['value'];
5822  }
5823  if (is_string($endDate = $eDate = self::_getDateValue($endDate))) {
5824  return self::$_errorCodes['value'];
5825  }
5826 
5827  if ($sDate > $eDate) {
5828  $startDate = $eDate;
5829  $endDate = $sDate;
5830  }
5831 
5832  // Execute function
5833  $startDoW = 6 - self::DAYOFWEEK($startDate,2);
5834  if ($startDoW < 0) { $startDoW = 0; }
5835  $endDoW = self::DAYOFWEEK($endDate,2);
5836  if ($endDoW >= 6) { $endDoW = 0; }
5837 
5838  $wholeWeekDays = floor(($endDate - $startDate) / 7) * 5;
5839  $partWeekDays = $endDoW + $startDoW;
5840  if ($partWeekDays > 5) {
5841  $partWeekDays -= 5;
5842  }
5843 
5844  // Test any extra holiday parameters
5845  $holidayCountedArray = array();
5846  foreach ($dateArgs as $holidayDate) {
5847  if (is_string($holidayDate = self::_getDateValue($holidayDate))) {
5848  return self::$_errorCodes['value'];
5849  }
5850  if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
5851  if ((self::DAYOFWEEK($holidayDate,2) < 6) && (!in_array($holidayDate,$holidayCountedArray))) {
5852  --$partWeekDays;
5853  $holidayCountedArray[] = $holidayDate;
5854  }
5855  }
5856  }
5857 
5858  if ($sDate > $eDate) {
5859  return 0 - ($wholeWeekDays + $partWeekDays);
5860  }
5861  return $wholeWeekDays + $partWeekDays;
5862  } // function NETWORKDAYS()
5863 
5864 
5873  public static function WORKDAY($startDate,$endDays) {
5874  $dateArgs = self::flattenArray(func_get_args());
5875 
5876  array_shift($dateArgs);
5877  array_shift($dateArgs);
5878 
5879  if (is_string($startDate = self::_getDateValue($startDate))) {
5880  return self::$_errorCodes['value'];
5881  }
5882  if (!is_numeric($endDays)) {
5883  return self::$_errorCodes['value'];
5884  }
5885  $endDate = (float) $startDate + (floor($endDays / 5) * 7) + ($endDays % 5);
5886  if ($endDays < 0) {
5887  $endDate += 7;
5888  }
5889 
5890  $endDoW = self::DAYOFWEEK($endDate,3);
5891  if ($endDoW >= 5) {
5892  if ($endDays >= 0) {
5893  $endDate += (7 - $endDoW);
5894  } else {
5895  $endDate -= ($endDoW - 5);
5896  }
5897  }
5898 
5899  // Test any extra holiday parameters
5900  if (count($dateArgs) > 0) {
5901  $holidayCountedArray = $holidayDates = array();
5902  foreach ($dateArgs as $holidayDate) {
5903  if (is_string($holidayDate = self::_getDateValue($holidayDate))) {
5904  return self::$_errorCodes['value'];
5905  }
5906  $holidayDates[] = $holidayDate;
5907  }
5908  if ($endDays >= 0) {
5909  sort($holidayDates, SORT_NUMERIC);
5910  } else {
5911  rsort($holidayDates, SORT_NUMERIC);
5912  }
5913  foreach ($holidayDates as $holidayDate) {
5914  if ($endDays >= 0) {
5915  if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
5916  if ((self::DAYOFWEEK($holidayDate,2) < 6) && (!in_array($holidayDate,$holidayCountedArray))) {
5917  ++$endDate;
5918  $holidayCountedArray[] = $holidayDate;
5919  }
5920  }
5921  } else {
5922  if (($holidayDate <= $startDate) && ($holidayDate >= $endDate)) {
5923  if ((self::DAYOFWEEK($holidayDate,2) < 6) && (!in_array($holidayDate,$holidayCountedArray))) {
5924  --$endDate;
5925  $holidayCountedArray[] = $holidayDate;
5926  }
5927  }
5928  }
5929  $endDoW = self::DAYOFWEEK($endDate,3);
5930  if ($endDoW >= 5) {
5931  if ($endDays >= 0) {
5932  $endDate += (7 - $endDoW);
5933  } else {
5934  $endDate -= ($endDoW - 5);
5935  }
5936  }
5937  }
5938  }
5939 
5940  switch (self::getReturnDateType()) {
5941  case self::RETURNDATE_EXCEL : return (float) $endDate;
5942  break;
5943  case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP($endDate);
5944  break;
5945  case self::RETURNDATE_PHP_OBJECT : return PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
5946  break;
5947  }
5948  } // function WORKDAY()
5949 
5950 
5957  public static function DAYOFMONTH($dateValue = 1) {
5958  $dateValue = self::flattenSingleValue($dateValue);
5959 
5960  if (is_string($dateValue = self::_getDateValue($dateValue))) {
5961  return self::$_errorCodes['value'];
5962  }
5963 
5964  // Execute function
5965  $PHPDateObject = &PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
5966 
5967  return (int) $PHPDateObject->format('j');
5968  } // function DAYOFMONTH()
5969 
5970 
5977  public static function DAYOFWEEK($dateValue = 1, $style = 1) {
5978  $dateValue = self::flattenSingleValue($dateValue);
5979  $style = floor(self::flattenSingleValue($style));
5980 
5981  if (is_string($dateValue = self::_getDateValue($dateValue))) {
5982  return self::$_errorCodes['value'];
5983  }
5984 
5985  // Execute function
5986  $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
5987  $DoW = $PHPDateObject->format('w');
5988 
5989  $firstDay = 1;
5990  switch ($style) {
5991  case 1: ++$DoW;
5992  break;
5993  case 2: if ($DoW == 0) { $DoW = 7; }
5994  break;
5995  case 3: if ($DoW == 0) { $DoW = 7; }
5996  $firstDay = 0;
5997  --$DoW;
5998  break;
5999  default:
6000  }
6001  if (self::$compatibilityMode == self::COMPATIBILITY_EXCEL) {
6002  // Test for Excel's 1900 leap year, and introduce the error as required
6003  if (($PHPDateObject->format('Y') == 1900) && ($PHPDateObject->format('n') <= 2)) {
6004  --$DoW;
6005  if ($DoW < $firstDay) {
6006  $DoW += 7;
6007  }
6008  }
6009  }
6010 
6011  return (int) $DoW;
6012  } // function DAYOFWEEK()
6013 
6014 
6022  public static function WEEKOFYEAR($dateValue = 1, $method = 1) {
6023  $dateValue = self::flattenSingleValue($dateValue);
6024  $method = floor(self::flattenSingleValue($method));
6025 
6026  if (!is_numeric($method)) {
6027  return self::$_errorCodes['value'];
6028  } elseif (($method < 1) || ($method > 2)) {
6029  return self::$_errorCodes['num'];
6030  }
6031 
6032  if (is_string($dateValue = self::_getDateValue($dateValue))) {
6033  return self::$_errorCodes['value'];
6034  }
6035 
6036  // Execute function
6037  $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
6038  $dayOfYear = $PHPDateObject->format('z');
6039  $dow = $PHPDateObject->format('w');
6040  $PHPDateObject->modify('-'.$dayOfYear.' days');
6041  $dow = $PHPDateObject->format('w');
6042  $daysInFirstWeek = 7 - (($dow + (2 - $method)) % 7);
6043  $dayOfYear -= $daysInFirstWeek;
6044  $weekOfYear = ceil($dayOfYear / 7) + 1;
6045 
6046  return (int) $weekOfYear;
6047  } // function WEEKOFYEAR()
6048 
6049 
6056  public static function MONTHOFYEAR($dateValue = 1) {
6057  $dateValue = self::flattenSingleValue($dateValue);
6058 
6059  if (is_string($dateValue = self::_getDateValue($dateValue))) {
6060  return self::$_errorCodes['value'];
6061  }
6062 
6063  // Execute function
6064  $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
6065 
6066  return (int) $PHPDateObject->format('n');
6067  } // function MONTHOFYEAR()
6068 
6069 
6076  public static function YEAR($dateValue = 1) {
6077  $dateValue = self::flattenSingleValue($dateValue);
6078 
6079  if (is_string($dateValue = self::_getDateValue($dateValue))) {
6080  return self::$_errorCodes['value'];
6081  }
6082 
6083  // Execute function
6084  $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
6085 
6086  return (int) $PHPDateObject->format('Y');
6087  } // function YEAR()
6088 
6089 
6096  public static function HOUROFDAY($timeValue = 0) {
6097  $timeValue = self::flattenSingleValue($timeValue);
6098 
6099  if (!is_numeric($timeValue)) {
6100  if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) {
6101  $testVal = strtok($timeValue,'/-: ');
6102  if (strlen($testVal) < strlen($timeValue)) {
6103  return self::$_errorCodes['value'];
6104  }
6105  }
6106  $timeValue = self::_getTimeValue($timeValue);
6107  if (is_string($timeValue)) {
6108  return self::$_errorCodes['value'];
6109  }
6110  }
6111  // Execute function
6112  if (is_real($timeValue)) {
6113  if ($timeValue >= 1) {
6114  $timeValue = fmod($timeValue,1);
6115  } elseif ($timeValue < 0.0) {
6116  return self::$_errorCodes['num'];
6117  }
6118  $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
6119  }
6120  return (int) date('G',$timeValue);
6121  } // function HOUROFDAY()
6122 
6123 
6130  public static function MINUTEOFHOUR($timeValue = 0) {
6131  $timeValue = $timeTester = self::flattenSingleValue($timeValue);
6132 
6133  if (!is_numeric($timeValue)) {
6134  if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) {
6135  $testVal = strtok($timeValue,'/-: ');
6136  if (strlen($testVal) < strlen($timeValue)) {
6137  return self::$_errorCodes['value'];
6138  }
6139  }
6140  $timeValue = self::_getTimeValue($timeValue);
6141  if (is_string($timeValue)) {
6142  return self::$_errorCodes['value'];
6143  }
6144  }
6145  // Execute function
6146  if (is_real($timeValue)) {
6147  if ($timeValue >= 1) {
6148  $timeValue = fmod($timeValue,1);
6149  } elseif ($timeValue < 0.0) {
6150  return self::$_errorCodes['num'];
6151  }
6152  $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
6153  }
6154  return (int) date('i',$timeValue);
6155  } // function MINUTEOFHOUR()
6156 
6157 
6164  public static function SECONDOFMINUTE($timeValue = 0) {
6165  $timeValue = self::flattenSingleValue($timeValue);
6166 
6167  if (!is_numeric($timeValue)) {
6168  if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) {
6169  $testVal = strtok($timeValue,'/-: ');
6170  if (strlen($testVal) < strlen($timeValue)) {
6171  return self::$_errorCodes['value'];
6172  }
6173  }
6174  $timeValue = self::_getTimeValue($timeValue);
6175  if (is_string($timeValue)) {
6176  return self::$_errorCodes['value'];
6177  }
6178  }
6179  // Execute function
6180  if (is_real($timeValue)) {
6181  if ($timeValue >= 1) {
6182  $timeValue = fmod($timeValue,1);
6183  } elseif ($timeValue < 0.0) {
6184  return self::$_errorCodes['num'];
6185  }
6186  $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
6187  }
6188  return (int) date('s',$timeValue);
6189  } // function SECONDOFMINUTE()
6190 
6191 
6192  private static function _adjustDateByMonths($dateValue = 0, $adjustmentMonths = 0) {
6193  // Execute function
6194  $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
6195  $oMonth = (int) $PHPDateObject->format('m');
6196  $oYear = (int) $PHPDateObject->format('Y');
6197 
6198  $adjustmentMonthsString = (string) $adjustmentMonths;
6199  if ($adjustmentMonths > 0) {
6200  $adjustmentMonthsString = '+'.$adjustmentMonths;
6201  }
6202  if ($adjustmentMonths != 0) {
6203  $PHPDateObject->modify($adjustmentMonthsString.' months');
6204  }
6205  $nMonth = (int) $PHPDateObject->format('m');
6206  $nYear = (int) $PHPDateObject->format('Y');
6207 
6208  $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12);
6209  if ($monthDiff != $adjustmentMonths) {
6210  $adjustDays = (int) $PHPDateObject->format('d');
6211  $adjustDaysString = '-'.$adjustDays.' days';
6212  $PHPDateObject->modify($adjustDaysString);
6213  }
6214  return $PHPDateObject;
6215  } // function _adjustDateByMonths()
6216 
6217 
6228  public static function EDATE($dateValue = 1, $adjustmentMonths = 0) {
6229  $dateValue = self::flattenSingleValue($dateValue);
6230  $adjustmentMonths = floor(self::flattenSingleValue($adjustmentMonths));
6231 
6232  if (!is_numeric($adjustmentMonths)) {
6233  return self::$_errorCodes['value'];
6234  }
6235 
6236  if (is_string($dateValue = self::_getDateValue($dateValue))) {
6237  return self::$_errorCodes['value'];
6238  }
6239 
6240  // Execute function
6241  $PHPDateObject = self::_adjustDateByMonths($dateValue,$adjustmentMonths);
6242 
6243  switch (self::getReturnDateType()) {
6244  case self::RETURNDATE_EXCEL : return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
6245  break;
6246  case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
6247  break;
6248  case self::RETURNDATE_PHP_OBJECT : return $PHPDateObject;
6249  break;
6250  }
6251  } // function EDATE()
6252 
6253 
6264  public static function EOMONTH($dateValue = 1, $adjustmentMonths = 0) {
6265  $dateValue = self::flattenSingleValue($dateValue);
6266  $adjustmentMonths = floor(self::flattenSingleValue($adjustmentMonths));
6267 
6268  if (!is_numeric($adjustmentMonths)) {
6269  return self::$_errorCodes['value'];
6270  }
6271 
6272  if (is_string($dateValue = self::_getDateValue($dateValue))) {
6273  return self::$_errorCodes['value'];
6274  }
6275 
6276  // Execute function
6277  $PHPDateObject = self::_adjustDateByMonths($dateValue,$adjustmentMonths+1);
6278  $adjustDays = (int) $PHPDateObject->format('d');
6279  $adjustDaysString = '-'.$adjustDays.' days';
6280  $PHPDateObject->modify($adjustDaysString);
6281 
6282  switch (self::getReturnDateType()) {
6283  case self::RETURNDATE_EXCEL : return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
6284  break;
6285  case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
6286  break;
6287  case self::RETURNDATE_PHP_OBJECT : return $PHPDateObject;
6288  break;
6289  }
6290  } // function EOMONTH()
6291 
6292 
6302  public static function TRUNC($value = 0, $number_digits = 0) {
6303  $value = self::flattenSingleValue($value);
6304  $number_digits = self::flattenSingleValue($number_digits);
6305 
6306  // Validate parameters
6307  if ($number_digits < 0) {
6308  return self::$_errorCodes['value'];
6309  }
6310 
6311  // Truncate
6312  if ($number_digits > 0) {
6313  $value = $value * pow(10, $number_digits);
6314  }
6315  $value = intval($value);
6316  if ($number_digits > 0) {
6317  $value = $value / pow(10, $number_digits);
6318  }
6319 
6320  // Return
6321  return $value;
6322  } // function TRUNC()
6323 
6333  public static function POWER($x = 0, $y = 2) {
6336 
6337  // Validate parameters
6338  if ($x == 0 && $y <= 0) {
6339  return self::$_errorCodes['divisionbyzero'];
6340  }
6341 
6342  // Return
6343  return pow($x, $y);
6344  } // function POWER()
6345 
6346 
6347  private static function _nbrConversionFormat($xVal,$places) {
6348  if (!is_null($places)) {
6349  if (strlen($xVal) <= $places) {
6350  return substr(str_pad($xVal,$places,'0',STR_PAD_LEFT),-10);
6351  } else {
6352  return self::$_errorCodes['num'];
6353  }
6354  }
6355 
6356  return substr($xVal,-10);
6357  } // function _nbrConversionFormat()
6358 
6359 
6368  public static function BINTODEC($x) {
6370 
6371  if (is_bool($x)) {
6372  if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) {
6373  $x = (int) $x;
6374  } else {
6375  return self::$_errorCodes['value'];
6376  }
6377  }
6378  if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) {
6379  $x = floor($x);
6380  }
6381  $x = (string) $x;
6382  if (strlen($x) > preg_match_all('/[01]/',$x,$out)) {
6383  return self::$_errorCodes['num'];
6384  }
6385  if (strlen($x) > 10) {
6386  return self::$_errorCodes['num'];
6387  } elseif (strlen($x) == 10) {
6388  // Two's Complement
6389  $x = substr($x,-9);
6390  return '-'.(512-bindec($x));
6391  }
6392  return bindec($x);
6393  } // function BINTODEC()
6394 
6395 
6404  public static function BINTOHEX($x, $places=null) {
6405  $x = floor(self::flattenSingleValue($x));
6406  $places = self::flattenSingleValue($places);
6407 
6408  if (is_bool($x)) {
6409  if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) {
6410  $x = (int) $x;
6411  } else {
6412  return self::$_errorCodes['value'];
6413  }
6414  }
6415  if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) {
6416  $x = floor($x);
6417  }
6418  $x = (string) $x;
6419  if (strlen($x) > preg_match_all('/[01]/',$x,$out)) {
6420  return self::$_errorCodes['num'];
6421  }
6422  if (strlen($x) > 10) {
6423  return self::$_errorCodes['num'];
6424  } elseif (strlen($x) == 10) {
6425  // Two's Complement
6426  return str_repeat('F',8).substr(strtoupper(dechex(bindec(substr($x,-9)))),-2);
6427  }
6428  $hexVal = (string) strtoupper(dechex(bindec($x)));
6429 
6430  return self::_nbrConversionFormat($hexVal,$places);
6431  } // function BINTOHEX()
6432 
6433 
6442  public static function BINTOOCT($x, $places=null) {
6443  $x = floor(self::flattenSingleValue($x));
6444  $places = self::flattenSingleValue($places);
6445 
6446  if (is_bool($x)) {
6447  if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) {
6448  $x = (int) $x;
6449  } else {
6450  return self::$_errorCodes['value'];
6451  }
6452  }
6453  if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) {
6454  $x = floor($x);
6455  }
6456  $x = (string) $x;
6457  if (strlen($x) > preg_match_all('/[01]/',$x,$out)) {
6458  return self::$_errorCodes['num'];
6459  }
6460  if (strlen($x) > 10) {
6461  return self::$_errorCodes['num'];
6462  } elseif (strlen($x) == 10) {
6463  // Two's Complement
6464  return str_repeat('7',7).substr(strtoupper(decoct(bindec(substr($x,-9)))),-3);
6465  }
6466  $octVal = (string) decoct(bindec($x));
6467 
6468  return self::_nbrConversionFormat($octVal,$places);
6469  } // function BINTOOCT()
6470 
6471 
6480  public static function DECTOBIN($x, $places=null) {
6482  $places = self::flattenSingleValue($places);
6483 
6484  if (is_bool($x)) {
6485  if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) {
6486  $x = (int) $x;
6487  } else {
6488  return self::$_errorCodes['value'];
6489  }
6490  }
6491  $x = (string) $x;
6492  if (strlen($x) > preg_match_all('/[-0123456789.]/',$x,$out)) {
6493  return self::$_errorCodes['value'];
6494  }
6495  $x = (string) floor($x);
6496  $r = decbin($x);
6497  if (strlen($r) == 32) {
6498  // Two's Complement
6499  $r = substr($r,-10);
6500  } elseif (strlen($r) > 11) {
6501  return self::$_errorCodes['num'];
6502  }
6503 
6504  return self::_nbrConversionFormat($r,$places);
6505  } // function DECTOBIN()
6506 
6507 
6516  public static function DECTOOCT($x, $places=null) {
6518  $places = self::flattenSingleValue($places);
6519 
6520  if (is_bool($x)) {
6521  if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) {
6522  $x = (int) $x;
6523  } else {
6524  return self::$_errorCodes['value'];
6525  }
6526  }
6527  $x = (string) $x;
6528  if (strlen($x) > preg_match_all('/[-0123456789.]/',$x,$out)) {
6529  return self::$_errorCodes['value'];
6530  }
6531  $x = (string) floor($x);
6532  $r = decoct($x);
6533  if (strlen($r) == 11) {
6534  // Two's Complement
6535  $r = substr($r,-10);
6536  }
6537 
6538  return self::_nbrConversionFormat($r,$places);
6539  } // function DECTOOCT()
6540 
6541 
6550  public static function DECTOHEX($x, $places=null) {
6552  $places = self::flattenSingleValue($places);
6553 
6554  if (is_bool($x)) {
6555  if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) {
6556  $x = (int) $x;
6557  } else {
6558  return self::$_errorCodes['value'];
6559  }
6560  }
6561  $x = (string) $x;
6562  if (strlen($x) > preg_match_all('/[-0123456789.]/',$x,$out)) {
6563  return self::$_errorCodes['value'];
6564  }
6565  $x = (string) floor($x);
6566  $r = strtoupper(dechex($x));
6567  if (strlen($r) == 8) {
6568  // Two's Complement
6569  $r = 'FF'.$r;
6570  }
6571 
6572  return self::_nbrConversionFormat($r,$places);
6573  } // function DECTOHEX()
6574 
6575 
6584  public static function HEXTOBIN($x, $places=null) {
6586  $places = self::flattenSingleValue($places);
6587 
6588  if (is_bool($x)) {
6589  return self::$_errorCodes['value'];
6590  }
6591  $x = (string) $x;
6592  if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
6593  return self::$_errorCodes['num'];
6594  }
6595  $binVal = decbin(hexdec($x));
6596 
6597  return substr(self::_nbrConversionFormat($binVal,$places),-10);
6598  } // function HEXTOBIN()
6599 
6600 
6609  public static function HEXTOOCT($x, $places=null) {
6611  $places = self::flattenSingleValue($places);
6612 
6613  if (is_bool($x)) {
6614  return self::$_errorCodes['value'];
6615  }
6616  $x = (string) $x;
6617  if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
6618  return self::$_errorCodes['num'];
6619  }
6620  $octVal = decoct(hexdec($x));
6621 
6622  return self::_nbrConversionFormat($octVal,$places);
6623  } // function HEXTOOCT()
6624 
6625 
6634  public static function HEXTODEC($x) {
6636 
6637  if (is_bool($x)) {
6638  return self::$_errorCodes['value'];
6639  }
6640  $x = (string) $x;
6641  if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
6642  return self::$_errorCodes['num'];
6643  }
6644  return hexdec($x);
6645  } // function HEXTODEC()
6646 
6647 
6656  public static function OCTTOBIN($x, $places=null) {
6658  $places = self::flattenSingleValue($places);
6659 
6660  if (is_bool($x)) {
6661  return self::$_errorCodes['value'];
6662  }
6663  $x = (string) $x;
6664  if (preg_match_all('/[01234567]/',$x,$out) != strlen($x)) {
6665  return self::$_errorCodes['num'];
6666  }
6667  $binVal = decbin(octdec($x));
6668 
6669  return self::_nbrConversionFormat($binVal,$places);
6670  } // function OCTTOBIN()
6671 
6672 
6681  public static function OCTTODEC($x) {
6683 
6684  if (is_bool($x)) {
6685  return self::$_errorCodes['value'];
6686  }
6687  $x = (string) $x;
6688  if (preg_match_all('/[01234567]/',$x,$out) != strlen($x)) {
6689  return self::$_errorCodes['num'];
6690  }
6691  return octdec($x);
6692  } // function OCTTODEC()
6693 
6694 
6703  public static function OCTTOHEX($x, $places=null) {
6705  $places = self::flattenSingleValue($places);
6706 
6707  if (is_bool($x)) {
6708  return self::$_errorCodes['value'];
6709  }
6710  $x = (string) $x;
6711  if (preg_match_all('/[01234567]/',$x,$out) != strlen($x)) {
6712  return self::$_errorCodes['num'];
6713  }
6714  $hexVal = strtoupper(dechex(octdec($x)));
6715 
6716  return self::_nbrConversionFormat($hexVal,$places);
6717  } // function OCTTOHEX()
6718 
6719 
6720  public static function _parseComplex($complexNumber) {
6721  $workString = (string) $complexNumber;
6722 
6723  $realNumber = $imaginary = 0;
6724  // Extract the suffix, if there is one
6725  $suffix = substr($workString,-1);
6726  if (!is_numeric($suffix)) {
6727  $workString = substr($workString,0,-1);
6728  } else {
6729  $suffix = '';
6730  }
6731 
6732  // Split the input into its Real and Imaginary components
6733  $leadingSign = 0;
6734  if (strlen($workString) > 0) {
6735  $leadingSign = (($workString{0} == '+') || ($workString{0} == '-')) ? 1 : 0;
6736  }
6737  $power = '';
6738  $realNumber = strtok($workString, '+-');
6739  if (strtoupper(substr($realNumber,-1)) == 'E') {
6740  $power = strtok('+-');
6741  ++$leadingSign;
6742  }
6743 
6744  $realNumber = substr($workString,0,strlen($realNumber)+strlen($power)+$leadingSign);
6745 
6746  if ($suffix != '') {
6747  $imaginary = substr($workString,strlen($realNumber));
6748 
6749  if (($imaginary == '') && (($realNumber == '') || ($realNumber == '+') || ($realNumber == '-'))) {
6750  $imaginary = $realNumber.'1';
6751  $realNumber = '0';
6752  } else if ($imaginary == '') {
6753  $imaginary = $realNumber;
6754  $realNumber = '0';
6755  } elseif (($imaginary == '+') || ($imaginary == '-')) {
6756  $imaginary .= '1';
6757  }
6758  }
6759 
6760  $complexArray = array( 'real' => $realNumber,
6761  'imaginary' => $imaginary,
6762  'suffix' => $suffix
6763  );
6764 
6765  return $complexArray;
6766  } // function _parseComplex()
6767 
6768 
6769  private static function _cleanComplex($complexNumber) {
6770  if ($complexNumber{0} == '+') $complexNumber = substr($complexNumber,1);
6771  if ($complexNumber{0} == '0') $complexNumber = substr($complexNumber,1);
6772  if ($complexNumber{0} == '.') $complexNumber = '0'.$complexNumber;
6773  if ($complexNumber{0} == '+') $complexNumber = substr($complexNumber,1);
6774  return $complexNumber;
6775  }
6776 
6777 
6788  public static function COMPLEX($realNumber=0.0, $imaginary=0.0, $suffix='i') {
6789  $realNumber = self::flattenSingleValue($realNumber);
6790  $imaginary = self::flattenSingleValue($imaginary);
6791  $suffix = self::flattenSingleValue($suffix);
6792 
6793  if (((is_numeric($realNumber)) && (is_numeric($imaginary))) &&
6794  (($suffix == 'i') || ($suffix == 'j') || ($suffix == ''))) {
6795  if ($realNumber == 0.0) {
6796  if ($imaginary == 0.0) {
6797  return (string) '0';
6798  } elseif ($imaginary == 1.0) {
6799  return (string) $suffix;
6800  } elseif ($imaginary == -1.0) {
6801  return (string) '-'.$suffix;
6802  }
6803  return (string) $imaginary.$suffix;
6804  } elseif ($imaginary == 0.0) {
6805  return (string) $realNumber;
6806  } elseif ($imaginary == 1.0) {
6807  return (string) $realNumber.'+'.$suffix;
6808  } elseif ($imaginary == -1.0) {
6809  return (string) $realNumber.'-'.$suffix;
6810  }
6811  if ($imaginary > 0) { $imaginary = (string) '+'.$imaginary; }
6812  return (string) $realNumber.$imaginary.$suffix;
6813  }
6814  return self::$_errorCodes['value'];
6815  } // function COMPLEX()
6816 
6817 
6826  public static function IMAGINARY($complexNumber) {
6827  $complexNumber = self::flattenSingleValue($complexNumber);
6828 
6829  $parsedComplex = self::_parseComplex($complexNumber);
6830  if (!is_array($parsedComplex)) {
6831  return $parsedComplex;
6832  }
6833  return $parsedComplex['imaginary'];
6834  } // function IMAGINARY()
6835 
6836 
6845  public static function IMREAL($complexNumber) {
6846  $complexNumber = self::flattenSingleValue($complexNumber);
6847 
6848  $parsedComplex = self::_parseComplex($complexNumber);
6849  if (!is_array($parsedComplex)) {
6850  return $parsedComplex;
6851  }
6852  return $parsedComplex['real'];
6853  } // function IMREAL()
6854 
6855 
6864  public static function IMABS($complexNumber) {
6865  $complexNumber = self::flattenSingleValue($complexNumber);
6866 
6867  $parsedComplex = self::_parseComplex($complexNumber);
6868  if (!is_array($parsedComplex)) {
6869  return $parsedComplex;
6870  }
6871  return sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary']));
6872  } // function IMABS()
6873 
6874 
6883  public static function IMARGUMENT($complexNumber) {
6884  $complexNumber = self::flattenSingleValue($complexNumber);
6885 
6886  $parsedComplex = self::_parseComplex($complexNumber);
6887  if (!is_array($parsedComplex)) {
6888  return $parsedComplex;
6889  }
6890 
6891  if ($parsedComplex['real'] == 0.0) {
6892  if ($parsedComplex['imaginary'] == 0.0) {
6893  return 0.0;
6894  } elseif($parsedComplex['imaginary'] < 0.0) {
6895  return pi() / -2;
6896  } else {
6897  return pi() / 2;
6898  }
6899  } elseif ($parsedComplex['real'] > 0.0) {
6900  return atan($parsedComplex['imaginary'] / $parsedComplex['real']);
6901  } elseif ($parsedComplex['imaginary'] < 0.0) {
6902  return 0 - (pi() - atan(abs($parsedComplex['imaginary']) / abs($parsedComplex['real'])));
6903  } else {
6904  return pi() - atan($parsedComplex['imaginary'] / abs($parsedComplex['real']));
6905  }
6906  } // function IMARGUMENT()
6907 
6908 
6917  public static function IMCONJUGATE($complexNumber) {
6918  $complexNumber = self::flattenSingleValue($complexNumber);
6919 
6920  $parsedComplex = self::_parseComplex($complexNumber);
6921 
6922  if (!is_array($parsedComplex)) {
6923  return $parsedComplex;
6924  }
6925 
6926  if ($parsedComplex['imaginary'] == 0.0) {
6927  return $parsedComplex['real'];
6928  } else {
6929  return self::_cleanComplex(self::COMPLEX($parsedComplex['real'], 0 - $parsedComplex['imaginary'], $parsedComplex['suffix']));
6930  }
6931  } // function IMCONJUGATE()
6932 
6933 
6942  public static function IMCOS($complexNumber) {
6943  $complexNumber = self::flattenSingleValue($complexNumber);
6944 
6945  $parsedComplex = self::_parseComplex($complexNumber);
6946  if (!is_array($parsedComplex)) {
6947  return $parsedComplex;
6948  }
6949 
6950  if ($parsedComplex['imaginary'] == 0.0) {
6951  return cos($parsedComplex['real']);
6952  } else {
6953  return self::IMCONJUGATE(self::COMPLEX(cos($parsedComplex['real']) * cosh($parsedComplex['imaginary']),sin($parsedComplex['real']) * sinh($parsedComplex['imaginary']),$parsedComplex['suffix']));
6954  }
6955  } // function IMCOS()
6956 
6957 
6966  public static function IMSIN($complexNumber) {
6967  $complexNumber = self::flattenSingleValue($complexNumber);
6968 
6969  $parsedComplex = self::_parseComplex($complexNumber);
6970  if (!is_array($parsedComplex)) {
6971  return $parsedComplex;
6972  }
6973 
6974  if ($parsedComplex['imaginary'] == 0.0) {
6975  return sin($parsedComplex['real']);
6976  } else {
6977  return self::COMPLEX(sin($parsedComplex['real']) * cosh($parsedComplex['imaginary']),cos($parsedComplex['real']) * sinh($parsedComplex['imaginary']),$parsedComplex['suffix']);
6978  }
6979  } // function IMSIN()
6980 
6981 
6990  public static function IMSQRT($complexNumber) {
6991  $complexNumber = self::flattenSingleValue($complexNumber);
6992 
6993  $parsedComplex = self::_parseComplex($complexNumber);
6994  if (!is_array($parsedComplex)) {
6995  return $parsedComplex;
6996  }
6997 
6998  $theta = self::IMARGUMENT($complexNumber);
6999  $d1 = cos($theta / 2);
7000  $d2 = sin($theta / 2);
7001  $r = sqrt(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])));
7002 
7003  if ($parsedComplex['suffix'] == '') {
7004  return self::COMPLEX($d1 * $r,$d2 * $r);
7005  } else {
7006  return self::COMPLEX($d1 * $r,$d2 * $r,$parsedComplex['suffix']);
7007  }
7008  } // function IMSQRT()
7009 
7010 
7019  public static function IMLN($complexNumber) {
7020  $complexNumber = self::flattenSingleValue($complexNumber);
7021 
7022  $parsedComplex = self::_parseComplex($complexNumber);
7023  if (!is_array($parsedComplex)) {
7024  return $parsedComplex;
7025  }
7026 
7027  if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
7028  return self::$_errorCodes['num'];
7029  }
7030 
7031  $logR = log(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])));
7032  $t = self::IMARGUMENT($complexNumber);
7033 
7034  if ($parsedComplex['suffix'] == '') {
7035  return self::COMPLEX($logR,$t);
7036  } else {
7037  return self::COMPLEX($logR,$t,$parsedComplex['suffix']);
7038  }
7039  } // function IMLN()
7040 
7041 
7050  public static function IMLOG10($complexNumber) {
7051  $complexNumber = self::flattenSingleValue($complexNumber);
7052 
7053  $parsedComplex = self::_parseComplex($complexNumber);
7054  if (!is_array($parsedComplex)) {
7055  return $parsedComplex;
7056  }
7057 
7058  if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
7059  return self::$_errorCodes['num'];
7060  } elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
7061  return log10($parsedComplex['real']);
7062  }
7063 
7064  return self::IMPRODUCT(log10(EULER),self::IMLN($complexNumber));
7065  } // function IMLOG10()
7066 
7067 
7076  public static function IMLOG2($complexNumber) {
7077  $complexNumber = self::flattenSingleValue($complexNumber);
7078 
7079  $parsedComplex = self::_parseComplex($complexNumber);
7080  if (!is_array($parsedComplex)) {
7081  return $parsedComplex;
7082  }
7083 
7084  if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
7085  return self::$_errorCodes['num'];
7086  } elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
7087  return log($parsedComplex['real'],2);
7088  }
7089 
7090  return self::IMPRODUCT(log(EULER,2),self::IMLN($complexNumber));
7091  } // function IMLOG2()
7092 
7093 
7102  public static function IMEXP($complexNumber) {
7103  $complexNumber = self::flattenSingleValue($complexNumber);
7104 
7105  $parsedComplex = self::_parseComplex($complexNumber);
7106  if (!is_array($parsedComplex)) {
7107  return $parsedComplex;
7108  }
7109 
7110  if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
7111  return '1';
7112  }
7113 
7114  $e = exp($parsedComplex['real']);
7115  $eX = $e * cos($parsedComplex['imaginary']);
7116  $eY = $e * sin($parsedComplex['imaginary']);
7117 
7118  if ($parsedComplex['suffix'] == '') {
7119  return self::COMPLEX($eX,$eY);
7120  } else {
7121  return self::COMPLEX($eX,$eY,$parsedComplex['suffix']);
7122  }
7123  } // function IMEXP()
7124 
7125 
7134  public static function IMPOWER($complexNumber,$realNumber) {
7135  $complexNumber = self::flattenSingleValue($complexNumber);
7136  $realNumber = self::flattenSingleValue($realNumber);
7137 
7138  if (!is_numeric($realNumber)) {
7139  return self::$_errorCodes['value'];
7140  }
7141 
7142  $parsedComplex = self::_parseComplex($complexNumber);
7143  if (!is_array($parsedComplex)) {
7144  return $parsedComplex;
7145  }
7146 
7147  $r = sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary']));
7148  $rPower = pow($r,$realNumber);
7149  $theta = self::IMARGUMENT($complexNumber) * $realNumber;
7150  if ($theta == 0) {
7151  return 1;
7152  } elseif ($parsedComplex['imaginary'] == 0.0) {
7153  return self::COMPLEX($rPower * cos($theta),$rPower * sin($theta),$parsedComplex['suffix']);
7154  } else {
7155  return self::COMPLEX($rPower * cos($theta),$rPower * sin($theta),$parsedComplex['suffix']);
7156  }
7157  } // function IMPOWER()
7158 
7159 
7169  public static function IMDIV($complexDividend,$complexDivisor) {
7170  $complexDividend = self::flattenSingleValue($complexDividend);
7171  $complexDivisor = self::flattenSingleValue($complexDivisor);
7172 
7173  $parsedComplexDividend = self::_parseComplex($complexDividend);
7174  if (!is_array($parsedComplexDividend)) {
7175  return $parsedComplexDividend;
7176  }
7177 
7178  $parsedComplexDivisor = self::_parseComplex($complexDivisor);
7179  if (!is_array($parsedComplexDivisor)) {
7180  return $parsedComplexDividend;
7181  }
7182 
7183  if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] != '') &&
7184  ($parsedComplexDividend['suffix'] != $parsedComplexDivisor['suffix'])) {
7185  return self::$_errorCodes['num'];
7186  }
7187  if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] == '')) {
7188  $parsedComplexDivisor['suffix'] = $parsedComplexDividend['suffix'];
7189  }
7190 
7191  $d1 = ($parsedComplexDividend['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['imaginary']);
7192  $d2 = ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['real']) - ($parsedComplexDividend['real'] * $parsedComplexDivisor['imaginary']);
7193  $d3 = ($parsedComplexDivisor['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDivisor['imaginary'] * $parsedComplexDivisor['imaginary']);
7194 
7195  $r = $d1/$d3;
7196  $i = $d2/$d3;
7197 
7198  if ($i > 0.0) {
7199  return self::_cleanComplex($r.'+'.$i.$parsedComplexDivisor['suffix']);
7200  } elseif ($i < 0.0) {
7201  return self::_cleanComplex($r.$i.$parsedComplexDivisor['suffix']);
7202  } else {
7203  return $r;
7204  }
7205  } // function IMDIV()
7206 
7207 
7217  public static function IMSUB($complexNumber1,$complexNumber2) {
7218  $complexNumber1 = self::flattenSingleValue($complexNumber1);
7219  $complexNumber2 = self::flattenSingleValue($complexNumber2);
7220 
7221  $parsedComplex1 = self::_parseComplex($complexNumber1);
7222  if (!is_array($parsedComplex1)) {
7223  return $parsedComplex1;
7224  }
7225 
7226  $parsedComplex2 = self::_parseComplex($complexNumber2);
7227  if (!is_array($parsedComplex2)) {
7228  return $parsedComplex2;
7229  }
7230 
7231  if ((($parsedComplex1['suffix'] != '') && ($parsedComplex2['suffix'] != '')) &&
7232  ($parsedComplex1['suffix'] != $parsedComplex2['suffix'])) {
7233  return self::$_errorCodes['num'];
7234  } elseif (($parsedComplex1['suffix'] == '') && ($parsedComplex2['suffix'] != '')) {
7235  $parsedComplex1['suffix'] = $parsedComplex2['suffix'];
7236  }
7237 
7238  $d1 = $parsedComplex1['real'] - $parsedComplex2['real'];
7239  $d2 = $parsedComplex1['imaginary'] - $parsedComplex2['imaginary'];
7240 
7241  return self::COMPLEX($d1,$d2,$parsedComplex1['suffix']);
7242  } // function IMSUB()
7243 
7244 
7253  public static function IMSUM() {
7254  // Return value
7255  $returnValue = self::_parseComplex('0');
7256  $activeSuffix = '';
7257 
7258  // Loop through the arguments
7259  $aArgs = self::flattenArray(func_get_args());
7260  foreach ($aArgs as $arg) {
7261  $parsedComplex = self::_parseComplex($arg);
7262  if (!is_array($parsedComplex)) {
7263  return $parsedComplex;
7264  }
7265 
7266  if ($activeSuffix == '') {
7267  $activeSuffix = $parsedComplex['suffix'];
7268  } elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) {
7269  return self::$_errorCodes['value'];
7270  }
7271 
7272  $returnValue['real'] += $parsedComplex['real'];
7273  $returnValue['imaginary'] += $parsedComplex['imaginary'];
7274  }
7275 
7276  if ($returnValue['imaginary'] == 0.0) { $activeSuffix = ''; }
7277  return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix);
7278  } // function IMSUM()
7279 
7280 
7289  public static function IMPRODUCT() {
7290  // Return value
7291  $returnValue = self::_parseComplex('1');
7292  $activeSuffix = '';
7293 
7294  // Loop through the arguments
7295  $aArgs = self::flattenArray(func_get_args());
7296  foreach ($aArgs as $arg) {
7297  $parsedComplex = self::_parseComplex($arg);
7298  if (!is_array($parsedComplex)) {
7299  return $parsedComplex;
7300  }
7301  $workValue = $returnValue;
7302  if (($parsedComplex['suffix'] != '') && ($activeSuffix == '')) {
7303  $activeSuffix = $parsedComplex['suffix'];
7304  } elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) {
7305  return self::$_errorCodes['num'];
7306  }
7307  $returnValue['real'] = ($workValue['real'] * $parsedComplex['real']) - ($workValue['imaginary'] * $parsedComplex['imaginary']);
7308  $returnValue['imaginary'] = ($workValue['real'] * $parsedComplex['imaginary']) + ($workValue['imaginary'] * $parsedComplex['real']);
7309  }
7310 
7311  if ($returnValue['imaginary'] == 0.0) { $activeSuffix = ''; }
7312  return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix);
7313  } // function IMPRODUCT()
7314 
7315 
7316  private static $_conversionUnits = array( 'g' => array( 'Group' => 'Mass', 'Unit Name' => 'Gram', 'AllowPrefix' => True ),
7317  'sg' => array( 'Group' => 'Mass', 'Unit Name' => 'Slug', 'AllowPrefix' => False ),
7318  'lbm' => array( 'Group' => 'Mass', 'Unit Name' => 'Pound mass (avoirdupois)', 'AllowPrefix' => False ),
7319  'u' => array( 'Group' => 'Mass', 'Unit Name' => 'U (atomic mass unit)', 'AllowPrefix' => True ),
7320  'ozm' => array( 'Group' => 'Mass', 'Unit Name' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => False ),
7321  'm' => array( 'Group' => 'Distance', 'Unit Name' => 'Meter', 'AllowPrefix' => True ),
7322  'mi' => array( 'Group' => 'Distance', 'Unit Name' => 'Statute mile', 'AllowPrefix' => False ),
7323  'Nmi' => array( 'Group' => 'Distance', 'Unit Name' => 'Nautical mile', 'AllowPrefix' => False ),
7324  'in' => array( 'Group' => 'Distance', 'Unit Name' => 'Inch', 'AllowPrefix' => False ),
7325  'ft' => array( 'Group' => 'Distance', 'Unit Name' => 'Foot', 'AllowPrefix' => False ),
7326  'yd' => array( 'Group' => 'Distance', 'Unit Name' => 'Yard', 'AllowPrefix' => False ),
7327  'ang' => array( 'Group' => 'Distance', 'Unit Name' => 'Angstrom', 'AllowPrefix' => True ),
7328  'Pica' => array( 'Group' => 'Distance', 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => False ),
7329  'yr' => array( 'Group' => 'Time', 'Unit Name' => 'Year', 'AllowPrefix' => False ),
7330  'day' => array( 'Group' => 'Time', 'Unit Name' => 'Day', 'AllowPrefix' => False ),
7331  'hr' => array( 'Group' => 'Time', 'Unit Name' => 'Hour', 'AllowPrefix' => False ),
7332  'mn' => array( 'Group' => 'Time', 'Unit Name' => 'Minute', 'AllowPrefix' => False ),
7333  'sec' => array( 'Group' => 'Time', 'Unit Name' => 'Second', 'AllowPrefix' => True ),
7334  'Pa' => array( 'Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => True ),
7335  'p' => array( 'Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => True ),
7336  'atm' => array( 'Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => True ),
7337  'at' => array( 'Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => True ),
7338  'mmHg' => array( 'Group' => 'Pressure', 'Unit Name' => 'mm of Mercury', 'AllowPrefix' => True ),
7339  'N' => array( 'Group' => 'Force', 'Unit Name' => 'Newton', 'AllowPrefix' => True ),
7340  'dyn' => array( 'Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => True ),
7341  'dy' => array( 'Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => True ),
7342  'lbf' => array( 'Group' => 'Force', 'Unit Name' => 'Pound force', 'AllowPrefix' => False ),
7343  'J' => array( 'Group' => 'Energy', 'Unit Name' => 'Joule', 'AllowPrefix' => True ),
7344  'e' => array( 'Group' => 'Energy', 'Unit Name' => 'Erg', 'AllowPrefix' => True ),
7345  'c' => array( 'Group' => 'Energy', 'Unit Name' => 'Thermodynamic calorie', 'AllowPrefix' => True ),
7346  'cal' => array( 'Group' => 'Energy', 'Unit Name' => 'IT calorie', 'AllowPrefix' => True ),
7347  'eV' => array( 'Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => True ),
7348  'ev' => array( 'Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => True ),
7349  'HPh' => array( 'Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => False ),
7350  'hh' => array( 'Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => False ),
7351  'Wh' => array( 'Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => True ),
7352  'wh' => array( 'Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => True ),
7353  'flb' => array( 'Group' => 'Energy', 'Unit Name' => 'Foot-pound', 'AllowPrefix' => False ),
7354  'BTU' => array( 'Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => False ),
7355  'btu' => array( 'Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => False ),
7356  'HP' => array( 'Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => False ),
7357  'h' => array( 'Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => False ),
7358  'W' => array( 'Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => True ),
7359  'w' => array( 'Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => True ),
7360  'T' => array( 'Group' => 'Magnetism', 'Unit Name' => 'Tesla', 'AllowPrefix' => True ),
7361  'ga' => array( 'Group' => 'Magnetism', 'Unit Name' => 'Gauss', 'AllowPrefix' => True ),
7362  'C' => array( 'Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => False ),
7363  'cel' => array( 'Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => False ),
7364  'F' => array( 'Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => False ),
7365  'fah' => array( 'Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => False ),
7366  'K' => array( 'Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => False ),
7367  'kel' => array( 'Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => False ),
7368  'tsp' => array( 'Group' => 'Liquid', 'Unit Name' => 'Teaspoon', 'AllowPrefix' => False ),
7369  'tbs' => array( 'Group' => 'Liquid', 'Unit Name' => 'Tablespoon', 'AllowPrefix' => False ),
7370  'oz' => array( 'Group' => 'Liquid', 'Unit Name' => 'Fluid Ounce', 'AllowPrefix' => False ),
7371  'cup' => array( 'Group' => 'Liquid', 'Unit Name' => 'Cup', 'AllowPrefix' => False ),
7372  'pt' => array( 'Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => False ),
7373  'us_pt' => array( 'Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => False ),
7374  'uk_pt' => array( 'Group' => 'Liquid', 'Unit Name' => 'U.K. Pint', 'AllowPrefix' => False ),
7375  'qt' => array( 'Group' => 'Liquid', 'Unit Name' => 'Quart', 'AllowPrefix' => False ),
7376  'gal' => array( 'Group' => 'Liquid', 'Unit Name' => 'Gallon', 'AllowPrefix' => False ),
7377  'l' => array( 'Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => True ),
7378  'lt' => array( 'Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => True )
7379  );
7380 
7381  private static $_conversionMultipliers = array( 'Y' => array( 'multiplier' => 1E24, 'name' => 'yotta' ),
7382  'Z' => array( 'multiplier' => 1E21, 'name' => 'zetta' ),
7383  'E' => array( 'multiplier' => 1E18, 'name' => 'exa' ),
7384  'P' => array( 'multiplier' => 1E15, 'name' => 'peta' ),
7385  'T' => array( 'multiplier' => 1E12, 'name' => 'tera' ),
7386  'G' => array( 'multiplier' => 1E9, 'name' => 'giga' ),
7387  'M' => array( 'multiplier' => 1E6, 'name' => 'mega' ),
7388  'k' => array( 'multiplier' => 1E3, 'name' => 'kilo' ),
7389  'h' => array( 'multiplier' => 1E2, 'name' => 'hecto' ),
7390  'e' => array( 'multiplier' => 1E1, 'name' => 'deka' ),
7391  'd' => array( 'multiplier' => 1E-1, 'name' => 'deci' ),
7392  'c' => array( 'multiplier' => 1E-2, 'name' => 'centi' ),
7393  'm' => array( 'multiplier' => 1E-3, 'name' => 'milli' ),
7394  'u' => array( 'multiplier' => 1E-6, 'name' => 'micro' ),
7395  'n' => array( 'multiplier' => 1E-9, 'name' => 'nano' ),
7396  'p' => array( 'multiplier' => 1E-12, 'name' => 'pico' ),
7397  'f' => array( 'multiplier' => 1E-15, 'name' => 'femto' ),
7398  'a' => array( 'multiplier' => 1E-18, 'name' => 'atto' ),
7399  'z' => array( 'multiplier' => 1E-21, 'name' => 'zepto' ),
7400  'y' => array( 'multiplier' => 1E-24, 'name' => 'yocto' )
7401  );
7402 
7403  private static $_unitConversions = array( 'Mass' => array( 'g' => array( 'g' => 1.0,
7404  'sg' => 6.85220500053478E-05,
7405  'lbm' => 2.20462291469134E-03,
7406  'u' => 6.02217000000000E+23,
7407  'ozm' => 3.52739718003627E-02
7408  ),
7409  'sg' => array( 'g' => 1.45938424189287E+04,
7410  'sg' => 1.0,
7411  'lbm' => 3.21739194101647E+01,
7412  'u' => 8.78866000000000E+27,
7413  'ozm' => 5.14782785944229E+02
7414  ),
7415  'lbm' => array( 'g' => 4.5359230974881148E+02,
7416  'sg' => 3.10810749306493E-02,
7417  'lbm' => 1.0,
7418  'u' => 2.73161000000000E+26,
7419  'ozm' => 1.60000023429410E+01
7420  ),
7421  'u' => array( 'g' => 1.66053100460465E-24,
7422  'sg' => 1.13782988532950E-28,
7423  'lbm' => 3.66084470330684E-27,
7424  'u' => 1.0,
7425  'ozm' => 5.85735238300524E-26
7426  ),
7427  'ozm' => array( 'g' => 2.83495152079732E+01,
7428  'sg' => 1.94256689870811E-03,
7429  'lbm' => 6.24999908478882E-02,
7430  'u' => 1.70725600000000E+25,
7431  'ozm' => 1.0
7432  )
7433  ),
7434  'Distance' => array( 'm' => array( 'm' => 1.0,
7435  'mi' => 6.21371192237334E-04,
7436  'Nmi' => 5.39956803455724E-04,
7437  'in' => 3.93700787401575E+01,
7438  'ft' => 3.28083989501312E+00,
7439  'yd' => 1.09361329797891E+00,
7440  'ang' => 1.00000000000000E+10,
7441  'Pica' => 2.83464566929116E+03
7442  ),
7443  'mi' => array( 'm' => 1.60934400000000E+03,
7444  'mi' => 1.0,
7445  'Nmi' => 8.68976241900648E-01,
7446  'in' => 6.33600000000000E+04,
7447  'ft' => 5.28000000000000E+03,
7448  'yd' => 1.76000000000000E+03,
7449  'ang' => 1.60934400000000E+13,
7450  'Pica' => 4.56191999999971E+06
7451  ),
7452  'Nmi' => array( 'm' => 1.85200000000000E+03,
7453  'mi' => 1.15077944802354E+00,
7454  'Nmi' => 1.0,
7455  'in' => 7.29133858267717E+04,
7456  'ft' => 6.07611548556430E+03,
7457  'yd' => 2.02537182785694E+03,
7458  'ang' => 1.85200000000000E+13,
7459  'Pica' => 5.24976377952723E+06
7460  ),
7461  'in' => array( 'm' => 2.54000000000000E-02,
7462  'mi' => 1.57828282828283E-05,
7463  'Nmi' => 1.37149028077754E-05,
7464  'in' => 1.0,
7465  'ft' => 8.33333333333333E-02,
7466  'yd' => 2.77777777686643E-02,
7467  'ang' => 2.54000000000000E+08,
7468  'Pica' => 7.19999999999955E+01
7469  ),
7470  'ft' => array( 'm' => 3.04800000000000E-01,
7471  'mi' => 1.89393939393939E-04,
7472  'Nmi' => 1.64578833693305E-04,
7473  'in' => 1.20000000000000E+01,
7474  'ft' => 1.0,
7475  'yd' => 3.33333333223972E-01,
7476  'ang' => 3.04800000000000E+09,
7477  'Pica' => 8.63999999999946E+02
7478  ),
7479  'yd' => array( 'm' => 9.14400000300000E-01,
7480  'mi' => 5.68181818368230E-04,
7481  'Nmi' => 4.93736501241901E-04,
7482  'in' => 3.60000000118110E+01,
7483  'ft' => 3.00000000000000E+00,
7484  'yd' => 1.0,
7485  'ang' => 9.14400000300000E+09,
7486  'Pica' => 2.59200000085023E+03
7487  ),
7488  'ang' => array( 'm' => 1.00000000000000E-10,
7489  'mi' => 6.21371192237334E-14,
7490  'Nmi' => 5.39956803455724E-14,
7491  'in' => 3.93700787401575E-09,
7492  'ft' => 3.28083989501312E-10,
7493  'yd' => 1.09361329797891E-10,
7494  'ang' => 1.0,
7495  'Pica' => 2.83464566929116E-07
7496  ),
7497  'Pica' => array( 'm' => 3.52777777777800E-04,
7498  'mi' => 2.19205948372629E-07,
7499  'Nmi' => 1.90484761219114E-07,
7500  'in' => 1.38888888888898E-02,
7501  'ft' => 1.15740740740748E-03,
7502  'yd' => 3.85802469009251E-04,
7503  'ang' => 3.52777777777800E+06,
7504  'Pica' => 1.0
7505  )
7506  ),
7507  'Time' => array( 'yr' => array( 'yr' => 1.0,
7508  'day' => 365.25,
7509  'hr' => 8766.0,
7510  'mn' => 525960.0,
7511  'sec' => 31557600.0
7512  ),
7513  'day' => array( 'yr' => 2.73785078713210E-03,
7514  'day' => 1.0,
7515  'hr' => 24.0,
7516  'mn' => 1440.0,
7517  'sec' => 86400.0
7518  ),
7519  'hr' => array( 'yr' => 1.14077116130504E-04,
7520  'day' => 4.16666666666667E-02,
7521  'hr' => 1.0,
7522  'mn' => 60.0,
7523  'sec' => 3600.0
7524  ),
7525  'mn' => array( 'yr' => 1.90128526884174E-06,
7526  'day' => 6.94444444444444E-04,
7527  'hr' => 1.66666666666667E-02,
7528  'mn' => 1.0,
7529  'sec' => 60.0
7530  ),
7531  'sec' => array( 'yr' => 3.16880878140289E-08,
7532  'day' => 1.15740740740741E-05,
7533  'hr' => 2.77777777777778E-04,
7534  'mn' => 1.66666666666667E-02,
7535  'sec' => 1.0
7536  )
7537  ),
7538  'Pressure' => array( 'Pa' => array( 'Pa' => 1.0,
7539  'p' => 1.0,
7540  'atm' => 9.86923299998193E-06,
7541  'at' => 9.86923299998193E-06,
7542  'mmHg' => 7.50061707998627E-03
7543  ),
7544  'p' => array( 'Pa' => 1.0,
7545  'p' => 1.0,
7546  'atm' => 9.86923299998193E-06,
7547  'at' => 9.86923299998193E-06,
7548  'mmHg' => 7.50061707998627E-03
7549  ),
7550  'atm' => array( 'Pa' => 1.01324996583000E+05,
7551  'p' => 1.01324996583000E+05,
7552  'atm' => 1.0,
7553  'at' => 1.0,
7554  'mmHg' => 760.0
7555  ),
7556  'at' => array( 'Pa' => 1.01324996583000E+05,
7557  'p' => 1.01324996583000E+05,
7558  'atm' => 1.0,
7559  'at' => 1.0,
7560  'mmHg' => 760.0
7561  ),
7562  'mmHg' => array( 'Pa' => 1.33322363925000E+02,
7563  'p' => 1.33322363925000E+02,
7564  'atm' => 1.31578947368421E-03,
7565  'at' => 1.31578947368421E-03,
7566  'mmHg' => 1.0
7567  )
7568  ),
7569  'Force' => array( 'N' => array( 'N' => 1.0,
7570  'dyn' => 1.0E+5,
7571  'dy' => 1.0E+5,
7572  'lbf' => 2.24808923655339E-01
7573  ),
7574  'dyn' => array( 'N' => 1.0E-5,
7575  'dyn' => 1.0,
7576  'dy' => 1.0,
7577  'lbf' => 2.24808923655339E-06
7578  ),
7579  'dy' => array( 'N' => 1.0E-5,
7580  'dyn' => 1.0,
7581  'dy' => 1.0,
7582  'lbf' => 2.24808923655339E-06
7583  ),
7584  'lbf' => array( 'N' => 4.448222,
7585  'dyn' => 4.448222E+5,
7586  'dy' => 4.448222E+5,
7587  'lbf' => 1.0
7588  )
7589  ),
7590  'Energy' => array( 'J' => array( 'J' => 1.0,
7591  'e' => 9.99999519343231E+06,
7592  'c' => 2.39006249473467E-01,
7593  'cal' => 2.38846190642017E-01,
7594  'eV' => 6.24145700000000E+18,
7595  'ev' => 6.24145700000000E+18,
7596  'HPh' => 3.72506430801000E-07,
7597  'hh' => 3.72506430801000E-07,
7598  'Wh' => 2.77777916238711E-04,
7599  'wh' => 2.77777916238711E-04,
7600  'flb' => 2.37304222192651E+01,
7601  'BTU' => 9.47815067349015E-04,
7602  'btu' => 9.47815067349015E-04
7603  ),
7604  'e' => array( 'J' => 1.00000048065700E-07,
7605  'e' => 1.0,
7606  'c' => 2.39006364353494E-08,
7607  'cal' => 2.38846305445111E-08,
7608  'eV' => 6.24146000000000E+11,
7609  'ev' => 6.24146000000000E+11,
7610  'HPh' => 3.72506609848824E-14,
7611  'hh' => 3.72506609848824E-14,
7612  'Wh' => 2.77778049754611E-11,
7613  'wh' => 2.77778049754611E-11,
7614  'flb' => 2.37304336254586E-06,
7615  'BTU' => 9.47815522922962E-11,
7616  'btu' => 9.47815522922962E-11
7617  ),
7618  'c' => array( 'J' => 4.18399101363672E+00,
7619  'e' => 4.18398900257312E+07,
7620  'c' => 1.0,
7621  'cal' => 9.99330315287563E-01,
7622  'eV' => 2.61142000000000E+19,
7623  'ev' => 2.61142000000000E+19,
7624  'HPh' => 1.55856355899327E-06,
7625  'hh' => 1.55856355899327E-06,
7626  'Wh' => 1.16222030532950E-03,
7627  'wh' => 1.16222030532950E-03,
7628  'flb' => 9.92878733152102E+01,
7629  'BTU' => 3.96564972437776E-03,
7630  'btu' => 3.96564972437776E-03
7631  ),
7632  'cal' => array( 'J' => 4.18679484613929E+00,
7633  'e' => 4.18679283372801E+07,
7634  'c' => 1.00067013349059E+00,
7635  'cal' => 1.0,
7636  'eV' => 2.61317000000000E+19,
7637  'ev' => 2.61317000000000E+19,
7638  'HPh' => 1.55960800463137E-06,
7639  'hh' => 1.55960800463137E-06,
7640  'Wh' => 1.16299914807955E-03,
7641  'wh' => 1.16299914807955E-03,
7642  'flb' => 9.93544094443283E+01,
7643  'BTU' => 3.96830723907002E-03,
7644  'btu' => 3.96830723907002E-03
7645  ),
7646  'eV' => array( 'J' => 1.60219000146921E-19,
7647  'e' => 1.60218923136574E-12,
7648  'c' => 3.82933423195043E-20,
7649  'cal' => 3.82676978535648E-20,
7650  'eV' => 1.0,
7651  'ev' => 1.0,
7652  'HPh' => 5.96826078912344E-26,
7653  'hh' => 5.96826078912344E-26,
7654  'Wh' => 4.45053000026614E-23,
7655  'wh' => 4.45053000026614E-23,
7656  'flb' => 3.80206452103492E-18,
7657  'BTU' => 1.51857982414846E-22,
7658  'btu' => 1.51857982414846E-22
7659  ),
7660  'ev' => array( 'J' => 1.60219000146921E-19,
7661  'e' => 1.60218923136574E-12,
7662  'c' => 3.82933423195043E-20,
7663  'cal' => 3.82676978535648E-20,
7664  'eV' => 1.0,
7665  'ev' => 1.0,
7666  'HPh' => 5.96826078912344E-26,
7667  'hh' => 5.96826078912344E-26,
7668  'Wh' => 4.45053000026614E-23,
7669  'wh' => 4.45053000026614E-23,
7670  'flb' => 3.80206452103492E-18,
7671  'BTU' => 1.51857982414846E-22,
7672  'btu' => 1.51857982414846E-22
7673  ),
7674  'HPh' => array( 'J' => 2.68451741316170E+06,
7675  'e' => 2.68451612283024E+13,
7676  'c' => 6.41616438565991E+05,
7677  'cal' => 6.41186757845835E+05,
7678  'eV' => 1.67553000000000E+25,
7679  'ev' => 1.67553000000000E+25,
7680  'HPh' => 1.0,
7681  'hh' => 1.0,
7682  'Wh' => 7.45699653134593E+02,
7683  'wh' => 7.45699653134593E+02,
7684  'flb' => 6.37047316692964E+07,
7685  'BTU' => 2.54442605275546E+03,
7686  'btu' => 2.54442605275546E+03
7687  ),
7688  'hh' => array( 'J' => 2.68451741316170E+06,
7689  'e' => 2.68451612283024E+13,
7690  'c' => 6.41616438565991E+05,
7691  'cal' => 6.41186757845835E+05,
7692  'eV' => 1.67553000000000E+25,
7693  'ev' => 1.67553000000000E+25,
7694  'HPh' => 1.0,
7695  'hh' => 1.0,
7696  'Wh' => 7.45699653134593E+02,
7697  'wh' => 7.45699653134593E+02,
7698  'flb' => 6.37047316692964E+07,
7699  'BTU' => 2.54442605275546E+03,
7700  'btu' => 2.54442605275546E+03
7701  ),
7702  'Wh' => array( 'J' => 3.59999820554720E+03,
7703  'e' => 3.59999647518369E+10,
7704  'c' => 8.60422069219046E+02,
7705  'cal' => 8.59845857713046E+02,
7706  'eV' => 2.24692340000000E+22,
7707  'ev' => 2.24692340000000E+22,
7708  'HPh' => 1.34102248243839E-03,
7709  'hh' => 1.34102248243839E-03,
7710  'Wh' => 1.0,
7711  'wh' => 1.0,
7712  'flb' => 8.54294774062316E+04,
7713  'BTU' => 3.41213254164705E+00,
7714  'btu' => 3.41213254164705E+00
7715  ),
7716  'wh' => array( 'J' => 3.59999820554720E+03,
7717  'e' => 3.59999647518369E+10,
7718  'c' => 8.60422069219046E+02,
7719  'cal' => 8.59845857713046E+02,
7720  'eV' => 2.24692340000000E+22,
7721  'ev' => 2.24692340000000E+22,
7722  'HPh' => 1.34102248243839E-03,
7723  'hh' => 1.34102248243839E-03,
7724  'Wh' => 1.0,
7725  'wh' => 1.0,
7726  'flb' => 8.54294774062316E+04,
7727  'BTU' => 3.41213254164705E+00,
7728  'btu' => 3.41213254164705E+00
7729  ),
7730  'flb' => array( 'J' => 4.21400003236424E-02,
7731  'e' => 4.21399800687660E+05,
7732  'c' => 1.00717234301644E-02,
7733  'cal' => 1.00649785509554E-02,
7734  'eV' => 2.63015000000000E+17,
7735  'ev' => 2.63015000000000E+17,
7736  'HPh' => 1.56974211145130E-08,
7737  'hh' => 1.56974211145130E-08,
7738  'Wh' => 1.17055614802000E-05,
7739  'wh' => 1.17055614802000E-05,
7740  'flb' => 1.0,
7741  'BTU' => 3.99409272448406E-05,
7742  'btu' => 3.99409272448406E-05
7743  ),
7744  'BTU' => array( 'J' => 1.05505813786749E+03,
7745  'e' => 1.05505763074665E+10,
7746  'c' => 2.52165488508168E+02,
7747  'cal' => 2.51996617135510E+02,
7748  'eV' => 6.58510000000000E+21,
7749  'ev' => 6.58510000000000E+21,
7750  'HPh' => 3.93015941224568E-04,
7751  'hh' => 3.93015941224568E-04,
7752  'Wh' => 2.93071851047526E-01,
7753  'wh' => 2.93071851047526E-01,
7754  'flb' => 2.50369750774671E+04,
7755  'BTU' => 1.0,
7756  'btu' => 1.0,
7757  ),
7758  'btu' => array( 'J' => 1.05505813786749E+03,
7759  'e' => 1.05505763074665E+10,
7760  'c' => 2.52165488508168E+02,
7761  'cal' => 2.51996617135510E+02,
7762  'eV' => 6.58510000000000E+21,
7763  'ev' => 6.58510000000000E+21,
7764  'HPh' => 3.93015941224568E-04,
7765  'hh' => 3.93015941224568E-04,
7766  'Wh' => 2.93071851047526E-01,
7767  'wh' => 2.93071851047526E-01,
7768  'flb' => 2.50369750774671E+04,
7769  'BTU' => 1.0,
7770  'btu' => 1.0,
7771  )
7772  ),
7773  'Power' => array( 'HP' => array( 'HP' => 1.0,
7774  'h' => 1.0,
7775  'W' => 7.45701000000000E+02,
7776  'w' => 7.45701000000000E+02
7777  ),
7778  'h' => array( 'HP' => 1.0,
7779  'h' => 1.0,
7780  'W' => 7.45701000000000E+02,
7781  'w' => 7.45701000000000E+02
7782  ),
7783  'W' => array( 'HP' => 1.34102006031908E-03,
7784  'h' => 1.34102006031908E-03,
7785  'W' => 1.0,
7786  'w' => 1.0
7787  ),
7788  'w' => array( 'HP' => 1.34102006031908E-03,
7789  'h' => 1.34102006031908E-03,
7790  'W' => 1.0,
7791  'w' => 1.0
7792  )
7793  ),
7794  'Magnetism' => array( 'T' => array( 'T' => 1.0,
7795  'ga' => 10000.0
7796  ),
7797  'ga' => array( 'T' => 0.0001,
7798  'ga' => 1.0
7799  )
7800  ),
7801  'Liquid' => array( 'tsp' => array( 'tsp' => 1.0,
7802  'tbs' => 3.33333333333333E-01,
7803  'oz' => 1.66666666666667E-01,
7804  'cup' => 2.08333333333333E-02,
7805  'pt' => 1.04166666666667E-02,
7806  'us_pt' => 1.04166666666667E-02,
7807  'uk_pt' => 8.67558516821960E-03,
7808  'qt' => 5.20833333333333E-03,
7809  'gal' => 1.30208333333333E-03,
7810  'l' => 4.92999408400710E-03,
7811  'lt' => 4.92999408400710E-03
7812  ),
7813  'tbs' => array( 'tsp' => 3.00000000000000E+00,
7814  'tbs' => 1.0,
7815  'oz' => 5.00000000000000E-01,
7816  'cup' => 6.25000000000000E-02,
7817  'pt' => 3.12500000000000E-02,
7818  'us_pt' => 3.12500000000000E-02,
7819  'uk_pt' => 2.60267555046588E-02,
7820  'qt' => 1.56250000000000E-02,
7821  'gal' => 3.90625000000000E-03,
7822  'l' => 1.47899822520213E-02,
7823  'lt' => 1.47899822520213E-02
7824  ),
7825  'oz' => array( 'tsp' => 6.00000000000000E+00,
7826  'tbs' => 2.00000000000000E+00,
7827  'oz' => 1.0,
7828  'cup' => 1.25000000000000E-01,
7829  'pt' => 6.25000000000000E-02,
7830  'us_pt' => 6.25000000000000E-02,
7831  'uk_pt' => 5.20535110093176E-02,
7832  'qt' => 3.12500000000000E-02,
7833  'gal' => 7.81250000000000E-03,
7834  'l' => 2.95799645040426E-02,
7835  'lt' => 2.95799645040426E-02
7836  ),
7837  'cup' => array( 'tsp' => 4.80000000000000E+01,
7838  'tbs' => 1.60000000000000E+01,
7839  'oz' => 8.00000000000000E+00,
7840  'cup' => 1.0,
7841  'pt' => 5.00000000000000E-01,
7842  'us_pt' => 5.00000000000000E-01,
7843  'uk_pt' => 4.16428088074541E-01,
7844  'qt' => 2.50000000000000E-01,
7845  'gal' => 6.25000000000000E-02,
7846  'l' => 2.36639716032341E-01,
7847  'lt' => 2.36639716032341E-01
7848  ),
7849  'pt' => array( 'tsp' => 9.60000000000000E+01,
7850  'tbs' => 3.20000000000000E+01,
7851  'oz' => 1.60000000000000E+01,
7852  'cup' => 2.00000000000000E+00,
7853  'pt' => 1.0,
7854  'us_pt' => 1.0,
7855  'uk_pt' => 8.32856176149081E-01,
7856  'qt' => 5.00000000000000E-01,
7857  'gal' => 1.25000000000000E-01,
7858  'l' => 4.73279432064682E-01,
7859  'lt' => 4.73279432064682E-01
7860  ),
7861  'us_pt' => array( 'tsp' => 9.60000000000000E+01,
7862  'tbs' => 3.20000000000000E+01,
7863  'oz' => 1.60000000000000E+01,
7864  'cup' => 2.00000000000000E+00,
7865  'pt' => 1.0,
7866  'us_pt' => 1.0,
7867  'uk_pt' => 8.32856176149081E-01,
7868  'qt' => 5.00000000000000E-01,
7869  'gal' => 1.25000000000000E-01,
7870  'l' => 4.73279432064682E-01,
7871  'lt' => 4.73279432064682E-01
7872  ),
7873  'uk_pt' => array( 'tsp' => 1.15266000000000E+02,
7874  'tbs' => 3.84220000000000E+01,
7875  'oz' => 1.92110000000000E+01,
7876  'cup' => 2.40137500000000E+00,
7877  'pt' => 1.20068750000000E+00,
7878  'us_pt' => 1.20068750000000E+00,
7879  'uk_pt' => 1.0,
7880  'qt' => 6.00343750000000E-01,
7881  'gal' => 1.50085937500000E-01,
7882  'l' => 5.68260698087162E-01,
7883  'lt' => 5.68260698087162E-01
7884  ),
7885  'qt' => array( 'tsp' => 1.92000000000000E+02,
7886  'tbs' => 6.40000000000000E+01,
7887  'oz' => 3.20000000000000E+01,
7888  'cup' => 4.00000000000000E+00,
7889  'pt' => 2.00000000000000E+00,
7890  'us_pt' => 2.00000000000000E+00,
7891  'uk_pt' => 1.66571235229816E+00,
7892  'qt' => 1.0,
7893  'gal' => 2.50000000000000E-01,
7894  'l' => 9.46558864129363E-01,
7895  'lt' => 9.46558864129363E-01
7896  ),
7897  'gal' => array( 'tsp' => 7.68000000000000E+02,
7898  'tbs' => 2.56000000000000E+02,
7899  'oz' => 1.28000000000000E+02,
7900  'cup' => 1.60000000000000E+01,
7901  'pt' => 8.00000000000000E+00,
7902  'us_pt' => 8.00000000000000E+00,
7903  'uk_pt' => 6.66284940919265E+00,
7904  'qt' => 4.00000000000000E+00,
7905  'gal' => 1.0,
7906  'l' => 3.78623545651745E+00,
7907  'lt' => 3.78623545651745E+00
7908  ),
7909  'l' => array( 'tsp' => 2.02840000000000E+02,
7910  'tbs' => 6.76133333333333E+01,
7911  'oz' => 3.38066666666667E+01,
7912  'cup' => 4.22583333333333E+00,
7913  'pt' => 2.11291666666667E+00,
7914  'us_pt' => 2.11291666666667E+00,
7915  'uk_pt' => 1.75975569552166E+00,
7916  'qt' => 1.05645833333333E+00,
7917  'gal' => 2.64114583333333E-01,
7918  'l' => 1.0,
7919  'lt' => 1.0
7920  ),
7921  'lt' => array( 'tsp' => 2.02840000000000E+02,
7922  'tbs' => 6.76133333333333E+01,
7923  'oz' => 3.38066666666667E+01,
7924  'cup' => 4.22583333333333E+00,
7925  'pt' => 2.11291666666667E+00,
7926  'us_pt' => 2.11291666666667E+00,
7927  'uk_pt' => 1.75975569552166E+00,
7928  'qt' => 1.05645833333333E+00,
7929  'gal' => 2.64114583333333E-01,
7930  'l' => 1.0,
7931  'lt' => 1.0
7932  )
7933  )
7934  );
7935 
7936 
7942  public static function getConversionGroups() {
7943  $conversionGroups = array();
7944  foreach(self::$_conversionUnits as $conversionUnit) {
7945  $conversionGroups[] = $conversionUnit['Group'];
7946  }
7947  return array_merge(array_unique($conversionGroups));
7948  } // function getConversionGroups()
7949 
7950 
7956  public static function getConversionGroupUnits($group = NULL) {
7957  $conversionGroups = array();
7958  foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup) {
7959  if ((is_null($group)) || ($conversionGroup['Group'] == $group)) {
7960  $conversionGroups[$conversionGroup['Group']][] = $conversionUnit;
7961  }
7962  }
7963  return $conversionGroups;
7964  } // function getConversionGroupUnits()
7965 
7966 
7972  public static function getConversionGroupUnitDetails($group = NULL) {
7973  $conversionGroups = array();
7974  foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup) {
7975  if ((is_null($group)) || ($conversionGroup['Group'] == $group)) {
7976  $conversionGroups[$conversionGroup['Group']][] = array( 'unit' => $conversionUnit,
7977  'description' => $conversionGroup['Unit Name']
7978  );
7979  }
7980  }
7981  return $conversionGroups;
7982  } // function getConversionGroupUnitDetails()
7983 
7984 
7990  public static function getConversionMultipliers() {
7992  } // function getConversionGroups()
7993 
7994 
8003  public static function CONVERTUOM($value, $fromUOM, $toUOM) {
8004  $value = self::flattenSingleValue($value);
8005  $fromUOM = self::flattenSingleValue($fromUOM);
8006  $toUOM = self::flattenSingleValue($toUOM);
8007 
8008  if (!is_numeric($value)) {
8009  return self::$_errorCodes['value'];
8010  }
8011  $fromMultiplier = 1;
8012  if (isset(self::$_conversionUnits[$fromUOM])) {
8013  $unitGroup1 = self::$_conversionUnits[$fromUOM]['Group'];
8014  } else {
8015  $fromMultiplier = substr($fromUOM,0,1);
8016  $fromUOM = substr($fromUOM,1);
8017  if (isset(self::$_conversionMultipliers[$fromMultiplier])) {
8018  $fromMultiplier = self::$_conversionMultipliers[$fromMultiplier]['multiplier'];
8019  } else {
8020  return self::$_errorCodes['na'];
8021  }
8022  if ((isset(self::$_conversionUnits[$fromUOM])) && (self::$_conversionUnits[$fromUOM]['AllowPrefix'])) {
8023  $unitGroup1 = self::$_conversionUnits[$fromUOM]['Group'];
8024  } else {
8025  return self::$_errorCodes['na'];
8026  }
8027  }
8028  $value *= $fromMultiplier;
8029 
8030  $toMultiplier = 1;
8031  if (isset(self::$_conversionUnits[$toUOM])) {
8032  $unitGroup2 = self::$_conversionUnits[$toUOM]['Group'];
8033  } else {
8034  $toMultiplier = substr($toUOM,0,1);
8035  $toUOM = substr($toUOM,1);
8036  if (isset(self::$_conversionMultipliers[$toMultiplier])) {
8037  $toMultiplier = self::$_conversionMultipliers[$toMultiplier]['multiplier'];
8038  } else {
8039  return self::$_errorCodes['na'];
8040  }
8041  if ((isset(self::$_conversionUnits[$toUOM])) && (self::$_conversionUnits[$toUOM]['AllowPrefix'])) {
8042  $unitGroup2 = self::$_conversionUnits[$toUOM]['Group'];
8043  } else {
8044  return self::$_errorCodes['na'];
8045  }
8046  }
8047  if ($unitGroup1 != $unitGroup2) {
8048  return self::$_errorCodes['na'];
8049  }
8050 
8051  if ($fromUOM == $toUOM) {
8052  return 1.0;
8053  } elseif ($unitGroup1 == 'Temperature') {
8054  if (($fromUOM == 'F') || ($fromUOM == 'fah')) {
8055  if (($toUOM == 'F') || ($toUOM == 'fah')) {
8056  return 1.0;
8057  } else {
8058  $value = (($value - 32) / 1.8);
8059  if (($toUOM == 'K') || ($toUOM == 'kel')) {
8060  $value += 273.15;
8061  }
8062  return $value;
8063  }
8064  } elseif ((($fromUOM == 'K') || ($fromUOM == 'kel')) &&
8065  (($toUOM == 'K') || ($toUOM == 'kel'))) {
8066  return 1.0;
8067  } elseif ((($fromUOM == 'C') || ($fromUOM == 'cel')) &&
8068  (($toUOM == 'C') || ($toUOM == 'cel'))) {
8069  return 1.0;
8070  }
8071  if (($toUOM == 'F') || ($toUOM == 'fah')) {
8072  if (($fromUOM == 'K') || ($fromUOM == 'kel')) {
8073  $value -= 273.15;
8074  }
8075  return ($value * 1.8) + 32;
8076  }
8077  if (($toUOM == 'C') || ($toUOM == 'cel')) {
8078  return $value - 273.15;
8079  }
8080  return $value + 273.15;
8081  }
8082  return ($value * self::$_unitConversions[$unitGroup1][$fromUOM][$toUOM]) / $toMultiplier;
8083  } // function CONVERTUOM()
8084 
8085 
8095  public static function BESSELI($x, $n) {
8097  $n = floor(self::flattenSingleValue($n));
8098 
8099  if ((is_numeric($x)) && (is_numeric($n))) {
8100  if ($n < 0) {
8101  return self::$_errorCodes['num'];
8102  }
8103  $f_2_PI = 2 * pi();
8104 
8105  if (abs($x) <= 30) {
8106  $fTerm = pow($x / 2, $n) / self::FACT($n);
8107  $nK = 1;
8108  $fResult = $fTerm;
8109  $fSqrX = pow($x,2) / 4;
8110  do {
8111  $fTerm *= $fSqrX;
8112  $fTerm /= ($nK * ($nK + $n));
8113  $fResult += $fTerm;
8114  } while ((abs($fTerm) > 1e-10) && (++$nK < 100));
8115  } else {
8116  $fXAbs = abs($x);
8117  $fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs);
8118  if (($n && 1) && ($x < 0)) {
8119  $fResult = -$fResult;
8120  }
8121  }
8122  return $fResult;
8123  }
8124  return self::$_errorCodes['value'];
8125  } // function BESSELI()
8126 
8127 
8137  public static function BESSELJ($x, $n) {
8139  $n = floor(self::flattenSingleValue($n));
8140 
8141  if ((is_numeric($x)) && (is_numeric($n))) {
8142  if ($n < 0) {
8143  return self::$_errorCodes['num'];
8144  }
8145  $f_2_DIV_PI = 2 / pi();
8146  $f_PI_DIV_2 = pi() / 2;
8147  $f_PI_DIV_4 = pi() / 4;
8148 
8149  $fResult = 0;
8150  if (abs($x) <= 30) {
8151  $fTerm = pow($x / 2, $n) / self::FACT($n);
8152  $nK = 1;
8153  $fResult = $fTerm;
8154  $fSqrX = pow($x,2) / -4;
8155  do {
8156  $fTerm *= $fSqrX;
8157  $fTerm /= ($nK * ($nK + $n));
8158  $fResult += $fTerm;
8159  } while ((abs($fTerm) > 1e-10) && (++$nK < 100));
8160  } else {
8161  $fXAbs = abs($x);
8162  $fResult = sqrt($f_2_DIV_PI / $fXAbs) * cos($fXAbs - $n * $f_PI_DIV_2 - $f_PI_DIV_4);
8163  if (($n && 1) && ($x < 0)) {
8164  $fResult = -$fResult;
8165  }
8166  }
8167  return $fResult;
8168  }
8169  return self::$_errorCodes['value'];
8170  } // function BESSELJ()
8171 
8172 
8173  private static function _Besselk0($fNum) {
8174  if ($fNum <= 2) {
8175  $fNum2 = $fNum * 0.5;
8176  $y = pow($fNum2,2);
8177  $fRet = -log($fNum2) * self::BESSELI($fNum, 0) +
8178  (-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y *
8179  (0.10750e-3 + $y * 0.74e-5))))));
8180  } else {
8181  $y = 2 / $fNum;
8182  $fRet = exp(-$fNum) / sqrt($fNum) *
8183  (1.25331414 + $y * (-0.7832358e-1 + $y * (0.2189568e-1 + $y * (-0.1062446e-1 + $y *
8184  (0.587872e-2 + $y * (-0.251540e-2 + $y * 0.53208e-3))))));
8185  }
8186  return $fRet;
8187  } // function _Besselk0()
8188 
8189 
8190  private static function _Besselk1($fNum) {
8191  if ($fNum <= 2) {
8192  $fNum2 = $fNum * 0.5;
8193  $y = pow($fNum2,2);
8194  $fRet = log($fNum2) * self::BESSELI($fNum, 1) +
8195  (1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y *
8196  (-0.110404e-2 + $y * (-0.4686e-4))))))) / $fNum;
8197  } else {
8198  $y = 2 / $fNum;
8199  $fRet = exp(-$fNum) / sqrt($fNum) *
8200  (1.25331414 + $y * (0.23498619 + $y * (-0.3655620e-1 + $y * (0.1504268e-1 + $y * (-0.780353e-2 + $y *
8201  (0.325614e-2 + $y * (-0.68245e-3)))))));
8202  }
8203  return $fRet;
8204  } // function _Besselk1()
8205 
8206 
8216  public static function BESSELK($x, $ord) {
8218  $ord = floor(self::flattenSingleValue($ord));
8219 
8220  if ((is_numeric($x)) && (is_numeric($ord))) {
8221  if ($ord < 0) {
8222  return self::$_errorCodes['num'];
8223  }
8224 
8225  switch($ord) {
8226  case 0 : return self::_Besselk0($x);
8227  break;
8228  case 1 : return self::_Besselk1($x);
8229  break;
8230  default : $fTox = 2 / $x;
8231  $fBkm = self::_Besselk0($x);
8232  $fBk = self::_Besselk1($x);
8233  for ($n = 1; $n < $ord; ++$n) {
8234  $fBkp = $fBkm + $n * $fTox * $fBk;
8235  $fBkm = $fBk;
8236  $fBk = $fBkp;
8237  }
8238  }
8239  return $fBk;
8240  }
8241  return self::$_errorCodes['value'];
8242  } // function BESSELK()
8243 
8244 
8245  private static function _Bessely0($fNum) {
8246  if ($fNum < 8.0) {
8247  $y = pow($fNum,2);
8248  $f1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y * (-86327.92757 + $y * 228.4622733))));
8249  $f2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * (47447.26470 + $y * (226.1030244 + $y))));
8250  $fRet = $f1 / $f2 + 0.636619772 * self::BESSELJ($fNum, 0) * log($fNum);
8251  } else {
8252  $z = 8.0 / $fNum;
8253  $y = pow($z,2);
8254  $xx = $fNum - 0.785398164;
8255  $f1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6)));
8256  $f2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y * (-0.934945152e-7))));
8257  $fRet = sqrt(0.636619772 / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2);
8258  }
8259  return $fRet;
8260  } // function _Bessely0()
8261 
8262 
8263  private static function _Bessely1($fNum) {
8264  if ($fNum < 8.0) {
8265  $y = pow($fNum,2);
8266  $f1 = $fNum * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y * (0.7349264551e9 + $y *
8267  (-0.4237922726e7 + $y * 0.8511937935e4)))));
8268  $f2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y *
8269  (0.1020426050e6 + $y * (0.3549632885e3 + $y)))));
8270  $fRet = $f1 / $f2 + 0.636619772 * ( self::BESSELJ($fNum, 1) * log($fNum) - 1 / $fNum);
8271  } else {
8272  $z = 8.0 / $fNum;
8273  $y = pow($z,2);
8274  $xx = $fNum - 2.356194491;
8275  $f1 = 1 + $y * (0.183105e-2 + $y * (-0.3516396496e-4 + $y * (0.2457520174e-5 + $y * (-0.240337019e6))));
8276  $f2 = 0.04687499995 + $y * (-0.2002690873e-3 + $y * (0.8449199096e-5 + $y * (-0.88228987e-6 + $y * 0.105787412e-6)));
8277  $fRet = sqrt(0.636619772 / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2);
8278  #i12430# ...but this seems to work much better.
8279 // $fRet = sqrt(0.636619772 / $fNum) * sin($fNum - 2.356194491);
8280  }
8281  return $fRet;
8282  } // function _Bessely1()
8283 
8284 
8294  public static function BESSELY($x, $ord) {
8296  $ord = floor(self::flattenSingleValue($ord));
8297 
8298  if ((is_numeric($x)) && (is_numeric($ord))) {
8299  if ($ord < 0) {
8300  return self::$_errorCodes['num'];
8301  }
8302 
8303  switch($ord) {
8304  case 0 : return self::_Bessely0($x);
8305  break;
8306  case 1 : return self::_Bessely1($x);
8307  break;
8308  default: $fTox = 2 / $x;
8309  $fBym = self::_Bessely0($x);
8310  $fBy = self::_Bessely1($x);
8311  for ($n = 1; $n < $ord; ++$n) {
8312  $fByp = $n * $fTox * $fBy - $fBym;
8313  $fBym = $fBy;
8314  $fBy = $fByp;
8315  }
8316  }
8317  return $fBy;
8318  }
8319  return self::$_errorCodes['value'];
8320  } // function BESSELY()
8321 
8322 
8332  public static function DELTA($a, $b=0) {
8333  $a = self::flattenSingleValue($a);
8334  $b = self::flattenSingleValue($b);
8335 
8336  return (int) ($a == $b);
8337  } // function DELTA()
8338 
8339 
8349  public static function GESTEP($number, $step=0) {
8350  $number = self::flattenSingleValue($number);
8351  $step = self::flattenSingleValue($step);
8352 
8353  return (int) ($number >= $step);
8354  } // function GESTEP()
8355 
8356 
8357  //
8358  // Private method to calculate the erf value
8359  //
8360  private static $_two_sqrtpi = 1.128379167095512574;
8361  private static $_rel_error = 1E-15;
8362 
8363  private static function _erfVal($x) {
8364  if (abs($x) > 2.2) {
8365  return 1 - self::_erfcVal($x);
8366  }
8367  $sum = $term = $x;
8368  $xsqr = pow($x,2);
8369  $j = 1;
8370  do {
8371  $term *= $xsqr / $j;
8372  $sum -= $term / (2 * $j + 1);
8373  ++$j;
8374  $term *= $xsqr / $j;
8375  $sum += $term / (2 * $j + 1);
8376  ++$j;
8377  if ($sum == 0) {
8378  break;
8379  }
8380  } while (abs($term / $sum) > self::$_rel_error);
8381  return self::$_two_sqrtpi * $sum;
8382  } // function _erfVal()
8383 
8384 
8395  public static function ERF($lower, $upper = null) {
8396  $lower = self::flattenSingleValue($lower);
8397  $upper = self::flattenSingleValue($upper);
8398 
8399  if (is_numeric($lower)) {
8400  if ($lower < 0) {
8401  return self::$_errorCodes['num'];
8402  }
8403  if (is_null($upper)) {
8404  return self::_erfVal($lower);
8405  }
8406  if (is_numeric($upper)) {
8407  if ($upper < 0) {
8408  return self::$_errorCodes['num'];
8409  }
8410  return self::_erfVal($upper) - self::_erfVal($lower);
8411  }
8412  }
8413  return self::$_errorCodes['value'];
8414  } // function ERF()
8415 
8416 
8417  //
8418  // Private method to calculate the erfc value
8419  //
8420  private static $_one_sqrtpi = 0.564189583547756287;
8421 
8422  private static function _erfcVal($x) {
8423  if (abs($x) < 2.2) {
8424  return 1 - self::_erfVal($x);
8425  }
8426  if ($x < 0) {
8427  return 2 - self::erfc(-$x);
8428  }
8429  $a = $n = 1;
8430  $b = $c = $x;
8431  $d = pow($x,2) + 0.5;
8432  $q1 = $q2 = $b / $d;
8433  $t = 0;
8434  do {
8435  $t = $a * $n + $b * $x;
8436  $a = $b;
8437  $b = $t;
8438  $t = $c * $n + $d * $x;
8439  $c = $d;
8440  $d = $t;
8441  $n += 0.5;
8442  $q1 = $q2;
8443  $q2 = $b / $d;
8444  } while ((abs($q1 - $q2) / $q2) > self::$_rel_error);
8445  return self::$_one_sqrtpi * exp(-$x * $x) * $q2;
8446  } // function _erfcVal()
8447 
8448 
8457  public static function ERFC($x) {
8459 
8460  if (is_numeric($x)) {
8461  if ($x < 0) {
8462  return self::$_errorCodes['num'];
8463  }
8464  return self::_erfcVal($x);
8465  }
8466  return self::$_errorCodes['value'];
8467  } // function ERFC()
8468 
8469 
8478  public static function LOWERCASE($mixedCaseString) {
8479  $mixedCaseString = self::flattenSingleValue($mixedCaseString);
8480 
8481  if (function_exists('mb_convert_case')) {
8482  return mb_convert_case($mixedCaseString, MB_CASE_LOWER, 'UTF-8');
8483  } else {
8484  return strtoupper($mixedCaseString);
8485  }
8486  } // function LOWERCASE()
8487 
8488 
8497  public static function UPPERCASE($mixedCaseString) {
8498  $mixedCaseString = self::flattenSingleValue($mixedCaseString);
8499 
8500  if (function_exists('mb_convert_case')) {
8501  return mb_convert_case($mixedCaseString, MB_CASE_UPPER, 'UTF-8');
8502  } else {
8503  return strtoupper($mixedCaseString);
8504  }
8505  } // function UPPERCASE()
8506 
8507 
8516  public static function PROPERCASE($mixedCaseString) {
8517  $mixedCaseString = self::flattenSingleValue($mixedCaseString);
8518 
8519  if (function_exists('mb_convert_case')) {
8520  return mb_convert_case($mixedCaseString, MB_CASE_TITLE, 'UTF-8');
8521  } else {
8522  return ucwords($mixedCaseString);
8523  }
8524  } // function PROPERCASE()
8525 
8526 
8539  public static function DOLLAR($value = 0, $decimals = 2) {
8540  $value = self::flattenSingleValue($value);
8541  $decimals = self::flattenSingleValue($decimals);
8542 
8543  // Validate parameters
8544  if (!is_numeric($value) || !is_numeric($decimals)) {
8545  return self::$_errorCodes['num'];
8546  }
8547  $decimals = floor($decimals);
8548 
8549  if ($decimals > 0) {
8550  return money_format('%.'.$decimals.'n',$value);
8551  } else {
8552  $round = pow(10,abs($decimals));
8553  if ($value < 0) { $round = 0-$round; }
8554  $value = self::MROUND($value,$round);
8555  // The implementation of money_format used if the standard PHP function is not available can't handle decimal places of 0,
8556  // so we display to 1 dp and chop off that character and the decimal separator using substr
8557  return substr(money_format('%.1n',$value),0,-2);
8558  }
8559  } // function DOLLAR()
8560 
8561 
8572  public static function DOLLARDE($fractional_dollar = Null, $fraction = 0) {
8573  $fractional_dollar = self::flattenSingleValue($fractional_dollar);
8574  $fraction = (int)self::flattenSingleValue($fraction);
8575 
8576  // Validate parameters
8577  if (is_null($fractional_dollar) || $fraction < 0) {
8578  return self::$_errorCodes['num'];
8579  }
8580  if ($fraction == 0) {
8581  return self::$_errorCodes['divisionbyzero'];
8582  }
8583 
8584  $dollars = floor($fractional_dollar);
8585  $cents = fmod($fractional_dollar,1);
8586  $cents /= $fraction;
8587  $cents *= pow(10,ceil(log10($fraction)));
8588  return $dollars + $cents;
8589  } // function DOLLARDE()
8590 
8591 
8602  public static function DOLLARFR($decimal_dollar = Null, $fraction = 0) {
8603  $decimal_dollar = self::flattenSingleValue($decimal_dollar);
8604  $fraction = (int)self::flattenSingleValue($fraction);
8605 
8606  // Validate parameters
8607  if (is_null($decimal_dollar) || $fraction < 0) {
8608  return self::$_errorCodes['num'];
8609  }
8610  if ($fraction == 0) {
8611  return self::$_errorCodes['divisionbyzero'];
8612  }
8613 
8614  $dollars = floor($decimal_dollar);
8615  $cents = fmod($decimal_dollar,1);
8616  $cents *= $fraction;
8617  $cents *= pow(10,-ceil(log10($fraction)));
8618  return $dollars + $cents;
8619  } // function DOLLARFR()
8620 
8621 
8631  public static function EFFECT($nominal_rate = 0, $npery = 0) {
8632  $nominal_rate = self::flattenSingleValue($nominal_rate);
8633  $npery = (int)self::flattenSingleValue($npery);
8634 
8635  // Validate parameters
8636  if ($nominal_rate <= 0 || $npery < 1) {
8637  return self::$_errorCodes['num'];
8638  }
8639 
8640  return pow((1 + $nominal_rate / $npery), $npery) - 1;
8641  } // function EFFECT()
8642 
8643 
8653  public static function NOMINAL($effect_rate = 0, $npery = 0) {
8654  $effect_rate = self::flattenSingleValue($effect_rate);
8655  $npery = (int)self::flattenSingleValue($npery);
8656 
8657  // Validate parameters
8658  if ($effect_rate <= 0 || $npery < 1) {
8659  return self::$_errorCodes['num'];
8660  }
8661 
8662  // Calculate
8663  return $npery * (pow($effect_rate + 1, 1 / $npery) - 1);
8664  } // function NOMINAL()
8665 
8666 
8679  public static function PV($rate = 0, $nper = 0, $pmt = 0, $fv = 0, $type = 0) {
8680  $rate = self::flattenSingleValue($rate);
8681  $nper = self::flattenSingleValue($nper);
8682  $pmt = self::flattenSingleValue($pmt);
8683  $fv = self::flattenSingleValue($fv);
8685 
8686  // Validate parameters
8687  if ($type != 0 && $type != 1) {
8688  return self::$_errorCodes['num'];
8689  }
8690 
8691  // Calculate
8692  if (!is_null($rate) && $rate != 0) {
8693  return (-$pmt * (1 + $rate * $type) * ((pow(1 + $rate, $nper) - 1) / $rate) - $fv) / pow(1 + $rate, $nper);
8694  } else {
8695  return -$fv - $pmt * $nper;
8696  }
8697  } // function PV()
8698 
8699 
8712  public static function FV($rate = 0, $nper = 0, $pmt = 0, $pv = 0, $type = 0) {
8713  $rate = self::flattenSingleValue($rate);
8714  $nper = self::flattenSingleValue($nper);
8715  $pmt = self::flattenSingleValue($pmt);
8716  $pv = self::flattenSingleValue($pv);
8718 
8719  // Validate parameters
8720  if ($type != 0 && $type != 1) {
8721  return self::$_errorCodes['num'];
8722  }
8723 
8724  // Calculate
8725  if (!is_null($rate) && $rate != 0) {
8726  return -$pv * pow(1 + $rate, $nper) - $pmt * (1 + $rate * $type) * (pow(1 + $rate, $nper) - 1) / $rate;
8727  } else {
8728  return -$pv - $pmt * $nper;
8729  }
8730  } // function FV()
8731 
8732 
8745  public static function PMT($rate = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0) {
8746  $rate = self::flattenSingleValue($rate);
8747  $nper = self::flattenSingleValue($nper);
8748  $pv = self::flattenSingleValue($pv);
8749  $fv = self::flattenSingleValue($fv);
8751 
8752  // Validate parameters
8753  if ($type != 0 && $type != 1) {
8754  return self::$_errorCodes['num'];
8755  }
8756 
8757  // Calculate
8758  if (!is_null($rate) && $rate != 0) {
8759  return (-$fv - $pv * pow(1 + $rate, $nper)) / (1 + $rate * $type) / ((pow(1 + $rate, $nper) - 1) / $rate);
8760  } else {
8761  return (-$pv - $fv) / $nper;
8762  }
8763  } // function PMT()
8764 
8765 
8778  public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0) {
8779  $rate = self::flattenSingleValue($rate);
8780  $pmt = self::flattenSingleValue($pmt);
8781  $pv = self::flattenSingleValue($pv);
8782  $fv = self::flattenSingleValue($fv);
8784 
8785  // Validate parameters
8786  if ($type != 0 && $type != 1) {
8787  return self::$_errorCodes['num'];
8788  }
8789 
8790  // Calculate
8791  if (!is_null($rate) && $rate != 0) {
8792  if ($pmt == 0 && $pv == 0) {
8793  return self::$_errorCodes['num'];
8794  }
8795  return log(($pmt * (1 + $rate * $type) / $rate - $fv) / ($pv + $pmt * (1 + $rate * $type) / $rate)) / log(1 + $rate);
8796  } else {
8797  if ($pmt == 0) {
8798  return self::$_errorCodes['num'];
8799  }
8800  return (-$pv -$fv) / $pmt;
8801  }
8802  } // function NPER()
8803 
8804 
8805  private static function _interestAndPrincipal($rate=0, $per=0, $nper=0, $pv=0, $fv=0, $type=0) {
8806  $pmt = self::PMT($rate, $nper, $pv, $fv, $type);
8807  $capital = $pv;
8808  for ($i = 1; $i<= $per; ++$i) {
8809  $interest = ($type && $i == 1)? 0 : -$capital * $rate;
8810  $principal = $pmt - $interest;
8811  $capital += $principal;
8812  }
8813  return array($interest, $principal);
8814  } // function _interestAndPrincipal()
8815 
8816 
8830  public static function IPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0) {
8831  $rate = self::flattenSingleValue($rate);
8832  $per = (int) self::flattenSingleValue($per);
8833  $nper = (int) self::flattenSingleValue($nper);
8834  $pv = self::flattenSingleValue($pv);
8835  $fv = self::flattenSingleValue($fv);
8836  $type = (int) self::flattenSingleValue($type);
8837 
8838  // Validate parameters
8839  if ($type != 0 && $type != 1) {
8840  return self::$_errorCodes['num'];
8841  }
8842  if ($per <= 0 || $per > $nper) {
8843  return self::$_errorCodes['value'];
8844  }
8845 
8846  // Calculate
8847  $interestAndPrincipal = self::_interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type);
8848  return $interestAndPrincipal[0];
8849  } // function IPMT()
8850 
8851 
8866  public static function CUMIPMT($rate, $nper, $pv, $start, $end, $type = 0) {
8867  $rate = self::flattenSingleValue($rate);
8868  $nper = (int) self::flattenSingleValue($nper);
8869  $pv = self::flattenSingleValue($pv);
8870  $start = (int) self::flattenSingleValue($start);
8871  $end = (int) self::flattenSingleValue($end);
8872  $type = (int) self::flattenSingleValue($type);
8873 
8874  // Validate parameters
8875  if ($type != 0 && $type != 1) {
8876  return self::$_errorCodes['num'];
8877  }
8878  if ($start < 1 || $start > $end) {
8879  return self::$_errorCodes['value'];
8880  }
8881 
8882  // Calculate
8883  $interest = 0;
8884  for ($per = $start; $per <= $end; ++$per) {
8885  $interest += self::IPMT($rate, $per, $nper, $pv, 0, $type);
8886  }
8887 
8888  return $interest;
8889  } // function CUMIPMT()
8890 
8891 
8905  public static function PPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0) {
8906  $rate = self::flattenSingleValue($rate);
8907  $per = (int) self::flattenSingleValue($per);
8908  $nper = (int) self::flattenSingleValue($nper);
8909  $pv = self::flattenSingleValue($pv);
8910  $fv = self::flattenSingleValue($fv);
8911  $type = (int) self::flattenSingleValue($type);
8912 
8913  // Validate parameters
8914  if ($type != 0 && $type != 1) {
8915  return self::$_errorCodes['num'];
8916  }
8917  if ($per <= 0 || $per > $nper) {
8918  return self::$_errorCodes['value'];
8919  }
8920 
8921  // Calculate
8922  $interestAndPrincipal = self::_interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type);
8923  return $interestAndPrincipal[1];
8924  } // function PPMT()
8925 
8926 
8941  public static function CUMPRINC($rate, $nper, $pv, $start, $end, $type = 0) {
8942  $rate = self::flattenSingleValue($rate);
8943  $nper = (int) self::flattenSingleValue($nper);
8944  $pv = self::flattenSingleValue($pv);
8945  $start = (int) self::flattenSingleValue($start);
8946  $end = (int) self::flattenSingleValue($end);
8947  $type = (int) self::flattenSingleValue($type);
8948 
8949  // Validate parameters
8950  if ($type != 0 && $type != 1) {
8951  return self::$_errorCodes['num'];
8952  }
8953  if ($start < 1 || $start > $end) {
8954  return self::$_errorCodes['value'];
8955  }
8956 
8957  // Calculate
8958  $principal = 0;
8959  for ($per = $start; $per <= $end; ++$per) {
8960  $principal += self::PPMT($rate, $per, $nper, $pv, 0, $type);
8961  }
8962 
8963  return $principal;
8964  } // function CUMPRINC()
8965 
8966 
8976  public static function NPV() {
8977  // Return value
8978  $returnValue = 0;
8979 
8980  // Loop trough arguments
8981  $aArgs = self::flattenArray(func_get_args());
8982 
8983  // Calculate
8984  $rate = array_shift($aArgs);
8985  for ($i = 1; $i <= count($aArgs); ++$i) {
8986  // Is it a numeric value?
8987  if (is_numeric($aArgs[$i - 1])) {
8988  $returnValue += $aArgs[$i - 1] / pow(1 + $rate, $i);
8989  }
8990  }
8991 
8992  // Return
8993  return $returnValue;
8994  } // function NPV()
8995 
8996 
9012  public static function DB($cost, $salvage, $life, $period, $month=12) {
9013  $cost = (float) self::flattenSingleValue($cost);
9014  $salvage = (float) self::flattenSingleValue($salvage);
9015  $life = (int) self::flattenSingleValue($life);
9016  $period = (int) self::flattenSingleValue($period);
9017  $month = (int) self::flattenSingleValue($month);
9018 
9019  // Validate
9020  if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($month))) {
9021  if ($cost == 0) {
9022  return 0.0;
9023  } elseif (($cost < 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($month < 1)) {
9024  return self::$_errorCodes['num'];
9025  }
9026  // Set Fixed Depreciation Rate
9027  $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life));
9028  $fixedDepreciationRate = round($fixedDepreciationRate, 3);
9029 
9030  // Loop through each period calculating the depreciation
9031  $previousDepreciation = 0;
9032  for ($per = 1; $per <= $period; ++$per) {
9033  if ($per == 1) {
9034  $depreciation = $cost * $fixedDepreciationRate * $month / 12;
9035  } elseif ($per == ($life + 1)) {
9036  $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate * (12 - $month) / 12;
9037  } else {
9038  $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate;
9039  }
9040  $previousDepreciation += $depreciation;
9041  }
9042  return $depreciation;
9043  }
9044  return self::$_errorCodes['value'];
9045  } // function DB()
9046 
9047 
9061  public static function DDB($cost, $salvage, $life, $period, $factor=2.0) {
9062  $cost = (float) self::flattenSingleValue($cost);
9063  $salvage = (float) self::flattenSingleValue($salvage);
9064  $life = (int) self::flattenSingleValue($life);
9065  $period = (int) self::flattenSingleValue($period);
9066  $factor = (float) self::flattenSingleValue($factor);
9067 
9068  // Validate
9069  if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($factor))) {
9070  if (($cost <= 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($factor <= 0.0) || ($period > $life)) {
9071  return self::$_errorCodes['num'];
9072  }
9073  // Set Fixed Depreciation Rate
9074  $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life));
9075  $fixedDepreciationRate = round($fixedDepreciationRate, 3);
9076 
9077  // Loop through each period calculating the depreciation
9078  $previousDepreciation = 0;
9079  for ($per = 1; $per <= $period; ++$per) {
9080  $depreciation = min( ($cost - $previousDepreciation) * ($factor / $life), ($cost - $salvage - $previousDepreciation) );
9081  $previousDepreciation += $depreciation;
9082  }
9083  return $depreciation;
9084  }
9085  return self::$_errorCodes['value'];
9086  } // function DDB()
9087 
9088 
9089  private static function _daysPerYear($year,$basis) {
9090  switch ($basis) {
9091  case 0 :
9092  case 2 :
9093  case 4 :
9094  $daysPerYear = 360;
9095  break;
9096  case 3 :
9097  $daysPerYear = 365;
9098  break;
9099  case 1 :
9100  if (self::_isLeapYear(self::YEAR($year))) {
9101  $daysPerYear = 366;
9102  } else {
9103  $daysPerYear = 365;
9104  }
9105  break;
9106  default :
9107  return self::$_errorCodes['num'];
9108  }
9109  return $daysPerYear;
9110  } // function _daysPerYear()
9111 
9112 
9131  public static function ACCRINT($issue, $firstinter, $settlement, $rate, $par=1000, $frequency=1, $basis=0) {
9132  $issue = self::flattenSingleValue($issue);
9133  $firstinter = self::flattenSingleValue($firstinter);
9134  $settlement = self::flattenSingleValue($settlement);
9135  $rate = (float) self::flattenSingleValue($rate);
9136  $par = (is_null($par)) ? 1000 : (float) self::flattenSingleValue($par);
9137  $frequency = (is_null($frequency)) ? 1 : (int) self::flattenSingleValue($frequency);
9138  $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis);
9139 
9140  // Validate
9141  if ((is_numeric($rate)) && (is_numeric($par))) {
9142  if (($rate <= 0) || ($par <= 0)) {
9143  return self::$_errorCodes['num'];
9144  }
9145  $daysBetweenIssueAndSettlement = self::YEARFRAC($issue, $settlement, $basis);
9146  if (!is_numeric($daysBetweenIssueAndSettlement)) {
9147  return $daysBetweenIssueAndSettlement;
9148  }
9149  $daysPerYear = self::_daysPerYear(self::YEAR($issue),$basis);
9150  if (!is_numeric($daysPerYear)) {
9151  return $daysPerYear;
9152  }
9153  $daysBetweenIssueAndSettlement *= $daysPerYear;
9154 
9155  return $par * $rate * ($daysBetweenIssueAndSettlement / $daysPerYear);
9156  }
9157  return self::$_errorCodes['value'];
9158  } // function ACCRINT()
9159 
9160 
9178  public static function ACCRINTM($issue, $settlement, $rate, $par=1000, $basis=0) {
9179  $issue = self::flattenSingleValue($issue);
9180  $settlement = self::flattenSingleValue($settlement);
9181  $rate = (float) self::flattenSingleValue($rate);
9182  $par = (is_null($par)) ? 1000 : (float) self::flattenSingleValue($par);
9183  $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis);
9184 
9185  // Validate
9186  if ((is_numeric($rate)) && (is_numeric($par))) {
9187  if (($rate <= 0) || ($par <= 0)) {
9188  return self::$_errorCodes['num'];
9189  }
9190  $daysBetweenIssueAndSettlement = self::YEARFRAC($issue, $settlement, $basis);
9191  if (!is_numeric($daysBetweenIssueAndSettlement)) {
9192  return $daysBetweenIssueAndSettlement;
9193  }
9194  $daysPerYear = self::_daysPerYear(self::YEAR($issue),$basis);
9195  if (!is_numeric($daysPerYear)) {
9196  return $daysPerYear;
9197  }
9198  $daysBetweenIssueAndSettlement *= $daysPerYear;
9199 
9200  return $par * $rate * ($daysBetweenIssueAndSettlement / $daysPerYear);
9201  }
9202  return self::$_errorCodes['value'];
9203  } // function ACCRINTM()
9204 
9205 
9206  public static function AMORDEGRC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis=0) {
9207  } // function AMORDEGRC()
9208 
9209 
9210  public static function AMORLINC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis=0) {
9211  } // function AMORLINC()
9212 
9213 
9233  public static function DISC($settlement, $maturity, $price, $redemption, $basis=0) {
9234  $settlement = self::flattenSingleValue($settlement);
9235  $maturity = self::flattenSingleValue($maturity);
9236  $price = (float) self::flattenSingleValue($price);
9237  $redemption = (float) self::flattenSingleValue($redemption);
9238  $basis = (int) self::flattenSingleValue($basis);
9239 
9240  // Validate
9241  if ((is_numeric($price)) && (is_numeric($redemption)) && (is_numeric($basis))) {
9242  if (($price <= 0) || ($redemption <= 0)) {
9243  return self::$_errorCodes['num'];
9244  }
9245  $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis);
9246  if (!is_numeric($daysBetweenSettlementAndMaturity)) {
9247  return $daysBetweenSettlementAndMaturity;
9248  }
9249 
9250  return ((1 - $price / $redemption) / $daysBetweenSettlementAndMaturity);
9251  }
9252  return self::$_errorCodes['value'];
9253  } // function DISC()
9254 
9255 
9275  public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis=0) {
9276  $settlement = self::flattenSingleValue($settlement);
9277  $maturity = self::flattenSingleValue($maturity);
9278  $discount = (float) self::flattenSingleValue($discount);
9279  $redemption = (float) self::flattenSingleValue($redemption);
9280  $basis = (int) self::flattenSingleValue($basis);
9281 
9282  // Validate
9283  if ((is_numeric($discount)) && (is_numeric($redemption)) && (is_numeric($basis))) {
9284  if (($discount <= 0) || ($redemption <= 0)) {
9285  return self::$_errorCodes['num'];
9286  }
9287  $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis);
9288  if (!is_numeric($daysBetweenSettlementAndMaturity)) {
9289  return $daysBetweenSettlementAndMaturity;
9290  }
9291 
9292  return $redemption * (1 - $discount * $daysBetweenSettlementAndMaturity);
9293  }
9294  return self::$_errorCodes['value'];
9295  } // function PRICEDISC()
9296 
9297 
9318  public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis=0) {
9319  $settlement = self::flattenSingleValue($settlement);
9320  $maturity = self::flattenSingleValue($maturity);
9321  $issue = self::flattenSingleValue($issue);
9322  $rate = self::flattenSingleValue($rate);
9323  $yield = self::flattenSingleValue($yield);
9324  $basis = (int) self::flattenSingleValue($basis);
9325 
9326  // Validate
9327  if (is_numeric($rate) && is_numeric($yield)) {
9328  if (($rate <= 0) || ($yield <= 0)) {
9329  return self::$_errorCodes['num'];
9330  }
9331  $daysPerYear = self::_daysPerYear(self::YEAR($settlement),$basis);
9332  if (!is_numeric($daysPerYear)) {
9333  return $daysPerYear;
9334  }
9335  $daysBetweenIssueAndSettlement = self::YEARFRAC($issue, $settlement, $basis);
9336  if (!is_numeric($daysBetweenIssueAndSettlement)) {
9337  return $daysBetweenIssueAndSettlement;
9338  }
9339  $daysBetweenIssueAndSettlement *= $daysPerYear;
9340  $daysBetweenIssueAndMaturity = self::YEARFRAC($issue, $maturity, $basis);
9341  if (!is_numeric($daysBetweenIssueAndMaturity)) {
9342  return $daysBetweenIssueAndMaturity;
9343  }
9344  $daysBetweenIssueAndMaturity *= $daysPerYear;
9345  $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis);
9346  if (!is_numeric($daysBetweenSettlementAndMaturity)) {
9347  return $daysBetweenSettlementAndMaturity;
9348  }
9349  $daysBetweenSettlementAndMaturity *= $daysPerYear;
9350 
9351  return ((100 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate * 100)) /
9352  (1 + (($daysBetweenSettlementAndMaturity / $daysPerYear) * $yield)) -
9353  (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate * 100));
9354  }
9355  return self::$_errorCodes['value'];
9356  } // function PRICEMAT()
9357 
9358 
9378  public static function RECEIVED($settlement, $maturity, $investment, $discount, $basis=0) {
9379  $settlement = self::flattenSingleValue($settlement);
9380  $maturity = self::flattenSingleValue($maturity);
9381  $investment = (float) self::flattenSingleValue($investment);
9382  $discount = (float) self::flattenSingleValue($discount);
9383  $basis = (int) self::flattenSingleValue($basis);
9384 
9385  // Validate
9386  if ((is_numeric($investment)) && (is_numeric($discount)) && (is_numeric($basis))) {
9387  if (($investment <= 0) || ($discount <= 0)) {
9388  return self::$_errorCodes['num'];
9389  }
9390  $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis);
9391  if (!is_numeric($daysBetweenSettlementAndMaturity)) {
9392  return $daysBetweenSettlementAndMaturity;
9393  }
9394 
9395  return $investment / ( 1 - ($discount * $daysBetweenSettlementAndMaturity));
9396  }
9397  return self::$_errorCodes['value'];
9398  } // function RECEIVED()
9399 
9400 
9420  public static function INTRATE($settlement, $maturity, $investment, $redemption, $basis=0) {
9421  $settlement = self::flattenSingleValue($settlement);
9422  $maturity = self::flattenSingleValue($maturity);
9423  $investment = (float) self::flattenSingleValue($investment);
9424  $redemption = (float) self::flattenSingleValue($redemption);
9425  $basis = (int) self::flattenSingleValue($basis);
9426 
9427  // Validate
9428  if ((is_numeric($investment)) && (is_numeric($redemption)) && (is_numeric($basis))) {
9429  if (($investment <= 0) || ($redemption <= 0)) {
9430  return self::$_errorCodes['num'];
9431  }
9432  $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis);
9433  if (!is_numeric($daysBetweenSettlementAndMaturity)) {
9434  return $daysBetweenSettlementAndMaturity;
9435  }
9436 
9437  return (($redemption / $investment) - 1) / ($daysBetweenSettlementAndMaturity);
9438  }
9439  return self::$_errorCodes['value'];
9440  } // function INTRATE()
9441 
9442 
9455  public static function TBILLEQ($settlement, $maturity, $discount) {
9456  $settlement = self::flattenSingleValue($settlement);
9457  $maturity = self::flattenSingleValue($maturity);
9458  $discount = self::flattenSingleValue($discount);
9459 
9460  // Use TBILLPRICE for validation
9461  $testValue = self::TBILLPRICE($settlement, $maturity, $discount);
9462  if (is_string($testValue)) {
9463  return $testValue;
9464  }
9465 
9466  if (is_string($maturity = self::_getDateValue($maturity))) {
9467  return self::$_errorCodes['value'];
9468  }
9469  ++$maturity;
9470 
9471  $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity);
9472  $daysBetweenSettlementAndMaturity *= 360;
9473 
9474  return (365 * $discount) / (360 - ($discount * ($daysBetweenSettlementAndMaturity)));
9475  } // function TBILLEQ()
9476 
9477 
9490  public static function TBILLPRICE($settlement, $maturity, $discount) {
9491  $settlement = self::flattenSingleValue($settlement);
9492  $maturity = self::flattenSingleValue($maturity);
9493  $discount = self::flattenSingleValue($discount);
9494 
9495  if (is_string($maturity = self::_getDateValue($maturity))) {
9496  return self::$_errorCodes['value'];
9497  }
9498  ++$maturity;
9499 
9500  // Validate
9501  if (is_numeric($discount)) {
9502  if ($discount <= 0) {
9503  return self::$_errorCodes['num'];
9504  }
9505 
9506  $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity);
9507  if (!is_numeric($daysBetweenSettlementAndMaturity)) {
9508  return $daysBetweenSettlementAndMaturity;
9509  }
9510  $daysBetweenSettlementAndMaturity *= 360;
9511  if ($daysBetweenSettlementAndMaturity > 360) {
9512  return self::$_errorCodes['num'];
9513  }
9514 
9515  $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360));
9516  if ($price <= 0) {
9517  return self::$_errorCodes['num'];
9518  }
9519  return $price;
9520  }
9521  return self::$_errorCodes['value'];
9522  } // function TBILLPRICE()
9523 
9524 
9537  public static function TBILLYIELD($settlement, $maturity, $price) {
9538  $settlement = self::flattenSingleValue($settlement);
9539  $maturity = self::flattenSingleValue($maturity);
9540  $price = self::flattenSingleValue($price);
9541 
9542  // Validate
9543  if (is_numeric($price)) {
9544  if ($price <= 0) {
9545  return self::$_errorCodes['num'];
9546  }
9547 
9548  $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity);
9549  if (!is_numeric($daysBetweenSettlementAndMaturity)) {
9550  return $daysBetweenSettlementAndMaturity;
9551  }
9552 
9553  $daysBetweenSettlementAndMaturity *= 360;
9554 // Sometimes we need to add 1, sometimes not. I haven't yet worked out the rule which determines this.
9555  ++$daysBetweenSettlementAndMaturity;
9556  if ($daysBetweenSettlementAndMaturity > 360) {
9557  return self::$_errorCodes['num'];
9558  }
9559 
9560  return ((100 - $price) / $price) * (360 / $daysBetweenSettlementAndMaturity);
9561  }
9562  return self::$_errorCodes['value'];
9563  } // function TBILLYIELD()
9564 
9565 
9576  public static function SLN($cost, $salvage, $life) {
9577  $cost = self::flattenSingleValue($cost);
9578  $salvage = self::flattenSingleValue($salvage);
9579  $life = self::flattenSingleValue($life);
9580 
9581  // Calculate
9582  if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life))) {
9583  if ($life < 0) {
9584  return self::$_errorCodes['num'];
9585  }
9586  return ($cost - $salvage) / $life;
9587  }
9588  return self::$_errorCodes['value'];
9589  } // function SLN()
9590 
9591 
9612  public static function YIELDMAT($settlement, $maturity, $issue, $rate, $price, $basis=0) {
9613  $settlement = self::flattenSingleValue($settlement);
9614  $maturity = self::flattenSingleValue($maturity);
9615  $issue = self::flattenSingleValue($issue);
9616  $rate = self::flattenSingleValue($rate);
9617  $price = self::flattenSingleValue($price);
9618  $basis = (int) self::flattenSingleValue($basis);
9619 
9620  // Validate
9621  if (is_numeric($rate) && is_numeric($price)) {
9622  if (($rate <= 0) || ($price <= 0)) {
9623  return self::$_errorCodes['num'];
9624  }
9625  $daysPerYear = self::_daysPerYear(self::YEAR($settlement),$basis);
9626  if (!is_numeric($daysPerYear)) {
9627  return $daysPerYear;
9628  }
9629  $daysBetweenIssueAndSettlement = self::YEARFRAC($issue, $settlement, $basis);
9630  if (!is_numeric($daysBetweenIssueAndSettlement)) {
9631  return $daysBetweenIssueAndSettlement;
9632  }
9633  $daysBetweenIssueAndSettlement *= $daysPerYear;
9634  $daysBetweenIssueAndMaturity = self::YEARFRAC($issue, $maturity, $basis);
9635  if (!is_numeric($daysBetweenIssueAndMaturity)) {
9636  return $daysBetweenIssueAndMaturity;
9637  }
9638  $daysBetweenIssueAndMaturity *= $daysPerYear;
9639  $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis);
9640  if (!is_numeric($daysBetweenSettlementAndMaturity)) {
9641  return $daysBetweenSettlementAndMaturity;
9642  }
9643  $daysBetweenSettlementAndMaturity *= $daysPerYear;
9644 
9645  return ((1 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate) - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) /
9646  (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) *
9647  ($daysPerYear / $daysBetweenSettlementAndMaturity);
9648  }
9649  return self::$_errorCodes['value'];
9650  } // function YIELDMAT()
9651 
9652 
9672  public static function YIELDDISC($settlement, $maturity, $price, $redemption, $basis=0) {
9673  $settlement = self::flattenSingleValue($settlement);
9674  $maturity = self::flattenSingleValue($maturity);
9675  $price = self::flattenSingleValue($price);
9676  $redemption = self::flattenSingleValue($redemption);
9677  $basis = (int) self::flattenSingleValue($basis);
9678 
9679  // Validate
9680  if (is_numeric($price) && is_numeric($redemption)) {
9681  if (($price <= 0) || ($redemption <= 0)) {
9682  return self::$_errorCodes['num'];
9683  }
9684  $daysPerYear = self::_daysPerYear(self::YEAR($settlement),$basis);
9685  if (!is_numeric($daysPerYear)) {
9686  return $daysPerYear;
9687  }
9688  $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity,$basis);
9689  if (!is_numeric($daysBetweenSettlementAndMaturity)) {
9690  return $daysBetweenSettlementAndMaturity;
9691  }
9692  $daysBetweenSettlementAndMaturity *= $daysPerYear;
9693 
9694  return (($redemption - $price) / $price) * ($daysPerYear / $daysBetweenSettlementAndMaturity);
9695  }
9696  return self::$_errorCodes['value'];
9697  } // function YIELDDISC()
9698 
9699 
9711  public static function CELL_ADDRESS($row, $column, $relativity=1, $referenceStyle=True, $sheetText='') {
9713  $column = self::flattenSingleValue($column);
9714  $relativity = self::flattenSingleValue($relativity);
9715  $sheetText = self::flattenSingleValue($sheetText);
9716 
9717  if ($sheetText > '') {
9718  if (strpos($sheetText,' ') !== False) { $sheetText = "'".$sheetText."'"; }
9719  $sheetText .='!';
9720  }
9721  if ((!is_bool($referenceStyle)) || $referenceStyle) {
9722  $rowRelative = $columnRelative = '$';
9723  $column = PHPExcel_Cell::stringFromColumnIndex($column-1);
9724  if (($relativity == 2) || ($relativity == 4)) { $columnRelative = ''; }
9725  if (($relativity == 3) || ($relativity == 4)) { $rowRelative = ''; }
9726  return $sheetText.$columnRelative.$column.$rowRelative.$row;
9727  } else {
9728  if (($relativity == 2) || ($relativity == 4)) { $column = '['.$column.']'; }
9729  if (($relativity == 3) || ($relativity == 4)) { $row = '['.$row.']'; }
9730  return $sheetText.'R'.$row.'C'.$column;
9731  }
9732  } // function CELL_ADDRESS()
9733 
9734 
9735  public static function COLUMN($cellAddress=Null) {
9736  if (is_null($cellAddress) || $cellAddress === '') {
9737  return 0;
9738  }
9739 
9740  foreach($cellAddress as $columnKey => $value) {
9741  return PHPExcel_Cell::columnIndexFromString($columnKey);
9742  }
9743  } // function COLUMN()
9744 
9745 
9746  public static function ROW($cellAddress=Null) {
9747  if ($cellAddress === Null) {
9748  return 0;
9749  }
9750 
9751  foreach($cellAddress as $columnKey => $rowValue) {
9752  foreach($rowValue as $rowKey => $cellValue) {
9753  return $rowKey;
9754  }
9755  }
9756  } // function ROW()
9757 
9758 
9759  public static function OFFSET($cellAddress=Null,$rows=0,$columns=0,$height=null,$width=null) {
9760  if ($cellAddress == Null) {
9761  return 0;
9762  }
9763 
9764  foreach($cellAddress as $startColumnKey => $rowValue) {
9765  $startColumnIndex = PHPExcel_Cell::columnIndexFromString($startColumnKey);
9766  foreach($rowValue as $startRowKey => $cellValue) {
9767  break 2;
9768  }
9769  }
9770 
9771  foreach($cellAddress as $endColumnKey => $rowValue) {
9772  foreach($rowValue as $endRowKey => $cellValue) {
9773  }
9774  }
9775  $endColumnIndex = PHPExcel_Cell::columnIndexFromString($endColumnKey);
9776 
9777  $startColumnIndex += --$columns;
9778  $startRowKey += $rows;
9779 
9780  if ($width == null) {
9781  $endColumnIndex += $columns -1;
9782  } else {
9783  $endColumnIndex = $startColumnIndex + $width;
9784  }
9785  if ($height == null) {
9786  $endRowKey += $rows;
9787  } else {
9788  $endRowKey = $startRowKey + $height -1;
9789  }
9790 
9791  if (($startColumnIndex < 0) || ($startRowKey <= 0)) {
9792  return self::$_errorCodes['reference'];
9793  }
9794 
9795  $startColumnKey = PHPExcel_Cell::stringFromColumnIndex($startColumnIndex);
9796  $endColumnKey = PHPExcel_Cell::stringFromColumnIndex($endColumnIndex);
9797 
9798  $startCell = $startColumnKey.$startRowKey;
9799  $endCell = $endColumnKey.$endRowKey;
9800 
9801  if ($startCell == $endCell) {
9802  return $startColumnKey.$startRowKey;
9803  } else {
9804  return $startColumnKey.$startRowKey.':'.$endColumnKey.$endRowKey;
9805  }
9806  } // function OFFSET()
9807 
9808 
9809  public static function CHOOSE() {
9810  $chooseArgs = func_get_args();
9811  $chosenEntry = self::flattenSingleValue(array_shift($chooseArgs));
9812  $entryCount = count($chooseArgs) - 1;
9813 
9814  if ((is_numeric($chosenEntry)) && (!is_bool($chosenEntry))) {
9815  --$chosenEntry;
9816  } else {
9817  return self::$_errorCodes['value'];
9818  }
9819  $chosenEntry = floor($chosenEntry);
9820  if (($chosenEntry <= 0) || ($chosenEntry > $entryCount)) {
9821  return self::$_errorCodes['value'];
9822  }
9823 
9824  if (is_array($chooseArgs[$chosenEntry])) {
9825  return self::flattenArray($chooseArgs[$chosenEntry]);
9826  } else {
9827  return $chooseArgs[$chosenEntry];
9828  }
9829  } // function CHOOSE()
9830 
9831 
9840  public static function MATCH($lookup_value, $lookup_array, $match_type=1) {
9841 
9842  // flatten the lookup_array
9843  $lookup_array = self::flattenArray($lookup_array);
9844 
9845  // flatten lookup_value since it may be a cell reference to a value or the value itself
9846  $lookup_value = self::flattenSingleValue($lookup_value);
9847 
9848  // MATCH is not case sensitive
9849  $lookup_value = strtolower($lookup_value);
9850 
9851  /*
9852  echo "--------------------<br>looking for $lookup_value in <br>";
9853  print_r($lookup_array);
9854  echo "<br>";
9855  //return 1;
9856  /**/
9857 
9858  // **
9859  // check inputs
9860  // **
9861  // lookup_value type has to be number, text, or logical values
9862  if (!is_numeric($lookup_value) && !is_string($lookup_value) && !is_bool($lookup_value)){
9863  // error: lookup_array should contain only number, text, or logical values
9864  //echo "error: lookup_array should contain only number, text, or logical values<br>";
9865  return self::$_errorCodes['na'];
9866  }
9867 
9868  // match_type is 0, 1 or -1
9869  if ($match_type!==0 && $match_type!==-1 && $match_type!==1){
9870  // error: wrong value for match_type
9871  //echo "error: wrong value for match_type<br>";
9872  return self::$_errorCodes['na'];
9873  }
9874 
9875  // lookup_array should not be empty
9876  if (sizeof($lookup_array)<=0){
9877  // error: empty range
9878  //echo "error: empty range ".sizeof($lookup_array)."<br>";
9879  return self::$_errorCodes['na'];
9880  }
9881 
9882  // lookup_array should contain only number, text, or logical values
9883  for ($i=0;$i<sizeof($lookup_array);++$i){
9884  // check the type of the value
9885  if (!is_numeric($lookup_array[$i]) && !is_string($lookup_array[$i]) && !is_bool($lookup_array[$i])){
9886  // error: lookup_array should contain only number, text, or logical values
9887  //echo "error: lookup_array should contain only number, text, or logical values<br>";
9888  return self::$_errorCodes['na'];
9889  }
9890  // convert tpo lowercase
9891  if (is_string($lookup_array[$i]))
9892  $lookup_array[$i] = strtolower($lookup_array[$i]);
9893  }
9894 
9895  // if match_type is 1 or -1, the list has to be ordered
9896  if($match_type==1 || $match_type==-1){
9897  // **
9898  // iniitialization
9899  // store the last value
9900  $iLastValue=$lookup_array[0];
9901  // **
9902  // loop on the cells
9903  for ($i=0;$i<sizeof($lookup_array);++$i){
9904  // check ascending order
9905  if(($match_type==1 && $lookup_array[$i]<$iLastValue)
9906  // OR check descending order
9907  || ($match_type==-1 && $lookup_array[$i]>$iLastValue)){
9908  // error: list is not ordered correctly
9909  //echo "error: list is not ordered correctly<br>";
9910  return self::$_errorCodes['na'];
9911  }
9912  }
9913  }
9914  // **
9915  // find the match
9916  // **
9917  // loop on the cells
9918  for ($i=0; $i < sizeof($lookup_array); ++$i){
9919  // if match_type is 0 <=> find the first value that is exactly equal to lookup_value
9920  if ($match_type==0 && $lookup_array[$i]==$lookup_value){
9921  // this is the exact match
9922  return $i+1;
9923  }
9924  // if match_type is -1 <=> find the smallest value that is greater than or equal to lookup_value
9925  if ($match_type==-1 && $lookup_array[$i] < $lookup_value){
9926  if ($i<1){
9927  // 1st cell was allready smaller than the lookup_value
9928  break;
9929  }
9930  else
9931  // the previous cell was the match
9932  return $i;
9933  }
9934  // if match_type is 1 <=> find the largest value that is less than or equal to lookup_value
9935  if ($match_type==1 && $lookup_array[$i] > $lookup_value){
9936  if ($i<1){
9937  // 1st cell was allready bigger than the lookup_value
9938  break;
9939  }
9940  else
9941  // the previous cell was the match
9942  return $i;
9943  }
9944  }
9945  // unsuccessful in finding a match, return #N/A error value
9946  //echo "unsuccessful in finding a match<br>";
9947  return self::$_errorCodes['na'];
9948  } // function MATCH()
9949 
9950 
9960  public static function INDEX($arrayValues,$rowNum = 0,$columnNum = 0) {
9961 
9962  if (($rowNum < 0) || ($columnNum < 0)) {
9963  return self::$_errorCodes['value'];
9964  }
9965 
9966  $rowKeys = array_keys($arrayValues);
9967  $columnKeys = array_keys($arrayValues[$rowKeys[0]]);
9968  if ($columnNum > count($columnKeys)) {
9969  return self::$_errorCodes['value'];
9970  } elseif ($columnNum == 0) {
9971  if ($rowNum == 0) {
9972  return $arrayValues;
9973  }
9974  $rowNum = $rowKeys[--$rowNum];
9975  $returnArray = array();
9976  foreach($arrayValues as $arrayColumn) {
9977  $returnArray[] = $arrayColumn[$rowNum];
9978  }
9979  return $returnArray;
9980  }
9981  $columnNum = $columnKeys[--$columnNum];
9982  if ($rowNum > count($rowKeys)) {
9983  return self::$_errorCodes['value'];
9984  } elseif ($rowNum == 0) {
9985  return $arrayValues[$columnNum];
9986  }
9987  $rowNum = $rowKeys[--$rowNum];
9988 
9989  return $arrayValues[$rowNum][$columnNum];
9990  } // function INDEX()
9991 
9992 
10004  public static function SYD($cost, $salvage, $life, $period) {
10005  $cost = self::flattenSingleValue($cost);
10006  $salvage = self::flattenSingleValue($salvage);
10007  $life = self::flattenSingleValue($life);
10008  $period = self::flattenSingleValue($period);
10009 
10010  // Calculate
10011  if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period))) {
10012  if (($life < 1) || ($salvage < $life) || ($period > $life)) {
10013  return self::$_errorCodes['num'];
10014  }
10015  return (($cost - $salvage) * ($life - $period + 1) * 2) / ($life * ($life + 1));
10016  }
10017  return self::$_errorCodes['value'];
10018  } // function SYD()
10019 
10020 
10029  public static function TRANSPOSE($matrixData) {
10030  $returnMatrix = array();
10031  if (!is_array($matrixData)) { $matrixData = array(array($matrixData)); }
10032 
10033  $column = 0;
10034  foreach($matrixData as $matrixRow) {
10035  $row = 0;
10036  foreach($matrixRow as $matrixCell) {
10037  $returnMatrix[$column][$row] = $matrixCell;
10038  ++$row;
10039  }
10040  ++$column;
10041  }
10042  return $returnMatrix;
10043  } // function TRANSPOSE()
10044 
10045 
10053  public static function MMULT($matrixData1,$matrixData2) {
10054  $matrixAData = $matrixBData = array();
10055  if (!is_array($matrixData1)) { $matrixData1 = array(array($matrixData1)); }
10056  if (!is_array($matrixData2)) { $matrixData2 = array(array($matrixData2)); }
10057 
10058  $rowA = 0;
10059  foreach($matrixData1 as $matrixRow) {
10060  $columnA = 0;
10061  foreach($matrixRow as $matrixCell) {
10062  if ((is_string($matrixCell)) || ($matrixCell === null)) {
10063  return self::$_errorCodes['value'];
10064  }
10065  $matrixAData[$rowA][$columnA] = $matrixCell;
10066  ++$columnA;
10067  }
10068  ++$rowA;
10069  }
10070  try {
10071  $matrixA = new Matrix($matrixAData);
10072  $rowB = 0;
10073  foreach($matrixData2 as $matrixRow) {
10074  $columnB = 0;
10075  foreach($matrixRow as $matrixCell) {
10076  if ((is_string($matrixCell)) || ($matrixCell === null)) {
10077  return self::$_errorCodes['value'];
10078  }
10079  $matrixBData[$rowB][$columnB] = $matrixCell;
10080  ++$columnB;
10081  }
10082  ++$rowB;
10083  }
10084  $matrixB = new Matrix($matrixBData);
10085 
10086  if (($rowA != $columnB) || ($rowB != $columnA)) {
10087  return self::$_errorCodes['value'];
10088  }
10089 
10090  return $matrixA->times($matrixB)->getArray();
10091  } catch (Exception $ex) {
10092  return self::$_errorCodes['value'];
10093  }
10094  } // function MMULT()
10095 
10096 
10103  public static function MINVERSE($matrixValues) {
10104  $matrixData = array();
10105  if (!is_array($matrixValues)) { $matrixValues = array(array($matrixValues)); }
10106 
10107  $row = $maxColumn = 0;
10108  foreach($matrixValues as $matrixRow) {
10109  $column = 0;
10110  foreach($matrixRow as $matrixCell) {
10111  if ((is_string($matrixCell)) || ($matrixCell === null)) {
10112  return self::$_errorCodes['value'];
10113  }
10114  $matrixData[$column][$row] = $matrixCell;
10115  ++$column;
10116  }
10117  if ($column > $maxColumn) { $maxColumn = $column; }
10118  ++$row;
10119  }
10120  if ($row != $maxColumn) { return self::$_errorCodes['value']; }
10121 
10122  try {
10123  $matrix = new Matrix($matrixData);
10124  return $matrix->inverse()->getArray();
10125  } catch (Exception $ex) {
10126  return self::$_errorCodes['value'];
10127  }
10128  } // function MINVERSE()
10129 
10130 
10137  public static function MDETERM($matrixValues) {
10138  $matrixData = array();
10139  if (!is_array($matrixValues)) { $matrixValues = array(array($matrixValues)); }
10140 
10141  $row = $maxColumn = 0;
10142  foreach($matrixValues as $matrixRow) {
10143  $column = 0;
10144  foreach($matrixRow as $matrixCell) {
10145  if ((is_string($matrixCell)) || ($matrixCell === null)) {
10146  return self::$_errorCodes['value'];
10147  }
10148  $matrixData[$column][$row] = $matrixCell;
10149  ++$column;
10150  }
10151  if ($column > $maxColumn) { $maxColumn = $column; }
10152  ++$row;
10153  }
10154  if ($row != $maxColumn) { return self::$_errorCodes['value']; }
10155 
10156  try {
10157  $matrix = new Matrix($matrixData);
10158  return $matrix->det();
10159  } catch (Exception $ex) {
10160  return self::$_errorCodes['value'];
10161  }
10162  } // function MDETERM()
10163 
10164 
10171  public static function SUMX2MY2($matrixData1,$matrixData2) {
10172  $array1 = self::flattenArray($matrixData1);
10173  $array2 = self::flattenArray($matrixData2);
10174  $count1 = count($array1);
10175  $count2 = count($array2);
10176  if ($count1 < $count2) {
10177  $count = $count1;
10178  } else {
10179  $count = $count2;
10180  }
10181 
10182  $result = 0;
10183  for ($i = 0; $i < $count; ++$i) {
10184  if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
10185  ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
10186  $result += ($array1[$i] * $array1[$i]) - ($array2[$i] * $array2[$i]);
10187  }
10188  }
10189 
10190  return $result;
10191  } // function SUMX2MY2()
10192 
10193 
10200  public static function SUMX2PY2($matrixData1,$matrixData2) {
10201  $array1 = self::flattenArray($matrixData1);
10202  $array2 = self::flattenArray($matrixData2);
10203  $count1 = count($array1);
10204  $count2 = count($array2);
10205  if ($count1 < $count2) {
10206  $count = $count1;
10207  } else {
10208  $count = $count2;
10209  }
10210 
10211  $result = 0;
10212  for ($i = 0; $i < $count; ++$i) {
10213  if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
10214  ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
10215  $result += ($array1[$i] * $array1[$i]) + ($array2[$i] * $array2[$i]);
10216  }
10217  }
10218 
10219  return $result;
10220  } // function SUMX2PY2()
10221 
10222 
10229  public static function SUMXMY2($matrixData1,$matrixData2) {
10230  $array1 = self::flattenArray($matrixData1);
10231  $array2 = self::flattenArray($matrixData2);
10232  $count1 = count($array1);
10233  $count2 = count($array2);
10234  if ($count1 < $count2) {
10235  $count = $count1;
10236  } else {
10237  $count = $count2;
10238  }
10239 
10240  $result = 0;
10241  for ($i = 0; $i < $count; ++$i) {
10242  if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
10243  ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
10244  $result += ($array1[$i] - $array2[$i]) * ($array1[$i] - $array2[$i]);
10245  }
10246  }
10247 
10248  return $result;
10249  } // function SUMXMY2()
10250 
10251 
10261  public static function VLOOKUP($lookup_value, $lookup_array, $index_number, $not_exact_match=true) {
10262  // index_number must be greater than or equal to 1
10263  if ($index_number < 1) {
10264  return self::$_errorCodes['value'];
10265  }
10266 
10267  // index_number must be less than or equal to the number of columns in lookup_array
10268  if ($index_number > count($lookup_array)) {
10269  return self::$_errorCodes['reference'];
10270  }
10271 
10272  // re-index lookup_array with numeric keys starting at 1
10273  array_unshift($lookup_array, array());
10274  $lookup_array = array_slice(array_values($lookup_array), 1, count($lookup_array), true);
10275 
10276  // look for an exact match
10277  $row_number = array_search($lookup_value, $lookup_array[1]);
10278 
10279  // if an exact match is required, we have what we need to return an appropriate response
10280  if ($not_exact_match == false) {
10281  if ($row_number === false) {
10282  return self::$_errorCodes['na'];
10283  } else {
10284  return $lookup_array[$index_number][$row_number];
10285  }
10286  }
10287 
10288  // TODO: The VLOOKUP spec in Excel states that, at this point, we should search for
10289  // the highest value that is less than lookup_value. However, documentation on how string
10290  // values should be treated here is sparse.
10291  return self::$_errorCodes['na'];
10292  } // function VLOOKUP()
10293 
10302  public static function LOOKUP($lookup_value, $lookup_vector, $result_vector=null) {
10303 
10304  // check for LOOKUP Syntax (view Excel documentation)
10305  if( is_null($result_vector) )
10306  {
10307  // TODO: Syntax 2 (array)
10308  } else {
10309  // Syntax 1 (vector)
10310  // get key (column or row) of lookup_vector
10311  $kl = key($lookup_vector);
10312  // check if lookup_value exists in lookup_vector
10313  if( in_array($lookup_value, $lookup_vector[$kl]) )
10314  {
10315  // FOUND IT! Get key of lookup_vector
10316  $k_res = array_search($lookup_value, $lookup_vector[$kl]);
10317  } else {
10318  // value NOT FOUND
10319  // Get the smallest value in lookup_vector
10320  // The LOOKUP spec in Excel states --> IMPORTANT - The values in lookup_vector must be placed in ascending order!
10321  $ksv = key($lookup_vector[$kl]);
10322  $smallest_value = $lookup_vector[$kl][$ksv];
10323  // If lookup_value is smaller than the smallest value in lookup_vector, LOOKUP gives the #N/A error value.
10324  if( $lookup_value < $smallest_value )
10325  {
10326  return self::$_errorCodes['na'];
10327  } else {
10328  // If LOOKUP can't find the lookup_value, it matches the largest value in lookup_vector that is less than or equal to lookup_value.
10329  // IMPORTANT : In Excel Documentation is not clear what happen if lookup_value is text!
10330  foreach( $lookup_vector[$kl] AS $kk => $value )
10331  {
10332  if( $lookup_value >= $value )
10333  {
10334  $k_res = $kk;
10335  }
10336  }
10337  }
10338  }
10339 
10340  // Returns a value from the same position in result_vector
10341  // get key (column or row) of result_vector
10342  $kr = key($result_vector);
10343  if( isset($result_vector[$kr][$k_res]) )
10344  {
10345  return $result_vector[$kr][$k_res];
10346  } else {
10347  // TODO: In Excel Documentation is not clear what happen here...
10348  }
10349  }
10350  } // function LOOKUP()
10351 
10352 
10359  public static function flattenArray($array) {
10360  if(!is_array ( $array ) ){
10361  $array = array ( $array );
10362  }
10363 
10364  $arrayValues = array();
10365 
10366  foreach ($array as $value) {
10367  if (is_scalar($value)) {
10368  $arrayValues[] = self::flattenSingleValue($value);
10369  } elseif (is_array($value)) {
10370  $arrayValues = array_merge($arrayValues, self::flattenArray($value));
10371  } else {
10372  $arrayValues[] = $value;
10373  }
10374  }
10375 
10376  return $arrayValues;
10377  } // function flattenArray()
10378 
10379 
10386  public static function flattenSingleValue($value = '') {
10387  if (is_array($value)) {
10388  $value = self::flattenSingleValue(array_pop($value));
10389  }
10390  return $value;
10391  } // function flattenSingleValue()
10392 
10393 } // class PHPExcel_Calculation_Functions
10394 
10395 
10396 //
10397 // There are a few mathematical functions that aren't available on all versions of PHP for all platforms
10398 // These functions aren't available in Windows implementations of PHP prior to version 5.3.0
10399 // So we test if they do exist for this version of PHP/operating platform; and if not we create them
10400 //
10401 if (!function_exists('acosh')) {
10402  function acosh($x) {
10403  return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2));
10404  } // function acosh()
10405 }
10406 
10407 if (!function_exists('asinh')) {
10408  function asinh($x) {
10409  return log($x + sqrt(1 + $x * $x));
10410  } // function asinh()
10411 }
10412 
10413 if (!function_exists('atanh')) {
10414  function atanh($x) {
10415  return (log(1 + $x) - log(1 - $x)) / 2;
10416  } // function atanh()
10417 }
10418 
10419 if (!function_exists('money_format')) {
10420  function money_format($format, $number) {
10421  $regex = array( '/%((?:[\^!\-]|\+|\(|\=.)*)([0-9]+)?(?:#([0-9]+))?',
10422  '(?:\.([0-9]+))?([in%])/'
10423  );
10424  $regex = implode('', $regex);
10425  if (setlocale(LC_MONETARY, null) == '') {
10426  setlocale(LC_MONETARY, '');
10427  }
10428  $locale = localeconv();
10429  $number = floatval($number);
10430  if (!preg_match($regex, $format, $fmatch)) {
10431  trigger_error("No format specified or invalid format", E_USER_WARNING);
10432  return $number;
10433  }
10434  $flags = array( 'fillchar' => preg_match('/\=(.)/', $fmatch[1], $match) ? $match[1] : ' ',
10435  'nogroup' => preg_match('/\^/', $fmatch[1]) > 0,
10436  'usesignal' => preg_match('/\+|\(/', $fmatch[1], $match) ? $match[0] : '+',
10437  'nosimbol' => preg_match('/\!/', $fmatch[1]) > 0,
10438  'isleft' => preg_match('/\-/', $fmatch[1]) > 0
10439  );
10440  $width = trim($fmatch[2]) ? (int)$fmatch[2] : 0;
10441  $left = trim($fmatch[3]) ? (int)$fmatch[3] : 0;
10442  $right = trim($fmatch[4]) ? (int)$fmatch[4] : $locale['int_frac_digits'];
10443  $conversion = $fmatch[5];
10444  $positive = true;
10445  if ($number < 0) {
10446  $positive = false;
10447  $number *= -1;
10448  }
10449  $letter = $positive ? 'p' : 'n';
10450  $prefix = $suffix = $cprefix = $csuffix = $signal = '';
10451  if (!$positive) {
10452  $signal = $locale['negative_sign'];
10453  switch (true) {
10454  case $locale['n_sign_posn'] == 0 || $flags['usesignal'] == '(':
10455  $prefix = '(';
10456  $suffix = ')';
10457  break;
10458  case $locale['n_sign_posn'] == 1:
10459  $prefix = $signal;
10460  break;
10461  case $locale['n_sign_posn'] == 2:
10462  $suffix = $signal;
10463  break;
10464  case $locale['n_sign_posn'] == 3:
10465  $cprefix = $signal;
10466  break;
10467  case $locale['n_sign_posn'] == 4:
10468  $csuffix = $signal;
10469  break;
10470  }
10471  }
10472  if (!$flags['nosimbol']) {
10473  $currency = $cprefix;
10474  $currency .= ($conversion == 'i' ? $locale['int_curr_symbol'] : $locale['currency_symbol']);
10475  $currency .= $csuffix;
10476  $currency = iconv('ISO-8859-1','UTF-8',$currency);
10477  } else {
10478  $currency = '';
10479  }
10480  $space = $locale["{$letter}_sep_by_space"] ? ' ' : '';
10481 
10482  $number = number_format($number, $right, $locale['mon_decimal_point'], $flags['nogroup'] ? '' : $locale['mon_thousands_sep'] );
10483  $number = explode($locale['mon_decimal_point'], $number);
10484 
10485  $n = strlen($prefix) + strlen($currency);
10486  if ($left > 0 && $left > $n) {
10487  if ($flags['isleft']) {
10488  $number[0] .= str_repeat($flags['fillchar'], $left - $n);
10489  } else {
10490  $number[0] = str_repeat($flags['fillchar'], $left - $n) . $number[0];
10491  }
10492  }
10493  $number = implode($locale['mon_decimal_point'], $number);
10494  if ($locale["{$letter}_cs_precedes"]) {
10495  $number = $prefix . $currency . $space . $number . $suffix;
10496  } else {
10497  $number = $prefix . $number . $space . $currency . $suffix;
10498  }
10499  if ($width > 0) {
10500  $number = str_pad($number, $width, $flags['fillchar'], $flags['isleft'] ? STR_PAD_RIGHT : STR_PAD_LEFT);
10501  }
10502  $format = str_replace($fmatch[0], $number, $format);
10503  return $format;
10504  } // function money_format()
10505 }