PHPExcel_Calculation
[ class tree: PHPExcel_Calculation ] [ index: PHPExcel_Calculation ] [ all elements ]

Source for file Functions.php

Documentation is available at Functions.php

  1. <?php
  2.  
  3. /**
  4.  * PHPExcel
  5.  *
  6.  * Copyright (c) 2006 - 2008 PHPExcel
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Lesser General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2.1 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Lesser General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Lesser General Public
  19.  * License along with this library; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  21.  *
  22.  * @category   PHPExcel
  23.  * @package    PHPExcel_Calculation
  24.  * @copyright  Copyright (c) 2006 - 2008 PHPExcel (http://www.codeplex.com/PHPExcel)
  25.  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
  26.  * @version    1.6.4, 2008-10-27
  27.  */
  28.  
  29.  
  30. define('EPS'2.22e-16);
  31. define('MAX_VALUE'1.2e308);
  32. define('LOG_GAMMA_X_MAX_VALUE'2.55e305);
  33. define('SQRT2PI'2.5066282746310005024157652848110452530069867406099);
  34. define('XMININ'2.23e-308);
  35. define('MAX_ITERATIONS'150);
  36. define('PRECISION'8.88E-016);
  37. define('EULER'2.71828182845904523536);
  38.  
  39. $savedPrecision ini_get('precision');
  40. if ($savedPrecision 15{
  41.     ini_set('precision',15);
  42. }
  43.  
  44.  
  45. /** PHPExcel_Cell */
  46. require_once 'PHPExcel/Cell.php';
  47.  
  48. /** PHPExcel_Cell_DataType */
  49. require_once 'PHPExcel/Cell/DataType.php';
  50.  
  51. /** PHPExcel_Shared_Date */
  52. require_once 'PHPExcel/Shared/Date.php';
  53.  
  54.  
  55. /**
  56.  * PHPExcel_Calculation_Functions
  57.  *
  58.  * @category   PHPExcel
  59.  * @package    PHPExcel_Calculation
  60.  * @copyright  Copyright (c) 2006 - 2008 PHPExcel (http://www.codeplex.com/PHPExcel)
  61.  */
  62.  
  63.     /** constants */
  64.     const COMPATIBILITY_EXCEL        'Excel';
  65.     const COMPATIBILITY_GNUMERIC    'Gnumeric';
  66.     const COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc';
  67.  
  68.     const RETURNDATE_PHP_NUMERIC 'P';
  69.     const RETURNDATE_PHP_OBJECT 'O';
  70.     const RETURNDATE_EXCEL 'E';
  71.  
  72.  
  73.     /**
  74.      * Compatibility mode to use for error checking and responses
  75.      *
  76.      * @var string 
  77.      */
  78.     private static $compatibilityMode    self::COMPATIBILITY_EXCEL;
  79.  
  80.     /**
  81.      * Data Type to use when returning date values
  82.      *
  83.      * @var integer 
  84.      */
  85.     private static $ReturnDateType    self::RETURNDATE_PHP_NUMERIC;
  86.  
  87.     /**
  88.      * List of error codes
  89.      *
  90.      * @var array 
  91.      */
  92.     private static $_errorCodes    array'null'                => '#NULL!',
  93.                                          'divisionbyzero'    => '#DIV/0!',
  94.                                          'value'            => '#VALUE!',
  95.                                          'reference'        => '#REF!',
  96.                                          'name'                => '#NAME?',
  97.                                          'num'                => '#NUM!',
  98.                                          'na'                => '#N/A'
  99.                                        );
  100.  
  101.  
  102.     /**
  103.      * Set the Compatibility Mode
  104.      *
  105.      * @param     string        $compatibilityMode        Compatibility Mode
  106.      * @return     boolean    (Success or Failure)
  107.      */
  108.     public static function setCompatibilityMode($compatibilityMode{
  109.         if (($compatibilityMode == self::COMPATIBILITY_EXCEL||
  110.             ($compatibilityMode == self::COMPATIBILITY_GNUMERIC||
  111.             ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  112.             self::$compatibilityMode $compatibilityMode;
  113.             return True;
  114.         }
  115.         return False;
  116.     }
  117.  
  118.     /**
  119.      * Return the current Compatibility Mode
  120.      *
  121.      * @return     string        $compatibilityMode        Compatibility Mode
  122.      */
  123.     public static function getCompatibilityMode({
  124.         return self::$compatibilityMode;
  125.     }
  126.  
  127.     /**
  128.      * Set the Return Date Format (Excel, PHP Serialized or PHP Object)
  129.      *
  130.      * @param     integer    $returnDateType            Return Date Format
  131.      * @return     boolean                            Success or failure
  132.      */
  133.     public static function setReturnDateType($returnDateType{
  134.         if (($returnDateType == self::RETURNDATE_PHP_NUMERIC||
  135.             ($returnDateType == self::RETURNDATE_PHP_OBJECT||
  136.             ($returnDateType == self::RETURNDATE_EXCEL)) {
  137.             self::$ReturnDateType $returnDateType;
  138.             return True;
  139.         }
  140.         return False;
  141.     }    //    function setReturnDateType()
  142.  
  143.  
  144.     /**
  145.      * Return the Return Date Format (Excel, PHP Serialized or PHP Object)
  146.      *
  147.      * @return     integer    $returnDateType            Return Date Format
  148.      */
  149.     public static function getReturnDateType({
  150.         return self::$ReturnDateType;
  151.     }    //    function getReturnDateType()
  152.  
  153.  
  154.     /**
  155.      * DUMMY
  156.      *
  157.      * @return  string    #NAME?
  158.      */
  159.     public static function DUMMY({
  160.         return self::$_errorCodes['name'];
  161.     }
  162.  
  163.     /**
  164.      * NA
  165.      *
  166.      * @return  string    #N/A!
  167.      */
  168.     public static function NA({
  169.         return self::$_errorCodes['na'];
  170.     }
  171.  
  172.     /**
  173.      * LOGICAL_AND
  174.      *
  175.      * Returns boolean TRUE if all its arguments are TRUE; returns FALSE if one or more argument is FALSE.
  176.      *
  177.      *    Booleans arguments are treated as True or False as appropriate
  178.      *    Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  179.      *    If any argument value is a string, or a Null, it is ignored
  180.      *
  181.      *    Quirk of Excel:
  182.      *        String values passed directly to the function rather than through a cell reference
  183.      *            e.g.=AND(1,"A",1)
  184.      *        will return a #VALUE! error, _not_ ignoring the string.
  185.      *        This behaviour is not replicated
  186.      *
  187.      * @param    array of mixed        Data Series
  188.      * @return  boolean 
  189.      */
  190.     public static function LOGICAL_AND({
  191.         // Return value
  192.         $returnValue True;
  193.  
  194.         // Loop through the arguments
  195.         $aArgs self::flattenArray(func_get_args());
  196.         $argCount 0;
  197.         foreach ($aArgs as $arg{
  198.             // Is it a boolean value?
  199.             if (is_bool($arg)) {
  200.                 $returnValue $returnValue && $arg;
  201.                 ++$argCount;
  202.             elseif ((is_numeric($arg)) && (!is_string($arg))) {
  203.                 $returnValue $returnValue && ($arg != 0);
  204.                 ++$argCount;
  205.             }
  206.         }
  207.  
  208.         // Return
  209.         if ($argCount == 0{
  210.             return self::$_errorCodes['value'];
  211.         }
  212.         return $returnValue;
  213.     }
  214.  
  215.     /**
  216.      * LOGICAL_OR
  217.      *
  218.      * Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE.
  219.      *
  220.      *    Booleans arguments are treated as True or False as appropriate
  221.      *    Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  222.      *    If any argument value is a string, or a Null, it is ignored
  223.      *
  224.      * @param    array of mixed        Data Series
  225.      * @return  boolean 
  226.      */
  227.     public static function LOGICAL_OR({
  228.         // Return value
  229.         $returnValue False;
  230.  
  231.         // Loop through the arguments
  232.         $aArgs self::flattenArray(func_get_args());
  233.         $argCount 0;
  234.         foreach ($aArgs as $arg{
  235.             // Is it a boolean value?
  236.             if (is_bool($arg)) {
  237.                 $returnValue $returnValue || $arg;
  238.                 ++$argCount;
  239.             elseif ((is_numeric($arg)) && (!is_string($arg))) {
  240.                 $returnValue $returnValue || ($arg != 0);
  241.                 ++$argCount;
  242.             }
  243.         }
  244.  
  245.         // Return
  246.         if ($argCount == 0{
  247.             return self::$_errorCodes['value'];
  248.         }
  249.         return $returnValue;
  250.     }
  251.  
  252.     /**
  253.      * LOGICAL_FALSE
  254.      *
  255.      * Returns FALSE.
  256.      *
  257.      * @return  boolean 
  258.      */
  259.     public static function LOGICAL_FALSE({
  260.         return False;
  261.     }
  262.  
  263.     /**
  264.      * LOGICAL_TRUE
  265.      *
  266.      * Returns TRUE.
  267.      *
  268.      * @return  boolean 
  269.      */
  270.     public static function LOGICAL_TRUE({
  271.         return True;
  272.     }
  273.  
  274.     /**
  275.      * ATAN2
  276.      *
  277.      * This function calculates the arc tangent of the two variables x and y. It is similar to
  278.      *        calculating the arc tangent of y / x, except that the signs of both arguments are used
  279.      *        to determine the quadrant of the result.
  280.      * Note that Excel reverses the arguments, so we need to reverse them here before calling the
  281.      *        standard PHP atan() function
  282.      *
  283.      * @param    float    $x        Number
  284.      * @param    float    $y        Number
  285.      * @return  float    Square Root of Number * Pi
  286.      */
  287.     public static function REVERSE_ATAN2($x$y{
  288.         $x    self::flattenSingleValue($x);
  289.         $y    self::flattenSingleValue($y);
  290.  
  291.         return atan2($y$x);
  292.     }
  293.  
  294.     /**
  295.      * SUM
  296.      *
  297.      * SUM computes the sum of all the values and cells referenced in the argument list.
  298.      *
  299.      * @param    array of mixed        Data Series
  300.      * @return  float 
  301.      */
  302.     public static function SUM({
  303.         // Return value
  304.         $returnValue 0;
  305.  
  306.         // Loop through the arguments
  307.         $aArgs self::flattenArray(func_get_args());
  308.         foreach ($aArgs as $arg{
  309.             // Is it a numeric value?
  310.             if ((is_numeric($arg)) && (!is_string($arg))) {
  311.                 $returnValue += $arg;
  312.             }
  313.         }
  314.  
  315.         // Return
  316.         return $returnValue;
  317.     }
  318.  
  319.     /**
  320.      * SUMSQ
  321.      *
  322.      * Returns the sum of the squares of the arguments
  323.      *
  324.      * @param    array of mixed        Data Series
  325.      * @return  float 
  326.      */
  327.     public static function SUMSQ({
  328.         // Return value
  329.         $returnValue 0;
  330.  
  331.         // Loop trough arguments
  332.         $aArgs self::flattenArray(func_get_args());
  333.         foreach ($aArgs as $arg{
  334.             // Is it a numeric value?
  335.             if ((is_numeric($arg)) && (!is_string($arg))) {
  336.                 $returnValue += pow($arg,2);
  337.             }
  338.         }
  339.  
  340.         // Return
  341.         return $returnValue;
  342.     }
  343.  
  344.     /**
  345.      * PRODUCT
  346.      *
  347.      * PRODUCT returns the product of all the values and cells referenced in the argument list.
  348.      *
  349.      * @param    array of mixed        Data Series
  350.      * @return  float 
  351.      */
  352.     public static function PRODUCT({
  353.         // Return value
  354.         $returnValue null;
  355.  
  356.         // Loop trough arguments
  357.         $aArgs self::flattenArray(func_get_args());
  358.         foreach ($aArgs as $arg{
  359.             // Is it a numeric value?
  360.             if ((is_numeric($arg)) && (!is_string($arg))) {
  361.                 if (is_null($returnValue)) {
  362.                     $returnValue $arg;
  363.                 else {
  364.                     $returnValue *= $arg;
  365.                 }
  366.             }
  367.         }
  368.  
  369.         // Return
  370.         if (is_null($returnValue)) {
  371.             return 0;
  372.         }
  373.         return $returnValue;
  374.     }
  375.  
  376.     /**
  377.      * QUOTIENT
  378.      *
  379.      * QUOTIENT function returns the integer portion of a division.numerator is the divided number
  380.      * and denominator is the divisor.
  381.      *
  382.      * @param    array of mixed        Data Series
  383.      * @return  float 
  384.      */
  385.     public static function QUOTIENT({
  386.         // Return value
  387.         $returnValue null;
  388.  
  389.         // Loop trough arguments
  390.         $aArgs self::flattenArray(func_get_args());
  391.         foreach ($aArgs as $arg{
  392.             // Is it a numeric value?
  393.             if ((is_numeric($arg)) && (!is_string($arg))) {
  394.                 if (is_null($returnValue)) {
  395.                     if (($returnValue == 0|| ($arg == 0)) {
  396.                         $returnValue 0;
  397.                     else {
  398.                         $returnValue $arg;
  399.                     }
  400.                 else {
  401.                     if (($returnValue == 0|| ($arg == 0)) {
  402.                         $returnValue 0;
  403.                     else {
  404.                         $returnValue /= $arg;
  405.                     }
  406.                 }
  407.             }
  408.         }
  409.  
  410.         // Return
  411.         return intval($returnValue);
  412.     }
  413.  
  414.     /**
  415.      * MIN
  416.      *
  417.      * MIN returns the value of the element of the values passed that has the smallest value,
  418.      * with negative numbers considered smaller than positive numbers.
  419.      *
  420.      * @param    array of mixed        Data Series
  421.      * @return  float 
  422.      */
  423.     public static function MIN({
  424.         // Return value
  425.         $returnValue null;
  426.  
  427.         // Loop trough arguments
  428.         $aArgs self::flattenArray(func_get_args());
  429.         foreach ($aArgs as $arg{
  430.             // Is it a numeric value?
  431.             if ((is_numeric($arg)) && (!is_string($arg))) {
  432.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  433.                     $returnValue $arg;
  434.                 }
  435.             }
  436.         }
  437.  
  438.         // Return
  439.         if(is_null($returnValue)) {
  440.             return 0;
  441.         }
  442.         return $returnValue;
  443.     }
  444.  
  445.     /**
  446.      * MINA
  447.      *
  448.      * Returns the smallest value in a list of arguments, including numbers, text, and logical values
  449.      *
  450.      * @param    array of mixed        Data Series
  451.      * @return  float 
  452.      */
  453.     public static function MINA({
  454.         // Return value
  455.         $returnValue null;
  456.  
  457.         // Loop through arguments
  458.         $aArgs self::flattenArray(func_get_args());
  459.         foreach ($aArgs as $arg{
  460.             // Is it a numeric value?
  461.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  462.                 if (is_bool($arg)) {
  463.                     $arg = (integer) $arg;
  464.                 elseif (is_string($arg)) {
  465.                     $arg 0;
  466.                 }
  467.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  468.                     $returnValue $arg;
  469.                 }
  470.             }
  471.         }
  472.  
  473.         // Return
  474.         if(is_null($returnValue)) {
  475.             return 0;
  476.         }
  477.         return $returnValue;
  478.     }
  479.  
  480.     /**
  481.      * SMALL
  482.      *
  483.      * Returns the nth smallest value in a data set. You can use this function to
  484.      * select a value based on its relative standing.
  485.      *
  486.      * @param    array of mixed        Data Series
  487.      * @param    float    Entry in the series to return
  488.      * @return    float 
  489.      */
  490.     public static function SMALL({
  491.         $aArgs self::flattenArray(func_get_args());
  492.  
  493.         // Calculate
  494.         $n array_pop($aArgs);
  495.  
  496.         if ((is_numeric($n)) && (!is_string($n))) {
  497.             $mArgs array();
  498.             foreach ($aArgs as $arg{
  499.                 // Is it a numeric value?
  500.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  501.                     $mArgs[$arg;
  502.                 }
  503.             }
  504.             $count self::COUNT($mArgs);
  505.             $n floor(--$n);
  506.             if (($n 0|| ($n >= $count|| ($count == 0)) {
  507.                 return self::$_errorCodes['num'];
  508.             }
  509.             sort($mArgs);
  510.             return $mArgs[$n];
  511.         }
  512.         return self::$_errorCodes['value'];
  513.     }
  514.  
  515.     /**
  516.      * MAX
  517.      *
  518.      * MAX returns the value of the element of the values passed that has the highest value,
  519.      * with negative numbers considered smaller than positive numbers.
  520.      *
  521.      * @param    array of mixed        Data Series
  522.      * @return  float 
  523.      */
  524.     public static function MAX({
  525.         // Return value
  526.         $returnValue null;
  527.  
  528.         // Loop trough arguments
  529.         $aArgs self::flattenArray(func_get_args());
  530.         foreach ($aArgs as $arg{
  531.             // Is it a numeric value?
  532.             if ((is_numeric($arg)) && (!is_string($arg))) {
  533.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  534.                     $returnValue $arg;
  535.                 }
  536.             }
  537.         }
  538.  
  539.         // Return
  540.         if(is_null($returnValue)) {
  541.             return 0;
  542.         }
  543.         return $returnValue;
  544.     }
  545.  
  546.     /**
  547.      * MAXA
  548.      *
  549.      * Returns the greatest value in a list of arguments, including numbers, text, and logical values
  550.      *
  551.      * @param    array of mixed        Data Series
  552.      * @return  float 
  553.      */
  554.     public static function MAXA({
  555.         // Return value
  556.         $returnValue null;
  557.  
  558.         // Loop through arguments
  559.         $aArgs self::flattenArray(func_get_args());
  560.         foreach ($aArgs as $arg{
  561.             // Is it a numeric value?
  562.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  563.                 if (is_bool($arg)) {
  564.                     $arg = (integer) $arg;
  565.                 elseif (is_string($arg)) {
  566.                     $arg 0;
  567.                 }
  568.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  569.                     $returnValue $arg;
  570.                 }
  571.             }
  572.         }
  573.  
  574.         // Return
  575.         if(is_null($returnValue)) {
  576.             return 0;
  577.         }
  578.         return $returnValue;
  579.     }
  580.  
  581.     /**
  582.      * LARGE
  583.      *
  584.      * Returns the nth largest value in a data set. You can use this function to
  585.      * select a value based on its relative standing.
  586.      *
  587.      * @param    array of mixed        Data Series
  588.      * @param    float    Entry in the series to return
  589.      * @return    float 
  590.      *
  591.      */
  592.     public static function LARGE({
  593.         $aArgs self::flattenArray(func_get_args());
  594.  
  595.         // Calculate
  596.         $n floor(array_pop($aArgs));
  597.  
  598.         if ((is_numeric($n)) && (!is_string($n))) {
  599.             $mArgs array();
  600.             foreach ($aArgs as $arg{
  601.                 // Is it a numeric value?
  602.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  603.                     $mArgs[$arg;
  604.                 }
  605.             }
  606.             $count self::COUNT($mArgs);
  607.             $n floor(--$n);
  608.             if (($n 0|| ($n >= $count|| ($count == 0)) {
  609.                 return self::$_errorCodes['num'];
  610.             }
  611.             rsort($mArgs);
  612.             return $mArgs[$n];
  613.         }
  614.         return self::$_errorCodes['value'];
  615.     }
  616.  
  617.     /**
  618.      * PERCENTILE
  619.      *
  620.      * Returns the nth percentile of values in a range..
  621.      *
  622.      * @param    array of mixed        Data Series
  623.      * @param    float    $entry        Entry in the series to return
  624.      * @return    float 
  625.      */
  626.     public static function PERCENTILE({
  627.         $aArgs self::flattenArray(func_get_args());
  628.  
  629.         // Calculate
  630.         $entry array_pop($aArgs);
  631.  
  632.         if ((is_numeric($entry)) && (!is_string($entry))) {
  633.             if (($entry 0|| ($entry 1)) {
  634.                 return self::$_errorCodes['num'];
  635.             }
  636.             $mArgs array();
  637.             foreach ($aArgs as $arg{
  638.                 // Is it a numeric value?
  639.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  640.                     $mArgs[$arg;
  641.                 }
  642.             }
  643.             $mValueCount count($mArgs);
  644.             if ($mValueCount 0{
  645.                 sort($mArgs);
  646.                 $count self::COUNT($mArgs);
  647.                 $index $entry ($count-1);
  648.                 $iBase floor($index);
  649.                 if ($index == $iBase{
  650.                     return $mArgs[$index];
  651.                 else {
  652.                     $iNext $iBase 1;
  653.                     $iProportion $index $iBase;
  654.                     return $mArgs[$iBase(($mArgs[$iNext$mArgs[$iBase]$iProportion;
  655.                 }
  656.             }
  657.         }
  658.         return self::$_errorCodes['value'];
  659.     }
  660.  
  661.     /**
  662.      * QUARTILE
  663.      *
  664.      * Returns the quartile of a data set.
  665.      *
  666.      * @param    array of mixed        Data Series
  667.      * @param    float    $entry        Entry in the series to return
  668.      * @return    float 
  669.      */
  670.     public static function QUARTILE({
  671.         $aArgs self::flattenArray(func_get_args());
  672.  
  673.         // Calculate
  674.         $entry floor(array_pop($aArgs));
  675.  
  676.         if ((is_numeric($entry)) && (!is_string($entry))) {
  677.             $entry /= 4;
  678.             if (($entry 0|| ($entry 1)) {
  679.                 return self::$_errorCodes['num'];
  680.             }
  681.             return self::PERCENTILE($aArgs,$entry);
  682.         }
  683.         return self::$_errorCodes['value'];
  684.     }
  685.  
  686.     /**
  687.      * COUNT
  688.      *
  689.      * Counts the number of cells that contain numbers within the list of arguments
  690.      *
  691.      * @param    array of mixed        Data Series
  692.      * @return  int 
  693.      */
  694.     public static function COUNT({
  695.         // Return value
  696.         $returnValue 0;
  697.  
  698.         // Loop trough arguments
  699.         $aArgs self::flattenArray(func_get_args());
  700.         foreach ($aArgs as $arg{
  701.             if ((is_bool($arg)) && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  702.                 $arg = (int) $arg;
  703.             }
  704.             // Is it a numeric value?
  705.             if ((is_numeric($arg)) && (!is_string($arg))) {
  706.                 ++$returnValue;
  707.             }
  708.         }
  709.  
  710.         // Return
  711.         return $returnValue;
  712.     }
  713.  
  714.     /**
  715.      * COUNTBLANK
  716.      *
  717.      * Counts the number of empty cells within the list of arguments
  718.      *
  719.      * @param    array of mixed        Data Series
  720.      * @return  int 
  721.      */
  722.     public static function COUNTBLANK({
  723.         // Return value
  724.         $returnValue 0;
  725.  
  726.         // Loop trough arguments
  727.         $aArgs self::flattenArray(func_get_args());
  728.         foreach ($aArgs as $arg{
  729.             // Is it a blank cell?
  730.             if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) {
  731.                 ++$returnValue;
  732.             }
  733.         }
  734.  
  735.         // Return
  736.         return $returnValue;
  737.     }
  738.  
  739.     /**
  740.      * COUNTA
  741.      *
  742.      * Counts the number of cells that are not empty within the list of arguments
  743.      *
  744.      * @param    array of mixed        Data Series
  745.      * @return  int 
  746.      */
  747.     public static function COUNTA({
  748.         // Return value
  749.         $returnValue 0;
  750.  
  751.         // Loop through arguments
  752.         $aArgs self::flattenArray(func_get_args());
  753.         foreach ($aArgs as $arg{
  754.             // Is it a numeric, boolean or string value?
  755.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  756.                 ++$returnValue;
  757.             }
  758.         }
  759.  
  760.         // Return
  761.         return $returnValue;
  762.     }
  763.  
  764.     /**
  765.      * AVERAGE
  766.      *
  767.      * Returns the average (arithmetic mean) of the arguments
  768.      *
  769.      * @param    array of mixed        Data Series
  770.      * @return  float 
  771.      */
  772.     public static function AVERAGE({
  773.         // Return value
  774.         $returnValue 0;
  775.  
  776.         // Loop through arguments
  777.         $aArgs self::flattenArray(func_get_args());
  778.         $aCount 0;
  779.         foreach ($aArgs as $arg{
  780.             if ((is_bool($arg))  && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  781.                 $arg = (integer) $arg;
  782.             }
  783.             // Is it a numeric value?
  784.             if ((is_numeric($arg)) && (!is_string($arg))) {
  785.                 if (is_null($returnValue)) {
  786.                     $returnValue $arg;
  787.                 else {
  788.                     $returnValue += $arg;
  789.                 }
  790.                 ++$aCount;
  791.             }
  792.         }
  793.  
  794.         // Return
  795.         if ($aCount 0{
  796.             return $returnValue $aCount;
  797.         else {
  798.             return self::$_errorCodes['divisionbyzero'];
  799.         }
  800.     }
  801.  
  802.     /**
  803.      * AVERAGEA
  804.      *
  805.      * Returns the average of its arguments, including numbers, text, and logical values
  806.      *
  807.      * @param    array of mixed        Data Series
  808.      * @return  float 
  809.      */
  810.     public static function AVERAGEA({
  811.         // Return value
  812.         $returnValue null;
  813.  
  814.         // Loop through arguments
  815.         $aArgs self::flattenArray(func_get_args());
  816.         $aCount 0;
  817.         foreach ($aArgs as $arg{
  818.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  819.                 if (is_bool($arg)) {
  820.                     $arg = (integer) $arg;
  821.                 elseif (is_string($arg)) {
  822.                     $arg 0;
  823.                 }
  824.                 if (is_null($returnValue)) {
  825.                     $returnValue $arg;
  826.                 else {
  827.                     $returnValue += $arg;
  828.                 }
  829.                 ++$aCount;
  830.             }
  831.         }
  832.  
  833.         // Return
  834.         if ($aCount 0{
  835.             return $returnValue $aCount;
  836.         else {
  837.             return self::$_errorCodes['divisionbyzero'];
  838.         }
  839.     }
  840.  
  841.     /**
  842.      * MEDIAN
  843.      *
  844.      * Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
  845.      *
  846.      * @param    array of mixed        Data Series
  847.      * @return  float 
  848.      */
  849.     public static function MEDIAN({
  850.         // Return value
  851.         $returnValue self::$_errorCodes['num'];
  852.  
  853.         $mArgs array();
  854.         // Loop through arguments
  855.         $aArgs self::flattenArray(func_get_args());
  856.         foreach ($aArgs as $arg{
  857.             // Is it a numeric value?
  858.             if ((is_numeric($arg)) && (!is_string($arg))) {
  859.                 $mArgs[$arg;
  860.             }
  861.         }
  862.  
  863.         $mValueCount count($mArgs);
  864.         if ($mValueCount 0{
  865.             sort($mArgs,SORT_NUMERIC);
  866.             $mValueCount $mValueCount 2;
  867.             if ($mValueCount == floor($mValueCount)) {
  868.                 $returnValue ($mArgs[$mValueCount--$mArgs[$mValueCount]2;
  869.             else {
  870.                 $mValueCount == floor($mValueCount);
  871.                 $returnValue $mArgs[$mValueCount];
  872.             }
  873.         }
  874.  
  875.         // Return
  876.         return $returnValue;
  877.     }
  878.  
  879.     //
  880.     //    Special variant of array_count_values that isn't limited to strings and integers,
  881.     //        but can work with floating point numbers as values
  882.     //
  883.     private static function modeCalc($data{
  884.         $frequencyArray array();
  885.         foreach($data as $datum{
  886.             $found False;
  887.             foreach($frequencyArray as $key => $value{
  888.                 if ((string)$value['value'== (string)$datum{
  889.                     ++$frequencyArray[$key]['frequency'];
  890.                     $found True;
  891.                     break;
  892.                 }
  893.             }
  894.             if (!$found{
  895.                 $frequencyArray[array('value'        => $datum,
  896.                                           'frequency'    =>    );
  897.             }
  898.         }
  899.  
  900.         foreach($frequencyArray as $key => $value{
  901.             $frequencyList[$key$value['frequency'];
  902.             $valueList[$key$value['value'];
  903.         }
  904.         array_multisort($frequencyListSORT_DESC$valueListSORT_ASCSORT_NUMERIC$frequencyArray);
  905.  
  906.         if ($frequencyArray[0]['frequency'== 1{
  907.             return self::NA();
  908.         }
  909.         return $frequencyArray[0]['value'];
  910.     }
  911.  
  912.     /**
  913.      * MODE
  914.      *
  915.      * Returns the most frequently occurring, or repetitive, value in an array or range of data
  916.      *
  917.      * @param    array of mixed        Data Series
  918.      * @return  float 
  919.      */
  920.     public static function MODE({
  921.         // Return value
  922.         $returnValue self::NA();
  923.  
  924.         // Loop through arguments
  925.         $aArgs self::flattenArray(func_get_args());
  926.  
  927.         $mArgs array();
  928.         foreach ($aArgs as $arg{
  929.             // Is it a numeric value?
  930.             if ((is_numeric($arg)) && (!is_string($arg))) {
  931.                 $mArgs[$arg;
  932.             }
  933.         }
  934.  
  935.         if (count($mArgs0{
  936.             return self::modeCalc($mArgs);
  937.         }
  938.  
  939.         // Return
  940.         return $returnValue;
  941.     }
  942.  
  943.     /**
  944.      * DEVSQ
  945.      *
  946.      * Returns the sum of squares of deviations of data points from their sample mean.
  947.      *
  948.      * @param    array of mixed        Data Series
  949.      * @return  float 
  950.      */
  951.     public static function DEVSQ({
  952.         // Return value
  953.         $returnValue null;
  954.  
  955.         $aMean self::AVERAGE(func_get_args());
  956.         if (!is_null($aMean)) {
  957.             $aArgs self::flattenArray(func_get_args());
  958.  
  959.             $aCount = -1;
  960.             foreach ($aArgs as $arg{
  961.                 // Is it a numeric value?
  962.                 if ((is_bool($arg))  && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  963.                     $arg = (int) $arg;
  964.                 }
  965.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  966.                     if (is_null($returnValue)) {
  967.                         $returnValue pow(($arg $aMean),2);
  968.                     else {
  969.                         $returnValue += pow(($arg $aMean),2);
  970.                     }
  971.                     ++$aCount;
  972.                 }
  973.             }
  974.  
  975.             // Return
  976.             if (is_null($returnValue)) {
  977.                 return self::$_errorCodes['num'];
  978.             else {
  979.                 return $returnValue;
  980.             }
  981.         }
  982.         return self::NA();
  983.     }
  984.  
  985.     /**
  986.      * AVEDEV
  987.      *
  988.      * Returns the average of the absolute deviations of data points from their mean.
  989.      * AVEDEV is a measure of the variability in a data set.
  990.      *
  991.      * @param    array of mixed        Data Series
  992.      * @return  float 
  993.      */
  994.     public static function AVEDEV({
  995.         $aArgs self::flattenArray(func_get_args());
  996.  
  997.         // Return value
  998.         $returnValue null;
  999.  
  1000.         $aMean self::AVERAGE($aArgs);
  1001.         if ($aMean != self::$_errorCodes['divisionbyzero']{
  1002.             $aCount 0;
  1003.             foreach ($aArgs as $arg{
  1004.                 if ((is_bool($arg))  && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  1005.                     $arg = (integer) $arg;
  1006.                 }
  1007.                 // Is it a numeric value?
  1008.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1009.                     if (is_null($returnValue)) {
  1010.                         $returnValue abs($arg $aMean);
  1011.                     else {
  1012.                         $returnValue += abs($arg $aMean);
  1013.                     }
  1014.                     ++$aCount;
  1015.                 }
  1016.             }
  1017.  
  1018.             // Return
  1019.             return $returnValue $aCount ;
  1020.         }
  1021.         return self::$_errorCodes['num'];
  1022.     }
  1023.  
  1024.     /**
  1025.      * GEOMEAN
  1026.      *
  1027.      * Returns the geometric mean of an array or range of positive data. For example, you
  1028.      * can use GEOMEAN to calculate average growth rate given compound interest with
  1029.      * variable rates.
  1030.      *
  1031.      * @param    array of mixed        Data Series
  1032.      * @return  float 
  1033.      */
  1034.     public static function GEOMEAN({
  1035.         $aMean self::PRODUCT(func_get_args());
  1036.         if (is_numeric($aMean&& ($aMean 0)) {
  1037.             $aArgs self::flattenArray(func_get_args());
  1038.             $aCount self::COUNT($aArgs;
  1039.             if (self::MIN($aArgs0{
  1040.                 return pow($aMean($aCount));
  1041.             }
  1042.         }
  1043.         return self::$_errorCodes['num'];
  1044.     }
  1045.  
  1046.     /**
  1047.      * HARMEAN
  1048.      *
  1049.      * Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the
  1050.      * arithmetic mean of reciprocals.
  1051.      *
  1052.      * @param    array of mixed        Data Series
  1053.      * @return  float 
  1054.      */
  1055.     public static function HARMEAN({
  1056.         // Return value
  1057.         $returnValue self::NA();
  1058.  
  1059.         // Loop through arguments
  1060.         $aArgs self::flattenArray(func_get_args());
  1061.         if (self::MIN($aArgs0{
  1062.             return self::$_errorCodes['num'];
  1063.         }
  1064.         $aCount 0;
  1065.         foreach ($aArgs as $arg{
  1066.             // Is it a numeric value?
  1067.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1068.                 if ($arg <= 0{
  1069.                     return self::$_errorCodes['num'];
  1070.                 }
  1071.                 if (is_null($returnValue)) {
  1072.                     $returnValue ($arg);
  1073.                 else {
  1074.                     $returnValue += ($arg);
  1075.                 }
  1076.                 ++$aCount;
  1077.             }
  1078.         }
  1079.  
  1080.         // Return
  1081.         if ($aCount 0{
  1082.             return ($returnValue $aCount);
  1083.         else {
  1084.             return $returnValue;
  1085.         }
  1086.     }
  1087.  
  1088.     /**
  1089.      * TRIMMEAN
  1090.      *
  1091.      * Returns the mean of the interior of a data set. TRIMMEAN calculates the mean
  1092.      * taken by excluding a percentage of data points from the top and bottom tails
  1093.      * of a data set.
  1094.      *
  1095.      * @param    array of mixed        Data Series
  1096.      * @param    float    Percentage to discard
  1097.      * @return    float 
  1098.      */
  1099.     public static function TRIMMEAN({
  1100.         $aArgs self::flattenArray(func_get_args());
  1101.  
  1102.         // Calculate
  1103.         $percent array_pop($aArgs);
  1104.  
  1105.         if ((is_numeric($percent)) && (!is_string($percent))) {
  1106.             if (($percent 0|| ($percent 1)) {
  1107.                 return self::$_errorCodes['num'];
  1108.             }
  1109.             $mArgs array();
  1110.             foreach ($aArgs as $arg{
  1111.                 // Is it a numeric value?
  1112.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1113.                     $mArgs[$arg;
  1114.                 }
  1115.             }
  1116.             $discard floor(self::COUNT($mArgs$percent 2);
  1117.             sort($mArgs);
  1118.             for ($i=0$i $discard++$i{
  1119.                 array_pop($mArgs);
  1120.                 array_shift($mArgs);
  1121.             }
  1122.             return self::AVERAGE($mArgs);
  1123.         }
  1124.         return self::$_errorCodes['value'];
  1125.     }
  1126.  
  1127.     /**
  1128.      * STDEV
  1129.      *
  1130.      * Estimates standard deviation based on a sample. The standard deviation is a measure of how
  1131.      * widely values are dispersed from the average value (the mean).
  1132.      *
  1133.      * @param    array of mixed        Data Series
  1134.      * @return  float 
  1135.      */
  1136.     public static function STDEV({
  1137.         // Return value
  1138.         $returnValue null;
  1139.  
  1140.         $aMean self::AVERAGE(func_get_args());
  1141.         if (!is_null($aMean)) {
  1142.             $aArgs self::flattenArray(func_get_args());
  1143.  
  1144.             $aCount = -1;
  1145.             foreach ($aArgs as $arg{
  1146.                 // Is it a numeric value?
  1147.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1148.                     if (is_null($returnValue)) {
  1149.                         $returnValue pow(($arg $aMean),2);
  1150.                     else {
  1151.                         $returnValue += pow(($arg $aMean),2);
  1152.                     }
  1153.                     ++$aCount;
  1154.                 }
  1155.             }
  1156.  
  1157.             // Return
  1158.             if (($aCount 0&& ($returnValue 0)) {
  1159.                 return sqrt($returnValue $aCount);
  1160.             }
  1161.         }
  1162.         return self::$_errorCodes['divisionbyzero'];
  1163.     }
  1164.  
  1165.     /**
  1166.      * STDEVA
  1167.      *
  1168.      * Estimates standard deviation based on a sample, including numbers, text, and logical values
  1169.      *
  1170.      * @param    array of mixed        Data Series
  1171.      * @return  float 
  1172.      */
  1173.     public static function STDEVA({
  1174.         // Return value
  1175.         $returnValue null;
  1176.  
  1177.         $aMean self::AVERAGEA(func_get_args());
  1178.         if (!is_null($aMean)) {
  1179.             $aArgs self::flattenArray(func_get_args());
  1180.  
  1181.             $aCount = -1;
  1182.             foreach ($aArgs as $arg{
  1183.                 // Is it a numeric value?
  1184.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1185.                     if (is_bool($arg)) {
  1186.                         $arg = (integer) $arg;
  1187.                     elseif (is_string($arg)) {
  1188.                         $arg 0;
  1189.                     }
  1190.                     if (is_null($returnValue)) {
  1191.                         $returnValue pow(($arg $aMean),2);
  1192.                     else {
  1193.                         $returnValue += pow(($arg $aMean),2);
  1194.                     }
  1195.                     ++$aCount;
  1196.                 }
  1197.             }
  1198.  
  1199.             // Return
  1200.             if (($aCount 0&& ($returnValue 0)) {
  1201.                 return sqrt($returnValue $aCount);
  1202.             }
  1203.         }
  1204.         return self::$_errorCodes['divisionbyzero'];
  1205.     }
  1206.  
  1207.     /**
  1208.      * STDEVP
  1209.      *
  1210.      * Calculates standard deviation based on the entire population
  1211.      *
  1212.      * @param    array of mixed        Data Series
  1213.      * @return  float 
  1214.      */
  1215.     public static function STDEVP({
  1216.         // Return value
  1217.         $returnValue null;
  1218.  
  1219.         $aMean self::AVERAGE(func_get_args());
  1220.         if (!is_null($aMean)) {
  1221.             $aArgs self::flattenArray(func_get_args());
  1222.  
  1223.             $aCount 0;
  1224.             foreach ($aArgs as $arg{
  1225.                 // Is it a numeric value?
  1226.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1227.                     if (is_null($returnValue)) {
  1228.                         $returnValue pow(($arg $aMean),2);
  1229.                     else {
  1230.                         $returnValue += pow(($arg $aMean),2);
  1231.                     }
  1232.                     ++$aCount;
  1233.                 }
  1234.             }
  1235.  
  1236.             // Return
  1237.             if (($aCount 0&& ($returnValue 0)) {
  1238.                 return sqrt($returnValue $aCount);
  1239.             }
  1240.         }
  1241.         return self::$_errorCodes['divisionbyzero'];
  1242.     }
  1243.  
  1244.     /**
  1245.      * STDEVPA
  1246.      *
  1247.      * Calculates standard deviation based on the entire population, including numbers, text, and logical values
  1248.      *
  1249.      * @param    array of mixed        Data Series
  1250.      * @return  float 
  1251.      */
  1252.     public static function STDEVPA({
  1253.         // Return value
  1254.         $returnValue null;
  1255.  
  1256.         $aMean self::AVERAGEA(func_get_args());
  1257.         if (!is_null($aMean)) {
  1258.             $aArgs self::flattenArray(func_get_args());
  1259.  
  1260.             $aCount 0;
  1261.             foreach ($aArgs as $arg{
  1262.                 // Is it a numeric value?
  1263.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1264.                     if (is_bool($arg)) {
  1265.                         $arg = (integer) $arg;
  1266.                     elseif (is_string($arg)) {
  1267.                         $arg 0;
  1268.                     }
  1269.                     if (is_null($returnValue)) {
  1270.                         $returnValue pow(($arg $aMean),2);
  1271.                     else {
  1272.                         $returnValue += pow(($arg $aMean),2);
  1273.                     }
  1274.                     ++$aCount;
  1275.                 }
  1276.             }
  1277.  
  1278.             // Return
  1279.             if (($aCount 0&& ($returnValue 0)) {
  1280.                 return sqrt($returnValue $aCount);
  1281.             }
  1282.         }
  1283.         return self::$_errorCodes['divisionbyzero'];
  1284.     }
  1285.  
  1286.     /**
  1287.      * VARFunc
  1288.      *
  1289.      * Estimates variance based on a sample.
  1290.      *
  1291.      * @param    array of mixed        Data Series
  1292.      * @return  float 
  1293.      */
  1294.     public static function VARFunc({
  1295.         // Return value
  1296.         $returnValue self::$_errorCodes['divisionbyzero'];
  1297.  
  1298.         $summerA $summerB 0;
  1299.  
  1300.         // Loop through arguments
  1301.         $aArgs self::flattenArray(func_get_args());
  1302.         $aCount 0;
  1303.         foreach ($aArgs as $arg{
  1304.             // Is it a numeric value?
  1305.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1306.                 $summerA += ($arg $arg);
  1307.                 $summerB += $arg;
  1308.                 ++$aCount;
  1309.             }
  1310.         }
  1311.  
  1312.         // Return
  1313.         if ($aCount 1{
  1314.             $summerA $summerA $aCount;
  1315.             $summerB ($summerB $summerB);
  1316.             $returnValue ($summerA $summerB($aCount ($aCount 1));
  1317.         }
  1318.         return $returnValue;
  1319.     }
  1320.  
  1321.     /**
  1322.      * VARA
  1323.      *
  1324.      * Estimates variance based on a sample, including numbers, text, and logical values
  1325.      *
  1326.      * @param    array of mixed        Data Series
  1327.      * @return  float 
  1328.      */
  1329.     public static function VARA({
  1330.         // Return value
  1331.         $returnValue self::$_errorCodes['divisionbyzero'];
  1332.  
  1333.         $summerA $summerB 0;
  1334.  
  1335.         // Loop through arguments
  1336.         $aArgs self::flattenArray(func_get_args());
  1337.         $aCount 0;
  1338.         foreach ($aArgs as $arg{
  1339.             // Is it a numeric value?
  1340.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1341.                 if (is_bool($arg)) {
  1342.                     $arg = (integer) $arg;
  1343.                 elseif (is_string($arg)) {
  1344.                     $arg 0;
  1345.                 }
  1346.                 $summerA += ($arg $arg);
  1347.                 $summerB += $arg;
  1348.                 ++$aCount;
  1349.             }
  1350.         }
  1351.  
  1352.         // Return
  1353.         if ($aCount 1{
  1354.             $summerA $summerA $aCount;
  1355.             $summerB ($summerB $summerB);
  1356.             $returnValue ($summerA $summerB($aCount ($aCount 1));
  1357.         }
  1358.         return $returnValue;
  1359.     }
  1360.  
  1361.     /**
  1362.      * VARP
  1363.      *
  1364.      * Calculates variance based on the entire population
  1365.      *
  1366.      * @param    array of mixed        Data Series
  1367.      * @return  float 
  1368.      */
  1369.     public static function VARP({
  1370.         // Return value
  1371.         $returnValue self::$_errorCodes['divisionbyzero'];
  1372.  
  1373.         $summerA $summerB 0;
  1374.  
  1375.         // Loop through arguments
  1376.         $aArgs self::flattenArray(func_get_args());
  1377.         $aCount 0;
  1378.         foreach ($aArgs as $arg{
  1379.             // Is it a numeric value?
  1380.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1381.                 $summerA += ($arg $arg);
  1382.                 $summerB += $arg;
  1383.                 ++$aCount;
  1384.             }
  1385.         }
  1386.  
  1387.         // Return
  1388.         if ($aCount 0{
  1389.             $summerA $summerA $aCount;
  1390.             $summerB ($summerB $summerB);
  1391.             $returnValue ($summerA $summerB($aCount $aCount);
  1392.         }
  1393.         return $returnValue;
  1394.     }
  1395.  
  1396.     /**
  1397.      * VARPA
  1398.      *
  1399.      * Calculates variance based on the entire population, including numbers, text, and logical values
  1400.      *
  1401.      * @param    array of mixed        Data Series
  1402.      * @return  float 
  1403.      */
  1404.     public static function VARPA({
  1405.         // Return value
  1406.         $returnValue self::$_errorCodes['divisionbyzero'];
  1407.  
  1408.         $summerA $summerB 0;
  1409.  
  1410.         // Loop through arguments
  1411.         $aArgs self::flattenArray(func_get_args());
  1412.         $aCount 0;
  1413.         foreach ($aArgs as $arg{
  1414.             // Is it a numeric value?
  1415.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1416.                 if (is_bool($arg)) {
  1417.                     $arg = (integer) $arg;
  1418.                 elseif (is_string($arg)) {
  1419.                     $arg 0;
  1420.                 }
  1421.                 $summerA += ($arg $arg);
  1422.                 $summerB += $arg;
  1423.                 ++$aCount;
  1424.             }
  1425.         }
  1426.  
  1427.         // Return
  1428.         if ($aCount 0{
  1429.             $summerA $summerA $aCount;
  1430.             $summerB ($summerB $summerB);
  1431.             $returnValue ($summerA $summerB($aCount $aCount);
  1432.         }
  1433.         return $returnValue;
  1434.     }
  1435.  
  1436.     /**
  1437.      * SUBTOTAL
  1438.      *
  1439.      * Returns a subtotal in a list or database.
  1440.      *
  1441.      * @param    int        the number 1 to 11 that specifies which function to
  1442.      *                     use in calculating subtotals within a list.
  1443.      * @param    array of mixed        Data Series
  1444.      * @return    float 
  1445.      */
  1446.     public static function SUBTOTAL({
  1447.         $aArgs self::flattenArray(func_get_args());
  1448.  
  1449.         // Calculate
  1450.         $subtotal array_shift($aArgs);
  1451.  
  1452.         if ((is_numeric($subtotal)) && (!is_string($subtotal))) {
  1453.             switch($subtotal{
  1454.                 case 1    :
  1455.                     return self::AVERAGE($aArgs);
  1456.                     break;
  1457.                 case 2    :
  1458.                     return self::COUNT($aArgs);
  1459.                     break;
  1460.                 case 3    :
  1461.                     return self::COUNTA($aArgs);
  1462.                     break;
  1463.                 case 4    :
  1464.                     return self::MAX($aArgs);
  1465.                     break;
  1466.                 case 5    :
  1467.                     return self::MIN($aArgs);
  1468.                     break;
  1469.                 case 6    :
  1470.                     return self::PRODUCT($aArgs);
  1471.                     break;
  1472.                 case 7    :
  1473.                     return self::STDEV($aArgs);
  1474.                     break;
  1475.                 case 8    :
  1476.                     return self::STDEVP($aArgs);
  1477.                     break;
  1478.                 case 9    :
  1479.                     return self::SUM($aArgs);
  1480.                     break;
  1481.                 case 10    :
  1482.                     return self::VARFunc($aArgs);
  1483.                     break;
  1484.                 case 11    :
  1485.                     return self::VARP($aArgs);
  1486.                     break;
  1487.             }
  1488.         }
  1489.         return self::$_errorCodes['value'];
  1490.     }
  1491.  
  1492.     /**
  1493.      * SQRTPI
  1494.      *
  1495.      * Returns the square root of (number * pi).
  1496.      *
  1497.      * @param    float    $number        Number
  1498.      * @return  float    Square Root of Number * Pi
  1499.      */
  1500.     public static function SQRTPI($number{
  1501.         $number    self::flattenSingleValue($number);
  1502.  
  1503.         if (is_numeric($number)) {
  1504.             if ($number 0{
  1505.                 return self::$_errorCodes['num'];
  1506.             }
  1507.             return sqrt($number pi()) ;
  1508.         }
  1509.         return self::$_errorCodes['value'];
  1510.     }
  1511.  
  1512.     /**
  1513.      * FACT
  1514.      *
  1515.      * Returns the factorial of a number.
  1516.      *
  1517.      * @param    float    $factVal    Factorial Value
  1518.      * @return  int        Factorial
  1519.      */
  1520.     public static function FACT($factVal{
  1521.         $factVal    self::flattenSingleValue($factVal);
  1522.  
  1523.         if (is_numeric($factVal)) {
  1524.             if ($factVal 0{
  1525.                 return self::$_errorCodes['num'];
  1526.             }
  1527.             $factLoop floor($factVal);
  1528.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  1529.                 if ($factVal $factLoop{
  1530.                     return self::$_errorCodes['num'];
  1531.                 }
  1532.             }
  1533.             $factorial 1;
  1534.             while ($factLoop 1{
  1535.                 $factorial *= $factLoop--;
  1536.             }
  1537.             return $factorial ;
  1538.         }
  1539.         return self::$_errorCodes['value'];
  1540.     }
  1541.  
  1542.     /**
  1543.      * FACTDOUBLE
  1544.      *
  1545.      * Returns the double factorial of a number.
  1546.      *
  1547.      * @param    float    $factVal    Factorial Value
  1548.      * @return  int        Double Factorial
  1549.      */
  1550.     public static function FACTDOUBLE($factVal{
  1551.         $factLoop    floor(self::flattenSingleValue($factVal));
  1552.  
  1553.         if (is_numeric($factLoop)) {
  1554.             if ($factVal 0{
  1555.                 return self::$_errorCodes['num'];
  1556.             }
  1557.             $factorial 1;
  1558.             while ($factLoop 1{
  1559.                 $factorial *= $factLoop--;
  1560.                 --$factLoop;
  1561.             }
  1562.             return $factorial ;
  1563.         }
  1564.         return self::$_errorCodes['value'];
  1565.     }
  1566.  
  1567.     /**
  1568.      * MULTINOMIAL
  1569.      *
  1570.      * Returns the ratio of the factorial of a sum of values to the product of factorials.
  1571.      *
  1572.      * @param    array of mixed        Data Series
  1573.      * @return  float 
  1574.      */
  1575.     public static function MULTINOMIAL({
  1576.  
  1577.         // Loop through arguments
  1578.         $aArgs self::flattenArray(func_get_args());
  1579.         $summer 0;
  1580.         $divisor 1;
  1581.         foreach ($aArgs as $arg{
  1582.             // Is it a numeric value?
  1583.             if (is_numeric($arg)) {
  1584.                 if ($arg 1{
  1585.                     return self::$_errorCodes['num'];
  1586.                 }
  1587.                 $summer += floor($arg);
  1588.                 $divisor *= self::FACT($arg);
  1589.             else {
  1590.                 return self::$_errorCodes['value'];
  1591.             }
  1592.         }
  1593.  
  1594.         // Return
  1595.         if ($summer 0{
  1596.             $summer self::FACT($summer);
  1597.             return $summer $divisor;
  1598.         }
  1599.         return 0;
  1600.     }
  1601.  
  1602.     /**
  1603.      * CEILING
  1604.      *
  1605.      * Returns number rounded up, away from zero, to the nearest multiple of significance.
  1606.      *
  1607.      * @param    float    $number            Number to round
  1608.      * @param    float    $significance    Significance
  1609.      * @return  float    Rounded Number
  1610.      */
  1611.     public static function CEILING($number,$significance=null{
  1612.         $number            self::flattenSingleValue($number);
  1613.         $significance    self::flattenSingleValue($significance);
  1614.  
  1615.         if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  1616.             $significance $number/abs($number);
  1617.         }
  1618.  
  1619.         if ((is_numeric($number)) && (is_numeric($significance))) {
  1620.             if (self::SIGN($number== self::SIGN($significance)) {
  1621.                 if ($significance == 0.0{
  1622.                     return 0;
  1623.                 }
  1624.                 return ceil($number $significance$significance;
  1625.             else {
  1626.                 return self::$_errorCodes['num'];
  1627.             }
  1628.         }
  1629.         return self::$_errorCodes['value'];
  1630.     }
  1631.  
  1632.     /**
  1633.      * EVEN
  1634.      *
  1635.      * Returns number rounded up to the nearest even integer.
  1636.      *
  1637.      * @param    float    $number            Number to round
  1638.      * @return  int        Rounded Number
  1639.      */
  1640.     public static function EVEN($number{
  1641.         $number    self::flattenSingleValue($number);
  1642.  
  1643.         if (is_numeric($number)) {
  1644.             $significance self::SIGN($number);
  1645.             return self::CEILING($number,$significance);
  1646.         }
  1647.         return self::$_errorCodes['value'];
  1648.     }
  1649.  
  1650.     /**
  1651.      * ODD
  1652.      *
  1653.      * Returns number rounded up to the nearest odd integer.
  1654.      *
  1655.      * @param    float    $number            Number to round
  1656.      * @return  int        Rounded Number
  1657.      */
  1658.     public static function ODD($number{
  1659.         $number    self::flattenSingleValue($number);
  1660.  
  1661.         if (is_numeric($number)) {
  1662.             $significance self::SIGN($number);
  1663.             if ($significance == 0{
  1664.                 return 1;
  1665.             }
  1666.             $result self::CEILING($number,$significance);
  1667.             if (self::IS_EVEN($result)) {
  1668.                 $result += $significance;
  1669.             }
  1670.             return $result;
  1671.         }
  1672.         return self::$_errorCodes['value'];
  1673.     }
  1674.  
  1675.     /**
  1676.      * ROUNDUP
  1677.      *
  1678.      * Rounds a number up to a specified number of decimal places
  1679.      *
  1680.      * @param    float    $number            Number to round
  1681.      * @param    int        $digits            Number of digits to which you want to round $number
  1682.      * @return  float    Rounded Number
  1683.      */
  1684.     public static function ROUNDUP($number,$digits{
  1685.         $number    self::flattenSingleValue($number);
  1686.         $digits    self::flattenSingleValue($digits);
  1687.  
  1688.         if (is_numeric($number)) {
  1689.             if ((is_numeric($digits)) && ($digits >= 0)) {
  1690.                 $significance pow(10,$digits);
  1691.                 return ceil($number $significance$significance;
  1692.             }
  1693.         }
  1694.         return self::$_errorCodes['value'];
  1695.     }
  1696.  
  1697.     /**
  1698.      * ROUNDDOWN
  1699.      *
  1700.      * Rounds a number down to a specified number of decimal places
  1701.      *
  1702.      * @param    float    $number            Number to round
  1703.      * @param    int        $digits            Number of digits to which you want to round $number
  1704.      * @return  float    Rounded Number
  1705.      */
  1706.     public static function ROUNDDOWN($number,$digits{
  1707.         $number    self::flattenSingleValue($number);
  1708.         $digits    self::flattenSingleValue($digits);
  1709.  
  1710.         if (is_numeric($number)) {
  1711.             if ((is_numeric($digits)) && ($digits >= 0)) {
  1712.                 $significance pow(10,$digits);
  1713.                 return floor($number $significance$significance;
  1714.             }
  1715.         }
  1716.         return self::$_errorCodes['value'];
  1717.     }
  1718.  
  1719.     /**
  1720.      * MROUND
  1721.      *
  1722.      * Rounds a number to the nearest multiple of a specified value
  1723.      *
  1724.      * @param    float    $number            Number to round
  1725.      * @param    int        $multiple        Multiple to which you want to round $number
  1726.      * @return  float    Rounded Number
  1727.      */
  1728.     public static function MROUND($number,$multiple{
  1729.         $number        self::flattenSingleValue($number);
  1730.         $multiple    self::flattenSingleValue($multiple);
  1731.  
  1732.         if ((is_numeric($number)) && (is_numeric($multiple))) {
  1733.             if ((self::SIGN($number)) == (self::SIGN($multiple))) {
  1734.                 $lowerVal floor($number $multiple$multiple;
  1735.                 $upperVal ceil($number $multiple$multiple;
  1736.                 $adjustUp abs($number $upperVal);
  1737.                 $adjustDown abs($number $lowerValPRECISION;
  1738.                 if ($adjustDown $adjustUp{
  1739.                     return $lowerVal;
  1740.                 }
  1741.                 return $upperVal;
  1742.             }
  1743.             return self::$_errorCodes['num'];
  1744.         }
  1745.         return self::$_errorCodes['value'];
  1746.     }
  1747.  
  1748.     /**
  1749.      * SIGN
  1750.      *
  1751.      * Determines the sign of a number. Returns 1 if the number is positive, zero (0)
  1752.      * if the number is 0, and -1 if the number is negative.
  1753.      *
  1754.      * @param    float    $number            Number to round
  1755.      * @return  int        sign value
  1756.      */
  1757.     public static function SIGN($number{
  1758.         $number    self::flattenSingleValue($number);
  1759.  
  1760.         if (is_numeric($number)) {
  1761.             if ($number == 0.0{
  1762.                 return 0;
  1763.             }
  1764.             return $number abs($number);
  1765.         }
  1766.         return self::$_errorCodes['value'];
  1767.     }
  1768.  
  1769.     /**
  1770.      * FLOOR
  1771.      *
  1772.      * Rounds number down, toward zero, to the nearest multiple of significance.
  1773.      *
  1774.      * @param    float    $number            Number to round
  1775.      * @param    float    $significance    Significance
  1776.      * @return  float    Rounded Number
  1777.      */
  1778.     public static function FLOOR($number,$significance=null{
  1779.         $number            self::flattenSingleValue($number);
  1780.         $significance    self::flattenSingleValue($significance);
  1781.  
  1782.         if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  1783.             $significance $number/abs($number);
  1784.         }
  1785.  
  1786.         if ((is_numeric($number)) && (is_numeric($significance))) {
  1787.             if ((float) $significance == 0.0{
  1788.                 return self::$_errorCodes['divisionbyzero'];
  1789.             }
  1790.             if (self::SIGN($number== self::SIGN($significance)) {
  1791.                 return floor($number $significance$significance;
  1792.             else {
  1793.                 return self::$_errorCodes['num'];
  1794.             }
  1795.         }
  1796.         return self::$_errorCodes['value'];
  1797.     }
  1798.  
  1799.     /**
  1800.      * PERMUT
  1801.      *
  1802.      * Returns the number of permutations for a given number of objects that can be
  1803.      * selected from number objects. A permutation is any set or subset of objects or
  1804.      * events where internal order is significant. Permutations are different from
  1805.      * combinations, for which the internal order is not significant. Use this function
  1806.      * for lottery-style probability calculations.
  1807.      *
  1808.      * @param    int        $numObjs    Number of different objects
  1809.      * @param    int        $numInSet    Number of objects in each permutation
  1810.      * @return  int        Number of permutations
  1811.      */
  1812.     public static function PERMUT($numObjs,$numInSet{
  1813.         $numObjs    self::flattenSingleValue($numObjs);
  1814.         $numInSet    self::flattenSingleValue($numInSet);
  1815.  
  1816.         if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
  1817.             if ($numObjs $numInSet{
  1818.                 return self::$_errorCodes['num'];
  1819.             }
  1820.             return self::FACT($numObjsself::FACT($numObjs $numInSet);
  1821.         }
  1822.         return self::$_errorCodes['value'];
  1823.     }
  1824.  
  1825.     /**
  1826.      * COMBIN
  1827.      *
  1828.      * Returns the number of combinations for a given number of items. Use COMBIN to
  1829.      * determine the total possible number of groups for a given number of items.
  1830.      *
  1831.      * @param    int        $numObjs    Number of different objects
  1832.      * @param    int        $numInSet    Number of objects in each combination
  1833.      * @return  int        Number of combinations
  1834.      */
  1835.     public static function COMBIN($numObjs,$numInSet{
  1836.         $numObjs    self::flattenSingleValue($numObjs);
  1837.         $numInSet    self::flattenSingleValue($numInSet);
  1838.  
  1839.         if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
  1840.             if ($numObjs $numInSet{
  1841.                 return self::$_errorCodes['num'];
  1842.             elseif ($numInSet 0{
  1843.                 return self::$_errorCodes['num'];
  1844.             }
  1845.             return (self::FACT($numObjsself::FACT($numObjs $numInSet)) self::FACT($numInSet);
  1846.         }
  1847.         return self::$_errorCodes['value'];
  1848.     }
  1849.  
  1850.     /**
  1851.      * SERIESSUM
  1852.      *
  1853.      * Returns the sum of a power series
  1854.      *
  1855.      * @param    float            $x    Input value to the power series
  1856.      * @param    float            $n    Initial power to which you want to raise $x
  1857.      * @param    float            $m    Step by which to increase $n for each term in the series
  1858.      * @param    array of mixed        Data Series
  1859.      * @return    float 
  1860.      */
  1861.     public static function SERIESSUM({
  1862.         // Return value
  1863.         $returnValue 0;
  1864.  
  1865.         // Loop trough arguments
  1866.         $aArgs self::flattenArray(func_get_args());
  1867.  
  1868.         $x array_shift($aArgs);
  1869.         $n array_shift($aArgs);
  1870.         $m array_shift($aArgs);
  1871.  
  1872.         if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) {
  1873.             // Calculate
  1874.             $i 0;
  1875.             foreach($aArgs as $arg{
  1876.                 // Is it a numeric value?
  1877.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1878.                     $returnValue += $arg pow($x,$n ($m $i++));
  1879.                 else {
  1880.                     return self::$_errorCodes['value'];
  1881.                 }
  1882.             }
  1883.             // Return
  1884.             return $returnValue;
  1885.         }
  1886.         return self::$_errorCodes['value'];
  1887.     }
  1888.  
  1889.     /**
  1890.      * STANDARDIZE
  1891.      *
  1892.      * Returns a normalized value from a distribution characterized by mean and standard_dev.
  1893.      *
  1894.      * @param    float    $value        Value to normalize
  1895.      * @param    float    $mean        Mean Value
  1896.      * @param    float    $stdDev        Standard Deviation
  1897.      * @return  float    Standardized value
  1898.      */
  1899.     public static function STANDARDIZE($value,$mean,$stdDev{
  1900.         $value    self::flattenSingleValue($value);
  1901.         $mean    self::flattenSingleValue($mean);
  1902.         $stdDev    self::flattenSingleValue($stdDev);
  1903.  
  1904.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  1905.             if ($stdDev <= 0{
  1906.                 return self::$_errorCodes['num'];
  1907.             }
  1908.             return ($value $mean$stdDev ;
  1909.         }
  1910.         return self::$_errorCodes['value'];
  1911.     }
  1912.  
  1913.     //
  1914.     //    Private method to return an array of the factors of the input value
  1915.     //
  1916.     private static function factors($value{
  1917.         $startVal floor($value/2);
  1918.  
  1919.         $factorArray array();
  1920.         for($i=$startVal$i>1--$i{
  1921.             if (($value/$i== floor($value/$i)) {
  1922.                 $subFactors self::factors($i);
  1923.                 if ($i == sqrt($value)) {
  1924.                     $factorArray array_merge($factorArray,$subFactors,$subFactors);
  1925.                 else {
  1926.                     $value /= $i;
  1927.                     $factorArray array_merge($factorArray,$subFactors);
  1928.                 }
  1929.             }
  1930.         }
  1931.         if (count($factorArray0{
  1932.             return $factorArray;
  1933.         else {
  1934.             return array((integer)$value);
  1935.         }
  1936.     }
  1937.  
  1938.     /**
  1939.      * LCM
  1940.      *
  1941.      * Returns the lowest common multiplier of a series of numbers
  1942.      *
  1943.      * @param    $array    Values to calculate the Lowest Common Multiplier
  1944.      * @return  int        Lowest Common Multiplier
  1945.      */
  1946.     public static function LCM({
  1947.         $aArgs self::flattenArray(func_get_args());
  1948.  
  1949.         $returnValue 1;
  1950.         $allPoweredFactors array();
  1951.         foreach($aArgs as $value{
  1952.             if (!is_numeric($value)) {
  1953.                 return self::$_errorCodes['value'];
  1954.             }
  1955.             if ($value 1{
  1956.                 return self::$_errorCodes['num'];
  1957.             }
  1958.             $myFactors self::factors(floor($value));
  1959.             $myCountedFactors array_count_values($myFactors);
  1960.             $myPoweredFactors array();
  1961.             foreach($myCountedFactors as $myCountedFactor => $myCountedPower{
  1962.                 $myPoweredFactors[$myCountedFactorpow($myCountedFactor,$myCountedPower);
  1963.             }
  1964.             foreach($myPoweredFactors as $myPoweredValue => $myPoweredFactor{
  1965.                 if (array_key_exists($myPoweredValue,$allPoweredFactors)) {
  1966.                     if ($allPoweredFactors[$myPoweredValue$myPoweredFactor{
  1967.                         $allPoweredFactors[$myPoweredValue$myPoweredFactor;
  1968.                     }
  1969.                 else {
  1970.                     $allPoweredFactors[$myPoweredValue$myPoweredFactor;
  1971.                 }
  1972.             }
  1973.         }
  1974.         foreach($allPoweredFactors as $allPoweredFactor{
  1975.             $returnValue *= (integer) $allPoweredFactor;
  1976.         }
  1977.         return $returnValue;
  1978.     }
  1979.  
  1980.     /**
  1981.      * GCD
  1982.      *
  1983.      * Returns the greatest common divisor of a series of numbers
  1984.      *
  1985.      * @param    $array    Values to calculate the Greatest Common Divisor
  1986.      * @return  int        Greatest Common Divisor
  1987.      */
  1988.     public static function GCD({
  1989.         $aArgs self::flattenArray(func_get_args());
  1990.  
  1991.         $returnValue 1;
  1992.         $allPoweredFactors array();
  1993.         foreach($aArgs as $value{
  1994.             if ($value == 0{
  1995.                 return 0;
  1996.             }
  1997.             $myFactors self::factors($value);
  1998.             $myCountedFactors array_count_values($myFactors);
  1999.             $allValuesFactors[$myCountedFactors;
  2000.         }
  2001.         $allValuesCount count($allValuesFactors);
  2002.         $mergedArray $allValuesFactors[0];
  2003.         for ($i=1;$i $allValuesCount++$i{
  2004.             $mergedArray array_intersect_key($mergedArray,$allValuesFactors[$i]);
  2005.         }
  2006.         $mergedArrayValues count($mergedArray);
  2007.         if ($mergedArrayValues == 0{
  2008.             return $returnValue;
  2009.         elseif ($mergedArrayValues 1{
  2010.             foreach($mergedArray as $mergedKey => $mergedValue{
  2011.                 foreach($allValuesFactors as $highestPowerTest{
  2012.                     foreach($highestPowerTest as $testKey => $testValue{
  2013.                         if (($testKey == $mergedKey&& ($testValue $mergedValue)) {
  2014.                             $mergedArray[$mergedKey$testValue;
  2015.                             $mergedValue $testValue;
  2016.                         }
  2017.                     }
  2018.                 }
  2019.             }
  2020.  
  2021.             $returnValue 1;
  2022.             foreach($mergedArray as $key => $value{
  2023.                 $returnValue *= pow($key,$value);
  2024.             }
  2025.             return $returnValue;
  2026.         else {
  2027.             $keys array_keys($mergedArray);
  2028.             $key $keys[0];
  2029.             $value $mergedArray[$key];
  2030.             foreach($allValuesFactors as $testValue{
  2031.                 foreach($testValue as $mergedKey => $mergedValue{
  2032.                     if (($mergedKey == $key&& ($mergedValue $value)) {
  2033.                         $value $mergedValue;
  2034.                     }
  2035.                 }
  2036.             }
  2037.             return pow($key,$value);
  2038.         }
  2039.     }
  2040.  
  2041.     /**
  2042.      * BINOMDIST
  2043.      *
  2044.      * Returns the individual term binomial distribution probability. Use BINOMDIST in problems with
  2045.      * a fixed number of tests or trials, when the outcomes of any trial are only success or failure,
  2046.      * when trials are independent, and when the probability of success is constant throughout the
  2047.      * experiment. For example, BINOMDIST can calculate the probability that two of the next three
  2048.      * babies born are male.
  2049.      *
  2050.      * @param    float        $value            Number of successes in trials
  2051.      * @param    float        $trials            Number of trials
  2052.      * @param    float        $probability    Probability of success on each trial
  2053.      * @param    boolean        $cumulative 
  2054.      * @return  float 
  2055.      *
  2056.      * @todo    Cumulative distribution function
  2057.      *
  2058.      */
  2059.     public static function BINOMDIST($value$trials$probability$cumulative{
  2060.         $value            floor(self::flattenSingleValue($value));
  2061.         $trials            floor(self::flattenSingleValue($trials));
  2062.         $probability    self::flattenSingleValue($probability);
  2063.  
  2064.         if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) {
  2065.             if (($value 0|| ($value $trials)) {
  2066.                 return self::$_errorCodes['num'];
  2067.             }
  2068.             if (($probability 0|| ($probability 1)) {
  2069.                 return self::$_errorCodes['num'];
  2070.             }
  2071.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  2072.                 if ($cumulative{
  2073.                     $summer 0;
  2074.                     for ($i 0$i <= $value++$i{
  2075.                         $summer += self::COMBIN($trials,$ipow($probability,$ipow($probability,$trials $i);
  2076.                     }
  2077.                     return $summer;
  2078.                 else {
  2079.                     return self::COMBIN($trials,$valuepow($probability,$valuepow($probability,$trials $value;
  2080.                 }
  2081.             }
  2082.         }
  2083.         return self::$_errorCodes['value'];
  2084.     }
  2085.  
  2086.     /**
  2087.      * NEGBINOMDIST
  2088.      *
  2089.      * Returns the negative binomial distribution. NEGBINOMDIST returns the probability that
  2090.      * there will be number_f failures before the number_s-th success, when the constant
  2091.      * probability of a success is probability_s. This function is similar to the binomial
  2092.      * distribution, except that the number of successes is fixed, and the number of trials is
  2093.      * variable. Like the binomial, trials are assumed to be independent.
  2094.      *
  2095.      * @param    float        $failures        Number of Failures
  2096.      * @param    float        $successes        Threshold number of Successes
  2097.      * @param    float        $probability    Probability of success on each trial
  2098.      * @return  float 
  2099.      *
  2100.      */
  2101.     public static function NEGBINOMDIST($failures$successes$probability{
  2102.         $failures        floor(self::flattenSingleValue($failures));
  2103.         $successes        floor(self::flattenSingleValue($successes));
  2104.         $probability    self::flattenSingleValue($probability);
  2105.  
  2106.         if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) {
  2107.             if (($failures 0|| ($successes 1)) {
  2108.                 return self::$_errorCodes['num'];
  2109.             }
  2110.             if (($probability 0|| ($probability 1)) {
  2111.                 return self::$_errorCodes['num'];
  2112.             }
  2113.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  2114.                 if (($failures $successes 1<= 0{
  2115.                     return self::$_errorCodes['num'];
  2116.                 }
  2117.             }
  2118.             return (self::COMBIN($failures $successes 1,$successes 1)) (pow($probability,$successes)) (pow($probability,$failures)) ;
  2119.         }
  2120.         return self::$_errorCodes['value'];
  2121.     }
  2122.  
  2123.  
  2124.     /**
  2125.      * CRITBINOM
  2126.      *
  2127.      * Returns the smallest value for which the cumulative binomial distribution is greater
  2128.      * than or equal to a criterion value
  2129.      *
  2130.      * See http://support.microsoft.com/kb/828117/ for details of the algorithm used
  2131.      *
  2132.      * @param    float        $trials            number of Bernoulli trials
  2133.      * @param    float        $probability    probability of a success on each trial
  2134.      * @param    float        $alpha            criterion value
  2135.      * @return  int 
  2136.      *
  2137.      *    @todo    Warning. This implementation differs from the algorithm detailed on the MS
  2138.      *             web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess
  2139.      *             This eliminates a potential endless loop error, but may have an adverse affect on the
  2140.      *             accuracy of the function (although all my tests have so far returned correct results).
  2141.      *
  2142.      */
  2143.     public static function CRITBINOM($trials$probability$alpha{
  2144.         $trials            floor(self::flattenSingleValue($trials));
  2145.         $probability    self::flattenSingleValue($probability);
  2146.         $alpha            self::flattenSingleValue($alpha);
  2147.  
  2148.         if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) {
  2149.             if ($trials 0{
  2150.                 return self::$_errorCodes['num'];
  2151.             }
  2152.             if (($probability 0|| ($probability 1)) {
  2153.                 return self::$_errorCodes['num'];
  2154.             }
  2155.             if (($alpha 0|| ($alpha 1)) {
  2156.                 return self::$_errorCodes['num'];
  2157.             }
  2158.             if ($alpha <= 0.5{
  2159.                 $t sqrt(log(pow($alpha,2)));
  2160.                 $trialsApprox ($t (2.515517 0.802853 $t 0.010328 $t $t(1.432788 $t 0.189269 $t $t 0.001308 $t $t $t));
  2161.             else {
  2162.                 $t sqrt(log(pow($alpha,2)));
  2163.                 $trialsApprox $t (2.515517 0.802853 $t 0.010328 $t $t(1.432788 $t 0.189269 $t $t 0.001308 $t $t $t);
  2164.             }
  2165.             $Guess floor($trials $probability $trialsApprox sqrt($trials $probability ($probability)));
  2166.             if ($Guess 0{
  2167.                 $Guess 0;
  2168.             elseif ($Guess $trials{
  2169.                 $Guess $trials;
  2170.             }
  2171.  
  2172.             $TotalUnscaledProbability $UnscaledPGuess $UnscaledCumPGuess 0.0;
  2173.             $EssentiallyZero 10e-12;
  2174.  
  2175.             $m floor($trials $probability);
  2176.             ++$TotalUnscaledProbability;
  2177.             if ($m == $Guess++$UnscaledPGuess}
  2178.             if ($m <= $Guess++$UnscaledCumPGuess}
  2179.  
  2180.             $PreviousValue 1;
  2181.             $Done False;
  2182.             $k $m 1;
  2183.             while ((!$Done&& ($k <= $trials)) {
  2184.                 $CurrentValue $PreviousValue ($trials $k 1$probability ($k ($probability));
  2185.                 $TotalUnscaledProbability += $CurrentValue;
  2186.                 if ($k == $Guess$UnscaledPGuess += $CurrentValue}
  2187.                 if ($k <= $Guess$UnscaledCumPGuess += $CurrentValue}
  2188.                 if ($CurrentValue <= $EssentiallyZero$Done True}
  2189.                 $PreviousValue $CurrentValue;
  2190.                 ++$k;
  2191.             }
  2192.  
  2193.             $PreviousValue 1;
  2194.             $Done False;
  2195.             $k $m 1;
  2196.             while ((!$Done&& ($k >= 0)) {
  2197.                 $CurrentValue $PreviousValue $k ($probability(($trials $k$probability);
  2198.                 $TotalUnscaledProbability += $CurrentValue;
  2199.                 if ($k == $Guess$UnscaledPGuess += $CurrentValue}
  2200.                 if ($k <= $Guess$UnscaledCumPGuess += $CurrentValue}
  2201.                 if (CurrentValue <= EssentiallyZero$Done True}
  2202.                 $PreviousValue $CurrentValue;
  2203.                 --$k;
  2204.             }
  2205.  
  2206.             $PGuess $UnscaledPGuess $TotalUnscaledProbability;
  2207.             $CumPGuess $UnscaledCumPGuess $TotalUnscaledProbability;
  2208.  
  2209. //            $CumPGuessMinus1 = $CumPGuess - $PGuess;
  2210.             $CumPGuessMinus1 $CumPGuess 1;
  2211.  
  2212.             while (True{
  2213.                 if (($CumPGuessMinus1 $alpha&& ($CumPGuess >= $alpha)) {
  2214.                     return $Guess;
  2215.                 elseif (($CumPGuessMinus1 $alpha&& ($CumPGuess $alpha)) {
  2216.                     $PGuessPlus1 $PGuess ($trials $Guess$probability $Guess ($probability);
  2217.                     $CumPGuessMinus1 $CumPGuess;
  2218.                     $CumPGuess $CumPGuess $PGuessPlus1;
  2219.                     $PGuess $PGuessPlus1;
  2220.                     ++$Guess;
  2221.                 elseif (($CumPGuessMinus1 >= $alpha&& ($CumPGuess >= $alpha)) {
  2222.                     $PGuessMinus1 $PGuess $Guess ($probability($trials $Guess 1$probability;
  2223.                     $CumPGuess $CumPGuessMinus1;
  2224.                     $CumPGuessMinus1 $CumPGuessMinus1 $PGuess;
  2225.                     $PGuess $PGuessMinus1;
  2226.                     --$Guess;
  2227.                 }
  2228.             }
  2229.         }
  2230.         return self::$_errorCodes['value'];
  2231.     }
  2232.  
  2233.     /**
  2234.      * CHIDIST
  2235.      *
  2236.      * Returns the one-tailed probability of the chi-squared distribution.
  2237.      *
  2238.      * @param    float        $value            Value for the function
  2239.      * @param    float        $degrees        degrees of freedom
  2240.      * @return  float 
  2241.      */
  2242.     public static function CHIDIST($value$degrees{
  2243.         $value        self::flattenSingleValue($value);
  2244.         $degrees    floor(self::flattenSingleValue($degrees));
  2245.  
  2246.         if ((is_numeric($value)) && (is_numeric($degrees))) {
  2247.             if ($degrees 1{
  2248.                 return self::$_errorCodes['num'];
  2249.             }
  2250.             if ($value 0{
  2251.                 if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  2252.                     return 1;
  2253.                 }
  2254.                 return self::$_errorCodes['num'];
  2255.             }
  2256.             return (self::incompleteGamma($degrees/2,$value/2self::gamma($degrees/2));
  2257.         }
  2258.         return self::$_errorCodes['value'];
  2259.     }
  2260.  
  2261.     /**
  2262.      * CHIINV
  2263.      *
  2264.      * Returns the one-tailed probability of the chi-squared distribution.
  2265.      *
  2266.      * @param    float        $probability    Probability for the function
  2267.      * @param    float        $degrees        degrees of freedom
  2268.      * @return  float 
  2269.      */
  2270.     public static function CHIINV($probability$degrees{
  2271.         $probability    self::flattenSingleValue($probability);
  2272.         $degrees        floor(self::flattenSingleValue($degrees));
  2273.  
  2274.         if ((is_numeric($probability)) && (is_numeric($degrees))) {
  2275.             $xLo 100;
  2276.             $xHi 0;
  2277.             $maxIteration 100;
  2278.  
  2279.             $x $xNew 1;
  2280.             $dx    1;
  2281.             $i 0;
  2282.  
  2283.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  2284.                 // Apply Newton-Raphson step
  2285.                 $result self::CHIDIST($x$degrees);
  2286.                 $error $result $probability;
  2287.                 if ($error == 0.0{
  2288.                     $dx 0;
  2289.                 elseif ($error 0.0{
  2290.                     $xLo $x;
  2291.                 else {
  2292.                     $xHi $x;
  2293.                 }
  2294.                 // Avoid division by zero
  2295.                 if ($result != 0.0{
  2296.                     $dx $error $result;
  2297.                     $xNew $x $dx;
  2298.                 }
  2299.                 // If the NR fails to converge (which for example may be the
  2300.                 // case if the initial guess is too rough) we apply a bisection
  2301.                 // step to determine a more narrow interval around the root.
  2302.                 if (($xNew $xLo|| ($xNew $xHi|| ($result == 0.0)) {
  2303.                     $xNew ($xLo $xHi2;
  2304.                     $dx $xNew $x;
  2305.                 }
  2306.                 $x $xNew;
  2307.             }
  2308.             if ($i == MAX_ITERATIONS{
  2309.                 return self::$_errorCodes['na'];
  2310.             }
  2311.             return round($x,12);
  2312.         }
  2313.         return self::$_errorCodes['value'];
  2314.     }
  2315.  
  2316.     /**
  2317.      * EXPONDIST
  2318.      *
  2319.      * Returns the exponential distribution. Use EXPONDIST to model the time between events,
  2320.      * such as how long an automated bank teller takes to deliver cash. For example, you can
  2321.      * use EXPONDIST to determine the probability that the process takes at most 1 minute.
  2322.      *
  2323.      * @param    float        $value            Value of the function
  2324.      * @param    float        $lambda            The parameter value
  2325.      * @param    boolean        $cumulative 
  2326.      * @return  float 
  2327.      */
  2328.     public static function EXPONDIST($value$lambda$cumulative{
  2329.         $value    self::flattenSingleValue($value);
  2330.         $lambda    self::flattenSingleValue($lambda);
  2331.         $cumulative    self::flattenSingleValue($cumulative);
  2332.  
  2333.         if ((is_numeric($value)) && (is_numeric($lambda))) {
  2334.             if (($value 0|| ($lambda 0)) {
  2335.                 return self::$_errorCodes['num'];
  2336.             }
  2337.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  2338.                 if ($cumulative{
  2339.                     return exp(0-$value*$lambda);
  2340.                 else {
  2341.                     return $lambda exp(0-$value*$lambda);
  2342.                 }
  2343.             }
  2344.         }
  2345.         return self::$_errorCodes['value'];
  2346.     }
  2347.  
  2348.     /**
  2349.      * FISHER
  2350.      *
  2351.      * Returns the Fisher transformation at x. This transformation produces a function that
  2352.      * is normally distributed rather than skewed. Use this function to perform hypothesis
  2353.      * testing on the correlation coefficient.
  2354.      *
  2355.      * @param    float        $value 
  2356.      * @return  float 
  2357.      */
  2358.     public static function FISHER($value{
  2359.         $value    self::flattenSingleValue($value);
  2360.  
  2361.         if (is_numeric($value)) {
  2362.             if (($value <= -1|| ($lambda >= 1)) {
  2363.                 return self::$_errorCodes['num'];
  2364.             }
  2365.             return 0.5 log((1+$value)/(1-$value));
  2366.         }
  2367.         return self::$_errorCodes['value'];
  2368.     }
  2369.  
  2370.     /**
  2371.      * FISHERINV
  2372.      *
  2373.      * Returns the inverse of the Fisher transformation. Use this transformation when
  2374.      * analyzing correlations between ranges or arrays of data. If y = FISHER(x), then
  2375.      * FISHERINV(y) = x.
  2376.      *
  2377.      * @param    float        $value 
  2378.      * @return  float 
  2379.      */
  2380.     public static function FISHERINV($value{
  2381.         $value    self::flattenSingleValue($value);
  2382.  
  2383.         if (is_numeric($value)) {
  2384.             return (exp($value1(exp($value1);
  2385.         }
  2386.         return self::$_errorCodes['value'];
  2387.     }
  2388.  
  2389.     // Function cache for logBeta
  2390.     private static $logBetaCache_p            0.0;
  2391.     private static $logBetaCache_q            0.0;
  2392.     private static $logBetaCache_result    0.0;
  2393.  
  2394.     /**
  2395.      * The natural logarithm of the beta function.
  2396.      * @param require p>0
  2397.      * @param require q>0
  2398.      * @return if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
  2399.      * @author Jaco van Kooten
  2400.      */
  2401.     private static function logBeta($p$q{
  2402.         if ($p != self::$logBetaCache_p || $q != self::$logBetaCache_q{
  2403.             self::$logBetaCache_p $p;
  2404.             self::$logBetaCache_q $q;
  2405.             if (($p <= 0.0|| ($q <= 0.0|| (($p $qLOG_GAMMA_X_MAX_VALUE)) {
  2406.                 self::$logBetaCache_result 0.0;
  2407.             else {
  2408.                 self::$logBetaCache_result self::logGamma($pself::logGamma($qself::logGamma($p $q);
  2409.             }
  2410.         }
  2411.         return self::$logBetaCache_result;
  2412.     }
  2413.  
  2414.     /**
  2415.      * Evaluates of continued fraction part of incomplete beta function.
  2416.      * Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
  2417.      * @author Jaco van Kooten
  2418.      */
  2419.     private static function betaFraction($x$p$q{
  2420.         $c 1.0;
  2421.         $sum_pq  $p $q;
  2422.         $p_plus  $p 1.0;
  2423.         $p_minus $p 1.0;
  2424.         $h 1.0 $sum_pq $x $p_plus;
  2425.         if (abs($hXMININ{
  2426.             $h XMININ;
  2427.         }
  2428.         $h 1.0 $h;
  2429.         $frac  $h;
  2430.         $m     1;
  2431.         $delta 0.0;
  2432.         while ($m <= MAX_ITERATIONS && abs($delta-1.0PRECISION {
  2433.             $m2 $m;
  2434.             // even index for d
  2435.             $d $m ($q $m$x ( ($p_minus $m2($p $m2));
  2436.             $h 1.0 $d $h;
  2437.             if (abs($hXMININ{
  2438.                 $h XMININ;
  2439.             }
  2440.             $h 1.0 $h;
  2441.             $c 1.0 $d $c;
  2442.             if (abs($cXMININ{
  2443.                 $c XMININ;
  2444.             }
  2445.             $frac *= $h $c;
  2446.             // odd index for d
  2447.             $d = -($p $m($sum_pq $m$x (($p $m2($p_plus $m2));
  2448.             $h 1.0 $d $h;
  2449.             if (abs($hXMININ{
  2450.                 $h XMININ;
  2451.             }
  2452.             $h 1.0 $h;
  2453.             $c 1.0 $d $c;
  2454.             if (abs($cXMININ{
  2455.                 $c XMININ;
  2456.             }
  2457.             $delta $h $c;
  2458.             $frac *= $delta;
  2459.             ++$m;
  2460.         }
  2461.         return $frac;
  2462.     }
  2463.  
  2464.     /**
  2465.      * logGamma function
  2466.      *
  2467.      * @version 1.1
  2468.      * @author Jaco van Kooten
  2469.      *
  2470.      *  Original author was Jaco van Kooten. Ported to PHP by Paul Meagher.
  2471.      *
  2472.      *  The natural logarithm of the gamma function. <br />
  2473.      *  Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz <br />
  2474.      *  Applied Mathematics Division <br />
  2475.      *  Argonne National Laboratory <br />
  2476.      *  Argonne, IL 60439 <br />
  2477.      *  <p>
  2478.      *  References:
  2479.      *  <ol>
  2480.      *  <li>W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural
  2481.      *      Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.</li>
  2482.      *  <li>K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.</li>
  2483.      *  <li>Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.</li>
  2484.      *  </ol>
  2485.      *  </p>
  2486.      *  <p>
  2487.      *  From the original documentation:
  2488.      *  </p>
  2489.      *  <p>
  2490.      *  This routine calculates the LOG(GAMMA) function for a positive real argument X.
  2491.      *  Computation is based on an algorithm outlined in references 1 and 2.
  2492.      *  The program uses rational functions that theoretically approximate LOG(GAMMA)
  2493.      *  to at least 18 significant decimal digits.  The approximation for X > 12 is from
  2494.      *  reference 3, while approximations for X < 12.0 are similar to those in reference
  2495.      *  1, but are unpublished. The accuracy achieved depends on the arithmetic system,
  2496.      *  the compiler, the intrinsic functions, and proper selection of the
  2497.      *  machine-dependent constants.
  2498.      *  </p>
  2499.      *  <p>
  2500.      *  Error returns: <br />
  2501.      *  The program returns the value XINF for X .LE. 0.0 or when overflow would occur.
  2502.      *  The computation is believed to be free of underflow and overflow.
  2503.      *  </p>
  2504.      * @return MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305
  2505.      */
  2506.  
  2507.     // Function cache for logGamma
  2508.     private static $logGammaCache_result    0.0;
  2509.     private static $logGammaCache_x        0.0;
  2510.  
  2511.     private static function logGamma($x{
  2512.         // Log Gamma related constants
  2513.         static $lg_d1 = -0.5772156649015328605195174;
  2514.         static $lg_d2 0.4227843350984671393993777;
  2515.         static $lg_d4 1.791759469228055000094023;
  2516.  
  2517.         static $lg_p1 array(    4.945235359296727046734888,
  2518.                                 201.8112620856775083915565,
  2519.                                 2290.838373831346393026739,
  2520.                                 11319.67205903380828685045,
  2521.                                 28557.24635671635335736389,
  2522.                                 38484.96228443793359990269,
  2523.                                 26377.48787624195437963534,
  2524.                                 7225.813979700288197698961 );
  2525.         static $lg_p2 array(    4.974607845568932035012064,
  2526.                                 542.4138599891070494101986,
  2527.                                 15506.93864978364947665077,
  2528.                                 184793.2904445632425417223,
  2529.                                 1088204.76946882876749847,
  2530.                                 3338152.967987029735917223,
  2531.                                 5106661.678927352456275255,
  2532.                                 3074109.054850539556250927 );
  2533.         static $lg_p4 array(    14745.02166059939948905062,
  2534.                                 2426813.369486704502836312,
  2535.                                 121475557.4045093227939592,
  2536.                                 2663432449.630976949898078,
  2537.                                 29403789566.34553899906876,
  2538.                                 170266573776.5398868392998,
  2539.                                 492612579337.743088758812,
  2540.                                 560625185622.3951465078242 );
  2541.  
  2542.         static $lg_q1 array(    67.48212550303777196073036,
  2543.                                 1113.332393857199323513008,
  2544.                                 7738.757056935398733233834,
  2545.                                 27639.87074403340708898585,
  2546.                                 54993.10206226157329794414,
  2547.                                 61611.22180066002127833352,
  2548.                                 36351.27591501940507276287,
  2549.                                 8785.536302431013170870835 );
  2550.         static $lg_q2 array(    183.0328399370592604055942,
  2551.                                 7765.049321445005871323047,
  2552.                                 133190.3827966074194402448,
  2553.                                 1136705.821321969608938755,
  2554.                                 5267964.117437946917577538,
  2555.                                 13467014.54311101692290052,
  2556.                                 17827365.30353274213975932,
  2557.                                 9533095.591844353613395747 );
  2558.         static $lg_q4 array(    2690.530175870899333379843,
  2559.                                 639388.5654300092398984238,
  2560.                                 41355999.30241388052042842,
  2561.                                 1120872109.61614794137657,
  2562.                                 14886137286.78813811542398,
  2563.                                 101680358627.2438228077304,
  2564.                                 341747634550.7377132798597,
  2565.                                 446315818741.9713286462081 );
  2566.  
  2567.         static $lg_c  array(    -0.001910444077728,
  2568.                                 8.4171387781295e-4,
  2569.                                 -5.952379913043012e-4,
  2570.                                 7.93650793500350248e-4,
  2571.                                 -0.002777777777777681622553,
  2572.                                 0.08333333333333333331554247,
  2573.                                 0.0057083835261 );
  2574.  
  2575.     // Rough estimate of the fourth root of logGamma_xBig
  2576.     static $lg_frtbig 2.25e76;
  2577.     static $pnt68     0.6796875;
  2578.  
  2579.  
  2580.     if ($x == self::$logGammaCache_x{
  2581.         return self::$logGammaCache_result;
  2582.     }
  2583.     $y $x;
  2584.     if ($y 0.0 && $y <= LOG_GAMMA_X_MAX_VALUE{
  2585.         if ($y <= EPS{
  2586.             $res = -log(y);
  2587.         elseif ($y <= 1.5{
  2588.             // ---------------------
  2589.             //  EPS .LT. X .LE. 1.5
  2590.             // ---------------------
  2591.             if ($y $pnt68{
  2592.                 $corr = -log($y);
  2593.                 $xm1  $y;
  2594.             else {
  2595.                 $corr 0.0;
  2596.                 $xm1  $y 1.0;
  2597.             }
  2598.             if ($y <= 0.5 || $y >= $pnt68{
  2599.                 $xden 1.0;
  2600.                 $xnum 0.0;
  2601.                 for ($i 0$i 8++$i{
  2602.                     $xnum $xnum $xm1 $lg_p1[$i];
  2603.                     $xden $xden $xm1 $lg_q1[$i];
  2604.                 }
  2605.                 $res $corr $xm1 ($lg_d1 $xm1 ($xnum $xden));
  2606.             else {
  2607.                 $xm2  $y 1.0;
  2608.                 $xden 1.0;
  2609.                 $xnum 0.0;
  2610.                 for ($i 0$i 8++$i{
  2611.                     $xnum $xnum $xm2 $lg_p2[$i];
  2612.                     $xden $xden $xm2 $lg_q2[$i];
  2613.                 }
  2614.                 $res $corr $xm2 ($lg_d2 $xm2 ($xnum $xden));
  2615.             }
  2616.         elseif ($y <= 4.0{
  2617.             // ---------------------
  2618.             //  1.5 .LT. X .LE. 4.0
  2619.             // ---------------------
  2620.             $xm2  $y 2.0;
  2621.             $xden 1.0;
  2622.             $xnum 0.0;
  2623.             for ($i 0$i 8++$i{
  2624.                 $xnum $xnum $xm2 $lg_p2[$i];
  2625.                 $xden $xden $xm2 $lg_q2[$i];
  2626.             }
  2627.             $res $xm2 ($lg_d2 $xm2 ($xnum $xden));
  2628.         elseif ($y <= 12.0{
  2629.             // ----------------------
  2630.             //  4.0 .LT. X .LE. 12.0
  2631.             // ----------------------
  2632.             $xm4  $y 4.0;
  2633.             $xden = -1.0;
  2634.             $xnum 0.0;
  2635.             for ($i 0$i 8++$i{
  2636.                 $xnum $xnum $xm4 $lg_p4[$i];
  2637.                 $xden $xden $xm4 $lg_q4[$i];
  2638.             }
  2639.             $res $lg_d4 $xm4 ($xnum $xden);
  2640.         else {
  2641.             // ---------------------------------
  2642.             //  Evaluate for argument .GE. 12.0
  2643.             // ---------------------------------
  2644.             $res 0.0;
  2645.             if ($y <= $lg_frtbig{
  2646.                 $res $lg_c[6];
  2647.                 $ysq $y $y;
  2648.                 for ($i 0$i 6++$i)
  2649.                     $res $res $ysq $lg_c[$i];
  2650.                 }
  2651.                 $res  /= $y;
  2652.                 $corr log($y);
  2653.                 $res  $res log(SQRT2PI0.5 $corr;
  2654.                 $res  += $y ($corr 1.0);
  2655.             }
  2656.         else {
  2657.             // --------------------------
  2658.             //  Return for bad arguments
  2659.             // --------------------------
  2660.             $res MAX_VALUE;
  2661.         }
  2662.         // ------------------------------
  2663.         //  Final adjustments and return
  2664.         // ------------------------------
  2665.         self::$logGammaCache_x $x;
  2666.         self::$logGammaCache_result $res;
  2667.         return $res;
  2668.     }
  2669.  
  2670.     /**
  2671.      * Beta function.
  2672.      *
  2673.      * @author Jaco van Kooten
  2674.      *
  2675.      * @param require p>0
  2676.      * @param require q>0
  2677.      * @return if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
  2678.      */
  2679.     private static function beta($p$q{
  2680.         if ($p <= 0.0 || $q <= 0.0 || ($p $qLOG_GAMMA_X_MAX_VALUE{
  2681.             return 0.0;
  2682.         else {
  2683.             return exp(self::logBeta($p$q));
  2684.         }
  2685.     }
  2686.  
  2687.     /**
  2688.      * Incomplete beta function
  2689.      *
  2690.      * @author Jaco van Kooten
  2691.      * @author Paul Meagher
  2692.      *
  2693.      *  The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992).
  2694.      * @param require 0<=x<=1
  2695.      * @param require p>0
  2696.      * @param require q>0
  2697.      * @return if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow
  2698.      */
  2699.     private static function incompleteBeta($x$p$q{
  2700.         if ($x <= 0.0{
  2701.             return 0.0;
  2702.         elseif ($x >= 1.0{
  2703.             return 1.0;
  2704.         elseif (($p <= 0.0|| ($q <= 0.0|| (($p $qLOG_GAMMA_X_MAX_VALUE)) {
  2705.             return 0.0;
  2706.         }
  2707.         $beta_gam exp((self::logBeta($p$q)) $p log($x$q log(1.0 $x));
  2708.         if ($x ($p 1.0($p $q 2.0)) {
  2709.             return $beta_gam self::betaFraction($x$p$q$p;
  2710.         else {
  2711.             return 1.0 ($beta_gam self::betaFraction($x$q$p$q);
  2712.         }
  2713.     }
  2714.  
  2715.     /**
  2716.      * BETADIST
  2717.      *
  2718.      * Returns the beta distribution.
  2719.      *
  2720.      * @param    float        $value            Value at which you want to evaluate the distribution
  2721.      * @param    float        $alpha            Parameter to the distribution
  2722.      * @param    float        $beta            Parameter to the distribution
  2723.      * @param    boolean        $cumulative 
  2724.      * @return  float 
  2725.      *
  2726.      */
  2727.     public static function BETADIST($value,$alpha,$beta,$rMin=0,$rMax=1{
  2728.         $value    self::flattenSingleValue($value);
  2729.         $alpha    self::flattenSingleValue($alpha);
  2730.         $beta    self::flattenSingleValue($beta);
  2731.         $rMin    self::flattenSingleValue($rMin);
  2732.         $rMax    self::flattenSingleValue($rMax);
  2733.  
  2734.         if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
  2735.             if (($value $rMin|| ($value $rMax|| ($alpha <= 0|| ($beta <= 0|| ($rMin == $rMax)) {
  2736.                 return self::$_errorCodes['num'];
  2737.             }
  2738.             if ($rMin $rMax{
  2739.                 $tmp $rMin;
  2740.                 $rMin $rMax;
  2741.                 $rMax $tmp;
  2742.             }
  2743.             $value -= $rMin;
  2744.             $value /= ($rMax $rMin);
  2745.             return self::incompleteBeta($value,$alpha,$beta);
  2746.         }
  2747.         return self::$_errorCodes['value'];
  2748.     }
  2749.  
  2750.     /**
  2751.      * BETAINV
  2752.      *
  2753.      * Returns the inverse of the beta distribution.
  2754.      *
  2755.      * @param    float        $probability    Probability at which you want to evaluate the distribution
  2756.      * @param    float        $alpha            Parameter to the distribution
  2757.      * @param    float        $beta            Parameter to the distribution
  2758.      * @param    boolean        $cumulative 
  2759.      * @return  float 
  2760.      *
  2761.      */
  2762.     public static function BETAINV($probability,$alpha,$beta,$rMin=0,$rMax=1{
  2763.         $probability    self::flattenSingleValue($probability);
  2764.         $alpha            self::flattenSingleValue($alpha);
  2765.         $beta            self::flattenSingleValue($beta);
  2766.         $rMin            self::flattenSingleValue($rMin);
  2767.         $rMax            self::flattenSingleValue($rMax);
  2768.  
  2769.         if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
  2770.             if (($alpha <= 0|| ($beta <= 0|| ($rMin == $rMax|| ($probability <= 0|| ($probability 1)) {
  2771.                 return self::$_errorCodes['num'];
  2772.             }
  2773.             if ($rMin $rMax{
  2774.                 $tmp $rMin;
  2775.                 $rMin $rMax;
  2776.                 $rMax $tmp;
  2777.             }
  2778.             $a 0;
  2779.             $b 2;
  2780.             $maxIteration 100;
  2781.  
  2782.             $i 0;
  2783.             while ((($b $aPRECISION&& ($i++ < MAX_ITERATIONS)) {
  2784.                 $guess ($a $b2;
  2785.                 $result self::BETADIST($guess$alpha$beta);
  2786.                 if (($result == $probability|| ($result == 0)) {
  2787.                     $b $a;
  2788.                 elseif ($result $probability{
  2789.                     $b $guess;
  2790.                 else {
  2791.                     $a $guess;
  2792.                 }
  2793.             }
  2794.             if ($i == MAX_ITERATIONS{
  2795.                 return self::$_errorCodes['na'];
  2796.             }
  2797.             return round($rMin $guess ($rMax $rMin),12);
  2798.         }
  2799.         return self::$_errorCodes['value'];
  2800.     }
  2801.  
  2802.     //
  2803.     //    Private implementation of the incomplete Gamma function
  2804.     //
  2805.     private static function incompleteGamma($a,$x{
  2806.         static $max 32;
  2807.         $summer 0;
  2808.         for ($n=0$n<=$max++$n{
  2809.             $divisor $a;
  2810.             for ($i=1$i<=$n++$i{
  2811.                 $divisor *= ($a $i);
  2812.             }
  2813.             $summer += (pow($x,$n$divisor);
  2814.         }
  2815.         return pow($x,$aexp(0-$x$summer;
  2816.     }
  2817.  
  2818.  
  2819.     //
  2820.     //    Private implementation of the Gamma function
  2821.     //
  2822.     private static function gamma($data{
  2823.         if ($data == 0.0return 0;
  2824.  
  2825.         static $p0 1.000000000190015;
  2826.         static $p array => 76.18009172947146,
  2827.                             => -86.50532032941677,
  2828.                             => 24.01409824083091,
  2829.                             => -1.231739572450155,
  2830.                             => 1.208650973866179e-3,
  2831.                             => -5.395239384953e-6
  2832.                           );
  2833.  
  2834.         $y $x $data;
  2835.         $tmp $x 5.5;
  2836.         $tmp -= ($x 0.5log($tmp);
  2837.  
  2838.         $summer $p0;
  2839.         for ($j=1;$j<=6;++$j{
  2840.             $summer += ($p[$j/ ++$y);
  2841.         }
  2842.         return exp($tmp log(2.5066282746310005 $summer $x));
  2843.     }
  2844.  
  2845.     /**
  2846.      * GAMMADIST
  2847.      *
  2848.      * Returns the gamma distribution.
  2849.      *
  2850.      * @param    float        $value            Value at which you want to evaluate the distribution
  2851.      * @param    float        $a                Parameter to the distribution
  2852.      * @param    float        $b                Parameter to the distribution
  2853.      * @param    boolean        $cumulative 
  2854.      * @return  float 
  2855.      *
  2856.      */
  2857.     public static function GAMMADIST($value,$a,$b,$cumulative{
  2858.         $value    self::flattenSingleValue($value);
  2859.         $a        self::flattenSingleValue($a);
  2860.         $b        self::flattenSingleValue($b);
  2861.  
  2862.         if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) {
  2863.             if (($value 0|| ($a <= 0|| ($b <= 0)) {
  2864.                 return self::$_errorCodes['num'];
  2865.             }
  2866.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  2867.                 if ($cumulative{
  2868.                     return self::incompleteGamma($a,$value $bself::gamma($a);
  2869.                 else {
  2870.                     return ((pow($b,$aself::gamma($a))) pow($value,$a-1exp(0-($value $b));
  2871.                 }
  2872.             }
  2873.         }
  2874.         return self::$_errorCodes['value'];
  2875.     }
  2876.  
  2877.     /**
  2878.      * GAMMAINV
  2879.      *
  2880.      * Returns the inverse of the beta distribution.
  2881.      *
  2882.      * @param    float        $probability    Probability at which you want to evaluate the distribution
  2883.      * @param    float        $alpha            Parameter to the distribution
  2884.      * @param    float        $beta            Parameter to the distribution
  2885.      * @param    boolean        $cumulative 
  2886.      * @return  float 
  2887.      *
  2888.      */
  2889.     public static function GAMMAINV($probability,$alpha,$beta{
  2890.         $probability    self::flattenSingleValue($probability);
  2891.         $alpha            self::flattenSingleValue($alpha);
  2892.         $beta            self::flattenSingleValue($beta);
  2893.         $rMin            self::flattenSingleValue($rMin);
  2894.         $rMax            self::flattenSingleValue($rMax);
  2895.  
  2896.         if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) {
  2897.             if (($alpha <= 0|| ($beta <= 0|| ($probability <= 0|| ($probability 1)) {
  2898.                 return self::$_errorCodes['num'];
  2899.             }
  2900.             $xLo 0;
  2901.             $xHi 100;
  2902.             $maxIteration 100;
  2903.  
  2904.             $x $xNew 1;
  2905.             $dx    1;
  2906.             $i 0;
  2907.  
  2908.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  2909.                 // Apply Newton-Raphson step
  2910.                 $result self::GAMMADIST($x$alpha$betaTrue);
  2911.                 $error $result $probability;
  2912.                 if ($error == 0.0{
  2913.                     $dx 0;
  2914.                 elseif ($error 0.0{
  2915.                     $xLo $x;
  2916.                 else {
  2917.                     $xHi $x;
  2918.                 }
  2919.                 // Avoid division by zero
  2920.                 if ($result != 0.0{
  2921.                     $dx $error $result;
  2922.                     $xNew $x $dx;
  2923.                 }
  2924.                 // If the NR fails to converge (which for example may be the
  2925.                 // case if the initial guess is too rough) we apply a bisection
  2926.                 // step to determine a more narrow interval around the root.
  2927.                 if (($xNew $xLo|| ($xNew $xHi|| ($result == 0.0)) {
  2928.                     $xNew ($xLo $xHi2;
  2929.                     $dx $xNew $x;
  2930.                 }
  2931.                 $x $xNew;
  2932.             }
  2933.             if ($i == MAX_ITERATIONS{
  2934.                 return self::$_errorCodes['na'];
  2935.             }
  2936.             return round($x,12);
  2937.         }
  2938.         return self::$_errorCodes['value'];
  2939.     }
  2940.  
  2941.     /**
  2942.      * GAMMALN
  2943.      *
  2944.      * Returns the natural logarithm of the gamma function.
  2945.      *
  2946.      * @param    float        $value 
  2947.      * @return  float 
  2948.      */
  2949.     public static function GAMMALN($value{
  2950.         $value    self::flattenSingleValue($value);
  2951.  
  2952.         if (is_numeric($value)) {
  2953.             if ($value <= 0{
  2954.                 return self::$_errorCodes['num'];
  2955.             }
  2956.             return log(self::gamma($value));
  2957.         }
  2958.         return self::$_errorCodes['value'];
  2959.     }
  2960.  
  2961.     /**
  2962.      * NORMDIST
  2963.      *
  2964.      * Returns the normal distribution for the specified mean and standard deviation. This
  2965.      * function has a very wide range of applications in statistics, including hypothesis
  2966.      * testing.
  2967.      *
  2968.      * @param    float        $value 
  2969.      * @param    float        $mean        Mean Value
  2970.      * @param    float        $stdDev        Standard Deviation
  2971.      * @param    boolean        $cumulative 
  2972.      * @return  float 
  2973.      *
  2974.      */
  2975.     public static function NORMDIST($value$mean$stdDev$cumulative{
  2976.         $value    self::flattenSingleValue($value);
  2977.         $mean    self::flattenSingleValue($mean);
  2978.         $stdDev    self::flattenSingleValue($stdDev);
  2979.  
  2980.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  2981.             if ($stdDev 0{
  2982.                 return self::$_errorCodes['num'];
  2983.             }
  2984.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  2985.                 if ($cumulative{
  2986.                     return 0.5 (self::erfVal(($value $mean($stdDev sqrt(2))));
  2987.                 else {
  2988.                     return ((SQRT2PI $stdDev)) exp(0  (pow($value $mean,2(pow($stdDev,2))));
  2989.                 }
  2990.             }
  2991.         }
  2992.         return self::$_errorCodes['value'];
  2993.     }
  2994.  
  2995.     /**
  2996.      * NORMSDIST
  2997.      *
  2998.      * Returns the standard normal cumulative distribution function. The distribution has
  2999.      * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a
  3000.      * table of standard normal curve areas.
  3001.      *
  3002.      * @param    float        $value 
  3003.      * @return  float 
  3004.      */
  3005.     public static function NORMSDIST($value{
  3006.         $value    self::flattenSingleValue($value);
  3007.  
  3008.         return self::NORMDIST($value01True);
  3009.     }
  3010.  
  3011.     /**
  3012.      * LOGNORMDIST
  3013.      *
  3014.      * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed
  3015.      * with parameters mean and standard_dev.
  3016.      *
  3017.      * @param    float        $value 
  3018.      * @return  float 
  3019.      */
  3020.     public static function LOGNORMDIST($value$mean$stdDev{
  3021.         $value    self::flattenSingleValue($value);
  3022.         $mean    self::flattenSingleValue($mean);
  3023.         $stdDev    self::flattenSingleValue($stdDev);
  3024.  
  3025.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  3026.             if (($value <= 0|| ($stdDev <= 0)) {
  3027.                 return self::$_errorCodes['num'];
  3028.             }
  3029.             return self::NORMSDIST((log($value$mean$stdDev);
  3030.         }
  3031.         return self::$_errorCodes['value'];
  3032.     }
  3033.  
  3034.     /***************************************************************************
  3035.      *                                inverse_ncdf.php
  3036.      *                            -------------------
  3037.      *   begin                : Friday, January 16, 2004
  3038.      *   copyright            : (C) 2004 Michael Nickerson
  3039.      *   email                : nickersonm@yahoo.com
  3040.      *
  3041.      ***************************************************************************/
  3042.     private static function inverse_ncdf($p{
  3043.         //    Inverse ncdf approximation by Peter J. Acklam, implementation adapted to
  3044.         //    PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
  3045.         //    a guide.  http://home.online.no/~pjacklam/notes/invnorm/index.html
  3046.         //    I have not checked the accuracy of this implementation.  Be aware that PHP
  3047.         //    will truncate the coeficcients to 14 digits.
  3048.  
  3049.         //    You have permission to use and distribute this function freely for
  3050.         //    whatever purpose you want, but please show common courtesy and give credit
  3051.         //    where credit is due.
  3052.  
  3053.         //    Input paramater is $p - probability - where 0 < p < 1.
  3054.  
  3055.         //    Coefficients in rational approximations
  3056.         static $a array(    => -3.969683028665376e+01,
  3057.                             => 2.209460984245205e+02,
  3058.                             => -2.759285104469687e+02,
  3059.                             => 1.383577518672690e+02,
  3060.                             => -3.066479806614716e+01,
  3061.                             => 2.506628277459239e+00
  3062.                           );
  3063.  
  3064.         static $b array(    => -5.447609879822406e+01,
  3065.                             => 1.615858368580409e+02,
  3066.                             => -1.556989798598866e+02,
  3067.                             => 6.680131188771972e+01,
  3068.                             => -1.328068155288572e+01
  3069.                           );
  3070.  
  3071.         static $c array(    => -7.784894002430293e-03,
  3072.                             => -3.223964580411365e-01,
  3073.                             => -2.400758277161838e+00,
  3074.                             => -2.549732539343734e+00,
  3075.                             => 4.374664141464968e+00,
  3076.                             => 2.938163982698783e+00
  3077.                           );
  3078.  
  3079.         static $d array(    => 7.784695709041462e-03,
  3080.                             => 3.224671290700398e-01,
  3081.                             => 2.445134137142996e+00,
  3082.                             => 3.754408661907416e+00
  3083.                           );
  3084.  
  3085.         //    Define lower and upper region break-points.
  3086.         $p_low =  0.02425;            //Use lower region approx. below this
  3087.         $p_high $p_low;        //Use upper region approx. above this
  3088.  
  3089.         if ($p && $p $p_low{
  3090.             //    Rational approximation for lower region.
  3091.             $q sqrt(-log($p));
  3092.             return ((((($c[1$q $c[2]$q $c[3]$q $c[4]$q $c[5]$q $c[6]/
  3093.                     (((($d[1$q $d[2]$q $d[3]$q $d[4]$q 1);
  3094.         elseif ($p_low <= $p && $p <= $p_high{
  3095.             //    Rational approximation for central region.
  3096.             $q $p 0.5;
  3097.             $r $q $q;
  3098.             return ((((($a[1$r $a[2]$r $a[3]$r $a[4]$r $a[5]$r $a[6]$q /
  3099.                    ((((($b[1$r $b[2]$r $b[3]$r $b[4]$r $b[5]$r 1);
  3100.         elseif ($p_high $p && $p 1{
  3101.             //    Rational approximation for upper region.
  3102.             $q sqrt(-log($p));
  3103.             return -((((($c[1$q $c[2]$q $c[3]$q $c[4]$q $c[5]$q $c[6]/
  3104.                      (((($d[1$q $d[2]$q $d[3]$q $d[4]$q 1);
  3105.         }
  3106.         //    If 0 < p < 1, return a null value
  3107.         return self::$_errorCodes['null'];
  3108.     }
  3109.  
  3110.     private static function inverse_ncdf2($prob{
  3111.         //    Approximation of inverse standard normal CDF developed by
  3112.         //    B. Moro, "The Full Monte," Risk 8(2), Feb 1995, 57-58.
  3113.  
  3114.         $a1 2.50662823884;
  3115.         $a2 = -18.61500062529;
  3116.         $a3 41.39119773534;
  3117.         $a4 = -25.44106049637;
  3118.  
  3119.         $b1 = -8.4735109309;
  3120.         $b2 23.08336743743;
  3121.         $b3 = -21.06224101826;
  3122.         $b4 3.13082909833;
  3123.  
  3124.         $c1 0.337475482272615;
  3125.         $c2 0.976169019091719;
  3126.         $c3 0.160797971491821;
  3127.         $c4 2.76438810333863E-02;
  3128.         $c5 3.8405729373609E-03;
  3129.         $c6 3.951896511919E-04;
  3130.         $c7 3.21767881768E-05;
  3131.         $c8 2.888167364E-07;
  3132.         $c9 3.960315187E-07;
  3133.  
  3134.         $y $prob 0.5;
  3135.         if (abs($y0.42{
  3136.             $z pow($y,2);
  3137.             $z $y ((($a4 $z $a3$z $a2$z $a1(((($b4 $z $b3$z $b2$z $b1$z 1);
  3138.         else {
  3139.             if ($y 0{
  3140.                 $z log(-log($prob));
  3141.             else {
  3142.                 $z log(-log($prob));
  3143.             }
  3144.             $z $c1 $z ($c2 $z ($c3 $z ($c4 $z ($c5 $z ($c6 $z ($c7 $z ($c8 $z $c9)))))));
  3145.             if ($y 0{
  3146.                 $z = -$z;
  3147.             }
  3148.         }
  3149.         return $z;
  3150.     }
  3151.  
  3152.     private static function inverse_ncdf3($p{
  3153.         //    ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3.
  3154.         //    Produces the normal deviate Z corresponding to a given lower
  3155.         //    tail area of P; Z is accurate to about 1 part in 10**16.
  3156.         //
  3157.         //    This is a PHP version of the original FORTRAN code that can
  3158.         //    be found at http://lib.stat.cmu.edu/apstat/
  3159.         $split1 0.425;
  3160.         $split2 5;
  3161.         $const1 0.180625;
  3162.         $const2 1.6;
  3163.  
  3164.         //    coefficients for p close to 0.5
  3165.         $a0 3.3871328727963666080;
  3166.         $a1 1.3314166789178437745E+2;
  3167.         $a2 1.9715909503065514427E+3;
  3168.         $a3 1.3731693765509461125E+4;
  3169.         $a4 4.5921953931549871457E+4;
  3170.         $a5 6.7265770927008700853E+4;
  3171.         $a6 3.3430575583588128105E+4;
  3172.         $a7 2.5090809287301226727E+3;
  3173.  
  3174.         $b1 4.2313330701600911252E+1;
  3175.         $b2 6.8718700749205790830E+2;
  3176.         $b3 5.3941960214247511077E+3;
  3177.         $b4 2.1213794301586595867E+4;
  3178.         $b5 3.9307895800092710610E+4;
  3179.         $b6 2.8729085735721942674E+4;
  3180.         $b7 5.2264952788528545610E+3;
  3181.  
  3182.         //    coefficients for p not close to 0, 0.5 or 1.
  3183.         $c0 1.42343711074968357734;
  3184.         $c1 4.63033784615654529590;
  3185.         $c2 5.76949722146069140550;
  3186.         $c3 3.64784832476320460504;
  3187.         $c4 1.27045825245236838258;
  3188.         $c5 2.41780725177450611770E-1;
  3189.         $c6 2.27238449892691845833E-2;
  3190.         $c7 7.74545014278341407640E-4;
  3191.  
  3192.         $d1 2.05319162663775882187;
  3193.         $d2 1.67638483018380384940;
  3194.         $d3 6.89767334985100004550E-1;
  3195.         $d4 1.48103976427480074590E-1;
  3196.         $d5 1.51986665636164571966E-2;
  3197.         $d6 5.47593808499534494600E-4;
  3198.         $d7 1.05075007164441684324E-9;
  3199.  
  3200.         //    coefficients for p near 0 or 1.
  3201.         $e0 6.65790464350110377720;
  3202.         $e1 5.46378491116411436990;
  3203.         $e2 1.78482653991729133580;
  3204.         $e3 2.96560571828504891230E-1;
  3205.         $e4 2.65321895265761230930E-2;
  3206.         $e5 1.24266094738807843860E-3;
  3207.         $e6 2.71155556874348757815E-5;
  3208.         $e7 2.01033439929228813265E-7;
  3209.  
  3210.         $f1 5.99832206555887937690E-1;
  3211.         $f2 1.36929880922735805310E-1;
  3212.         $f3 1.48753612908506148525E-2;
  3213.         $f4 7.86869131145613259100E-4;
  3214.         $f5 1.84631831751005468180E-5;
  3215.         $f6 1.42151175831644588870E-7;
  3216.         $f7 2.04426310338993978564E-15;
  3217.  
  3218.         $q $p 0.5;
  3219.  
  3220.         //    computation for p close to 0.5
  3221.         if (abs($q<= split1{
  3222.             $R $const1 $q $q;
  3223.             $z $q ((((((($a7 $R $a6$R $a5$R $a4$R $a3$R $a2$R $a1$R $a0/
  3224.                       ((((((($b7 $R $b6$R $b5$R $b4$R $b3$R $b2$R $b1$R 1);
  3225.         else {
  3226.             if ($q 0{
  3227.                 $R $p;
  3228.             else {
  3229.                 $R $p;
  3230.             }
  3231.             $R pow(-log($R),2);
  3232.  
  3233.             //    computation for p not close to 0, 0.5 or 1.
  3234.             If ($R <= $split2{
  3235.                 $R $R $const2;
  3236.                 $z ((((((($c7 $R $c6$R $c5$R $c4$R $c3$R $c2$R $c1$R $c0/
  3237.                      ((((((($d7 $R $d6$R $d5$R $d4$R $d3$R $d2$R $d1$R 1);
  3238.             else {
  3239.             //    computation for p near 0 or 1.
  3240.                 $R $R $split2;
  3241.                 $z ((((((($e7 $R $e6$R $e5$R $e4$R $e3$R $e2$R $e1$R $e0/
  3242.                      ((((((($f7 $R $f6$R $f5$R $f4$R $f3$R $f2$R $f1$R 1);
  3243.             }
  3244.             if ($q 0{
  3245.                 $z = -$z;
  3246.             }
  3247.         }
  3248.         return $z;
  3249.     }
  3250.  
  3251.     /**
  3252.      * NORMINV
  3253.      *
  3254.      * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation.
  3255.      *
  3256.      * @param    float        $value 
  3257.      * @param    float        $mean        Mean Value
  3258.      * @param    float        $stdDev        Standard Deviation
  3259.      * @return  float 
  3260.      *
  3261.      */
  3262.     public static function NORMINV($probability,$mean,$stdDev{
  3263.         $probability    self::flattenSingleValue($probability);
  3264.         $mean            self::flattenSingleValue($mean);
  3265.         $stdDev            self::flattenSingleValue($stdDev);
  3266.  
  3267.         if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  3268.             if (($probability 0|| ($probability 1)) {
  3269.                 return self::$_errorCodes['num'];
  3270.             }
  3271.             if ($stdDev 0{
  3272.                 return self::$_errorCodes['num'];
  3273.             }
  3274.             return (self::inverse_ncdf($probability$stdDev$mean;
  3275.         }
  3276.         return self::$_errorCodes['value'];
  3277.     }
  3278.  
  3279.     /**
  3280.      * NORMSINV
  3281.      *
  3282.      * Returns the inverse of the standard normal cumulative distribution
  3283.      *
  3284.      * @param    float        $value 
  3285.      * @return  float 
  3286.      */
  3287.     public static function NORMSINV($value{
  3288.         return self::NORMINV($value01);
  3289.     }
  3290.  
  3291.     /**
  3292.      * LOGINV
  3293.      *
  3294.      * Returns the inverse of the normal cumulative distribution
  3295.      *
  3296.      * @param    float        $value 
  3297.      * @return  float 
  3298.      *
  3299.      * @todo    Try implementing P J Acklam's refinement algorithm for greater
  3300.      *             accuracy if I can get my head round the mathematics
  3301.      *             (as described at) http://home.online.no/~pjacklam/notes/invnorm/
  3302.      */
  3303.     public static function LOGINV($probability$mean$stdDev{
  3304.         $probability    self::flattenSingleValue($probability);
  3305.         $mean            self::flattenSingleValue($mean);
  3306.         $stdDev            self::flattenSingleValue($stdDev);
  3307.  
  3308.         if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  3309.             if (($probability 0|| ($probability 1|| ($stdDev <= 0)) {
  3310.                 return self::$_errorCodes['num'];
  3311.             }
  3312.             return exp($mean $stdDev self::NORMSINV($probability));
  3313.         }
  3314.         return self::$_errorCodes['value'];
  3315.     }
  3316.  
  3317.     /**
  3318.      * HYPGEOMDIST
  3319.      *
  3320.      * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of
  3321.      * sample successes, given the sample size, population successes, and population size.
  3322.      *
  3323.      * @param    float        $sampleSuccesses        Number of successes in the sample
  3324.      * @param    float        $sampleNumber            Size of the sample
  3325.      * @param    float        $populationSuccesses    Number of successes in the population
  3326.      * @param    float        $populationNumber        Population size
  3327.      * @return  float 
  3328.      *
  3329.      */
  3330.     public static function HYPGEOMDIST($sampleSuccesses$sampleNumber$populationSuccesses$populationNumber{
  3331.         $sampleSuccesses        floor(self::flattenSingleValue($sampleSuccesses));
  3332.         $sampleNumber            floor(self::flattenSingleValue($sampleNumber));
  3333.         $populationSuccesses    floor(self::flattenSingleValue($populationSuccesses));
  3334.         $populationNumber        floor(self::flattenSingleValue($populationNumber));
  3335.  
  3336.         if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) {
  3337.             if (($sampleSuccesses 0|| ($sampleSuccesses $sampleNumber|| ($sampleSuccesses $populationSuccesses)) {
  3338.                 return self::$_errorCodes['num'];
  3339.             }
  3340.             if (($sampleNumber <= 0|| ($sampleNumber $populationNumber)) {
  3341.                 return self::$_errorCodes['num'];
  3342.             }
  3343.             if (($populationSuccesses <= 0|| ($populationSuccesses $populationNumber)) {
  3344.                 return self::$_errorCodes['num'];
  3345.             }
  3346.             return self::COMBIN($populationSuccesses,$sampleSuccesses*
  3347.                    self::COMBIN($populationNumber $populationSuccesses,$sampleNumber $sampleSuccesses/
  3348.                    self::COMBIN($populationNumber,$sampleNumber);
  3349.         }
  3350.         return self::$_errorCodes['value'];
  3351.     }
  3352.  
  3353.     public static function hypGeom($sampleSuccesses$sampleNumber$populationSuccesses$populationNumber{
  3354.         return self::COMBIN($populationSuccesses,$sampleSuccesses*
  3355.                self::COMBIN($populationNumber $populationSuccesses,$sampleNumber $sampleSuccesses/
  3356.                self::COMBIN($populationNumber,$sampleNumber);
  3357.     }
  3358.  
  3359.     /**
  3360.      * TDIST
  3361.      *
  3362.      * Returns the probability of Student's T distribution.
  3363.      *
  3364.      * @param    float        $value            Value for the function
  3365.      * @param    float        $degrees        degrees of freedom
  3366.      * @param    float        $tails            number of tails (1 or 2)
  3367.      * @return  float 
  3368.      */
  3369.     public static function TDIST($value$degrees$tails{
  3370.         $value        self::flattenSingleValue($value);
  3371.         $degrees    floor(self::flattenSingleValue($degrees));
  3372.         $tails        floor(self::flattenSingleValue($tails));
  3373.  
  3374.         if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) {
  3375.             if (($value 0|| ($degrees 1|| ($tails 1|| ($tails 2)) {
  3376.                 return self::$_errorCodes['num'];
  3377.             }
  3378.             //    tdist, which finds the probability that corresponds to a given value
  3379.             //    of t with k degrees of freedom.  This algorithm is translated from a
  3380.             //    pascal function on p81 of "Statistical Computing in Pascal" by D
  3381.             //    Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd:
  3382.             //    London).  The above Pascal algorithm is itself a translation of the
  3383.             //    fortran algoritm "AS 3" by B E Cooper of the Atlas Computer
  3384.             //    Laboratory as reported in (among other places) "Applied Statistics
  3385.             //    Algorithms", editied by P Griffiths and I D Hill (1985; Ellis
  3386.             //    Horwood Ltd.; W. Sussex, England).
  3387. //            $ta = 2 / pi();
  3388.             $ta 0.636619772367581;
  3389.             $tterm $degrees;
  3390.             $ttheta atan2($value,sqrt($tterm));
  3391.             $tc cos($ttheta);
  3392.             $ts sin($ttheta);
  3393.             $tsum 0;
  3394.  
  3395.             if (($degrees 2== 1{
  3396.                 $ti 3;
  3397.                 $tterm $tc;
  3398.             else {
  3399.                 $ti 2;
  3400.                 $tterm 1;
  3401.             }
  3402.  
  3403.             $tsum $tterm;
  3404.             while ($ti $degrees{
  3405.                 $tterm *= $tc $tc ($ti 1$ti;
  3406.                 $tsum += $tterm;
  3407.                 $ti += 2;
  3408.             }
  3409.             $tsum *= $ts;
  3410.             if (($degrees 2== 1$tsum $ta ($tsum $ttheta)}
  3411.             $tValue 0.5 ($tsum);
  3412.             if ($tails == 1{
  3413.                 return abs($tValue);
  3414.             else {
  3415.                 return abs(($tValue$tValue);
  3416.             }
  3417.         }
  3418.         return self::$_errorCodes['value'];
  3419.     }
  3420.  
  3421.     /**
  3422.      * TINV
  3423.      *
  3424.      * Returns the one-tailed probability of the chi-squared distribution.
  3425.      *
  3426.      * @param    float        $probability    Probability for the function
  3427.      * @param    float        $degrees        degrees of freedom
  3428.      * @return  float 
  3429.      */
  3430.     public static function TINV($probability$degrees{
  3431.         $probability    self::flattenSingleValue($probability);
  3432.         $degrees        floor(self::flattenSingleValue($degrees));
  3433.  
  3434.         if ((is_numeric($probability)) && (is_numeric($degrees))) {
  3435.             $xLo 100;
  3436.             $xHi 0;
  3437.             $maxIteration 100;
  3438.  
  3439.             $x $xNew 1;
  3440.             $dx    1;
  3441.             $i 0;
  3442.  
  3443.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  3444.                 // Apply Newton-Raphson step
  3445.                 $result self::TDIST($x$degrees2);
  3446.                 $error $result $probability;
  3447.                 if ($error == 0.0{
  3448.                     $dx 0;
  3449.                 elseif ($error 0.0{
  3450.                     $xLo $x;
  3451.                 else {
  3452.                     $xHi $x;
  3453.                 }
  3454.                 // Avoid division by zero
  3455.                 if ($result != 0.0{
  3456.                     $dx $error $result;
  3457.                     $xNew $x $dx;
  3458.                 }
  3459.                 // If the NR fails to converge (which for example may be the
  3460.                 // case if the initial guess is too rough) we apply a bisection
  3461.                 // step to determine a more narrow interval around the root.
  3462.                 if (($xNew $xLo|| ($xNew $xHi|| ($result == 0.0)) {
  3463.                     $xNew ($xLo $xHi2;
  3464.                     $dx $xNew $x;
  3465.                 }
  3466.                 $x $xNew;
  3467.             }
  3468.             if ($i == MAX_ITERATIONS{
  3469.                 return self::$_errorCodes['na'];
  3470.             }
  3471.             return round($x,12);
  3472.         }
  3473.         return self::$_errorCodes['value'];
  3474.     }
  3475.  
  3476.     /**
  3477.      * CONFIDENCE
  3478.      *
  3479.      * Returns the confidence interval for a population mean
  3480.      *
  3481.      * @param    float        $alpha 
  3482.      * @param    float        $stdDev        Standard Deviation
  3483.      * @param    float        $size 
  3484.      * @return  float 
  3485.      *
  3486.      */
  3487.     public static function CONFIDENCE($alpha,$stdDev,$size{
  3488.         $alpha    self::flattenSingleValue($alpha);
  3489.         $stdDev    self::flattenSingleValue($stdDev);
  3490.         $size    floor(self::flattenSingleValue($size));
  3491.  
  3492.         if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) {
  3493.             if (($alpha <= 0|| ($alpha >= 1)) {
  3494.                 return self::$_errorCodes['num'];
  3495.             }
  3496.             if (($stdDev <= 0|| ($size 1)) {
  3497.                 return self::$_errorCodes['num'];
  3498.             }
  3499.             return self::NORMSINV($alpha 2$stdDev sqrt($size);
  3500.         }
  3501.         return self::$_errorCodes['value'];
  3502.     }
  3503.  
  3504.     /**
  3505.      * POISSON
  3506.      *
  3507.      * Returns the Poisson distribution. A common application of the Poisson distribution
  3508.      * is predicting the number of events over a specific time, such as the number of
  3509.      * cars arriving at a toll plaza in 1 minute.
  3510.      *
  3511.      * @param    float        $value 
  3512.      * @param    float        $mean        Mean Value
  3513.      * @param    boolean        $cumulative 
  3514.      * @return  float 
  3515.      *
  3516.      */
  3517.     public static function POISSON($value$mean$cumulative{
  3518.         $value    self::flattenSingleValue($value);
  3519.         $mean    self::flattenSingleValue($mean);
  3520.  
  3521.         if ((is_numeric($value)) && (is_numeric($mean))) {
  3522.             if (($value <= 0|| ($mean <= 0)) {
  3523.                 return self::$_errorCodes['num'];
  3524.             }
  3525.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  3526.                 if ($cumulative{
  3527.                     $summer 0;
  3528.                     for ($i 0$i <= floor($value)++$i{
  3529.                         $summer += pow($mean,$iself::FACT($i);
  3530.                     }
  3531.                     return exp(0-$mean$summer;
  3532.                 else {
  3533.                     return (exp(0-$meanpow($mean,$value)) self::FACT($value);
  3534.                 }
  3535.             }
  3536.         }
  3537.         return self::$_errorCodes['value'];
  3538.     }
  3539.  
  3540.     /**
  3541.      * WEIBULL
  3542.      *
  3543.      * Returns the Weibull distribution. Use this distribution in reliability
  3544.      * analysis, such as calculating a device's mean time to failure.
  3545.      *
  3546.      * @param    float        $value 
  3547.      * @param    float        $alpha        Alpha Parameter
  3548.      * @param    float        $beta        Beta Parameter
  3549.      * @param    boolean        $cumulative 
  3550.      * @return  float 
  3551.      *
  3552.      */
  3553.     public static function WEIBULL($value$alpha$beta$cumulative{
  3554.         $value    self::flattenSingleValue($value);
  3555.         $alpha    self::flattenSingleValue($alpha);
  3556.         $beta    self::flattenSingleValue($beta);
  3557.  
  3558.         if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) {
  3559.             if (($value 0|| ($alpha <= 0|| ($beta <= 0)) {
  3560.                 return self::$_errorCodes['num'];
  3561.             }
  3562.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  3563.                 if ($cumulative{
  3564.                     return exp(pow($value $beta,$alpha));
  3565.                 else {
  3566.                     return ($alpha pow($beta,$alpha)) pow($value,$alpha 1exp(pow($value $beta,$alpha));
  3567.                 }
  3568.             }
  3569.         }
  3570.         return self::$_errorCodes['value'];
  3571.     }
  3572.  
  3573.     /**
  3574.      * SKEW
  3575.      *
  3576.      * Returns the skewness of a distribution. Skewness characterizes the degree of asymmetry
  3577.      * of a distribution around its mean. Positive skewness indicates a distribution with an
  3578.      * asymmetric tail extending toward more positive values. Negative skewness indicates a
  3579.      * distribution with an asymmetric tail extending toward more negative values.
  3580.      *
  3581.      * @param    array    Data Series
  3582.      * @return  float 
  3583.      */
  3584.     public static function SKEW({
  3585.         $aArgs self::flattenArray(func_get_args());
  3586.         $mean self::AVERAGE($aArgs);
  3587.         $stdDev self::STDEV($aArgs);
  3588.  
  3589.         $count $summer 0;
  3590.         // Loop through arguments
  3591.         foreach ($aArgs as $arg{
  3592.             // Is it a numeric value?
  3593.             if ((is_numeric($arg)) && (!is_string($arg))) {
  3594.                 $summer += pow((($arg $mean$stdDev),3;
  3595.                 ++$count;
  3596.             }
  3597.         }
  3598.  
  3599.         // Return
  3600.         if ($count 2{
  3601.             return $summer ($count (($count-1($count-2)));
  3602.         }
  3603.         return self::$_errorCodes['divisionbyzero'];
  3604.     }
  3605.  
  3606.     /**
  3607.      * KURT
  3608.      *
  3609.      * Returns the kurtosis of a data set. Kurtosis characterizes the relative peakedness
  3610.      * or flatness of a distribution compared with the normal distribution. Positive
  3611.      * kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a
  3612.      * relatively flat distribution.
  3613.      *
  3614.      * @param    array    Data Series
  3615.      * @return  float 
  3616.      */
  3617.     public static function KURT({
  3618.         $aArgs self::flattenArray(func_get_args());
  3619.         $mean self::AVERAGE($aArgs);
  3620.         $stdDev self::STDEV($aArgs);
  3621.  
  3622.         if ($stdDev 0{
  3623.             $count $summer 0;
  3624.             // Loop through arguments
  3625.             foreach ($aArgs as $arg{
  3626.                 // Is it a numeric value?
  3627.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  3628.                     $summer += pow((($arg $mean$stdDev),4;
  3629.                     ++$count;
  3630.                 }
  3631.             }
  3632.  
  3633.             // Return
  3634.             if ($count 3{
  3635.                 return $summer ($count ($count+1(($count-1($count-2($count-3))) (pow($count-1,2(($count-2($count-3)));
  3636.             }
  3637.         }
  3638.         return self::$_errorCodes['divisionbyzero'];
  3639.     }
  3640.  
  3641.     /**
  3642.      * RAND
  3643.      *
  3644.      * @param    int        $min    Minimal value
  3645.      * @param    int        $max    Maximal value
  3646.      * @return  int        Random number
  3647.      */
  3648.     public static function RAND($min 0$max 0{
  3649.         $min        self::flattenSingleValue($min);
  3650.         $max        self::flattenSingleValue($max);
  3651.  
  3652.         if ($min == && $max == 0{
  3653.             return (rand(0,10000000)) 10000000;
  3654.         else {
  3655.             return rand($min$max);
  3656.         }
  3657.     }
  3658.  
  3659.     /**
  3660.      * MOD
  3661.      *
  3662.      * @param    int        $a        Dividend
  3663.      * @param    int        $b        Divisor
  3664.      * @return  int        Remainder
  3665.      */
  3666.     public static function MOD($a 1$b 1{
  3667.         $a        self::flattenSingleValue($a);
  3668.         $b        self::flattenSingleValue($b);
  3669.  
  3670.         return $a $b;
  3671.     }
  3672.  
  3673.     /**
  3674.      * ASCIICODE
  3675.      *
  3676.      * @param    string    $character    Value
  3677.      * @return  int 
  3678.      */
  3679.     public static function ASCIICODE($characters{
  3680.         $characters    self::flattenSingleValue($characters);
  3681.         if (is_bool($characters)) {
  3682.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  3683.                 $characters = (int) $characters;
  3684.             else {
  3685.                 if ($characters{
  3686.                     $characters 'True';
  3687.                 else {
  3688.                     $characters 'False';
  3689.                 }
  3690.             }
  3691.         }
  3692.  
  3693.         if (strlen($characters0{
  3694.             return ord(substr($characters01));
  3695.         }
  3696.         return self::$_errorCodes['value'];
  3697.     }
  3698.  
  3699.     /**
  3700.      * CONCATENATE
  3701.      *
  3702.      * @return  string 
  3703.      */
  3704.     public static function CONCATENATE({
  3705.         // Return value
  3706.         $returnValue '';
  3707.  
  3708.         // Loop trough arguments
  3709.         $aArgs self::flattenArray(func_get_args());
  3710.         foreach ($aArgs as $arg{
  3711.             if (is_bool($arg)) {
  3712.                 if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  3713.                     $arg = (int) $arg;
  3714.                 else {
  3715.                     if ($arg{
  3716.                         $arg 'TRUE';
  3717.                     else {
  3718.                         $arg 'FALSE';
  3719.                     }
  3720.                 }
  3721.             }
  3722.             $returnValue .= $arg;
  3723.         }
  3724.  
  3725.         // Return
  3726.         return $returnValue;
  3727.     }
  3728.  
  3729.     /**
  3730.      * SEARCHSENSITIVE
  3731.      *
  3732.      * @param    string    $needle        The string to look for
  3733.      * @param    string    $haystack    The string in which to look
  3734.      * @param    int        $offset        Offset within $haystack
  3735.      * @return  string 
  3736.      */
  3737.     public static function SEARCHSENSITIVE($needle,$haystack,$offset=1{
  3738.         $needle        = (string) self::flattenSingleValue($needle);
  3739.         $haystack    = (string) self::flattenSingleValue($haystack);
  3740.         $offset        self::flattenSingleValue($offset);
  3741.  
  3742.         if (($offset 0&& (strlen($haystack$offset)) {
  3743.             $pos strpos($haystack$needle--$offset);
  3744.             if ($pos !== false{
  3745.                 return ++$pos;
  3746.             }
  3747.         }
  3748.         return self::$_errorCodes['value'];
  3749.     }
  3750.  
  3751.     /**
  3752.      * SEARCHINSENSITIVE
  3753.      *
  3754.      * @param    string    $needle        The string to look for
  3755.      * @param    string    $haystack    The string in which to look
  3756.      * @param    int        $offset        Offset within $haystack
  3757.      * @return  string 
  3758.      */
  3759.     public static function SEARCHINSENSITIVE($needle,$haystack,$offset=1{
  3760.         $needle        = (string) self::flattenSingleValue($needle);
  3761.         $haystack    = (string) self::flattenSingleValue($haystack);
  3762.         $offset        self::flattenSingleValue($offset);
  3763.  
  3764.         if (($offset 0&& (strlen($haystack$offset)) {
  3765.             $pos stripos($haystack$needle--$offset);
  3766.             if ($pos !== false{
  3767.                 return ++$pos;
  3768.             }
  3769.         }
  3770.         return self::$_errorCodes['value'];
  3771.     }
  3772.  
  3773.     /**
  3774.      * LEFT
  3775.      *
  3776.      * @param    string    $value    Value
  3777.      * @param    int        $chars    Number of characters
  3778.      * @return  string 
  3779.      */
  3780.     public static function LEFT($value ''$chars null{
  3781.         $value        self::flattenSingleValue($value);
  3782.         $chars        self::flattenSingleValue($chars);
  3783.  
  3784.         return substr($value0$chars);
  3785.     }
  3786.  
  3787.     /**
  3788.      * RIGHT
  3789.      *
  3790.      * @param    string    $value    Value
  3791.      * @param    int        $chars    Number of characters
  3792.      * @return  string 
  3793.      */
  3794.     public static function RIGHT($value ''$chars null{
  3795.         $value        self::flattenSingleValue($value);
  3796.         $chars        self::flattenSingleValue($chars);
  3797.  
  3798.         return substr($valuestrlen($value$chars);
  3799.     }
  3800.  
  3801.     /**
  3802.      * MID
  3803.      *
  3804.      * @param    string    $value    Value
  3805.      * @param    int        $start    Start character
  3806.      * @param    int        $chars    Number of characters
  3807.      * @return  string 
  3808.      */
  3809.     public static function MID($value ''$start 1$chars null{
  3810.         $value        self::flattenSingleValue($value);
  3811.         $start        self::flattenSingleValue($start);
  3812.         $chars        self::flattenSingleValue($chars);
  3813.  
  3814.         return substr($value--$start$chars);
  3815.     }
  3816.  
  3817.     /**
  3818.      * RETURNSTRING
  3819.      *
  3820.      * @param    mixed    $value    Value to check
  3821.      * @return  boolean 
  3822.      */
  3823.     public static function RETURNSTRING($testValue ''{
  3824.         $testValue    self::flattenSingleValue($testValue);
  3825.  
  3826.         if (is_string($testValue)) {
  3827.             return $testValue;
  3828.         }
  3829.         return Null;
  3830.     }
  3831.  
  3832.     /**
  3833.      * TRIMSPACES
  3834.      *
  3835.      * @param    mixed    $value    Value to check
  3836.      * @return  string 
  3837.      */
  3838.     public static function TRIMSPACES($stringValue ''{
  3839.         $stringValue    self::flattenSingleValue($stringValue);
  3840.  
  3841.         if (is_string($stringValue)) {
  3842.             return str_replace('  ',' ',trim($stringValue));
  3843.         }
  3844.         return Null;
  3845.     }
  3846.  
  3847.     private static $_invalidChars Null;
  3848.  
  3849.     /**
  3850.      * TRIMNONPRINTABLE
  3851.      *
  3852.      * @param    mixed    $value    Value to check
  3853.      * @return  string 
  3854.      */
  3855.     public static function TRIMNONPRINTABLE($stringValue ''{
  3856.         $stringValue    self::flattenSingleValue($stringValue);
  3857.  
  3858.         if (self::$_invalidChars == Null{
  3859.             self::$_invalidChars range(chr(0),chr(31));
  3860.         }
  3861.  
  3862.         if (is_string($stringValue)) {
  3863.             return str_replace(self::$_invalidChars,'',trim($stringValue,"\x00..\x1F"));
  3864.         }
  3865.         return Null;
  3866.     }
  3867.  
  3868.     /**
  3869.      * IS_BLANK
  3870.      *
  3871.      * @param    mixed    $value    Value to check
  3872.      * @return  boolean 
  3873.      */
  3874.     public static function IS_BLANK($value ''{
  3875.         $value    self::flattenSingleValue($value);
  3876.  
  3877.         return (is_null($value|| (is_string($value&& ($value == '')));
  3878.     }
  3879.  
  3880.     /**
  3881.      * IS_ERR
  3882.      *
  3883.      * @param    mixed    $value    Value to check
  3884.      * @return  boolean 
  3885.      */
  3886.     public static function IS_ERR($value ''{
  3887.         $value        self::flattenSingleValue($value);
  3888.  
  3889.         return self::IS_ERROR($value&& (!self::IS_NA($value));
  3890.     }
  3891.  
  3892.     /**
  3893.      * IS_ERROR
  3894.      *
  3895.      * @param    mixed    $value    Value to check
  3896.      * @return  boolean 
  3897.      */
  3898.     public static function IS_ERROR($value ''{
  3899.         $value        self::flattenSingleValue($value);
  3900.  
  3901.         return in_array($valuearray_values(self::$_errorCodes));
  3902.     }
  3903.  
  3904.     /**
  3905.      * IS_NA
  3906.      *
  3907.      * @param    mixed    $value    Value to check
  3908.      * @return  boolean 
  3909.      */
  3910.     public static function IS_NA($value ''{
  3911.         $value        self::flattenSingleValue($value);
  3912.  
  3913.         return ($value == self::$_errorCodes['na']);
  3914.     }
  3915.  
  3916.     /**
  3917.      * IS_EVEN
  3918.      *
  3919.      * @param    mixed    $value    Value to check
  3920.      * @return  boolean 
  3921.      */
  3922.     public static function IS_EVEN($value 0{
  3923.         $value        self::flattenSingleValue($value);
  3924.  
  3925.         while (intval($value!= $value{
  3926.             $value *= 10;
  3927.         }
  3928.         return ($value == 0);
  3929.     }
  3930.  
  3931.     /**
  3932.      * IS_NUMBER
  3933.      *
  3934.      * @param    mixed    $value        Value to check
  3935.      * @return  boolean 
  3936.      */
  3937.     public static function IS_NUMBER($value 0{
  3938.         $value        self::flattenSingleValue($value);
  3939.  
  3940.         return is_numeric($value);
  3941.     }
  3942.  
  3943.     /**
  3944.      * IS_LOGICAL
  3945.      *
  3946.      * @param    mixed    $value        Value to check
  3947.      * @return  boolean 
  3948.      */
  3949.     public static function IS_LOGICAL($value true{
  3950.         $value        self::flattenSingleValue($value);
  3951.  
  3952.         return is_bool($value);
  3953.     }
  3954.  
  3955.     /**
  3956.      * IS_TEXT
  3957.      *
  3958.      * @param    mixed    $value        Value to check
  3959.      * @return  boolean 
  3960.      */
  3961.     public static function IS_TEXT($value ''{
  3962.         $value        self::flattenSingleValue($value);
  3963.  
  3964.         return is_string($value);
  3965.     }
  3966.  
  3967.     /**
  3968.      * STATEMENT_IF
  3969.      *
  3970.      * @param    mixed    $value        Value to check
  3971.      * @param    mixed    $truepart    Value when true
  3972.      * @param    mixed    $falsepart    Value when false
  3973.      * @return  mixed 
  3974.      */
  3975.     public static function STATEMENT_IF($value true$truepart ''$falsepart ''{
  3976.         $value        self::flattenSingleValue($value);
  3977.         $truepart    self::flattenSingleValue($truepart);
  3978.         $falsepart    self::flattenSingleValue($falsepart);
  3979.  
  3980.         return ($value $truepart $falsepart);
  3981.     }
  3982.  
  3983.     /**
  3984.      * STATEMENT_IFERROR
  3985.      *
  3986.      * @param    mixed    $value        Value to check , is also value when no error
  3987.      * @param    mixed    $errorpart    Value when error
  3988.      * @return  mixed 
  3989.      */
  3990.     public static function STATEMENT_IFERROR($value ''$errorpart ''{
  3991.         return self::STATEMENT_IF(self::IS_ERROR($value)$errorpart$value);
  3992.     }
  3993.  
  3994.     /**
  3995.      * VERSION
  3996.      *
  3997.      * @return  string    Version information
  3998.      */
  3999.     public static function VERSION({
  4000.         return 'PHPExcel 1.6.4, 2008-10-27';
  4001.     }
  4002.  
  4003.     /**
  4004.      * DATE
  4005.      *
  4006.      * @param    long    $year 
  4007.      * @param    long    $month 
  4008.      * @param    long    $day 
  4009.      * @return  mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  4010.      *                         depending on the value of the ReturnDateType flag
  4011.      */
  4012.     public static function DATE($year 0$month 1$day 1{
  4013.         $year    = (integer) self::flattenSingleValue($year);
  4014.         $month    = (integer) self::flattenSingleValue($month);
  4015.         $day    = (integer) self::flattenSingleValue($day);
  4016.  
  4017.         $baseYear PHPExcel_Shared_Date::getExcelCalendar();
  4018.         // Validate parameters
  4019.         if ($year ($baseYear-1900)) {
  4020.             return self::$_errorCodes['num'];
  4021.         }
  4022.         if ((($baseYear-1900!= 0&& ($year $baseYear&& ($year >= 1900)) {
  4023.             return self::$_errorCodes['num'];
  4024.         }
  4025.  
  4026.         if (($year $baseYear&& ($year ($baseYear-1900))) {
  4027.             $year += 1900;
  4028.         }
  4029.  
  4030.         if ($month 1{
  4031.             //    Handle year/month adjustment if month < 1
  4032.             --$month;
  4033.             $year += ceil($month 121;
  4034.             $month 13 abs($month 12);
  4035.         elseif ($month 12{
  4036.             //    Handle year/month adjustment if month > 12
  4037.             $year += floor($month 12);
  4038.             $month ($month 12);
  4039.         }
  4040.  
  4041.         // Re-validate the year parameter after adjustments
  4042.         if (($year $baseYear|| ($year >= 10000)) {
  4043.             return self::$_errorCodes['num'];
  4044.         }
  4045.  
  4046.         // Execute function
  4047.         $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel($year$month$day);
  4048.         switch (self::getReturnDateType()) {
  4049.             case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  4050.                                                   break;
  4051.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
  4052.                                                   break;
  4053.             case self::RETURNDATE_PHP_OBJECT    return PHPExcel_Shared_Date::ExcelToPHPObject($excelDateValue);
  4054.                                                   break;
  4055.         }
  4056.     }
  4057.  
  4058.     /**
  4059.      * TIME
  4060.      *
  4061.      * @param    long    $hour 
  4062.      * @param    long    $minute 
  4063.      * @param    long    $second 
  4064.      * @return  mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  4065.      *                         depending on the value of the ReturnDateType flag
  4066.      */
  4067.     public static function TIME($hour 0$minute 0$second 0{
  4068.         $hour    self::flattenSingleValue($hour);
  4069.         $minute    self::flattenSingleValue($minute);
  4070.         $second    self::flattenSingleValue($second);
  4071.  
  4072.         if ($hour == ''$hour 0}
  4073.         if ($minute == ''$minute 0}
  4074.         if ($second == ''$second 0}
  4075.  
  4076.         if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) {
  4077.             return self::$_errorCodes['value'];
  4078.         }
  4079.         $hour    = (integer) $hour;
  4080.         $minute    = (integer) $minute;
  4081.         $second    = (integer) $second;
  4082.  
  4083.         if ($second 0{
  4084.             $minute += floor($second 60);
  4085.             $second 60 abs($second 60);
  4086.             if ($second == 60$second 0}
  4087.         elseif ($second >= 60{
  4088.             $minute += floor($second 60);
  4089.             $second $second 60;
  4090.         }
  4091.         if ($minute 0{
  4092.             $hour += floor($minute 60);
  4093.             $minute 60 abs($minute 60);
  4094.             if ($minute == 60$minute 0}
  4095.         elseif ($minute >= 60{
  4096.             $hour += floor($minute 60);
  4097.             $minute $minute 60;
  4098.         }
  4099.  
  4100.         if ($hour 23{
  4101.             $hour $hour 24;
  4102.         elseif ($hour 0{
  4103.             return self::$_errorCodes['num'];
  4104.         }
  4105.  
  4106.         // Execute function
  4107.         switch (self::getReturnDateType()) {
  4108.             case self::RETURNDATE_EXCEL            $date 0;
  4109.                                                   $calendar PHPExcel_Shared_Date::getExcelCalendar();
  4110.                                                   if ($calendar != PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900{
  4111.                                                      $date 1;
  4112.                                                   }
  4113.                                                   return (float) PHPExcel_Shared_Date::FormattedPHPToExcel($calendar1$date$hour$minute$second);
  4114.                                                   break;
  4115.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(197011$hour-1$minute$second));    // -2147468400; //    -2147472000 + 3600
  4116.                                                   break;
  4117.             case self::RETURNDATE_PHP_OBJECT    $dayAdjust 0;
  4118.                                                   if ($hour 0{
  4119.                                                      $dayAdjust floor($hour 24);
  4120.                                                      $hour 24 abs($hour 24);
  4121.                                                      if ($hour == 24$hour 0}
  4122.                                                   elseif ($hour >= 24{
  4123.                                                      $dayAdjust floor($hour 24);
  4124.                                                      $hour $hour 24;
  4125.                                                   }
  4126.                                                   $phpDateObject new DateTime('1900-01-01 '.$hour.':'.$minute.':'.$second);
  4127.                                                   if ($dayAdjust != 0{
  4128.                                                      $phpDateObject->modify($dayAdjust.' days');
  4129.                                                   }
  4130.                                                   return $phpDateObject;
  4131.                                                   break;
  4132.         }
  4133.     }
  4134.  
  4135.     /**
  4136.      * DATEVALUE
  4137.      *
  4138.      * @param    string    $dateValue 
  4139.      * @return  mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  4140.      *                         depending on the value of the ReturnDateType flag
  4141.      */
  4142.     public static function DATEVALUE($dateValue 1{
  4143.         $dateValue    self::flattenSingleValue($dateValue);
  4144.  
  4145.         $PHPDateArray date_parse($dateValue);
  4146.         if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  4147.             $testVal1 strtok($dateValue,'/- ');
  4148.             if ($testVal1 !== False{
  4149.                 $testVal2 strtok('/- ');
  4150.                 if ($testVal2 !== False{
  4151.                     $testVal3 strtok('/- ');
  4152.                     if ($testVal3 === False{
  4153.                         $testVal3 strftime('%Y');
  4154.                     }
  4155.                 else {
  4156.                     return self::$_errorCodes['value'];
  4157.                 }
  4158.             else {
  4159.                 return self::$_errorCodes['value'];
  4160.             }
  4161.             $PHPDateArray date_parse($testVal1.'-'.$testVal2.'-'.$testVal3);
  4162.             if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  4163.                 $PHPDateArray date_parse($testVal2.'-'.$testVal1.'-'.$testVal3);
  4164.                 if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  4165.                     return self::$_errorCodes['value'];
  4166.                 }
  4167.             }
  4168.         }
  4169.  
  4170.         if (($PHPDateArray !== False&& ($PHPDateArray['error_count'== 0)) {
  4171.             // Execute function
  4172.             if ($PHPDateArray['year'== '')    $PHPDateArray['year'strftime('%Y')}
  4173.             if ($PHPDateArray['month'== '')    $PHPDateArray['month'strftime('%m')}
  4174.             if ($PHPDateArray['day'== '')        $PHPDateArray['day'strftime('%d')}
  4175.             $excelDateValue floor(PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']));
  4176.  
  4177.             switch (self::getReturnDateType()) {
  4178.                 case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  4179.                                                       break;
  4180.                 case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
  4181.                                                       break;
  4182.                 case self::RETURNDATE_PHP_OBJECT    return new DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00');
  4183.                                                       break;
  4184.             }
  4185.         }
  4186.         return self::$_errorCodes['value'];
  4187.     }
  4188.  
  4189.     /**
  4190.      * _getDateValue
  4191.      *
  4192.      * @param    string    $dateValue 
  4193.      * @return  mixed    Excel date/time serial value, or string if error
  4194.      */
  4195.     private static function _getDateValue($dateValue{
  4196.         if (!is_numeric($dateValue)) {
  4197.             if ((is_string($dateValue)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  4198.                 return self::$_errorCodes['value'];
  4199.             }
  4200.             if ((is_object($dateValue)) && ($dateValue instanceof PHPExcel_Shared_Date::$dateTimeObjectType)) {
  4201.                 $dateValue PHPExcel_Shared_Date::PHPToExcel($dateValue);
  4202.             else {
  4203.                 $saveReturnDateType self::getReturnDateType();
  4204.                 self::setReturnDateType(self::RETURNDATE_EXCEL);
  4205.                 $dateValue self::DATEVALUE($dateValue);
  4206.                 self::setReturnDateType($saveReturnDateType);
  4207.             }
  4208.         elseif (!is_float($dateValue)) {
  4209.             $dateValue PHPExcel_Shared_Date::PHPToExcel($dateValue);
  4210.         }
  4211.         return $dateValue;
  4212.     }
  4213.  
  4214.     /**
  4215.      * TIMEVALUE
  4216.      *
  4217.      * @param    string    $timeValue 
  4218.      * @return  mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  4219.      *                         depending on the value of the ReturnDateType flag
  4220.      */
  4221.     public static function TIMEVALUE($timeValue{
  4222.         $timeValue    self::flattenSingleValue($timeValue);
  4223.  
  4224.         if ((($PHPDateArray date_parse($timeValue)) !== False&& ($PHPDateArray['error_count'== 0)) {
  4225.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  4226.                 $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']);
  4227.             else {
  4228.                 $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel(1900,1,1,$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']1;
  4229.             }
  4230.  
  4231.             switch (self::getReturnDateType()) {
  4232.                 case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  4233.                                                       break;
  4234.                 case self::RETURNDATE_PHP_NUMERIC    return (integer) $phpDateValue PHPExcel_Shared_Date::ExcelToPHP($excelDateValue+255693600;;
  4235.                                                       break;
  4236.                 case self::RETURNDATE_PHP_OBJECT    return new DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']);
  4237.                                                       break;
  4238.             }
  4239.         }
  4240.         return self::$_errorCodes['value'];
  4241.     }
  4242.  
  4243.     /**
  4244.      * _getTimeValue
  4245.      *
  4246.      * @param    string    $timeValue 
  4247.      * @return  mixed    Excel date/time serial value, or string if error
  4248.      */
  4249.     private static function _getTimeValue($timeValue{
  4250.         $saveReturnDateType self::getReturnDateType();
  4251.         self::setReturnDateType(self::RETURNDATE_EXCEL);
  4252.         $timeValue self::TIMEVALUE($timeValue);
  4253.         self::setReturnDateType($saveReturnDateType);
  4254.         return $timeValue;
  4255.     }
  4256.  
  4257.     /**
  4258.      * DATETIMENOW
  4259.      *
  4260.      * @return  mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  4261.      *                         depending on the value of the ReturnDateType flag
  4262.      */
  4263.     public static function DATETIMENOW({
  4264.         $saveTimeZone date_default_timezone_get();
  4265.         date_default_timezone_set('UTC');
  4266.         $retValue False;
  4267.         switch (self::getReturnDateType()) {
  4268.             case self::RETURNDATE_EXCEL            $retValue = (float) PHPExcel_Shared_Date::PHPToExcel(time());
  4269.                                                   break;
  4270.             case self::RETURNDATE_PHP_NUMERIC    $retValue = (integer) time();
  4271.                                                   break;
  4272.             case self::RETURNDATE_PHP_OBJECT    $retValue new DateTime();
  4273.                                                   break;
  4274.         }
  4275.         date_default_timezone_set($saveTimeZone);
  4276.  
  4277.         return $retValue;
  4278.     }
  4279.  
  4280.     /**
  4281.      * DATENOW
  4282.      *
  4283.      * @return  mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  4284.      *                         depending on the value of the ReturnDateType flag
  4285.      */
  4286.     public static function DATENOW({
  4287.         $saveTimeZone date_default_timezone_get();
  4288.         date_default_timezone_set('UTC');
  4289.         $retValue False;
  4290.         $excelDateTime floor(PHPExcel_Shared_Date::PHPToExcel(time()));
  4291.         switch (self::getReturnDateType()) {
  4292.             case self::RETURNDATE_EXCEL            $retValue = (float) $excelDateTime;
  4293.                                                   break;
  4294.             case self::RETURNDATE_PHP_NUMERIC    $retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime3600;
  4295.                                                   break;
  4296.             case self::RETURNDATE_PHP_OBJECT    $retValue PHPExcel_Shared_Date::ExcelToPHPObject($excelDateTime);
  4297.                                                   break;
  4298.         }
  4299.         date_default_timezone_set($saveTimeZone);
  4300.  
  4301.         return $retValue;
  4302.     }
  4303.  
  4304.     private static function isLeapYear($year{
  4305.         return ((($year 4== 0&& (($year 100!= 0|| (($year 400== 0));
  4306.     }
  4307.  
  4308.     private static function dateDiff360($startDay$startMonth$startYear$endDay$endMonth$endYear$methodUS{
  4309.         if ($startDay == 31{
  4310.             --$startDay;
  4311.         elseif ($methodUS && ($startMonth == && ($startDay == 29 || ($startDay == 28 && !self::isLeapYear($startYear))))) {
  4312.             $startDay 30;
  4313.         }
  4314.         if ($endDay == 31{
  4315.             if ($methodUS && $startDay != 30{
  4316.                 $endDay 1;
  4317.                 if ($endMonth == 12{
  4318.                     ++$endYear;
  4319.                     $endMonth 1;
  4320.                 else {
  4321.                     ++$endMonth;
  4322.                 }
  4323.             else {
  4324.                 $endDay 30;
  4325.             }
  4326.         }
  4327.  
  4328.         return $endDay $endMonth 30 $endYear 360 $startDay $startMonth 30 $startYear 360;
  4329.     }
  4330.  
  4331.     /**
  4332.      * DAYS360
  4333.      *
  4334.      * @param    long    $startDate        Excel date serial value or a standard date string
  4335.      * @param    long    $endDate        Excel date serial value or a standard date string
  4336.      * @param    boolean    $method            US or European Method
  4337.      * @return  long    PHP date/time serial
  4338.      */
  4339.     public static function DAYS360($startDate 0$endDate 0$method false{
  4340.         $startDate    self::flattenSingleValue($startDate);
  4341.         $endDate    self::flattenSingleValue($endDate);
  4342.  
  4343.         if (is_string($startDate self::_getDateValue($startDate))) {
  4344.             return self::$_errorCodes['value'];
  4345.         }
  4346.         if (is_string($endDate self::_getDateValue($endDate))) {
  4347.             return self::$_errorCodes['value'];
  4348.         }
  4349.  
  4350.         // Execute function
  4351.         $PHPStartDateObject PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
  4352.         $startDay $PHPStartDateObject->format('j');
  4353.         $startMonth $PHPStartDateObject->format('n');
  4354.         $startYear $PHPStartDateObject->format('Y');
  4355.  
  4356.         $PHPEndDateObject PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  4357.         $endDay $PHPEndDateObject->format('j');
  4358.         $endMonth $PHPEndDateObject->format('n');
  4359.         $endYear $PHPEndDateObject->format('Y');
  4360.  
  4361.         return self::dateDiff360($startDay$startMonth$startYear$endDay$endMonth$endYear!$method);
  4362.     }
  4363.  
  4364.     /**
  4365.      * DATEDIF
  4366.      *
  4367.      * @param    long    $startDate        Excel date serial value or a standard date string
  4368.      * @param    long    $endDate        Excel date serial value or a standard date string
  4369.      * @param    string    $unit 
  4370.      * @return  long    Interval between the dates
  4371.      */
  4372.     public static function DATEDIF($startDate 0$endDate 0$unit 'D'{
  4373.         $startDate    self::flattenSingleValue($startDate);
  4374.         $endDate    self::flattenSingleValue($endDate);
  4375.         $unit        strtoupper(self::flattenSingleValue($unit));
  4376.  
  4377.         if (is_string($startDate self::_getDateValue($startDate))) {
  4378.             return self::$_errorCodes['value'];
  4379.         }
  4380.         if (is_string($endDate self::_getDateValue($endDate))) {
  4381.             return self::$_errorCodes['value'];
  4382.         }
  4383.  
  4384.         // Validate parameters
  4385.         if ($startDate >= $endDate{
  4386.             return self::$_errorCodes['num'];
  4387.         }
  4388.  
  4389.         // Execute function
  4390.         $difference $endDate $startDate;
  4391.  
  4392.         $PHPStartDateObject PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
  4393.         $startDays $PHPStartDateObject->format('j');
  4394.         $startMonths $PHPStartDateObject->format('n');
  4395.         $startYears $PHPStartDateObject->format('Y');
  4396.  
  4397.         $PHPEndDateObject PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  4398.         $endDays $PHPEndDateObject->format('j');
  4399.         $endMonths $PHPEndDateObject->format('n');
  4400.         $endYears $PHPEndDateObject->format('Y');
  4401.  
  4402.         $retVal self::$_errorCodes['num'];
  4403.         switch ($unit{
  4404.             case 'D':
  4405.                 $retVal intval($difference);
  4406.                 break;
  4407.             case 'M':
  4408.                 $retVal intval($endMonths $startMonths(intval($endYears $startYears12);
  4409.                 //    We're only interested in full months
  4410.                 if ($endDays $startDays{
  4411.                     --$retVal;
  4412.                 }
  4413.                 break;
  4414.             case 'Y':
  4415.                 $retVal intval($endYears $startYears);
  4416.                 //    We're only interested in full months
  4417.                 if ($endMonths $startMonths{
  4418.                     --$retVal;
  4419.                 elseif (($endMonths == $startMonths&& ($endDays $startDays)) {
  4420.                     --$retVal;
  4421.                 }
  4422.                 break;
  4423.             case 'MD':
  4424.                 if ($endDays $startDays{
  4425.                     $retVal $endDays;
  4426.                     $PHPEndDateObject->modify('-'.$endDays.' days');
  4427.                     $adjustDays $PHPEndDateObject->format('j');
  4428.                     if ($adjustDays $startDays{
  4429.                         $retVal += ($adjustDays $startDays);
  4430.                     }
  4431.                 else {
  4432.                     $retVal $endDays $startDays;
  4433.                 }
  4434.                 break;
  4435.             case 'YM':
  4436.                 $retVal abs(intval($endMonths $startMonths));
  4437.                 //    We're only interested in full months
  4438.                 if ($endDays $startDays{
  4439.                     --$retVal;
  4440.                 }
  4441.                 break;
  4442.             case 'YD':
  4443.                 $retVal intval($difference);
  4444.                 if ($endYears $startYears{
  4445.                     while ($endYears $startYears{
  4446.                         $PHPEndDateObject->modify('-1 year');
  4447.                         $endYears $PHPEndDateObject->format('Y');
  4448.                     }
  4449.                     $retVal abs($PHPEndDateObject->format('z'$PHPStartDateObject->format('z'));
  4450.                 }
  4451.                 break;
  4452.         }
  4453.         return $retVal;
  4454.     }
  4455.  
  4456.     /**
  4457.      * YEARFRAC
  4458.      *
  4459.      * @param    long    $startDate        Excel date serial value or a standard date string
  4460.      * @param    long    $endDate        Excel date serial value or a standard date string
  4461.      * @param    integer    $method            Method used for the calculation
  4462.      * @return  long    PHP date/time serial
  4463.      */
  4464.     public static function YEARFRAC($startDate 0$endDate 0$method 0{
  4465.         $startDate    self::flattenSingleValue($startDate);
  4466.         $endDate    self::flattenSingleValue($endDate);
  4467.         $method        self::flattenSingleValue($method);
  4468.  
  4469.         if (is_string($startDate self::_getDateValue($startDate))) {
  4470.             return self::$_errorCodes['value'];
  4471.         }
  4472.         if (is_string($endDate self::_getDateValue($endDate))) {
  4473.             return self::$_errorCodes['value'];
  4474.         }
  4475.  
  4476.         if ((is_numeric($method)) && (!is_string($method))) {
  4477.             switch($method{
  4478.                 case 0    :
  4479.                     return self::DAYS360($startDate,$endDate360;
  4480.                     break;
  4481.                 case 1    :
  4482.                     $startYear self::YEAR($startDate);
  4483.                     $endYear self::YEAR($endDate);
  4484.                     $leapDay 0;
  4485.                     if (self::isLeapYear($startYear|| self::isLeapYear($endYear)) {
  4486.                         $leapDay 1;
  4487.                     }
  4488.                     return self::DATEDIF($startDate,$endDate(365 $leapDay);
  4489.                     break;
  4490.                 case 2    :
  4491.                     return self::DATEDIF($startDate,$endDate360;
  4492.                     break;
  4493.                 case 3    :
  4494.                     return self::DATEDIF($startDate,$endDate365;
  4495.                     break;
  4496.                 case 4    :
  4497.                     return self::DAYS360($startDate,$endDate,True360;
  4498.                     break;
  4499.             }
  4500.         }
  4501.         return self::$_errorCodes['value'];
  4502.     }
  4503.  
  4504.     /**
  4505.      * NETWORKDAYS
  4506.      *
  4507.      * @param    mixed                Start date
  4508.      * @param    mixed                End date
  4509.      * @param    array of mixed        Optional Date Series
  4510.      * @return  long    Interval between the dates
  4511.      */
  4512.     public static function NETWORKDAYS($startDate,$endDate{
  4513.         //    Flush the mandatory start and end date that are referenced in the function definition
  4514.         $dateArgs self::flattenArray(func_get_args());
  4515.         array_shift($dateArgs);
  4516.         array_shift($dateArgs);
  4517.  
  4518.         //    Validate the start and end dates
  4519.         if (is_string($startDate $sDate self::_getDateValue($startDate))) {
  4520.             return self::$_errorCodes['value'];
  4521.         }
  4522.         if (is_string($endDate $eDate self::_getDateValue($endDate))) {
  4523.             return self::$_errorCodes['value'];
  4524.         }
  4525.  
  4526.         if ($sDate $eDate{
  4527.             $startDate $eDate;
  4528.             $endDate $sDate;
  4529.         }
  4530.  
  4531.         // Execute function
  4532.         $startDoW self::DAYOFWEEK($startDate,2);
  4533.         if ($startDoW 0$startDoW 0}
  4534.         $endDoW self::DAYOFWEEK($endDate,2);
  4535.         if ($endDoW >= 6$endDoW 0}
  4536.  
  4537.         $wholeWeekDays floor(($endDate $startDate75;
  4538.         $partWeekDays $endDoW $startDoW;
  4539.         if ($partWeekDays 5{
  4540.             $partWeekDays -= 5;
  4541.         }
  4542.  
  4543.         //    Test any extra holiday parameters
  4544.         $holidayCountedArray array();
  4545.         foreach ($dateArgs as $holidayDate{
  4546.             if (is_string($holidayDate self::_getDateValue($holidayDate))) {
  4547.                 return self::$_errorCodes['value'];
  4548.             }
  4549.             if (($holidayDate >= $startDate&& ($holidayDate <= $endDate)) {
  4550.                 if ((self::DAYOFWEEK($holidayDate,26&& (!in_array($holidayDate,$holidayCountedArray))) {
  4551.                     --$partWeekDays;
  4552.                     $holidayCountedArray[$holidayDate;
  4553.                 }
  4554.             }
  4555.         }
  4556.  
  4557.         if ($sDate $eDate{
  4558.             return ($wholeWeekDays $partWeekDays);
  4559.         }
  4560.         return $wholeWeekDays $partWeekDays;
  4561.     }
  4562.  
  4563.     /**
  4564.      * WORKDAY
  4565.      *
  4566.      * @param    mixed                Start date
  4567.      * @param    mixed                number of days for adjustment
  4568.      * @param    array of mixed        Optional Date Series
  4569.      * @return  long    Interval between the dates
  4570.      */
  4571.     public static function WORKDAY($startDate,$endDays{
  4572.         $dateArgs self::flattenArray(func_get_args());
  4573.  
  4574.         array_shift($dateArgs);
  4575.         array_shift($dateArgs);
  4576.  
  4577.         if (is_string($startDate self::_getDateValue($startDate))) {
  4578.             return self::$_errorCodes['value'];
  4579.         }
  4580.         if (!is_numeric($endDays)) {
  4581.             return self::$_errorCodes['value'];
  4582.         }
  4583.         $endDate = (float) $startDate (floor($endDays 57($endDays 5);
  4584.         if ($endDays 0{
  4585.             $endDate += 7;
  4586.         }
  4587.  
  4588.         $endDoW self::DAYOFWEEK($endDate,3);
  4589.         if ($endDoW >= 5{
  4590.             if ($endDays >= 0{
  4591.                 $endDate += ($endDoW);
  4592.             else {
  4593.                 $endDate -= ($endDoW 5);
  4594.             }
  4595.         }
  4596.  
  4597.         //    Test any extra holiday parameters
  4598.         if (count($dateArgs0{
  4599.             $holidayCountedArray $holidayDates array();
  4600.             foreach ($dateArgs as $holidayDate{
  4601.                 if (is_string($holidayDate self::_getDateValue($holidayDate))) {
  4602.                     return self::$_errorCodes['value'];
  4603.                 }
  4604.                 $holidayDates[$holidayDate;
  4605.             }
  4606.             if ($endDays >= 0{
  4607.                 sort($holidayDatesSORT_NUMERIC);
  4608.             else {
  4609.                 rsort($holidayDatesSORT_NUMERIC);
  4610.             }
  4611.             foreach ($holidayDates as $holidayDate{
  4612.                 if ($endDays >= 0{
  4613.                     if (($holidayDate >= $startDate&& ($holidayDate <= $endDate)) {
  4614.                         if ((self::DAYOFWEEK($holidayDate,26&& (!in_array($holidayDate,$holidayCountedArray))) {
  4615.                             ++$endDate;
  4616.                             $holidayCountedArray[$holidayDate;
  4617.                         }
  4618.                     }
  4619.                 else {
  4620.                     if (($holidayDate <= $startDate&& ($holidayDate >= $endDate)) {
  4621.                         if ((self::DAYOFWEEK($holidayDate,26&& (!in_array($holidayDate,$holidayCountedArray))) {
  4622.                             --$endDate;
  4623.                             $holidayCountedArray[$holidayDate;
  4624.                         }
  4625.                     }
  4626.                 }
  4627.                 $endDoW self::DAYOFWEEK($endDate,3);
  4628.                 if ($endDoW >= 5{
  4629.                     if ($endDays >= 0{
  4630.                         $endDate += ($endDoW);
  4631.                     else {
  4632.                         $endDate -= ($endDoW 5);
  4633.                     }
  4634.                 }
  4635.             }
  4636.         }
  4637.  
  4638.         switch (self::getReturnDateType()) {
  4639.             case self::RETURNDATE_EXCEL            return (float) $endDate;
  4640.                                                   break;
  4641.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($endDate);
  4642.                                                   break;
  4643.             case self::RETURNDATE_PHP_OBJECT    return PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  4644.                                                   break;
  4645.         }
  4646.     }
  4647.  
  4648.     /**
  4649.      * DAYOFMONTH
  4650.      *
  4651.      * @param    long    $dateValue        Excel date serial value or a standard date string
  4652.      * @return  int        Day
  4653.      */
  4654.     public static function DAYOFMONTH($dateValue 1{
  4655.         $dateValue    self::flattenSingleValue($dateValue);
  4656.  
  4657.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  4658.             return self::$_errorCodes['value'];
  4659.         }
  4660.  
  4661.         // Execute function
  4662.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  4663.  
  4664.         return $PHPDateObject->format('j');
  4665.     }
  4666.  
  4667.     /**
  4668.      * DAYOFWEEK
  4669.      *
  4670.      * @param    long    $dateValue        Excel date serial value or a standard date string
  4671.      * @return  int        Day
  4672.      */
  4673.     public static function DAYOFWEEK($dateValue 1$style 1{
  4674.         $dateValue    self::flattenSingleValue($dateValue);
  4675.         $style        floor(self::flattenSingleValue($style));
  4676.  
  4677.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  4678.             return self::$_errorCodes['value'];
  4679.         }
  4680.  
  4681.         // Execute function
  4682.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  4683.         $DoW $PHPDateObject->format('w');
  4684.         $firstDay 1;
  4685.         switch ($style{
  4686.             case 1: ++$DoW;
  4687.                     break;
  4688.             case 2if ($DoW == 0$DoW 7}
  4689.                     break;
  4690.             case 3if ($DoW == 0$DoW 7}
  4691.                     $firstDay 0;
  4692.                     --$DoW;
  4693.                     break;
  4694.             default:
  4695.         }
  4696.         if (self::$compatibilityMode == self::COMPATIBILITY_EXCEL{
  4697.             //    Test for Excel's 1900 leap year, and introduce the error as required
  4698.             if (($PHPDateObject->format('Y'== 1900&& ($PHPDateObject->format('n'<= 2)) {
  4699.                 --$DoW;
  4700.                 if ($DoW $firstDay{
  4701.                     $DoW += 7;
  4702.                 }
  4703.             }
  4704.         }
  4705.  
  4706.         return $DoW;
  4707.     }
  4708.  
  4709.     /**
  4710.      * WEEKOFYEAR
  4711.      *
  4712.      * @param    long    $dateValue        Excel date serial value or a standard date string
  4713.      * @param    boolean    $method            Week begins on Sunday or Monday
  4714.      * @return  int        Week Number
  4715.      */
  4716.     public static function WEEKOFYEAR($dateValue 1$method 1{
  4717.         $dateValue    self::flattenSingleValue($dateValue);
  4718.         $method        floor(self::flattenSingleValue($method));
  4719.  
  4720.         if (!is_numeric($method)) {
  4721.             return self::$_errorCodes['value'];
  4722.         elseif (($method 1|| ($method 2)) {
  4723.             return self::$_errorCodes['num'];
  4724.         }
  4725.  
  4726.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  4727.             return self::$_errorCodes['value'];
  4728.         }
  4729.  
  4730.         // Execute function
  4731.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  4732.         $dayOfYear $PHPDateObject->format('z');
  4733.         $dow $PHPDateObject->format('w');
  4734.         $PHPDateObject->modify('-'.$dayOfYear.' days');
  4735.         $dow $PHPDateObject->format('w');
  4736.         $daysInFirstWeek (($dow ($method)) 7);
  4737.         $dayOfYear -= $daysInFirstWeek;
  4738.         $weekOfYear ceil($dayOfYear 71;
  4739.  
  4740.         return $weekOfYear;
  4741.     }
  4742.  
  4743.     /**
  4744.      * MONTHOFYEAR
  4745.      *
  4746.      * @param    long    $dateValue        Excel date serial value or a standard date string
  4747.      * @return  int        Month
  4748.      */
  4749.     public static function MONTHOFYEAR($dateValue 1{
  4750.         $dateValue    self::flattenSingleValue($dateValue);
  4751.  
  4752.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  4753.             return self::$_errorCodes['value'];
  4754.         }
  4755.  
  4756.         // Execute function
  4757.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  4758.  
  4759.         return $PHPDateObject->format('n');
  4760.     }
  4761.  
  4762.     /**
  4763.      * YEAR
  4764.      *
  4765.      * @param    long    $dateValue        Excel date serial value or a standard date string
  4766.      * @return  int        Year
  4767.      */
  4768.     public static function YEAR($dateValue 1{
  4769.         $dateValue    self::flattenSingleValue($dateValue);
  4770.  
  4771.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  4772.             return self::$_errorCodes['value'];
  4773.         }
  4774.  
  4775.         // Execute function
  4776.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  4777.  
  4778.         return $PHPDateObject->format('Y');
  4779.     }
  4780.  
  4781.     /**
  4782.      * HOUROFDAY
  4783.      *
  4784.      * @param    mixed    $timeValue        Excel time serial value or a standard time string
  4785.      * @return  int        Hour
  4786.      */
  4787.     public static function HOUROFDAY($timeValue 0{
  4788.         $timeValue    self::flattenSingleValue($timeValue);
  4789.  
  4790.         if (!is_numeric($timeValue)) {
  4791.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  4792.                 $testVal strtok($timeValue,'/-: ');
  4793.                 if (strlen($testValstrlen($timeValue)) {
  4794.                     return self::$_errorCodes['value'];
  4795.                 }
  4796.             }
  4797.             $timeValue self::_getTimeValue($timeValue);
  4798.             if (is_string($timeValue)) {
  4799.                 return self::$_errorCodes['value'];
  4800.             }
  4801.         }
  4802.         // Execute function
  4803.         if (is_real($timeValue)) {
  4804.             $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  4805.         }
  4806.         return date('G',$timeValue);
  4807.     }
  4808.  
  4809.     /**
  4810.      * MINUTEOFHOUR
  4811.      *
  4812.      * @param    long    $timeValue        Excel time serial value or a standard time string
  4813.      * @return  int        Minute
  4814.      */
  4815.     public static function MINUTEOFHOUR($timeValue 0{
  4816.         $timeValue $timeTester    self::flattenSingleValue($timeValue);
  4817.  
  4818.         if (!is_numeric($timeValue)) {
  4819.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  4820.                 $testVal strtok($timeValue,'/-: ');
  4821.                 if (strlen($testValstrlen($timeValue)) {
  4822.                     return self::$_errorCodes['value'];
  4823.                 }
  4824.             }
  4825.             $timeValue self::_getTimeValue($timeValue);
  4826.             if (is_string($timeValue)) {
  4827.                 return self::$_errorCodes['value'];
  4828.             }
  4829.         }
  4830.         // Execute function
  4831.         if (is_real($timeValue)) {
  4832.             $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  4833.         }
  4834.         return (int) date('i',$timeValue);
  4835.     }
  4836.  
  4837.     /**
  4838.      * SECONDOFMINUTE
  4839.      *
  4840.      * @param    long    $timeValue        Excel time serial value or a standard time string
  4841.      * @return  int        Second
  4842.      */
  4843.     public static function SECONDOFMINUTE($timeValue 0{
  4844.         $timeValue    self::flattenSingleValue($timeValue);
  4845.  
  4846.         if (!is_numeric($timeValue)) {
  4847.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  4848.                 $testVal strtok($timeValue,'/-: ');
  4849.                 if (strlen($testValstrlen($timeValue)) {
  4850.                     return self::$_errorCodes['value'];
  4851.                 }
  4852.             }
  4853.             $timeValue self::_getTimeValue($timeValue);
  4854.             if (is_string($timeValue)) {
  4855.                 return self::$_errorCodes['value'];
  4856.             }
  4857.         }
  4858.         // Execute function
  4859.         if (is_real($timeValue)) {
  4860.             $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  4861.         }
  4862.         return (int) date('s',$timeValue);
  4863.     }
  4864.  
  4865.     private static function adjustDateByMonths ($dateValue 0$adjustmentMonths 0{
  4866.         // Execute function
  4867.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  4868.         $oMonth = (int) $PHPDateObject->format('m');
  4869.         $oYear = (int) $PHPDateObject->format('Y');
  4870.  
  4871.         $adjustmentMonthsString = (string) $adjustmentMonths;
  4872.         if ($adjustmentMonths 0{
  4873.             $adjustmentMonthsString '+'.$adjustmentMonths;
  4874.         }
  4875.         if ($adjustmentMonths != 0{
  4876.             $PHPDateObject->modify($adjustmentMonthsString.' months');
  4877.         }
  4878.         $nMonth = (int) $PHPDateObject->format('m');
  4879.         $nYear = (int) $PHPDateObject->format('Y');
  4880.  
  4881.         $monthDiff ($nMonth $oMonth(($nYear $oYear12);
  4882.         if ($monthDiff != $adjustmentMonths{
  4883.             $adjustDays = (int) $PHPDateObject->format('d');
  4884.             $adjustDaysString '-'.$adjustDays.' days';
  4885.             $PHPDateObject->modify($adjustDaysString);
  4886.         }
  4887.         return $PHPDateObject;
  4888.     }
  4889.  
  4890.     /**
  4891.      * EDATE
  4892.      *
  4893.      * Returns the serial number that represents the date that is the indicated number of months before or after a specified date
  4894.      * (the start_date). Use EDATE to calculate maturity dates or due dates that fall on the same day of the month as the date of issue.
  4895.      *
  4896.      * @param    long    $dateValue                Excel date serial value or a standard date string
  4897.      * @param    int        $adjustmentMonths        Number of months to adjust by
  4898.      * @return  long    Excel date serial value
  4899.      */
  4900.     public static function EDATE($dateValue 1$adjustmentMonths 0{
  4901.         $dateValue            self::flattenSingleValue($dateValue);
  4902.         $adjustmentMonths    floor(self::flattenSingleValue($adjustmentMonths));
  4903.  
  4904.         if (!is_numeric($adjustmentMonths)) {
  4905.             return self::$_errorCodes['value'];
  4906.         }
  4907.  
  4908.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  4909.             return self::$_errorCodes['value'];
  4910.         }
  4911.  
  4912.         // Execute function
  4913.         $PHPDateObject self::adjustDateByMonths($dateValue,$adjustmentMonths);
  4914.  
  4915.         switch (self::getReturnDateType()) {
  4916.             case self::RETURNDATE_EXCEL            return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
  4917.                                                   break;
  4918.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
  4919.                                                   break;
  4920.             case self::RETURNDATE_PHP_OBJECT    return $PHPDateObject;
  4921.                                                   break;
  4922.         }
  4923.     }
  4924.  
  4925.     /**
  4926.      * EOMONTH
  4927.      *
  4928.      * Returns the serial number for the last day of the month that is the indicated number of months before or after start_date.
  4929.      * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
  4930.      *
  4931.      * @param    long    $dateValue            Excel date serial value or a standard date string
  4932.      * @param    int        $adjustmentMonths    Number of months to adjust by
  4933.      * @return  long    Excel date serial value
  4934.      */
  4935.     public static function EOMONTH($dateValue 1$adjustmentMonths 0{
  4936.         $dateValue            self::flattenSingleValue($dateValue);
  4937.         $adjustmentMonths    floor(self::flattenSingleValue($adjustmentMonths));
  4938.  
  4939.         if (!is_numeric($adjustmentMonths)) {
  4940.             return self::$_errorCodes['value'];
  4941.         }
  4942.  
  4943.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  4944.             return self::$_errorCodes['value'];
  4945.         }
  4946.  
  4947.         // Execute function
  4948.         $PHPDateObject self::adjustDateByMonths($dateValue,$adjustmentMonths+1);
  4949.         $adjustDays = (int) $PHPDateObject->format('d');
  4950.         $adjustDaysString '-'.$adjustDays.' days';
  4951.         $PHPDateObject->modify($adjustDaysString);
  4952.  
  4953.         switch (self::getReturnDateType()) {
  4954.             case self::RETURNDATE_EXCEL            return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
  4955.                                                   break;
  4956.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
  4957.                                                   break;
  4958.             case self::RETURNDATE_PHP_OBJECT    return $PHPDateObject;
  4959.                                                   break;
  4960.         }
  4961.     }
  4962.  
  4963.     /**
  4964.      * TRUNC
  4965.      *
  4966.      * Truncates value to the number of fractional digits by number_digits.
  4967.      *
  4968.      * @param    float        $value 
  4969.      * @param    int            $number_digits 
  4970.      * @return  float        Truncated value
  4971.      */
  4972.     public static function TRUNC($value 0$number_digits 0{
  4973.         $value            self::flattenSingleValue($value);
  4974.         $number_digits    self::flattenSingleValue($number_digits);
  4975.  
  4976.         // Validate parameters
  4977.         if ($number_digits 0{
  4978.             return self::$_errorCodes['value'];
  4979.         }
  4980.  
  4981.         // Truncate
  4982.         if ($number_digits 0{
  4983.             $value $value pow(10$number_digits);
  4984.         }
  4985.         $value intval($value);
  4986.         if ($number_digits 0{
  4987.             $value $value pow(10$number_digits);
  4988.         }
  4989.  
  4990.         // Return
  4991.         return $value;
  4992.     }
  4993.  
  4994.     /**
  4995.      * POWER
  4996.      *
  4997.      * Computes x raised to the power y.
  4998.      *
  4999.      * @param    float        $x 
  5000.      * @param    float        $y 
  5001.      * @return  float 
  5002.      */
  5003.     public static function POWER($x 0$y 2{
  5004.         $x    self::flattenSingleValue($x);
  5005.         $y    self::flattenSingleValue($y);
  5006.  
  5007.         // Validate parameters
  5008.         if ($x 0{
  5009.             return self::$_errorCodes['num'];
  5010.         }
  5011.         if ($x == && $y <= 0{
  5012.             return self::$_errorCodes['divisionbyzero'];
  5013.         }
  5014.  
  5015.         // Return
  5016.         return pow($x$y);
  5017.     }
  5018.  
  5019.     /**
  5020.      * BINTODEC
  5021.      *
  5022.      * Return a binary value as Decimal.
  5023.      *
  5024.      * @param    string        $x 
  5025.      * @return  string 
  5026.      */
  5027.     public static function BINTODEC($x{
  5028.         $x    self::flattenSingleValue($x);
  5029.  
  5030.         if (is_bool($x)) {
  5031.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5032.                 $x = (int) $x;
  5033.             else {
  5034.                 return self::$_errorCodes['value'];
  5035.             }
  5036.         }
  5037.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  5038.             $x floor($x);
  5039.         }
  5040.         $x = (string) $x;
  5041.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  5042.             return self::$_errorCodes['num'];
  5043.         }
  5044.         if (strlen($x10{
  5045.             return self::$_errorCodes['num'];
  5046.         elseif (strlen($x== 10{
  5047.             //    Two's Complement
  5048.             $x substr($x,-9);
  5049.             return '-'.(512-bindec($x));
  5050.         }
  5051.         return bindec($x);
  5052.     }
  5053.  
  5054.     /**
  5055.      * BINTOHEX
  5056.      *
  5057.      * Return a binary value as Hex.
  5058.      *
  5059.      * @param    string        $x 
  5060.      * @return  string 
  5061.      */
  5062.     public static function BINTOHEX($x{
  5063.         $x    floor(self::flattenSingleValue($x));
  5064.  
  5065.         if (is_bool($x)) {
  5066.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5067.                 $x = (int) $x;
  5068.             else {
  5069.                 return self::$_errorCodes['value'];
  5070.             }
  5071.         }
  5072.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  5073.             $x floor($x);
  5074.         }
  5075.         $x = (string) $x;
  5076.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  5077.             return self::$_errorCodes['num'];
  5078.         }
  5079.         if (strlen($x10{
  5080.             return self::$_errorCodes['num'];
  5081.         elseif (strlen($x== 10{
  5082.             //    Two's Complement
  5083.             return str_repeat('F',8).substr(strtoupper(dechex(bindec(substr($x,-9)))),-2);
  5084.         }
  5085.         return strtoupper(dechex(bindec($x)));
  5086.     }
  5087.  
  5088.     /**
  5089.      * BINTOOCT
  5090.      *
  5091.      * Return a binary value as Octal.
  5092.      *
  5093.      * @param    string        $x 
  5094.      * @return  string 
  5095.      */
  5096.     public static function BINTOOCT($x{
  5097.         $x    floor(self::flattenSingleValue($x));
  5098.  
  5099.         if (is_bool($x)) {
  5100.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5101.                 $x = (int) $x;
  5102.             else {
  5103.                 return self::$_errorCodes['value'];
  5104.             }
  5105.         }
  5106.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  5107.             $x floor($x);
  5108.         }
  5109.         $x = (string) $x;
  5110.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  5111.             return self::$_errorCodes['num'];
  5112.         }
  5113.         if (strlen($x10{
  5114.             return self::$_errorCodes['num'];
  5115.         elseif (strlen($x== 10{
  5116.             //    Two's Complement
  5117.             return str_repeat('7',7).substr(strtoupper(dechex(bindec(substr($x,-9)))),-3);
  5118.         }
  5119.         return decoct(bindec($x));
  5120.     }
  5121.  
  5122.     /**
  5123.      * DECTOBIN
  5124.      *
  5125.      * Return an octal value as binary.
  5126.      *
  5127.      * @param    string        $x 
  5128.      * @return  string 
  5129.      */
  5130.     public static function DECTOBIN($x{
  5131.         $x    self::flattenSingleValue($x);
  5132.  
  5133.         if (is_bool($x)) {
  5134.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5135.                 $x = (int) $x;
  5136.             else {
  5137.                 return self::$_errorCodes['value'];
  5138.             }
  5139.         }
  5140.         $x = (string) $x;
  5141.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  5142.             return self::$_errorCodes['value'];
  5143.         }
  5144.         $x = (string) floor($x);
  5145.         $r decbin($x);
  5146.         if (strlen($r== 32{
  5147.             //    Two's Complement
  5148.             $r substr($r,-10);
  5149.         elseif (strlen($r11{
  5150.             return self::$_errorCodes['num'];
  5151.         }
  5152.         return $r;
  5153.     }
  5154.  
  5155.     /**
  5156.      * DECTOOCT
  5157.      *
  5158.      * Return an octal value as binary.
  5159.      *
  5160.      * @param    string        $x 
  5161.      * @return  string 
  5162.      */
  5163.     public static function DECTOOCT($x{
  5164.         $x    self::flattenSingleValue($x);
  5165.  
  5166.         if (is_bool($x)) {
  5167.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5168.                 $x = (int) $x;
  5169.             else {
  5170.                 return self::$_errorCodes['value'];
  5171.             }
  5172.         }
  5173.         $x = (string) $x;
  5174.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  5175.             return self::$_errorCodes['value'];
  5176.         }
  5177.         $x = (string) floor($x);
  5178.         $r decoct($x);
  5179.         if (strlen($r== 11{
  5180.             //    Two's Complement
  5181.             $r substr($r,-10);
  5182.         }
  5183.         return ($r);
  5184.     }
  5185.  
  5186.     /**
  5187.      * DECTOHEX
  5188.      *
  5189.      * Return an octal value as binary.
  5190.      *
  5191.      * @param    string        $x 
  5192.      * @return  string 
  5193.      */
  5194.     public static function DECTOHEX($x{
  5195.         $x    self::flattenSingleValue($x);
  5196.  
  5197.         if (is_bool($x)) {
  5198.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5199.                 $x = (int) $x;
  5200.             else {
  5201.                 return self::$_errorCodes['value'];
  5202.             }
  5203.         }
  5204.         $x = (string) $x;
  5205.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  5206.             return self::$_errorCodes['value'];
  5207.         }
  5208.         $x = (string) floor($x);
  5209.         $r strtoupper(dechex($x));
  5210.         if (strlen($r== 8{
  5211.             //    Two's Complement
  5212.             $r 'FF'.$r;
  5213.         }
  5214.         return ($r);
  5215.     }
  5216.  
  5217.     /**
  5218.      * HEXTOBIN
  5219.      *
  5220.      * Return a hex value as binary.
  5221.      *
  5222.      * @param    string        $x 
  5223.      * @return  string 
  5224.      */
  5225.     public static function HEXTOBIN($x{
  5226.         $x    self::flattenSingleValue($x);
  5227.  
  5228.         if (is_bool($x)) {
  5229.             return self::$_errorCodes['value'];
  5230.         }
  5231.         $x = (string) $x;
  5232.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  5233.             return self::$_errorCodes['num'];
  5234.         }
  5235.         return decbin(hexdec($x));
  5236.     }
  5237.  
  5238.     /**
  5239.      * HEXTOOCT
  5240.      *
  5241.      * Return a hex value as octal.
  5242.      *
  5243.      * @param    string        $x 
  5244.      * @return  string 
  5245.      */
  5246.     public static function HEXTOOCT($x{
  5247.         $x    self::flattenSingleValue($x);
  5248.  
  5249.         if (is_bool($x)) {
  5250.             return self::$_errorCodes['value'];
  5251.         }
  5252.         $x = (string) $x;
  5253.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  5254.             return self::$_errorCodes['num'];
  5255.         }
  5256.         return decoct(hexdec($x));
  5257.     }
  5258.  
  5259.     /**
  5260.      * HEXTODEC
  5261.      *
  5262.      * Return a hex value as octal.
  5263.      *
  5264.      * @param    string        $x 
  5265.      * @return  string 
  5266.      */
  5267.     public static function HEXTODEC($x{
  5268.         $x    self::flattenSingleValue($x);
  5269.  
  5270.         if (is_bool($x)) {
  5271.             return self::$_errorCodes['value'];
  5272.         }
  5273.         $x = (string) $x;
  5274.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  5275.             return self::$_errorCodes['num'];
  5276.         }
  5277.         return hexdec($x);
  5278.     }
  5279.  
  5280.     /**
  5281.      * OCTTOBIN
  5282.      *
  5283.      * Return an octal value as binary.
  5284.      *
  5285.      * @param    string        $x 
  5286.      * @return  string 
  5287.      */
  5288.     public static function OCTTOBIN($x{
  5289.         $x    self::flattenSingleValue($x);
  5290.  
  5291.         if (is_bool($x)) {
  5292.             return self::$_errorCodes['value'];
  5293.         }
  5294.         $x = (string) $x;
  5295.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  5296.             return self::$_errorCodes['num'];
  5297.         }
  5298.         return decbin(octdec($x));
  5299.     }
  5300.  
  5301.     /**
  5302.      * OCTTODEC
  5303.      *
  5304.      * Return an octal value as binary.
  5305.      *
  5306.      * @param    string        $x 
  5307.      * @return  string 
  5308.      */
  5309.     public static function OCTTODEC($x{
  5310.         $x    self::flattenSingleValue($x);
  5311.  
  5312.         if (is_bool($x)) {
  5313.             return self::$_errorCodes['value'];
  5314.         }
  5315.         $x = (string) $x;
  5316.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  5317.             return self::$_errorCodes['num'];
  5318.         }
  5319.         return octdec($x);
  5320.     }
  5321.  
  5322.     /**
  5323.      * OCTTOHEX
  5324.      *
  5325.      * Return an octal value as hex.
  5326.      *
  5327.      * @param    string        $x 
  5328.      * @return  string 
  5329.      */
  5330.     public static function OCTTOHEX($x{
  5331.         $x    self::flattenSingleValue($x);
  5332.  
  5333.         if (is_bool($x)) {
  5334.             return self::$_errorCodes['value'];
  5335.         }
  5336.         $x = (string) $x;
  5337.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  5338.             return self::$_errorCodes['num'];
  5339.         }
  5340.         return strtoupper(dechex(octdec($x)));
  5341.     }
  5342.  
  5343.     public function parseComplex($complexNumber{
  5344.         $workString $complexNumber;
  5345.  
  5346.         $realNumber $imaginary 0;
  5347.         //    Extract the suffix, if there is one
  5348.         $suffix substr($workString,-1);
  5349.         if (!is_numeric($suffix)) {
  5350.             $workString substr($workString,0,-1);
  5351.         else {
  5352.             $suffix '';
  5353.         }
  5354.  
  5355.         //    Split the input into its Real and Imaginary components
  5356.         $leadingSign (($workString{0== '+'|| ($workString{0== '-')) 0;
  5357.         $power '';
  5358.         $realNumber strtok($workString'+-');
  5359.         if (strtoupper(substr($realNumber,-1)) == 'E'{
  5360.             $power strtok('+-');
  5361.             ++$leadingSign;
  5362.         }
  5363.         $realNumber substr($workString,0,strlen($realNumber)+strlen($power)+$leadingSign);
  5364.  
  5365.         if ($suffix != ''{
  5366.             $imaginary substr($workString,strlen($realNumber));
  5367.  
  5368.             if (($imaginary == ''&& (($realNumber == ''|| ($realNumber == '+'|| ($realNumber == '-'))) {
  5369.                 $imaginary $realNumber.'1';
  5370.                 $realNumber '0';
  5371.             else if ($imaginary == ''{
  5372.                 $imaginary $realNumber;
  5373.                 $realNumber '0';
  5374.             elseif (($imaginary == '+'|| ($imaginary == '-')) {
  5375.                 $imaginary .= '1';
  5376.             }
  5377.         }
  5378.  
  5379.         $complexArray array'real'        => $realNumber,
  5380.                                'imaginary'    => $imaginary,
  5381.                                'suffix'        => $suffix
  5382.                              );
  5383.  
  5384.         return $complexArray;
  5385.     }
  5386.  
  5387.     /**
  5388.      * COMPLEX
  5389.      *
  5390.      * returns a complex number of the form x + yi or x + yj.
  5391.      *
  5392.      * @param    float        $realNumber 
  5393.      * @param    float        $imaginary 
  5394.      * @param    string        $suffix 
  5395.      * @return  string 
  5396.      */
  5397.     public static function COMPLEX($realNumber=0.0$imaginary=0.0$suffix='i'{
  5398.         $realNumber    self::flattenSingleValue($realNumber);
  5399.         $imaginary    self::flattenSingleValue($imaginary);
  5400.         $suffix        self::flattenSingleValue($suffix);
  5401.  
  5402.         if (((is_numeric($realNumber)) && (is_numeric($imaginary))) &&
  5403.             (($suffix == 'i'|| ($suffix == 'j'))) {
  5404.             if ($realNumber == 0.0{
  5405.                 if ($imaginary == 0.0{
  5406.                     return (string) '0';
  5407.                 elseif ($imaginary == 1.0{
  5408.                     return (string) $suffix;
  5409.                 elseif ($imaginary == -1.0{
  5410.                     return (string) '-'.$suffix;
  5411.                 }
  5412.                 return (string) $imaginary.$suffix;
  5413.             elseif ($imaginary == 0.0{
  5414.                 return (string) $realNumber;
  5415.             elseif ($imaginary == 1.0{
  5416.                 return (string) $realNumber.'+'.$suffix;
  5417.             elseif ($imaginary == -1.0{
  5418.                 return (string) $realNumber.'-'.$suffix;
  5419.             }
  5420.             if ($imaginary 0$imaginary = (string) '+'.$imaginary}
  5421.             return (string) $realNumber.$imaginary.$suffix;
  5422.         }
  5423.         return self::$_errorCodes['value'];
  5424.     }
  5425.  
  5426.     /**
  5427.      * IMAGINARY
  5428.      *
  5429.      * Returns the imaginary coefficient of a complex number in x + yi or x + yj text format.
  5430.      *
  5431.      * @param    string        $complexNumber 
  5432.      * @return  real 
  5433.      */
  5434.     public static function IMAGINARY($complexNumber{
  5435.         $complexNumber    self::flattenSingleValue($complexNumber);
  5436.  
  5437.         $parsedComplex self::parseComplex($complexNumber);
  5438.         if (!is_array($parsedComplex)) {
  5439.             return $parsedComplex;
  5440.         }
  5441.         return $parsedComplex['imaginary'];
  5442.     }
  5443.  
  5444.     /**
  5445.      * IMREAL
  5446.      *
  5447.      * Returns the real coefficient of a complex number in x + yi or x + yj text format.
  5448.      *
  5449.      * @param    string        $complexNumber 
  5450.      * @return  real 
  5451.      */
  5452.     public static function IMREAL($complexNumber{
  5453.         $complexNumber    self::flattenSingleValue($complexNumber);
  5454.  
  5455.         $parsedComplex self::parseComplex($complexNumber);
  5456.         if (!is_array($parsedComplex)) {
  5457.             return $parsedComplex;
  5458.         }
  5459.         return $parsedComplex['real'];
  5460.     }
  5461.  
  5462.     /**
  5463.      * IMABS
  5464.      *
  5465.      * Returns the absolute value (modulus) of a complex number in x + yi or x + yj text format.
  5466.      *
  5467.      * @param    string        $complexNumber 
  5468.      * @return  real 
  5469.      */
  5470.     public static function IMABS($complexNumber{
  5471.         $complexNumber    self::flattenSingleValue($complexNumber);
  5472.  
  5473.         $parsedComplex self::parseComplex($complexNumber);
  5474.         if (!is_array($parsedComplex)) {
  5475.             return $parsedComplex;
  5476.         }
  5477.         return sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary']));
  5478.     }
  5479.  
  5480.     /**
  5481.      * IMARGUMENT
  5482.      *
  5483.      * Returns the argument theta of a complex number, i.e. the angle in radians from the real axis to the representation of the number in polar coordinates.
  5484.      *
  5485.      * @param    string        $complexNumber 
  5486.      * @return  string 
  5487.      */
  5488.     public static function IMARGUMENT($complexNumber{
  5489.         $complexNumber    self::flattenSingleValue($complexNumber);
  5490.  
  5491.         $parsedComplex self::parseComplex($complexNumber);
  5492.         if (!is_array($parsedComplex)) {
  5493.             return $parsedComplex;
  5494.         }
  5495.  
  5496.         if ($parsedComplex['real'== 0.0{
  5497.             if ($parsedComplex['imaginary'== 0.0{
  5498.                 return 0.0;
  5499.             elseif($parsedComplex['imaginary'0.0{
  5500.                 return pi(/ -2;
  5501.             else {
  5502.                 return pi(2;
  5503.             }
  5504.         elseif ($parsedComplex['real'0.0{
  5505.             return atan($parsedComplex['imaginary'$parsedComplex['real']);
  5506.         elseif ($parsedComplex['imaginary'0.0{
  5507.             return (pi(atan(abs($parsedComplex['imaginary']abs($parsedComplex['real'])));
  5508.         else {
  5509.             return pi(atan($parsedComplex['imaginary'abs($parsedComplex['real']));
  5510.         }
  5511.     }
  5512.  
  5513.     /**
  5514.      * IMCONJUGATE
  5515.      *
  5516.      * Returns the complex conjugate of a complex number in x + yi or x + yj text format.
  5517.      *
  5518.      * @param    string        $complexNumber 
  5519.      * @return  string 
  5520.      */
  5521.     public static function IMCONJUGATE($complexNumber{
  5522.         $complexNumber    self::flattenSingleValue($complexNumber);
  5523.  
  5524.         $parsedComplex self::parseComplex($complexNumber);
  5525.  
  5526.         if (!is_array($parsedComplex)) {
  5527.             return $parsedComplex;
  5528.         }
  5529.  
  5530.         if ($parsedComplex['imaginary'== 0.0{
  5531.             return $parsedComplex['real'];
  5532.         else {
  5533.             return self::COMPLEX($parsedComplex['real']$parsedComplex['imaginary']$parsedComplex['suffix']);
  5534.         }
  5535.     }
  5536.  
  5537.     /**
  5538.      * IMCOS
  5539.      *
  5540.      * Returns the cosine of a complex number in x + yi or x + yj text format.
  5541.      *
  5542.      * @param    string        $complexNumber 
  5543.      * @return  string 
  5544.      */
  5545.     public static function IMCOS($complexNumber{
  5546.         $complexNumber    self::flattenSingleValue($complexNumber);
  5547.  
  5548.         $parsedComplex self::parseComplex($complexNumber);
  5549.         if (!is_array($parsedComplex)) {
  5550.             return $parsedComplex;
  5551.         }
  5552.  
  5553.         if ($parsedComplex['imaginary'== 0.0{
  5554.             return cos($parsedComplex['real']);
  5555.         else {
  5556.             return self::IMCONJUGATE(self::COMPLEX(cos($parsedComplex['real']cosh($parsedComplex['imaginary']),sin($parsedComplex['real']sinh($parsedComplex['imaginary']),$parsedComplex['suffix']));
  5557.         }
  5558.     }
  5559.  
  5560.     /**
  5561.      * IMSIN
  5562.      *
  5563.      * Returns the sine of a complex number in x + yi or x + yj text format.
  5564.      *
  5565.      * @param    string        $complexNumber 
  5566.      * @return  string 
  5567.      */
  5568.     public static function IMSIN($complexNumber{
  5569.         $complexNumber    self::flattenSingleValue($complexNumber);
  5570.  
  5571.         $parsedComplex self::parseComplex($complexNumber);
  5572.         if (!is_array($parsedComplex)) {
  5573.             return $parsedComplex;
  5574.         }
  5575.  
  5576.         if ($parsedComplex['imaginary'== 0.0{
  5577.             return sin($parsedComplex['real']);
  5578.         else {
  5579.             return self::COMPLEX(sin($parsedComplex['real']cosh($parsedComplex['imaginary']),cos($parsedComplex['real']sinh($parsedComplex['imaginary']),$parsedComplex['suffix']);
  5580.         }
  5581.     }
  5582.  
  5583.     /**
  5584.      * IMSQRT
  5585.      *
  5586.      * Returns the square root of a complex number in x + yi or x + yj text format.
  5587.      *
  5588.      * @param    string        $complexNumber 
  5589.      * @return  string 
  5590.      */
  5591.     public static function IMSQRT($complexNumber{
  5592.         $complexNumber    self::flattenSingleValue($complexNumber);
  5593.  
  5594.         $parsedComplex self::parseComplex($complexNumber);
  5595.         if (!is_array($parsedComplex)) {
  5596.             return $parsedComplex;
  5597.         }
  5598.  
  5599.         $theta self::IMARGUMENT($complexNumber);
  5600.         $d1 cos($theta 2);
  5601.         $d2 sin($theta 2);
  5602.         $r sqrt(sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary'])));
  5603.  
  5604.         if ($parsedComplex['suffix'== ''{
  5605.             return self::COMPLEX($d1 $r,$d2 $r);
  5606.         else {
  5607.             return self::COMPLEX($d1 $r,$d2 $r,$parsedComplex['suffix']);
  5608.         }
  5609.     }
  5610.  
  5611.     /**
  5612.      * IMLN
  5613.      *
  5614.      * Returns the natural logarithm of a complex number in x + yi or x + yj text format.
  5615.      *
  5616.      * @param    string        $complexNumber 
  5617.      * @return  string 
  5618.      */
  5619.     public static function IMLN($complexNumber{
  5620.         $complexNumber    self::flattenSingleValue($complexNumber);
  5621.  
  5622.         $parsedComplex self::parseComplex($complexNumber);
  5623.         if (!is_array($parsedComplex)) {
  5624.             return $parsedComplex;
  5625.         }
  5626.  
  5627.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  5628.             return self::$_errorCodes['num'];
  5629.         }
  5630.  
  5631.         $logR log(sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary'])));
  5632.         $t self::IMARGUMENT($complexNumber);
  5633.  
  5634.         if ($parsedComplex['suffix'== ''{
  5635.             return self::COMPLEX($logR,$t);
  5636.         else {
  5637.             return self::COMPLEX($logR,$t,$parsedComplex['suffix']);
  5638.         }
  5639.     }
  5640.  
  5641.     /**
  5642.      * IMLOG10
  5643.      *
  5644.      * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
  5645.      *
  5646.      * @param    string        $complexNumber 
  5647.      * @return  string 
  5648.      */
  5649.     public static function IMLOG10($complexNumber{
  5650.         $complexNumber    self::flattenSingleValue($complexNumber);
  5651.  
  5652.         $parsedComplex self::parseComplex($complexNumber);
  5653.         if (!is_array($parsedComplex)) {
  5654.             return $parsedComplex;
  5655.         }
  5656.  
  5657.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  5658.             return self::$_errorCodes['num'];
  5659.         elseif (($parsedComplex['real'0.0&& ($parsedComplex['imaginary'== 0.0)) {
  5660.             return log10($parsedComplex['real']);
  5661.         }
  5662.  
  5663.         return self::IMPRODUCT(log10(EULER),self::IMLN($complexNumber));
  5664.     }
  5665.  
  5666.     /**
  5667.      * IMLOG2
  5668.      *
  5669.      * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
  5670.      *
  5671.      * @param    string        $complexNumber 
  5672.      * @return  string 
  5673.      */
  5674.     public static function IMLOG2($complexNumber{
  5675.         $complexNumber    self::flattenSingleValue($complexNumber);
  5676.  
  5677.         $parsedComplex self::parseComplex($complexNumber);
  5678.         if (!is_array($parsedComplex)) {
  5679.             return $parsedComplex;
  5680.         }
  5681.  
  5682.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  5683.             return self::$_errorCodes['num'];
  5684.         elseif (($parsedComplex['real'0.0&& ($parsedComplex['imaginary'== 0.0)) {
  5685.             return log($parsedComplex['real'],2);
  5686.         }
  5687.  
  5688.         return self::IMPRODUCT(log(EULER,2),self::IMLN($complexNumber));
  5689.     }
  5690.  
  5691.     /**
  5692.      * IMEXP
  5693.      *
  5694.      * Returns the exponential of a complex number in x + yi or x + yj text format.
  5695.      *
  5696.      * @param    string        $complexNumber 
  5697.      * @return  string 
  5698.      */
  5699.     public static function IMEXP($complexNumber{
  5700.         $complexNumber    self::flattenSingleValue($complexNumber);
  5701.  
  5702.         $parsedComplex self::parseComplex($complexNumber);
  5703.         if (!is_array($parsedComplex)) {
  5704.             return $parsedComplex;
  5705.         }
  5706.  
  5707.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  5708.             return '1';
  5709.         }
  5710.  
  5711.         $e exp($parsedComplex['real']);
  5712.         $eX $e cos($parsedComplex['imaginary']);
  5713.         $eY $e sin($parsedComplex['imaginary']);
  5714.  
  5715.         if ($parsedComplex['suffix'== ''{
  5716.             return self::COMPLEX($eX,$eY);
  5717.         else {
  5718.             return self::COMPLEX($eX,$eY,$parsedComplex['suffix']);
  5719.         }
  5720.     }
  5721.  
  5722.     /**
  5723.      * IMPOWER
  5724.      *
  5725.      * Returns a complex number in x + yi or x + yj text format raised to a power.
  5726.      *
  5727.      * @param    string        $complexNumber 
  5728.      * @return  string 
  5729.      */
  5730.     public static function IMPOWER($complexNumber,$realNumber{
  5731.         $complexNumber    self::flattenSingleValue($complexNumber);
  5732.         $realNumber        self::flattenSingleValue($realNumber);
  5733.  
  5734.         if (!is_numeric($realNumber)) {
  5735.             return self::$_errorCodes['value'];
  5736.         }
  5737.  
  5738.         $parsedComplex self::parseComplex($complexNumber);
  5739.         if (!is_array($parsedComplex)) {
  5740.             return $parsedComplex;
  5741.         }
  5742.  
  5743.         $r sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary']));
  5744.         $rPower pow($r,$realNumber);
  5745.         $theta self::IMARGUMENT($complexNumber$realNumber;
  5746.         if ($parsedComplex['imaginary'== 0.0{
  5747.             return self::COMPLEX($rPower cos($theta),$rPower sin($theta),$parsedComplex['suffix']);
  5748.         else {
  5749.             return self::COMPLEX($rPower cos($theta),$rPower sin($theta),$parsedComplex['suffix']);
  5750.         }
  5751.     }
  5752.  
  5753.     /**
  5754.      * IMDIV
  5755.      *
  5756.      * Returns the quotient of two complex numbers in x + yi or x + yj text format.
  5757.      *
  5758.      * @param    string        $complexDividend 
  5759.      * @param    string        $complexDivisor 
  5760.      * @return  real 
  5761.      */
  5762.     public static function IMDIV($complexDividend,$complexDivisor{
  5763.         $complexDividend    self::flattenSingleValue($complexDividend);
  5764.         $complexDivisor    self::flattenSingleValue($complexDivisor);
  5765.  
  5766.         $parsedComplexDividend self::parseComplex($complexDividend);
  5767.         if (!is_array($parsedComplexDividend)) {
  5768.             return $parsedComplexDividend;
  5769.         }
  5770.  
  5771.         $parsedComplexDivisor self::parseComplex($complexDivisor);
  5772.         if (!is_array($parsedComplexDivisor)) {
  5773.             return $parsedComplexDividend;
  5774.         }
  5775.  
  5776.         if ($parsedComplexDividend['suffix'!= $parsedComplexDivisor['suffix']{
  5777.             return self::$_errorCodes['num'];
  5778.         }
  5779.  
  5780.         $d1 ($parsedComplexDividend['real'$parsedComplexDivisor['real']($parsedComplexDividend['imaginary'$parsedComplexDivisor['imaginary']);
  5781.         $d2 ($parsedComplexDividend['imaginary'$parsedComplexDivisor['real']($parsedComplexDividend['real'$parsedComplexDivisor['imaginary']);
  5782.         $d3 ($parsedComplexDivisor['real'$parsedComplexDivisor['real']($parsedComplexDivisor['imaginary'$parsedComplexDivisor['imaginary']);
  5783.  
  5784.         return $d1/$d3.$d2/$d3.$parsedComplexDivisor['suffix'];
  5785.     }
  5786.  
  5787.     /**
  5788.      * IMSUB
  5789.      *
  5790.      * Returns the difference of two complex numbers in x + yi or x + yj text format.
  5791.      *
  5792.      * @param    string        $complexNumber1 
  5793.      * @param    string        $complexNumber2 
  5794.      * @return  real 
  5795.      */
  5796.     public static function IMSUB($complexNumber1,$complexNumber2{
  5797.         $complexNumber1    self::flattenSingleValue($complexNumber1);
  5798.         $complexNumber2    self::flattenSingleValue($complexNumber2);
  5799.  
  5800.         $parsedComplex1 self::parseComplex($complexNumber1);
  5801.         if (!is_array($parsedComplex1)) {
  5802.             return $parsedComplex1;
  5803.         }
  5804.  
  5805.         $parsedComplex2 self::parseComplex($complexNumber2);
  5806.         if (!is_array($parsedComplex2)) {
  5807.             return $parsedComplex2;
  5808.         }
  5809.  
  5810.         if ($parsedComplex1['suffix'!= $parsedComplex2['suffix']{
  5811.             return self::$_errorCodes['num'];
  5812.         }
  5813.  
  5814.         $d1 $parsedComplex1['real'$parsedComplex2['real'];
  5815.         $d2 $parsedComplex1['imaginary'$parsedComplex2['imaginary'];
  5816.  
  5817.         return self::COMPLEX($d1,$d2,$parsedComplex1['suffix']);
  5818.     }
  5819.  
  5820.     /**
  5821.      * IMSUM
  5822.      *
  5823.      * Returns the sum of two or more complex numbers in x + yi or x + yj text format.
  5824.      *
  5825.      * @param    array of mixed        Data Series
  5826.      * @return  real 
  5827.      */
  5828.     public static function IMSUM({
  5829.         // Return value
  5830.         $returnValue self::parseComplex('0');
  5831.         $activeSuffix '';
  5832.  
  5833.         // Loop through the arguments
  5834.         $aArgs self::flattenArray(func_get_args());
  5835.         foreach ($aArgs as $arg{
  5836.             $parsedComplex self::parseComplex($arg);
  5837.             if (!is_array($parsedComplex)) {
  5838.                 return $parsedComplex;
  5839.             }
  5840.  
  5841.             if ($activeSuffix == ''{
  5842.                 $activeSuffix $parsedComplex['suffix'];
  5843.             elseif ($activeSuffix != $parsedComplex['suffix']{
  5844.                 return self::$_errorCodes['num'];
  5845.             }
  5846.  
  5847.             $returnValue['real'+= $parsedComplex['real'];
  5848.             $returnValue['imaginary'+= $parsedComplex['imaginary'];
  5849.         }
  5850.  
  5851.         if ($returnValue['imaginary'== 0.0$activeSuffix ''}
  5852.         return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix);
  5853.     }
  5854.  
  5855.     /**
  5856.      * IMPRODUCT
  5857.      *
  5858.      * Returns the product of two or more complex numbers in x + yi or x + yj text format.
  5859.      *
  5860.      * @param    array of mixed        Data Series
  5861.      * @return  real 
  5862.      */
  5863.     public static function IMPRODUCT({
  5864.         // Return value
  5865.         $returnValue self::parseComplex('1');
  5866.         $activeSuffix '';
  5867.  
  5868.         // Loop through the arguments
  5869.         $aArgs self::flattenArray(func_get_args());
  5870.         foreach ($aArgs as $arg{
  5871.             $parsedComplex self::parseComplex($arg);
  5872.             if (!is_array($parsedComplex)) {
  5873.                 return $parsedComplex;
  5874.             }
  5875.             $workValue $returnValue;
  5876.             if (($parsedComplex['suffix'!= ''&& ($activeSuffix == '')) {
  5877.                 $activeSuffix $parsedComplex['suffix'];
  5878.             elseif (($parsedComplex['suffix'!= ''&& ($activeSuffix != $parsedComplex['suffix'])) {
  5879.                 return self::$_errorCodes['num'];
  5880.             }
  5881.             $returnValue['real'($workValue['real'$parsedComplex['real']($workValue['imaginary'$parsedComplex['imaginary']);
  5882.             $returnValue['imaginary'($workValue['real'$parsedComplex['imaginary']($workValue['imaginary'$parsedComplex['real']);
  5883.         }
  5884.  
  5885.         if ($returnValue['imaginary'== 0.0$activeSuffix ''}
  5886.         return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix);
  5887.     }
  5888.  
  5889.     /**
  5890.      * BESSELI
  5891.      *
  5892.      * Returns the modified Bessel function, which is equivalent to the Bessel function evaluated for purely imaginary arguments
  5893.      *
  5894.      * @param    float        $x 
  5895.      * @param    float        $n 
  5896.      * @return  int 
  5897.      */
  5898.     public static function BESSELI($x$n{
  5899.         $x    self::flattenSingleValue($x);
  5900.         $n    floor(self::flattenSingleValue($n));
  5901.  
  5902.         if ((is_numeric($x)) && (is_numeric($n))) {
  5903.             if ($n 0{
  5904.                 return self::$_errorCodes['num'];
  5905.             }
  5906.             $f_2_PI pi();
  5907.  
  5908.             if (abs($x<= 30{
  5909.                 $fTerm pow($x 2$nself::FACT($n);
  5910.                 $nK 1;
  5911.                 $fResult $fTerm;
  5912.                 $fSqrX pow($x,24;
  5913.                 do {
  5914.                     $fTerm *= $fSqrX;
  5915.                     $fTerm /= ($nK ($nK $n));
  5916.                     $fResult += $fTerm;
  5917.                 while ((abs($fTerm1e-10&& (++$nK 100));
  5918.             else {
  5919.                 $fXAbs abs($x);
  5920.                 $fResult exp($fXAbssqrt($f_2_PI $fXAbs);
  5921.                 if (($n && 1&& ($x 0)) {
  5922.                     $fResult = -$fResult;
  5923.                 }
  5924.             }
  5925.             return $fResult;
  5926.         }
  5927.         return self::$_errorCodes['value'];
  5928.     }
  5929.  
  5930.     /**
  5931.      * BESSELJ
  5932.      *
  5933.      * Returns the Bessel function
  5934.      *
  5935.      * @param    float        $x 
  5936.      * @param    float        $n 
  5937.      * @return  int 
  5938.      */
  5939.     public static function BESSELJ($x$n{
  5940.         $x    self::flattenSingleValue($x);
  5941.         $n    floor(self::flattenSingleValue($n));
  5942.  
  5943.         if ((is_numeric($x)) && (is_numeric($n))) {
  5944.             if ($n 0{
  5945.                 return self::$_errorCodes['num'];
  5946.             }
  5947.             $f_2_DIV_PI pi();
  5948.             $f_PI_DIV_2 pi(2;
  5949.             $f_PI_DIV_4 pi(4;
  5950.  
  5951.             $fResult 0;
  5952.             if (abs($x<= 30{
  5953.                 $fTerm pow($x 2$nself::FACT($n);
  5954.                 $nK 1;
  5955.                 $fResult $fTerm;
  5956.                 $fSqrX pow($x,2/ -4;
  5957.                 do {
  5958.                     $fTerm *= $fSqrX;
  5959.                     $fTerm /= ($nK ($nK $n));
  5960.                     $fResult += $fTerm;
  5961.                 while ((abs($fTerm1e-10&& (++$nK 100));
  5962.             else {
  5963.                 $fXAbs abs($x);
  5964.                 $fResult sqrt($f_2_DIV_PI $fXAbscos($fXAbs $n $f_PI_DIV_2 $f_PI_DIV_4);
  5965.                 if (($n && 1&& ($x 0)) {
  5966.                     $fResult = -$fResult;
  5967.                 }
  5968.             }
  5969.             return $fResult;
  5970.         }
  5971.         return self::$_errorCodes['value'];
  5972.     }
  5973.  
  5974.     private static function Besselk0($fNum{
  5975.         if ($fNum <= 2{
  5976.             $fNum2 $fNum 0.5;
  5977.             $y pow($fNum2,2);
  5978.             $fRet = -log($fNum2self::BESSELI($fNum0+
  5979.                     (-0.57721566 $y (0.42278420 $y (0.23069756 $y (0.3488590e-1 $y (0.262698e-2 $y *
  5980.                     (0.10750e-3 $y 0.74e-5))))));
  5981.         else {
  5982.             $y $fNum;
  5983.             $fRet exp(-$fNumsqrt($fNum*
  5984.                     (1.25331414 $y (-0.7832358e-1 $y (0.2189568e-1 $y (-0.1062446e-1 $y *
  5985.                     (0.587872e-2 $y (-0.251540e-2 $y 0.53208e-3))))));
  5986.         }
  5987.         return $fRet;
  5988.     }
  5989.  
  5990.     private static function Besselk1($fNum{
  5991.         if ($fNum <= 2{
  5992.             $fNum2 $fNum 0.5;
  5993.             $y pow($fNum2,2);
  5994.             $fRet log($fNum2self::BESSELI($fNum1+
  5995.                     ($y (0.15443144 $y (-0.67278579 $y (-0.18156897 $y (-0.1919402e-1 $y *
  5996.                     (-0.110404e-2 $y (-0.4686e-4))))))) $fNum;
  5997.         else {
  5998.             $y $fNum;
  5999.             $fRet exp(-$fNumsqrt($fNum*
  6000.                     (1.25331414 $y (0.23498619 $y (-0.3655620e-1 $y (0.1504268e-1 $y (-0.780353e-2 $y *
  6001.                     (0.325614e-2 $y (-0.68245e-3)))))));
  6002.         }
  6003.         return $fRet;
  6004.     }
  6005.  
  6006.     /**
  6007.      * BESSELK
  6008.      *
  6009.      * Returns the modified Bessel function, which is equivalent to the Bessel functions evaluated for purely imaginary arguments.
  6010.      *
  6011.      * @param    float        $x 
  6012.      * @param    float        $n 
  6013.      * @return  int 
  6014.      */
  6015.     public static function BESSELK($x$ord{
  6016.         $x    self::flattenSingleValue($x);
  6017.         $n    floor(self::flattenSingleValue($ord));
  6018.  
  6019.         if ((is_numeric($x)) && (is_numeric($ord))) {
  6020.             if ($ord 0{
  6021.                 return self::$_errorCodes['num'];
  6022.             }
  6023.  
  6024.             switch($ord{
  6025.                 case :    return self::Besselk0($x);
  6026.                             break;
  6027.                 case :    return self::Besselk1($x);
  6028.                             break;
  6029.                 default :    $fTox    $x;
  6030.                             $fBkm    self::Besselk0($x);
  6031.                             $fBk    self::Besselk1($x);
  6032.                             for ($n 1$n $ord++$n{
  6033.                                 $fBkp    $fBkm $n $fTox $fBk;
  6034.                                 $fBkm    $fBk;
  6035.                                 $fBk    $fBkp;
  6036.                             }
  6037.             }
  6038.             return $fBk;
  6039.         }
  6040.         return self::$_errorCodes['value'];
  6041.     }
  6042.  
  6043.     private static function Bessely0($fNum{
  6044.         if ($fNum 8{
  6045.             $y pow($fNum,2);
  6046.             $f1 = -2957821389.0 $y (7062834065.0 $y (-512359803.6 $y (10879881.29 $y (-86327.92757 $y 228.4622733))));
  6047.             $f2 40076544269.0 $y (745249964.8 $y (7189466.438 $y (47447.26470 $y (226.1030244 $y))));
  6048.             $fRet $f1 $f2 0.636619772 self::BESSELJ($fNum0log($fNum);
  6049.         else {
  6050.             $z $fNum;
  6051.             $y pow($z,2);
  6052.             $xx $fNum 0.785398164;
  6053.             $f1 $y (-0.1098628627e-2 $y (0.2734510407e-4 $y (-0.2073370639e-5 $y 0.2093887211e-6)));
  6054.             $f2 = -0.1562499995e-1 $y (0.1430488765e-3 $y (-0.6911147651e-5 $y (0.7621095161e-6 $y (-0.934945152e-7))));
  6055.             $fRet sqrt(0.636619772 $fNum(sin($xx$f1 $z cos($xx$f2);
  6056.         }
  6057.         return $fRet;
  6058.     }
  6059.  
  6060.     private static function Bessely1($fNum{
  6061.         if ($fNum 8{
  6062.             $y pow($fNum,2);
  6063.             $f1 $fNum (-0.4900604943e13 $y (0.1275274390e13 $y (-0.5153438139e11 $y (0.7349264551e9 $y *
  6064.                 (-0.4237922726e7 $y 0.8511937935e4)))));
  6065.             $f2 0.2499580570e14 $y (0.4244419664e12 $y (0.3733650367e10 $y (0.2245904002e8 $y *
  6066.                 (0.1020426050e6 $y (0.3549632885e3 $y)))));
  6067.             $fRet $f1 $f2 0.636619772 self::BESSELJ($fNum1log($fNum$fNum);
  6068.         else {
  6069.             $z $fNum;
  6070.             $y $z $z;
  6071.             $xx $fNum 2.356194491;
  6072.             $f1 $y (0.183105e-2 $y (-0.3516396496e-4 $y (0.2457520174e-5 $y (-0.240337019e6))));
  6073.             $f2 0.04687499995 $y (-0.2002690873e-3 $y (0.8449199096e-5 $y (-0.88228987e-6 $y 0.105787412e-6)));
  6074.             $fRet sqrt(0.636619772 $fNum(sin($xx$f1 $z cos($xx$f2);
  6075.             #i12430# ...but this seems to work much better.
  6076. //            $fRet = sqrt(0.636619772 / $fNum) * sin($fNum - 2.356194491);
  6077.         }
  6078.         return $fRet;
  6079.     }
  6080.  
  6081.     /**
  6082.      * BESSELY
  6083.      *
  6084.      * Returns the Bessel function, which is also called the Weber function or the Neumann function.
  6085.      *
  6086.      * @param    float        $x 
  6087.      * @param    float        $n 
  6088.      * @return  int 
  6089.      */
  6090.     public static function BESSELY($x$ord{
  6091.         $x    self::flattenSingleValue($x);
  6092.         $n    floor(self::flattenSingleValue($ord));
  6093.  
  6094.         if ((is_numeric($x)) && (is_numeric($ord))) {
  6095.             if ($ord 0{
  6096.                 return self::$_errorCodes['num'];
  6097.             }
  6098.  
  6099.             switch($ord{
  6100.                 case :    return self::Bessely0($x);
  6101.                             break;
  6102.                 case :    return self::Bessely1($x);
  6103.                             break;
  6104.                 default:    $fTox    $x;
  6105.                             $fBym    self::Bessely0($x);
  6106.                             $fBy    self::Bessely1($x);
  6107.                             for ($n 1$n $ord++$n{
  6108.                                 $fByp    $n $fTox $fBy $fBym;
  6109.                                 $fBym    $fBy;
  6110.                                 $fBy    $fByp;
  6111.                             }
  6112.             }
  6113.             return $fBy;
  6114.         }
  6115.         return self::$_errorCodes['value'];
  6116.     }
  6117.  
  6118.     /**
  6119.      * DELTA
  6120.      *
  6121.      * Tests whether two values are equal. Returns 1 if number1 = number2; returns 0 otherwise.
  6122.      *
  6123.      * @param    float        $a 
  6124.      * @param    float        $b 
  6125.      * @return  int 
  6126.      */
  6127.     public static function DELTA($a$b=0{
  6128.         $a    self::flattenSingleValue($a);
  6129.         $b    self::flattenSingleValue($b);
  6130.  
  6131.         return (int) ($a == $b);
  6132.     }
  6133.  
  6134.     /**
  6135.      * GESTEP
  6136.      *
  6137.      * Returns 1 if number = step; returns 0 (zero) otherwise
  6138.      *
  6139.      * @param    float        $number 
  6140.      * @param    float        $step 
  6141.      * @return  int 
  6142.      */
  6143.     public static function GESTEP($number$step=0{
  6144.         $number    self::flattenSingleValue($number);
  6145.         $step    self::flattenSingleValue($step);
  6146.  
  6147.         return (int) ($number >= $step);
  6148.     }
  6149.  
  6150.     //
  6151.     //    Private method to calculate the erf value
  6152.     //
  6153.     private static $two_sqrtpi 1.128379167095512574;
  6154.     private static $rel_error 1E-15;
  6155.  
  6156.     private static function erfVal($x{
  6157.         if (abs($x2.2{
  6158.             return self::erfcVal($x);
  6159.         }
  6160.         $sum $term $x;
  6161.         $xsqr pow($x,2);
  6162.         $j 1;
  6163.         do {
  6164.             $term *= $xsqr $j;
  6165.             $sum -= $term ($j 1);
  6166.             ++$j;
  6167.             $term *= $xsqr $j;
  6168.             $sum += $term ($j 1);
  6169.             ++$j;
  6170.             if ($sum == 0{
  6171.                 break;
  6172.             }
  6173.         while (abs($term $sumself::$rel_error);
  6174.         return  self::$two_sqrtpi $sum;
  6175.     }
  6176.  
  6177.     /**
  6178.      * ERF
  6179.      *
  6180.      * Returns the error function integrated between lower_limit and upper_limit
  6181.      *
  6182.      * @param    float        $lower    lower bound for integrating ERF
  6183.      * @param    float        $upper    upper bound for integrating ERF.
  6184.      *                                 If omitted, ERF integrates between zero and lower_limit
  6185.      * @return  int 
  6186.      */
  6187.     public static function ERF($lower$upper 0{
  6188.         $lower    self::flattenSingleValue($lower);
  6189.         $upper    self::flattenSingleValue($upper);
  6190.  
  6191.         if ((is_numeric($lower)) && (is_numeric($upper))) {
  6192.             if (($lower 0|| ($upper 0)) {
  6193.                 return self::$_errorCodes['num'];
  6194.             }
  6195.             if ($upper $lower{
  6196.                 return self::erfVal($upperself::erfVal($lower);
  6197.             else {
  6198.                 return self::erfVal($lowerself::erfVal($upper);
  6199.             }
  6200.         }
  6201.         return self::$_errorCodes['value'];
  6202.     }
  6203.  
  6204.     //
  6205.     //    Private method to calculate the erfc value
  6206.     //
  6207.     private static $one_sqrtpi 0.564189583547756287;
  6208.  
  6209.     private static function erfcVal($x{
  6210.         if (abs($x2.2{
  6211.             return self::erfVal($x);
  6212.         }
  6213.         if ($x 0{
  6214.             return self::erfc(-$x);
  6215.         }
  6216.         $a $n 1;
  6217.         $b $c $x;
  6218.         $d pow($x,20.5;
  6219.         $q1 $q2 $b $d;
  6220.         $t 0;
  6221.         do {
  6222.             $t $a $n $b $x;
  6223.             $a $b;
  6224.             $b $t;
  6225.             $t $c $n $d $x;
  6226.             $c $d;
  6227.             $d $t;
  6228.             $n += 0.5;
  6229.             $q1 $q2;
  6230.             $q2 $b $d;
  6231.         while ((abs($q1 $q2$q2self::$rel_error);
  6232.         return self::$one_sqrtpi exp(-$x $x$q2;
  6233.     }
  6234.  
  6235.     /**
  6236.      * ERFC
  6237.      *
  6238.      * Returns the complementary ERF function integrated between x and infinity
  6239.      *
  6240.      * @param    float        $x        The lower bound for integrating ERF
  6241.      * @return  int 
  6242.      */
  6243.     public static function ERFC($x{
  6244.         $x    self::flattenSingleValue($x);
  6245.  
  6246.         if (is_numeric($x)) {
  6247.             if ($x 0{
  6248.                 return self::$_errorCodes['num'];
  6249.             }
  6250.             return self::erfcVal($x);
  6251.         }
  6252.         return self::$_errorCodes['value'];
  6253.     }
  6254.  
  6255.     /**
  6256.      * EFFECT
  6257.      *
  6258.      * Returns the effective interest rate given the nominal rate and the number of compounding payments per year.
  6259.      *
  6260.      * @param    float    $nominal_rate      Nominal interest rate
  6261.      * @param    int        $npery               Number of compounding payments per year
  6262.      * @return    float 
  6263.      */
  6264.     public static function EFFECT($nominal_rate 0$npery 0{
  6265.         $nominal_rate    self::flattenSingleValue($$nominal_rate);
  6266.         $npery            = (int)self::flattenSingleValue($npery);
  6267.  
  6268.         // Validate parameters
  6269.         if ($$nominal_rate <= || $npery 1{
  6270.             return self::$_errorCodes['num'];
  6271.         }
  6272.  
  6273.         return pow(($nominal_rate $npery)$npery1;
  6274.     }
  6275.  
  6276.     /**
  6277.      * NOMINAL
  6278.      *
  6279.      * Returns the nominal interest rate given the effective rate and the number of compounding payments per year.
  6280.      *
  6281.      * @param    float    $effect_rate    Effective interest rate
  6282.      * @param    int        $npery            Number of compounding payments per year
  6283.      * @return    float 
  6284.      */
  6285.     public static function NOMINAL($effect_rate 0$npery 0{
  6286.         $effect_rate    self::flattenSingleValue($effect_rate);
  6287.         $npery            = (int)self::flattenSingleValue($npery);
  6288.  
  6289.         // Validate parameters
  6290.         if ($effect_rate <= || $npery 1{
  6291.             return self::$_errorCodes['num'];
  6292.         }
  6293.  
  6294.         // Calculate
  6295.         return $npery (pow($effect_rate 1$npery1);
  6296.     }
  6297.  
  6298.     /**
  6299.      * PV
  6300.      *
  6301.      * Returns the Present Value of a cash flow with constant payments and interest rate (annuities).
  6302.      *
  6303.      * @param    float    $rate    Interest rate per period
  6304.      * @param    int        $nper    Number of periods
  6305.      * @param    float    $pmt    Periodic payment (annuity)
  6306.      * @param    float    $fv        Future Value
  6307.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  6308.      * @return    float 
  6309.      */
  6310.     public static function PV($rate 0$nper 0$pmt 0$fv 0$type 0{
  6311.         $rate    self::flattenSingleValue($rate);
  6312.         $nper    self::flattenSingleValue($nper);
  6313.         $pmt    self::flattenSingleValue($pmt);
  6314.         $fv        self::flattenSingleValue($fv);
  6315.         $type    self::flattenSingleValue($type);
  6316.  
  6317.         // Validate parameters
  6318.         if ($type != && $type != 1{
  6319.             return self::$_errorCodes['num'];
  6320.         }
  6321.  
  6322.         // Calculate
  6323.         if (!is_null($rate&& $rate != 0{
  6324.             return (-$pmt ($rate $type((pow($rate$nper1$rate$fvpow($rate$nper);
  6325.         else {
  6326.             return -$fv $pmt $nper;
  6327.         }
  6328.     }
  6329.  
  6330.     /**
  6331.      * FV
  6332.      *
  6333.      * Returns the Future Value of a cash flow with constant payments and interest rate (annuities).
  6334.      *
  6335.      * @param    float    $rate    Interest rate per period
  6336.      * @param    int        $nper    Number of periods
  6337.      * @param    float    $pmt    Periodic payment (annuity)
  6338.      * @param    float    $pv        Present Value
  6339.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  6340.      * @return    float 
  6341.      */
  6342.     public static function FV($rate 0$nper 0$pmt 0$pv 0$type 0{
  6343.         $rate    self::flattenSingleValue($rate);
  6344.         $nper    self::flattenSingleValue($nper);
  6345.         $pmt    self::flattenSingleValue($pmt);
  6346.         $pv        self::flattenSingleValue($pv);
  6347.         $type    self::flattenSingleValue($type);
  6348.  
  6349.         // Validate parameters
  6350.         if ($type != && $type != 1{
  6351.             return self::$_errorCodes['num'];
  6352.         }
  6353.  
  6354.         // Calculate
  6355.         if (!is_null($rate&& $rate != 0{
  6356.             return -$pv pow($rate$nper$pmt ($rate $type(pow($rate$nper1$rate;
  6357.         else {
  6358.             return -$pv $pmt $nper;
  6359.         }
  6360.     }
  6361.  
  6362.     /**
  6363.      * PMT
  6364.      *
  6365.      * Returns the constant payment (annuity) for a cash flow with a constant interest rate.
  6366.      *
  6367.      * @param    float    $rate    Interest rate per period
  6368.      * @param    int        $nper    Number of periods
  6369.      * @param    float    $pv        Present Value
  6370.      * @param    float    $fv        Future Value
  6371.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  6372.      * @return    float 
  6373.      */
  6374.     public static function PMT($rate 0$nper 0$pv 0$fv 0$type 0{
  6375.         $rate    self::flattenSingleValue($rate);
  6376.         $nper    self::flattenSingleValue($nper);
  6377.         $pv        self::flattenSingleValue($pv);
  6378.         $fv        self::flattenSingleValue($fv);
  6379.         $type    self::flattenSingleValue($type);
  6380.  
  6381.         // Validate parameters
  6382.         if ($type != && $type != 1{
  6383.             return self::$_errorCodes['num'];
  6384.         }
  6385.  
  6386.         // Calculate
  6387.         if (!is_null($rate&& $rate != 0{
  6388.             return (-$fv $pv pow($rate$nper)) ($rate $type((pow($rate$nper1$rate);
  6389.         else {
  6390.             return (-$pv $fv$nper;
  6391.         }
  6392.     }
  6393.  
  6394.     /**
  6395.      * NPER
  6396.      *
  6397.      * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate.
  6398.      *
  6399.      * @param    float    $rate    Interest rate per period
  6400.      * @param    int        $pmt    Periodic payment (annuity)
  6401.      * @param    float    $pv        Present Value
  6402.      * @param    float    $fv        Future Value
  6403.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  6404.      * @return    float 
  6405.      */
  6406.     public static function NPER($rate 0$pmt 0$pv 0$fv 0$type 0{
  6407.         $rate    self::flattenSingleValue($rate);
  6408.         $pmt    self::flattenSingleValue($pmt);
  6409.         $pv        self::flattenSingleValue($pv);
  6410.         $fv        self::flattenSingleValue($fv);
  6411.         $type    self::flattenSingleValue($type);
  6412.  
  6413.         // Validate parameters
  6414.         if ($type != && $type != 1{
  6415.             return self::$_errorCodes['num'];
  6416.         }
  6417.  
  6418.         // Calculate
  6419.         if (!is_null($rate&& $rate != 0{
  6420.             if ($pmt == && $pv == 0{
  6421.                 return self::$_errorCodes['num'];
  6422.             }
  6423.             return log(($pmt ($rate $type$rate $fv($pv $pmt ($rate $type$rate)) log($rate);
  6424.         else {
  6425.             if ($pmt == 0{
  6426.                 return self::$_errorCodes['num'];
  6427.             }
  6428.             return (-$pv -$fv$pmt;
  6429.         }
  6430.     }
  6431.  
  6432.     /**
  6433.      * NPV
  6434.      *
  6435.      * Returns the Net Present Value of a cash flow series given a discount rate.
  6436.      *
  6437.      * @param    float    Discount interest rate
  6438.      * @param    array    Cash flow series
  6439.      * @return    float 
  6440.      */
  6441.     public static function NPV({
  6442.         // Return value
  6443.         $returnValue 0;
  6444.  
  6445.         // Loop trough arguments
  6446.         $aArgs self::flattenArray(func_get_args());
  6447.  
  6448.         // Calculate
  6449.         $rate array_shift($aArgs);
  6450.         for ($i 1$i <= count($aArgs)++$i{
  6451.             // Is it a numeric value?
  6452.             if (is_numeric($aArgs[$i 1])) {
  6453.                 $returnValue += $aArgs[$i 1pow($rate$i);
  6454.             }
  6455.         }
  6456.  
  6457.         // Return
  6458.         return $returnValue;
  6459.     }
  6460.  
  6461.     /**
  6462.      * ACCRINT
  6463.      *
  6464.      * Computes the accrued interest for a security that pays periodic interest.
  6465.      *
  6466.      * @param    int        $issue 
  6467.      * @param    int        $firstInterest 
  6468.      * @param    int        $settlement 
  6469.      * @param    int        $rate 
  6470.      * @param    int        $par 
  6471.      * @param    int        $frequency 
  6472.      * @param    int        $basis 
  6473.      * @return  int        The accrued interest for a security that pays periodic interest.
  6474.      */
  6475.     /*
  6476.     public static function ACCRINT($issue = 0, $firstInterest = 0, $settlement = 0, $rate = 0, $par = 1000, $frequency = 1, $basis = 0) {
  6477.         $issue            = self::flattenSingleValue($issue);
  6478.         $firstInterest    = self::flattenSingleValue($firstInterest);
  6479.         $settlement    = self::flattenSingleValue($settlement);
  6480.         $rate            = self::flattenSingleValue($rate);
  6481.         $par            = self::flattenSingleValue($par);
  6482.         $frequency        = self::flattenSingleValue($frequency);
  6483.         $basis            = self::flattenSingleValue($basis);
  6484.  
  6485.         // Perform checks
  6486.         if ($issue >= $settlement || $rate <= 0 || $par <= 0 || !($frequency == 1 || $frequency == 2 || $frequency == 4) || $basis < 0 || $basis > 4) return self::$_errorCodes['num'];
  6487.  
  6488.         // Calculate value
  6489.         return $par * ($rate / $frequency) *
  6490.     }
  6491.     */
  6492.  
  6493.     /**
  6494.      * SLN
  6495.      *
  6496.      * Returns the straight-line depreciation of an asset for one period
  6497.      *
  6498.      * @param    cost        Initial cost of the asset
  6499.      * @param    salvage        Value at the end of the depreciation
  6500.      * @param    life        Number of periods over which the asset is depreciated
  6501.      * @return    float 
  6502.      */
  6503.     public static function SLN($cost$salvage$life{
  6504.         $cost        self::flattenSingleValue($cost);
  6505.         $salvage    self::flattenSingleValue($salvage);
  6506.         $life        self::flattenSingleValue($life);
  6507.  
  6508.         // Calculate
  6509.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life))) {
  6510.             if ($life 0{
  6511.                 return self::$_errorCodes['num'];
  6512.             }
  6513.             return ($cost $salvage$life;
  6514.         }
  6515.         return self::$_errorCodes['value'];
  6516.     }
  6517.  
  6518.     /**
  6519.      * CELL_ADDRESS
  6520.      *
  6521.      * Returns the straight-line depreciation of an asset for one period
  6522.      *
  6523.      * @param    row            Row number to use in the cell reference
  6524.      * @param    column        Column number to use in the cell reference
  6525.      * @param    relativity    Flag indicating the type of reference to return
  6526.      * @param    sheetText    Name of worksheet to use
  6527.      * @return    string 
  6528.      */
  6529.     public static function CELL_ADDRESS($row$column$relativity=1$referenceStyle=True$sheetText=''{
  6530.         $row        self::flattenSingleValue($row);
  6531.         $column        self::flattenSingleValue($column);
  6532.         $relativity    self::flattenSingleValue($relativity);
  6533.         $sheetText    self::flattenSingleValue($sheetText);
  6534.  
  6535.         if ($sheetText ''{
  6536.             if (strpos($sheetText,' '!== False$sheetText "'".$sheetText."'"}
  6537.             $sheetText .='!';
  6538.         }
  6539.         if (!$referenceStyle{
  6540.             if (($relativity == 2|| ($relativity == 4)) $column '['.$column.']'}
  6541.             if (($relativity == 3|| ($relativity == 4)) $row '['.$row.']'}
  6542.             return $sheetText.'R'.$row.'C'.$column;
  6543.         else {
  6544.             $rowRelative $columnRelative '$';
  6545.             $column PHPExcel_Cell::stringFromColumnIndex($column-1);
  6546.             if (($relativity == 2|| ($relativity == 4)) $columnRelative ''}
  6547.             if (($relativity == 3|| ($relativity == 4)) $rowRelative ''}
  6548.             return $sheetText.$columnRelative.$column.$rowRelative.$row;
  6549.         }
  6550.     }
  6551.  
  6552.  
  6553.     public static function COLUMN($cellAddress=Null{
  6554.         if ($cellAddress === Null{
  6555.             return 0;
  6556.         }
  6557.  
  6558.         foreach($cellAddress as $columnKey => $value{
  6559.             return PHPExcel_Cell::columnIndexFromString($columnKey);
  6560.         }
  6561.     }    //    function COLUMN()
  6562.  
  6563.  
  6564.     public static function ROW($cellAddress=Null{
  6565.         if ($cellAddress === Null{
  6566.             return 0;
  6567.         }
  6568.  
  6569.         foreach($cellAddress as $columnKey => $rowValue{
  6570.             foreach($rowValue as $rowKey => $cellValue{
  6571.                 return $rowKey;
  6572.             }
  6573.         }
  6574.     }    //    function ROW()
  6575.  
  6576.  
  6577.     public static function OFFSET($cellAddress=Null,$rows=0,$columns=0,$height=null,$width=null{
  6578.         if ($cellAddress === Null{
  6579.             return 0;
  6580.         }
  6581.  
  6582.         foreach($cellAddress as $startColumnKey => $rowValue{
  6583.             $startColumnIndex PHPExcel_Cell::columnIndexFromString($startColumnKey);
  6584.             foreach($rowValue as $startRowKey => $cellValue{
  6585.                 break 2;
  6586.             }
  6587.         }
  6588.  
  6589.         foreach($cellAddress as $endColumnKey => $rowValue{
  6590.             foreach($rowValue as $endRowKey => $cellValue{
  6591.             }
  6592.         }
  6593.         $endColumnIndex PHPExcel_Cell::columnIndexFromString($endColumnKey);
  6594.  
  6595.         $startColumnIndex += --$columns;
  6596.         $startRowKey += $rows;
  6597.  
  6598.         if ($width == null{
  6599.             $endColumnIndex += $columns -1;
  6600.         else {
  6601.             $endColumnIndex $startColumnIndex $width;
  6602.         }
  6603.         if ($height == null{
  6604.             $endRowKey += $rows;
  6605.         else {
  6606.             $endRowKey $startRowKey $height -1;
  6607.         }
  6608.  
  6609.         if (($startColumnIndex 0|| ($startRowKey <= 0)) {
  6610.             return self::$_errorCodes['reference'];
  6611.         }
  6612.  
  6613.         $startColumnKey PHPExcel_Cell::stringFromColumnIndex($startColumnIndex);
  6614.         $endColumnKey PHPExcel_Cell::stringFromColumnIndex($endColumnIndex);
  6615.  
  6616.         $startCell $startColumnKey.$startRowKey;
  6617.         $endCell $endColumnKey.$endRowKey;
  6618.  
  6619.         if ($startCell == $endCell{
  6620.             return $startColumnKey.$startRowKey;
  6621.         else {
  6622.             return $startColumnKey.$startRowKey.':'.$endColumnKey.$endRowKey;
  6623.         }
  6624.     }    //    function COLUMN()
  6625.  
  6626.  
  6627.     public static function CHOOSE({
  6628.         $chooseArgs func_get_args();
  6629.         $chosenEntry self::flattenSingleValue(array_shift($chooseArgs));
  6630.         $entryCount count($chooseArgs1;
  6631.  
  6632.         if ((is_numeric($chosenEntry)) && (!is_bool($chosenEntry))) {
  6633.             --$chosenEntry;
  6634.         else {
  6635.             return self::$_errorCodes['value'];
  6636.         }
  6637.         $chosenEntry floor($chosenEntry);
  6638.         if (($chosenEntry <= 0|| ($chosenEntry $entryCount)) {
  6639.             return self::$_errorCodes['value'];
  6640.         }
  6641.  
  6642.         if (is_array($chooseArgs[$chosenEntry])) {
  6643.             return self::flattenArray($chooseArgs[$chosenEntry]);
  6644.         else {
  6645.             return $chooseArgs[$chosenEntry];
  6646.         }
  6647.     }
  6648.     /**
  6649.      * MATCH
  6650.      * The MATCH function searches for a specified item in a range of cells
  6651.      * @param    lookup_value    The value that you want to match in lookup_array
  6652.      * @param    lookup_array    The range of cells being searched
  6653.      * @param    match_type        The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means  below. If match_type is 1 or -1, the list has to be ordered.
  6654.      * @return    integer        the relative position of the found item
  6655.      */
  6656.     public static function MATCH($lookup_value$lookup_array$match_type=1{
  6657.  
  6658.         // flatten the lookup_array
  6659.         $lookup_array self::flattenArray($lookup_array);
  6660.  
  6661.         // flatten lookup_value since it may be a cell reference to a value or the value itself
  6662.         $lookup_value self::flattenSingleValue($lookup_value);
  6663.  
  6664.         // MATCH is not case sensitive
  6665.         $lookup_value strtolower($lookup_value);
  6666.  
  6667.         /*
  6668.         echo "--------------------<br>looking for $lookup_value in <br>";
  6669.         print_r($lookup_array);
  6670.         echo "<br>";
  6671.         //return 1;
  6672.         /**/
  6673.  
  6674.         // **
  6675.         // check inputs
  6676.         // **
  6677.         // lookup_value type has to be number, text, or logical values
  6678.         if (!is_numeric($lookup_value&& !is_string($lookup_value&& !is_bool($lookup_value)){
  6679.             // error: lookup_array should contain only number, text, or logical values
  6680.             //echo "error: lookup_array should contain only number, text, or logical values<br>";
  6681.             return self::$_errorCodes['na'];
  6682.         }
  6683.  
  6684.         // match_type is 0, 1 or -1
  6685.         if ($match_type!==&& $match_type!==-&& $match_type!==1){
  6686.             // error: wrong value for match_type
  6687.             //echo "error: wrong value for match_type<br>";
  6688.             return self::$_errorCodes['na'];
  6689.         }
  6690.  
  6691.         // lookup_array should not be empty
  6692.         if (sizeof($lookup_array)<=0){
  6693.             // error: empty range
  6694.             //echo "error: empty range ".sizeof($lookup_array)."<br>";
  6695.             return self::$_errorCodes['na'];
  6696.         }
  6697.  
  6698.         // lookup_array should contain only number, text, or logical values
  6699.         for ($i=0;$i<sizeof($lookup_array);++$i){
  6700.             // check the type of the value
  6701.             if (!is_numeric($lookup_array[$i]&& !is_string($lookup_array[$i]&& !is_bool($lookup_array[$i])){
  6702.                 // error: lookup_array should contain only number, text, or logical values
  6703.                 //echo "error: lookup_array should contain only number, text, or logical values<br>";
  6704.                 return self::$_errorCodes['na'];
  6705.             }
  6706.             // convert tpo lowercase
  6707.             if (is_string($lookup_array[$i]))
  6708.                 $lookup_array[$istrtolower($lookup_array[$i]);
  6709.         }
  6710.  
  6711.         // if match_type is 1 or -1, the list has to be ordered
  6712.         if($match_type==|| $match_type==-1){
  6713.             // **
  6714.             // iniitialization
  6715.             // store the last value
  6716.             $iLastValue=$lookup_array[0];
  6717.             // **
  6718.             // loop on the cells
  6719.             for ($i=0;$i<sizeof($lookup_array);++$i){
  6720.                 // check ascending order
  6721.                 if(($match_type==&& $lookup_array[$i]<$iLastValue)
  6722.                     // OR check descending order
  6723.                     || ($match_type==-&& $lookup_array[$i]>$iLastValue)){
  6724.                     // error: list is not ordered correctly
  6725.                     //echo "error: list is not ordered correctly<br>";
  6726.                     return self::$_errorCodes['na'];
  6727.                 }
  6728.             }
  6729.         }
  6730.         // **
  6731.         // find the match
  6732.         // **
  6733.         // loop on the cells
  6734.         for ($i=0$i sizeof($lookup_array)++$i){
  6735.             // if match_type is 0 <=> find the first value that is exactly equal to lookup_value
  6736.             if ($match_type==&& $lookup_array[$i]==$lookup_value){
  6737.                 // this is the exact match
  6738.                 return $i+1;
  6739.             }
  6740.             // if match_type is -1 <=> find the smallest value that is greater than or equal to lookup_value
  6741.             if ($match_type==-&& $lookup_array[$i$lookup_value){
  6742.                 if ($i<1){
  6743.                     // 1st cell was allready smaller than the lookup_value
  6744.                     break;
  6745.                 }
  6746.                 else
  6747.                     // the previous cell was the match
  6748.                     return $i;
  6749.             }
  6750.             // if match_type is 1 <=> find the largest value that is less than or equal to lookup_value
  6751.             if ($match_type==&& $lookup_array[$i$lookup_value){
  6752.                 if ($i<1){
  6753.                     // 1st cell was allready bigger than the lookup_value
  6754.                     break;
  6755.                 }
  6756.                 else
  6757.                     // the previous cell was the match
  6758.                     return $i;
  6759.             }
  6760.         }
  6761.         // unsuccessful in finding a match, return #N/A error value
  6762.         //echo "unsuccessful in finding a match<br>";
  6763.         return self::$_errorCodes['na'];
  6764.     }
  6765.     /**
  6766.      * Uses an index to choose a value from a reference or array
  6767.      * implemented: Return the value of a specified cell or array of cells    Array form
  6768.      * not implemented: Return a reference to specified cells    Reference form
  6769.      *
  6770.      * @param    range_array    a range of cells or an array constant
  6771.      * @param    row_num        selects the row in array from which to return a value. If row_num is omitted, column_num is required.
  6772.      * @param    column_num    selects the column in array from which to return a value. If column_num is omitted, row_num is required.
  6773.      */
  6774.     public static function INDEX($range_array,$row_num=null,$column_num=null{
  6775.         // **
  6776.         // check inputs
  6777.         // **
  6778.         // at least one of row_num and column_num is required
  6779.         if ($row_num==null && $column_num==null){
  6780.             // error: row_num and column_num are both undefined
  6781.             //echo "error: row_num and column_num are both undefined<br>";
  6782.             return self::$_errorCodes['value'];
  6783.         }
  6784.         // default values for row_num and column_num
  6785.         if ($row_num==null){
  6786.             $row_num 1;
  6787.         }
  6788.         if ($column_num==null){
  6789.             $column_num 1;
  6790.         }
  6791.  
  6792.         /* debug
  6793.         print_r($range_array);
  6794.         echo "<br>$row_num , $column_num<br>";
  6795.         /**/
  6796.  
  6797.         // row_num and column_num may not have negative values
  6798.         if (($row_num!=null && $row_num 0|| ($column_num!=null && $column_num 0)) {
  6799.             // error: row_num or column_num has negative value
  6800.             //echo "error: row_num or column_num has negative value<br>";
  6801.             return self::$_errorCodes['value'];
  6802.         }
  6803.         // **
  6804.         // convert column and row numbers into array indeces
  6805.         // **
  6806.         // array is zero based
  6807.         --$column_num;
  6808.         --$row_num;
  6809.  
  6810.         // retrieve the columns
  6811.         $columnKeys array_keys($range_array);
  6812.  
  6813.         // retrieve the rows
  6814.         $rowKeys array_keys($range_array[$columnKeys[0]]);
  6815.  
  6816.         // test ranges
  6817.         if ($column_num >= sizeof($columnKeys)){
  6818.             // error: column_num is out of range
  6819.             //echo "error: column_num is out of range - $column_num > ".sizeof($columnKeys)."<br>";
  6820.             return self::$_errorCodes['reference'];
  6821.         }
  6822.         if ($row_num >= sizeof($rowKeys)){
  6823.             // error: row_num is out of range
  6824.             //echo "error: row_num is out of range - $row_num > ".sizeof($rowKeys)."<br>";
  6825.             return self::$_errorCodes['reference'];
  6826.         }
  6827.         // compute and return result
  6828.         return $range_array[$columnKeys[$column_num]][$rowKeys[$row_num]];
  6829.     }
  6830.  
  6831. /*    public static function INDEX($arrayValues,$rowNum = 0,$columnNum = 0) {
  6832.  
  6833.         if (($rowNum < 0) || ($columnNum < 0)) {
  6834.             return self::$_errorCodes['value'];
  6835.         }
  6836.  
  6837.         $columnKeys = array_keys($arrayValues);
  6838.         $rowKeys = array_keys($arrayValues[$columnKeys[0]]);
  6839.         if ($columnNum > count($columnKeys)) {
  6840.             return self::$_errorCodes['value'];
  6841.         } elseif ($columnNum == 0) {
  6842.             if ($rowNum == 0) {
  6843.                 return $arrayValues;
  6844.             }
  6845.             $rowNum = $rowKeys[--$rowNum];
  6846.             $returnArray = array();
  6847.             foreach($arrayValues as $arrayColumn) {
  6848.                 $returnArray[] = $arrayColumn[$rowNum];
  6849.             }
  6850.             return $returnArray;
  6851.         }
  6852.         $columnNum = $columnKeys[--$columnNum];
  6853.         if ($rowNum > count($rowKeys)) {
  6854.             return self::$_errorCodes['value'];
  6855.         } elseif ($rowNum == 0) {
  6856.             return $arrayValues[$columnNum];
  6857.         }
  6858.         $rowNum = $rowKeys[--$rowNum];
  6859.  
  6860.         return $arrayValues[$columnNum][$rowNum];
  6861.     }
  6862. */
  6863.     /**
  6864.      * SYD
  6865.      *
  6866.      * Returns the sum-of-years' digits depreciation of an asset for a specified period.
  6867.      *
  6868.      * @param    cost        Initial cost of the asset
  6869.      * @param    salvage        Value at the end of the depreciation
  6870.      * @param    life        Number of periods over which the asset is depreciated
  6871.      * @param    period        Period
  6872.      * @return    float 
  6873.      */
  6874.     public static function SYD($cost$salvage$life$period{
  6875.         $cost        self::flattenSingleValue($cost);
  6876.         $salvage    self::flattenSingleValue($salvage);
  6877.         $life        self::flattenSingleValue($life);
  6878.         $period        self::flattenSingleValue($period);
  6879.  
  6880.         // Calculate
  6881.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period))) {
  6882.             if (($life 1|| ($salvage $life)) {
  6883.                 return self::$_errorCodes['num'];
  6884.             }
  6885.             return (($cost $salvage($life $period 12($life ($life 1));
  6886.         }
  6887.         return self::$_errorCodes['value'];
  6888.     }
  6889.  
  6890.     /**
  6891.     * VLOOKUP
  6892.     * The VLOOKUP function searches for value in the left-most column of lookup_array and returns the value in the same row based on the index_number.
  6893.     * @param    lookup_value    The value that you want to match in lookup_array
  6894.     * @param    lookup_array    The range of cells being searched
  6895.     * @param    index_number    The column number in table_array from which the matching value must be returned. The first column is 1.
  6896.     * @param    not_exact_match    Determines if you are looking for an exact match based on lookup_value.
  6897.     * @return    mixed            The value of the found cell
  6898.     */
  6899.     public static function VLOOKUP($lookup_value$lookup_array$index_number$not_exact_match=true{
  6900.         // index_number must be greater than or equal to 1
  6901.         if ($index_number 1{
  6902.             return self::$_errorCodes['value'];
  6903.         }
  6904.  
  6905.         // index_number must be less than or equal to the number of columns in lookup_array
  6906.         if ($index_number count($lookup_array)) {
  6907.             return self::$_errorCodes['reference'];
  6908.         }
  6909.  
  6910.         // re-index lookup_array with numeric keys starting at 1
  6911.         array_unshift($lookup_arrayarray());
  6912.         $lookup_array array_slice(array_values($lookup_array)1count($lookup_array)true);
  6913.  
  6914.         // look for an exact match
  6915.         $row_number array_search($lookup_value$lookup_array[1]);
  6916.  
  6917.         // if an exact match is required, we have what we need to return an appropriate response
  6918.         if ($not_exact_match == false{
  6919.             if ($row_number === false{
  6920.                 return self::$_errorCodes['na'];
  6921.             else {
  6922.                 return $lookup_array[$index_number][$row_number];
  6923.             }
  6924.         }
  6925.  
  6926.         // TODO: The VLOOKUP spec in Excel states that, at this point, we should search for
  6927.         // the highest value that is less than lookup_value. However, documentation on how string
  6928.         // values should be treated here is sparse.
  6929.         return self::$_errorCodes['na'];
  6930.     }
  6931.  
  6932.     /**
  6933.     * LOOKUP
  6934.     * The LOOKUP function searches for value either from a one-row or one-column range or from an array.
  6935.     * @param    lookup_value    The value that you want to match in lookup_array
  6936.     * @param    lookup_vector    The range of cells being searched
  6937.     * @param    result_vector    The column from which the matching value must be returned
  6938.     * @return    mixed            The value of the found cell
  6939.     */
  6940.     public static function LOOKUP($lookup_value$lookup_vector$result_vector=null{
  6941.  
  6942.         // check for LOOKUP Syntax (view Excel documentation)
  6943.         ifis_null($result_vector) )
  6944.         {
  6945.         // TODO: Syntax 2 (array)
  6946.         else {
  6947.         // Syntax 1 (vector)
  6948.             // get key (column or row) of lookup_vector
  6949.             $kl key($lookup_vector);
  6950.             // check if lookup_value exists in lookup_vector
  6951.             ifin_array($lookup_value$lookup_vector[$kl]) )
  6952.             {
  6953.             // FOUND IT! Get key of lookup_vector
  6954.                 $k_res array_search($lookup_value$lookup_vector[$kl]);
  6955.             else {
  6956.             // value NOT FOUND
  6957.                 // Get the smallest value in lookup_vector
  6958.                 // The LOOKUP spec in Excel states --> IMPORTANT - The values in lookup_vector must be placed in ascending order!
  6959.                 $ksv key($lookup_vector[$kl]);
  6960.                 $smallest_value $lookup_vector[$kl][$ksv];
  6961.                 // If lookup_value is smaller than the smallest value in lookup_vector, LOOKUP gives the #N/A error value.
  6962.                 if$lookup_value $smallest_value )
  6963.                 {
  6964.                     return self::$_errorCodes['na'];
  6965.                 else {
  6966.                     // 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.
  6967.                     // IMPORTANT : In Excel Documentation is not clear what happen if lookup_value is text!
  6968.                     foreach$lookup_vector[$klAS $kk => $value )
  6969.                     {
  6970.                         if$lookup_value >= $value )
  6971.                         {
  6972.                             $k_res $kk;
  6973.                         }
  6974.                     }
  6975.                 }
  6976.             }
  6977.  
  6978.             // Returns a value from the same position in result_vector
  6979.             // get key (column or row) of result_vector
  6980.             $kr key($result_vector);
  6981.             ifisset($result_vector[$kr][$k_res]) )
  6982.             {
  6983.                 return $result_vector[$kr][$k_res];
  6984.             else {
  6985.                 // TODO: In Excel Documentation is not clear what happen here...
  6986.             }
  6987.         }
  6988.      }
  6989.  
  6990.  
  6991.     /**
  6992.      * Flatten multidemensional array
  6993.      *
  6994.      * @param    array    $array    Array to be flattened
  6995.      * @return  array    Flattened array
  6996.      */
  6997.     public static function flattenArray($array{
  6998.         $arrayValues array();
  6999.  
  7000.         foreach ($array as $value{
  7001.             if (is_scalar($value)) {
  7002.                 $arrayValues[self::flattenSingleValue($value);
  7003.             elseif (is_array($value)) {
  7004.                 $arrayValues array_merge($arrayValuesself::flattenArray($value));
  7005.             else {
  7006.                 $arrayValues[$value;
  7007.             }
  7008.         }
  7009.  
  7010.         return $arrayValues;
  7011.     }
  7012.  
  7013.     /**
  7014.      * Convert an array with one element to a flat value
  7015.      *
  7016.      * @param    mixed        $value        Array or flat value
  7017.      * @return    mixed 
  7018.      */
  7019.     public static function flattenSingleValue($value ''{
  7020.         if (is_array($value)) {
  7021.             $value self::flattenSingleValue(array_pop($value));
  7022.         }
  7023.         return $value;
  7024.     }
  7025. }
  7026.  
  7027.  
  7028. //
  7029. //    There are a few mathematical functions that aren't available on all versions of PHP for all platforms
  7030. //    These functions aren't available in Windows implementations of PHP prior to version 5.3.0
  7031. //    So we test if they do exist for this version of PHP/operating platform; and if not we create them
  7032. //
  7033. if (!function_exists('acosh')) {
  7034.     function acosh($x{
  7035.         return log(sqrt(($x 12sqrt(($x 12));
  7036.     }
  7037. }
  7038.  
  7039. if (!function_exists('asinh')) {
  7040.     function asinh($x{
  7041.         return log($x sqrt($x $x));
  7042.     }
  7043. }
  7044.  
  7045. if (!function_exists('atanh')) {
  7046.     function atanh($x{
  7047.         return (log($xlog($x)) 2;
  7048.     }
  7049. }
  7050.  
  7051. ?>

Documentation generated on Mon, 27 Oct 2008 08:39:42 +0100 by phpDocumentor 1.4.1