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.  * PHPExcel
  4.  *
  5.  * Copyright (c) 2006 - 2010 PHPExcel
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  *
  21.  * @category    PHPExcel
  22.  * @package        PHPExcel_Calculation
  23.  * @copyright    Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel)
  24.  * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
  25.  * @version        1.7.4, 2010-08-26
  26.  */
  27.  
  28.  
  29. /** PHPExcel root directory */
  30. if (!defined('PHPEXCEL_ROOT')) {
  31.     /**
  32.      * @ignore
  33.      */
  34.     define('PHPEXCEL_ROOT'dirname(__FILE__'/../../');
  35.     require(PHPEXCEL_ROOT 'PHPExcel/Autoloader.php');
  36.     // check mbstring.func_overload
  37.     if (ini_get('mbstring.func_overload'2{
  38.         throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).');
  39.     }
  40. }
  41.  
  42.  
  43. /** EPS */
  44. define('EPS'2.22e-16);
  45.  
  46. /** MAX_VALUE */
  47. define('MAX_VALUE'1.2e308);
  48.  
  49. /** LOG_GAMMA_X_MAX_VALUE */
  50. define('LOG_GAMMA_X_MAX_VALUE'2.55e305);
  51.  
  52. /** SQRT2PI */
  53. define('SQRT2PI'2.5066282746310005024157652848110452530069867406099);
  54.  
  55. /** 2 / PI */
  56. define('M_2DIVPI'0.63661977236758134307553505349006);
  57.  
  58. /** XMININ */
  59. define('XMININ'2.23e-308);
  60.  
  61. /** MAX_ITERATIONS */
  62. define('MAX_ITERATIONS'256);
  63. /** FINANCIAL_MAX_ITERATIONS */
  64. define('FINANCIAL_MAX_ITERATIONS'128);
  65.  
  66. /** PRECISION */
  67. define('PRECISION'8.88E-016);
  68. /** FINANCIAL_PRECISION */
  69. define('FINANCIAL_PRECISION'1.0e-08);
  70.  
  71. /** EULER */
  72. define('EULER'2.71828182845904523536);
  73.  
  74. $savedPrecision ini_get('precision');
  75. if ($savedPrecision 16{
  76.     ini_set('precision',16);
  77. }
  78.  
  79.  
  80. /** Matrix */
  81. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/JAMA/Matrix.php';
  82. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/trend/trendClass.php';
  83.  
  84.  
  85. /**
  86.  * PHPExcel_Calculation_Functions
  87.  *
  88.  * @category    PHPExcel
  89.  * @package        PHPExcel_Calculation
  90.  * @copyright    Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel)
  91.  */
  92.  
  93.     /** constants */
  94.     const COMPATIBILITY_EXCEL        'Excel';
  95.     const COMPATIBILITY_GNUMERIC    'Gnumeric';
  96.     const COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc';
  97.  
  98.     const RETURNDATE_PHP_NUMERIC    'P';
  99.     const RETURNDATE_PHP_OBJECT        'O';
  100.     const RETURNDATE_EXCEL            'E';
  101.  
  102.  
  103.     /**
  104.      *    Compatibility mode to use for error checking and responses
  105.      *
  106.      *    @access    private
  107.      *    @var string 
  108.      */
  109.     private static $compatibilityMode    self::COMPATIBILITY_EXCEL;
  110.  
  111.     /**
  112.      *    Data Type to use when returning date values
  113.      *
  114.      *    @access    private
  115.      *    @var string 
  116.      */
  117.     private static $ReturnDateType    self::RETURNDATE_EXCEL;
  118.  
  119.     /**
  120.      *    List of error codes
  121.      *
  122.      *    @access    private
  123.      *    @var array 
  124.      */
  125.     private static $_errorCodes    array'null'                => '#NULL!',
  126.                                          'divisionbyzero'    => '#DIV/0!',
  127.                                          'value'            => '#VALUE!',
  128.                                          'reference'        => '#REF!',
  129.                                          'name'                => '#NAME?',
  130.                                          'num'                => '#NUM!',
  131.                                          'na'                => '#N/A',
  132.                                          'gettingdata'        => '#GETTING_DATA'
  133.                                        );
  134.  
  135.  
  136.     /**
  137.      *    Set the Compatibility Mode
  138.      *
  139.      *    @access    public
  140.      *    @category Function Configuration
  141.      *    @param     string        $compatibilityMode        Compatibility Mode
  142.      *                                                 Permitted values are:
  143.      *                                                     PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL            'Excel'
  144.      *                                                     PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
  145.      *                                                     PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
  146.      *    @return     boolean    (Success or Failure)
  147.      */
  148.     public static function setCompatibilityMode($compatibilityMode{
  149.         if (($compatibilityMode == self::COMPATIBILITY_EXCEL||
  150.             ($compatibilityMode == self::COMPATIBILITY_GNUMERIC||
  151.             ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  152.             self::$compatibilityMode $compatibilityMode;
  153.             return True;
  154.         }
  155.         return False;
  156.     }    //    function setCompatibilityMode()
  157.  
  158.  
  159.     /**
  160.      *    Return the current Compatibility Mode
  161.      *
  162.      *    @access    public
  163.      *    @category Function Configuration
  164.      *    @return     string        Compatibility Mode
  165.      *                             Possible Return values are:
  166.      *                                 PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL            'Excel'
  167.      *                                 PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
  168.      *                                 PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
  169.      */
  170.     public static function getCompatibilityMode({
  171.         return self::$compatibilityMode;
  172.     }    //    function getCompatibilityMode()
  173.  
  174.  
  175.     /**
  176.      *    Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
  177.      *
  178.      *    @access    public
  179.      *    @category Function Configuration
  180.      *    @param     string    $returnDateType            Return Date Format
  181.      *                                                 Permitted values are:
  182.      *                                                     PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC        'P'
  183.      *                                                     PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT        'O'
  184.      *                                                     PHPExcel_Calculation_Functions::RETURNDATE_EXCEL            'E'
  185.      *    @return     boolean                            Success or failure
  186.      */
  187.     public static function setReturnDateType($returnDateType{
  188.         if (($returnDateType == self::RETURNDATE_PHP_NUMERIC||
  189.             ($returnDateType == self::RETURNDATE_PHP_OBJECT||
  190.             ($returnDateType == self::RETURNDATE_EXCEL)) {
  191.             self::$ReturnDateType $returnDateType;
  192.             return True;
  193.         }
  194.         return False;
  195.     }    //    function setReturnDateType()
  196.  
  197.  
  198.     /**
  199.      *    Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
  200.      *
  201.      *    @access    public
  202.      *    @category Function Configuration
  203.      *    @return     string        Return Date Format
  204.      *                             Possible Return values are:
  205.      *                                 PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC        'P'
  206.      *                                 PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT        'O'
  207.      *                                 PHPExcel_Calculation_Functions::RETURNDATE_EXCEL            'E'
  208.      */
  209.     public static function getReturnDateType({
  210.         return self::$ReturnDateType;
  211.     }    //    function getReturnDateType()
  212.  
  213.  
  214.     /**
  215.      *    DUMMY
  216.      *
  217.      *    @access    public
  218.      *    @category Error Returns
  219.      *    @return    string    #Not Yet Implemented
  220.      */
  221.     public static function DUMMY({
  222.         return '#Not Yet Implemented';
  223.     }    //    function DUMMY()
  224.  
  225.  
  226.     /**
  227.      *    NA
  228.      *
  229.      *    Excel Function:
  230.      *        =NA()
  231.      *
  232.      *    Returns the error value #N/A
  233.      *        #N/A is the error value that means "no value is available."
  234.      *
  235.      *    @access    public
  236.      *    @category Logical Functions
  237.      *    @return    string    #N/A!
  238.      */
  239.     public static function NA({
  240.         return self::$_errorCodes['na'];
  241.     }    //    function NA()
  242.  
  243.  
  244.     /**
  245.      *    NAN
  246.      *
  247.      *    Returns the error value #NUM!
  248.      *
  249.      *    @access    public
  250.      *    @category Error Returns
  251.      *    @return    string    #NUM!
  252.      */
  253.     public static function NaN({
  254.         return self::$_errorCodes['num'];
  255.     }    //    function NAN()
  256.  
  257.  
  258.     /**
  259.      *    NAME
  260.      *
  261.      *    Returns the error value #NAME?
  262.      *
  263.      *    @access    public
  264.      *    @category Error Returns
  265.      *    @return    string    #NAME?
  266.      */
  267.     public static function NAME({
  268.         return self::$_errorCodes['name'];
  269.     }    //    function NAME()
  270.  
  271.  
  272.     /**
  273.      *    REF
  274.      *
  275.      *    Returns the error value #REF!
  276.      *
  277.      *    @access    public
  278.      *    @category Error Returns
  279.      *    @return    string    #REF!
  280.      */
  281.     public static function REF({
  282.         return self::$_errorCodes['reference'];
  283.     }    //    function REF()
  284.  
  285.  
  286.     /**
  287.      *    VALUE
  288.      *
  289.      *    Returns the error value #VALUE!
  290.      *
  291.      *    @access    public
  292.      *    @category Error Returns
  293.      *    @return    string    #VALUE!
  294.      */
  295.     public static function VALUE({
  296.         return self::$_errorCodes['value'];
  297.     }    //    function VALUE()
  298.  
  299.  
  300.     private static function isMatrixValue($idx{
  301.         return ((substr_count($idx,'.'<= 1|| (preg_match('/\.[A-Z]/',$idx0));
  302.     }
  303.  
  304.  
  305.     private static function isValue($idx{
  306.         return (substr_count($idx,'.'== 0);
  307.     }
  308.  
  309.  
  310.     private static function isCellValue($idx{
  311.         return (substr_count($idx,'.'1);
  312.     }
  313.  
  314.  
  315.     /**
  316.      *    LOGICAL_AND
  317.      *
  318.      *    Returns boolean TRUE if all its arguments are TRUE; returns FALSE if one or more argument is FALSE.
  319.      *
  320.      *    Excel Function:
  321.      *        =AND(logical1[,logical2[, ...]])
  322.      *
  323.      *        The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
  324.      *            or references that contain logical values.
  325.      *
  326.      *        Boolean arguments are treated as True or False as appropriate
  327.      *        Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  328.      *        If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
  329.      *            the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
  330.      *
  331.      *    @access    public
  332.      *    @category Logical Functions
  333.      *    @param    mixed        $arg,...        Data values
  334.      *    @return    boolean        The logical AND of the arguments.
  335.      */
  336.     public static function LOGICAL_AND({
  337.         // Return value
  338.         $returnValue True;
  339.  
  340.         // Loop through the arguments
  341.         $aArgs self::flattenArray(func_get_args());
  342.         $argCount 0;
  343.         foreach ($aArgs as $arg{
  344.             // Is it a boolean value?
  345.             if (is_bool($arg)) {
  346.                 $returnValue $returnValue && $arg;
  347.             elseif ((is_numeric($arg)) && (!is_string($arg))) {
  348.                 $returnValue $returnValue && ($arg != 0);
  349.             elseif (is_string($arg)) {
  350.                 $arg strtoupper($arg);
  351.                 if ($arg == 'TRUE'{
  352.                     $arg 1;
  353.                 elseif ($arg == 'FALSE'{
  354.                     $arg 0;
  355.                 else {
  356.                     return self::$_errorCodes['value'];
  357.                 }
  358.                 $returnValue $returnValue && ($arg != 0);
  359.             }
  360.             ++$argCount;
  361.         }
  362.  
  363.         // Return
  364.         if ($argCount == 0{
  365.             return self::$_errorCodes['value'];
  366.         }
  367.         return $returnValue;
  368.     }    //    function LOGICAL_AND()
  369.  
  370.  
  371.     /**
  372.      *    LOGICAL_OR
  373.      *
  374.      *    Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE.
  375.      *
  376.      *    Excel Function:
  377.      *        =OR(logical1[,logical2[, ...]])
  378.      *
  379.      *        The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
  380.      *            or references that contain logical values.
  381.      *
  382.      *        Boolean arguments are treated as True or False as appropriate
  383.      *        Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  384.      *        If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
  385.      *            the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
  386.      *
  387.      *    @access    public
  388.      *    @category Logical Functions
  389.      *    @param    mixed        $arg,...        Data values
  390.      *    @return    boolean        The logical OR of the arguments.
  391.      */
  392.     public static function LOGICAL_OR({
  393.         // Return value
  394.         $returnValue False;
  395.  
  396.         // Loop through the arguments
  397.         $aArgs self::flattenArray(func_get_args());
  398.         $argCount 0;
  399.         foreach ($aArgs as $arg{
  400.             // Is it a boolean value?
  401.             if (is_bool($arg)) {
  402.                 $returnValue $returnValue || $arg;
  403.             elseif ((is_numeric($arg)) && (!is_string($arg))) {
  404.                 $returnValue $returnValue || ($arg != 0);
  405.             elseif (is_string($arg)) {
  406.                 $arg strtoupper($arg);
  407.                 if ($arg == 'TRUE'{
  408.                     $arg 1;
  409.                 elseif ($arg == 'FALSE'{
  410.                     $arg 0;
  411.                 else {
  412.                     return self::$_errorCodes['value'];
  413.                 }
  414.                 $returnValue $returnValue || ($arg != 0);
  415.             }
  416.             ++$argCount;
  417.         }
  418.  
  419.         // Return
  420.         if ($argCount == 0{
  421.             return self::$_errorCodes['value'];
  422.         }
  423.         return $returnValue;
  424.     }    //    function LOGICAL_OR()
  425.  
  426.  
  427.     /**
  428.      *    LOGICAL_FALSE
  429.      *
  430.      *    Returns the boolean FALSE.
  431.      *
  432.      *    Excel Function:
  433.      *        =FALSE()
  434.      *
  435.      *    @access    public
  436.      *    @category Logical Functions
  437.      *    @return    boolean        False
  438.      */
  439.     public static function LOGICAL_FALSE({
  440.         return False;
  441.     }    //    function LOGICAL_FALSE()
  442.  
  443.  
  444.     /**
  445.      *    LOGICAL_TRUE
  446.      *
  447.      *    Returns the boolean TRUE.
  448.      *
  449.      *    Excel Function:
  450.      *        =TRUE()
  451.      *
  452.      *    @access    public
  453.      *    @category Logical Functions
  454.      *    @return    boolean        True
  455.      */
  456.     public static function LOGICAL_TRUE({
  457.         return True;
  458.     }    //    function LOGICAL_TRUE()
  459.  
  460.  
  461.     /**
  462.      *    LOGICAL_NOT
  463.      *
  464.      *    Returns the boolean inverse of the argument.
  465.      *
  466.      *    Excel Function:
  467.      *        =NOT(logical)
  468.      *
  469.      *        The argument must evaluate to a logical value such as TRUE or FALSE
  470.      *
  471.      *        Boolean arguments are treated as True or False as appropriate
  472.      *        Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  473.      *        If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
  474.      *            the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
  475.      *
  476.      *    @access    public
  477.      *    @category Logical Functions
  478.      *    @param    mixed        $logical    A value or expression that can be evaluated to TRUE or FALSE
  479.      *    @return    boolean        The boolean inverse of the argument.
  480.      */
  481.     public static function LOGICAL_NOT($logical{
  482.         $logical self::flattenSingleValue($logical);
  483.         if (is_string($logical)) {
  484.             $logical strtoupper($logical);
  485.             if ($logical == 'TRUE'{
  486.                 return False;
  487.             elseif ($logical == 'FALSE'{
  488.                 return True;
  489.             else {
  490.                 return self::$_errorCodes['value'];
  491.             }
  492.         }
  493.  
  494.         return !$logical;
  495.     }    //    function LOGICAL_NOT()
  496.  
  497.  
  498.     /**
  499.      *    STATEMENT_IF
  500.      *
  501.      *    Returns one value if a condition you specify evaluates to TRUE and another value if it evaluates to FALSE.
  502.      *
  503.      *    Excel Function:
  504.      *        =IF(condition[,returnIfTrue[,returnIfFalse]])
  505.      *
  506.      *        Condition is any value or expression that can be evaluated to TRUE or FALSE.
  507.      *            For example, A10=100 is a logical expression; if the value in cell A10 is equal to 100,
  508.      *            the expression evaluates to TRUE. Otherwise, the expression evaluates to FALSE.
  509.      *            This argument can use any comparison calculation operator.
  510.      *        ReturnIfTrue is the value that is returned if condition evaluates to TRUE.
  511.      *            For example, if this argument is the text string "Within budget" and the condition argument evaluates to TRUE,
  512.      *            then the IF function returns the text "Within budget"
  513.      *            If condition is TRUE and ReturnIfTrue is blank, this argument returns 0 (zero). To display the word TRUE, use
  514.      *            the logical value TRUE for this argument.
  515.      *            ReturnIfTrue can be another formula.
  516.      *        ReturnIfFalse is the value that is returned if condition evaluates to FALSE.
  517.      *            For example, if this argument is the text string "Over budget" and the condition argument evaluates to FALSE,
  518.      *            then the IF function returns the text "Over budget".
  519.      *            If condition is FALSE and ReturnIfFalse is omitted, then the logical value FALSE is returned.
  520.      *            If condition is FALSE and ReturnIfFalse is blank, then the value 0 (zero) is returned.
  521.      *            ReturnIfFalse can be another formula.
  522.      *
  523.      *    @access    public
  524.      *    @category Logical Functions
  525.      *    @param    mixed    $condition        Condition to evaluate
  526.      *    @param    mixed    $returnIfTrue    Value to return when condition is true
  527.      *    @param    mixed    $returnIfFalse    Optional value to return when condition is false
  528.      *    @return    mixed    The value of returnIfTrue or returnIfFalse determined by condition
  529.      */
  530.     public static function STATEMENT_IF($condition true$returnIfTrue 0$returnIfFalse False{
  531.         $condition        (is_null($condition))        True :    (boolean) self::flattenSingleValue($condition);
  532.         $returnIfTrue    (is_null($returnIfTrue))    :        self::flattenSingleValue($returnIfTrue);
  533.         $returnIfFalse    (is_null($returnIfFalse))    False :    self::flattenSingleValue($returnIfFalse);
  534.  
  535.         return ($condition $returnIfTrue $returnIfFalse);
  536.     }    //    function STATEMENT_IF()
  537.  
  538.  
  539.     /**
  540.      *    STATEMENT_IFERROR
  541.      *
  542.      *    Excel Function:
  543.      *        =IFERROR(testValue,errorpart)
  544.      *
  545.      *    @access    public
  546.      *    @category Logical Functions
  547.      *    @param    mixed    $testValue    Value to check, is also the value returned when no error
  548.      *    @param    mixed    $errorpart    Value to return when testValue is an error condition
  549.      *    @return    mixed    The value of errorpart or testValue determined by error condition
  550.      */
  551.     public static function STATEMENT_IFERROR($testValue ''$errorpart ''{
  552.         $testValue    (is_null($testValue))    '' :    self::flattenSingleValue($testValue);
  553.         $errorpart    (is_null($errorpart))    '' :    self::flattenSingleValue($errorpart);
  554.  
  555.         return self::STATEMENT_IF(self::IS_ERROR($testValue)$errorpart$testValue);
  556.     }    //    function STATEMENT_IFERROR()
  557.  
  558.  
  559.     /**
  560.      *    HYPERLINK
  561.      *
  562.      *    Excel Function:
  563.      *        =HYPERLINK(linkURL,displayName)
  564.      *
  565.      *    @access    public
  566.      *    @category Logical Functions
  567.      *    @param    string    $linkURL        Value to check, is also the value returned when no error
  568.      *    @param    string    $displayName    Value to return when testValue is an error condition
  569.      *    @return    mixed    The value of errorpart or testValue determined by error condition
  570.      */
  571.     public static function HYPERLINK($linkURL ''$displayName nullPHPExcel_Cell $pCell null{
  572.         $args func_get_args();
  573.         $pCell array_pop($args);
  574.  
  575.         $linkURL        (is_null($linkURL))        '' :    self::flattenSingleValue($linkURL);
  576.         $displayName    (is_null($displayName))    '' :    self::flattenSingleValue($displayName);
  577.  
  578.         if ((!is_object($pCell)) || (trim($linkURL== '')) {
  579.             return self::$_errorCodes['reference'];
  580.         }
  581.  
  582.         if ((is_object($displayName)) || trim($displayName== ''{
  583.             $displayName $linkURL;
  584.         }
  585.  
  586.         $pCell->getHyperlink()->setUrl($linkURL);
  587.  
  588.         return $displayName;
  589.     }    //    function HYPERLINK()
  590.  
  591.  
  592.     /**
  593.      *    ATAN2
  594.      *
  595.      *    This function calculates the arc tangent of the two variables x and y. It is similar to
  596.      *        calculating the arc tangent of y ï¿½ x, except that the signs of both arguments are used
  597.      *        to determine the quadrant of the result.
  598.      *    The arctangent is the angle from the x-axis to a line containing the origin (0, 0) and a
  599.      *        point with coordinates (xCoordinate, yCoordinate). The angle is given in radians between
  600.      *        -pi and pi, excluding -pi.
  601.      *
  602.      *    Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard
  603.      *        PHP atan2() function, so we need to reverse them here before calling the PHP atan() function.
  604.      *
  605.      *    Excel Function:
  606.      *        ATAN2(xCoordinate,yCoordinate)
  607.      *
  608.      *    @access    public
  609.      *    @category Mathematical and Trigonometric Functions
  610.      *    @param    float    $xCoordinate        The x-coordinate of the point.
  611.      *    @param    float    $yCoordinate        The y-coordinate of the point.
  612.      *    @return    float    The inverse tangent of the specified x- and y-coordinates.
  613.      */
  614.     public static function REVERSE_ATAN2($xCoordinate$yCoordinate{
  615.         $xCoordinate    = (float) self::flattenSingleValue($xCoordinate);
  616.         $yCoordinate    = (float) self::flattenSingleValue($yCoordinate);
  617.  
  618.         if (($xCoordinate == 0&& ($yCoordinate == 0)) {
  619.             return self::$_errorCodes['divisionbyzero'];
  620.         }
  621.  
  622.         return atan2($yCoordinate$xCoordinate);
  623.     }    //    function REVERSE_ATAN2()
  624.  
  625.  
  626.     /**
  627.      *    LOG_BASE
  628.      *
  629.      *    Returns the logarithm of a number to a specified base. The default base is 10.
  630.      *
  631.      *    Excel Function:
  632.      *        LOG(number[,base])
  633.      *
  634.      *    @access    public
  635.      *    @category Mathematical and Trigonometric Functions
  636.      *    @param    float    $value        The positive real number for which you want the logarithm
  637.      *    @param    float    $base        The base of the logarithm. If base is omitted, it is assumed to be 10.
  638.      *    @return    float 
  639.      */
  640.     public static function LOG_BASE($number$base=10{
  641.         $number    self::flattenSingleValue($number);
  642.         $base    (is_null($base))    10 :    (float) self::flattenSingleValue($base);
  643.  
  644.         return log($number$base);
  645.     }    //    function LOG_BASE()
  646.  
  647.  
  648.     /**
  649.      *    SUM
  650.      *
  651.      *    SUM computes the sum of all the values and cells referenced in the argument list.
  652.      *
  653.      *    Excel Function:
  654.      *        SUM(value1[,value2[, ...]])
  655.      *
  656.      *    @access    public
  657.      *    @category Mathematical and Trigonometric Functions
  658.      *    @param    mixed        $arg,...        Data values
  659.      *    @return    float 
  660.      */
  661.     public static function SUM({
  662.         // Return value
  663.         $returnValue 0;
  664.  
  665.         // Loop through the arguments
  666.         $aArgs self::flattenArray(func_get_args());
  667.         foreach ($aArgs as $arg{
  668.             // Is it a numeric value?
  669.             if ((is_numeric($arg)) && (!is_string($arg))) {
  670.                 $returnValue += $arg;
  671.             }
  672.         }
  673.  
  674.         // Return
  675.         return $returnValue;
  676.     }    //    function SUM()
  677.  
  678.  
  679.     /**
  680.      *    SUMSQ
  681.      *
  682.      *    SUMSQ returns the sum of the squares of the arguments
  683.      *
  684.      *    Excel Function:
  685.      *        SUMSQ(value1[,value2[, ...]])
  686.      *
  687.      *    @access    public
  688.      *    @category Mathematical and Trigonometric Functions
  689.      *    @param    mixed        $arg,...        Data values
  690.      *    @return    float 
  691.      */
  692.     public static function SUMSQ({
  693.         // Return value
  694.         $returnValue 0;
  695.  
  696.         // Loop through arguments
  697.         $aArgs self::flattenArray(func_get_args());
  698.         foreach ($aArgs as $arg{
  699.             // Is it a numeric value?
  700.             if ((is_numeric($arg)) && (!is_string($arg))) {
  701.                 $returnValue += ($arg $arg);
  702.             }
  703.         }
  704.  
  705.         // Return
  706.         return $returnValue;
  707.     }    //    function SUMSQ()
  708.  
  709.  
  710.     /**
  711.      *    PRODUCT
  712.      *
  713.      *    PRODUCT returns the product of all the values and cells referenced in the argument list.
  714.      *
  715.      *    Excel Function:
  716.      *        PRODUCT(value1[,value2[, ...]])
  717.      *
  718.      *    @access    public
  719.      *    @category Mathematical and Trigonometric Functions
  720.      *    @param    mixed        $arg,...        Data values
  721.      *    @return    float 
  722.      */
  723.     public static function PRODUCT({
  724.         // Return value
  725.         $returnValue null;
  726.  
  727.         // Loop through arguments
  728.         $aArgs self::flattenArray(func_get_args());
  729.         foreach ($aArgs as $arg{
  730.             // Is it a numeric value?
  731.             if ((is_numeric($arg)) && (!is_string($arg))) {
  732.                 if (is_null($returnValue)) {
  733.                     $returnValue $arg;
  734.                 else {
  735.                     $returnValue *= $arg;
  736.                 }
  737.             }
  738.         }
  739.  
  740.         // Return
  741.         if (is_null($returnValue)) {
  742.             return 0;
  743.         }
  744.         return $returnValue;
  745.     }    //    function PRODUCT()
  746.  
  747.  
  748.     /**
  749.      *    QUOTIENT
  750.      *
  751.      *    QUOTIENT function returns the integer portion of a division. Numerator is the divided number
  752.      *        and denominator is the divisor.
  753.      *
  754.      *    Excel Function:
  755.      *        QUOTIENT(value1[,value2[, ...]])
  756.      *
  757.      *    @access    public
  758.      *    @category Mathematical and Trigonometric Functions
  759.      *    @param    mixed        $arg,...        Data values
  760.      *    @return    float 
  761.      */
  762.     public static function QUOTIENT({
  763.         // Return value
  764.         $returnValue null;
  765.  
  766.         // Loop through arguments
  767.         $aArgs self::flattenArray(func_get_args());
  768.         foreach ($aArgs as $arg{
  769.             // Is it a numeric value?
  770.             if ((is_numeric($arg)) && (!is_string($arg))) {
  771.                 if (is_null($returnValue)) {
  772.                     $returnValue ($arg == 0$arg;
  773.                 else {
  774.                     if (($returnValue == 0|| ($arg == 0)) {
  775.                         $returnValue 0;
  776.                     else {
  777.                         $returnValue /= $arg;
  778.                     }
  779.                 }
  780.             }
  781.         }
  782.  
  783.         // Return
  784.         return intval($returnValue);
  785.     }    //    function QUOTIENT()
  786.  
  787.  
  788.     /**
  789.      *    MIN
  790.      *
  791.      *    MIN returns the value of the element of the values passed that has the smallest value,
  792.      *        with negative numbers considered smaller than positive numbers.
  793.      *
  794.      *    Excel Function:
  795.      *        MIN(value1[,value2[, ...]])
  796.      *
  797.      *    @access    public
  798.      *    @category Statistical Functions
  799.      *    @param    mixed        $arg,...        Data values
  800.      *    @return    float 
  801.      */
  802.     public static function MIN({
  803.         // Return value
  804.         $returnValue null;
  805.  
  806.         // Loop through arguments
  807.         $aArgs self::flattenArray(func_get_args());
  808.         foreach ($aArgs as $arg{
  809.             // Is it a numeric value?
  810.             if ((is_numeric($arg)) && (!is_string($arg))) {
  811.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  812.                     $returnValue $arg;
  813.                 }
  814.             }
  815.         }
  816.  
  817.         // Return
  818.         if(is_null($returnValue)) {
  819.             return 0;
  820.         }
  821.         return $returnValue;
  822.     }    //    function MIN()
  823.  
  824.  
  825.     /**
  826.      *    MINA
  827.      *
  828.      *    Returns the smallest value in a list of arguments, including numbers, text, and logical values
  829.      *
  830.      *    Excel Function:
  831.      *        MINA(value1[,value2[, ...]])
  832.      *
  833.      *    @access    public
  834.      *    @category Statistical Functions
  835.      *    @param    mixed        $arg,...        Data values
  836.      *    @return    float 
  837.      */
  838.     public static function MINA({
  839.         // Return value
  840.         $returnValue null;
  841.  
  842.         // Loop through arguments
  843.         $aArgs self::flattenArray(func_get_args());
  844.         foreach ($aArgs as $arg{
  845.             // Is it a numeric value?
  846.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  847.                 if (is_bool($arg)) {
  848.                     $arg = (integer) $arg;
  849.                 elseif (is_string($arg)) {
  850.                     $arg 0;
  851.                 }
  852.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  853.                     $returnValue $arg;
  854.                 }
  855.             }
  856.         }
  857.  
  858.         // Return
  859.         if(is_null($returnValue)) {
  860.             return 0;
  861.         }
  862.         return $returnValue;
  863.     }    //    function MINA()
  864.  
  865.  
  866.     /**
  867.      *    MINIF
  868.      *
  869.      *    Returns the minimum value within a range of cells that contain numbers within the list of arguments
  870.      *
  871.      *    Excel Function:
  872.      *        MINIF(value1[,value2[, ...]],condition)
  873.      *
  874.      *    @access    public
  875.      *    @category Mathematical and Trigonometric Functions
  876.      *    @param    mixed        $arg,...        Data values
  877.      *    @param    string        $condition        The criteria that defines which cells will be checked.
  878.      *    @return    float 
  879.      */
  880.     public static function MINIF($aArgs,$condition,$sumArgs array()) {
  881.         // Return value
  882.         $returnValue null;
  883.  
  884.         $aArgs self::flattenArray($aArgs);
  885.         $sumArgs self::flattenArray($sumArgs);
  886.         if (count($sumArgs== 0{
  887.             $sumArgs $aArgs;
  888.         }
  889.         $condition self::_ifCondition($condition);
  890.         // Loop through arguments
  891.         foreach ($aArgs as $key => $arg{
  892.             if (!is_numeric($arg)) $arg PHPExcel_Calculation::_wrapResult(strtoupper($arg))}
  893.             $testCondition '='.$arg.$condition;
  894.             if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
  895.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  896.                     $returnValue $arg;
  897.                 }
  898.             }
  899.         }
  900.  
  901.         // Return
  902.         return $returnValue;
  903.     }    //    function MINIF()
  904.  
  905.  
  906.     /**
  907.      *    SMALL
  908.      *
  909.      *    Returns the nth smallest value in a data set. You can use this function to
  910.      *        select a value based on its relative standing.
  911.      *
  912.      *    Excel Function:
  913.      *        SMALL(value1[,value2[, ...]],entry)
  914.      *
  915.      *    @access    public
  916.      *    @category Statistical Functions
  917.      *    @param    mixed        $arg,...        Data values
  918.      *    @param    int            $entry            Position (ordered from the smallest) in the array or range of data to return
  919.      *    @return    float 
  920.      */
  921.     public static function SMALL({
  922.         $aArgs self::flattenArray(func_get_args());
  923.  
  924.         // Calculate
  925.         $entry array_pop($aArgs);
  926.  
  927.         if ((is_numeric($entry)) && (!is_string($entry))) {
  928.             $mArgs array();
  929.             foreach ($aArgs as $arg{
  930.                 // Is it a numeric value?
  931.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  932.                     $mArgs[$arg;
  933.                 }
  934.             }
  935.             $count self::COUNT($mArgs);
  936.             $entry floor(--$entry);
  937.             if (($entry 0|| ($entry >= $count|| ($count == 0)) {
  938.                 return self::$_errorCodes['num'];
  939.             }
  940.             sort($mArgs);
  941.             return $mArgs[$entry];
  942.         }
  943.         return self::$_errorCodes['value'];
  944.     }    //    function SMALL()
  945.  
  946.  
  947.     /**
  948.      *    MAX
  949.      *
  950.      *    MAX returns the value of the element of the values passed that has the highest value,
  951.      *        with negative numbers considered smaller than positive numbers.
  952.      *
  953.      *    Excel Function:
  954.      *        MAX(value1[,value2[, ...]])
  955.      *
  956.      *    @access    public
  957.      *    @category Statistical Functions
  958.      *    @param    mixed        $arg,...        Data values
  959.      *    @return    float 
  960.      */
  961.     public static function MAX({
  962.         // Return value
  963.         $returnValue null;
  964.  
  965.         // Loop through arguments
  966.         $aArgs self::flattenArray(func_get_args());
  967.         foreach ($aArgs as $arg{
  968.             // Is it a numeric value?
  969.             if ((is_numeric($arg)) && (!is_string($arg))) {
  970.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  971.                     $returnValue $arg;
  972.                 }
  973.             }
  974.         }
  975.  
  976.         // Return
  977.         if(is_null($returnValue)) {
  978.             return 0;
  979.         }
  980.         return $returnValue;
  981.     }    //    function MAX()
  982.  
  983.  
  984.     /**
  985.      *    MAXA
  986.      *
  987.      *    Returns the greatest value in a list of arguments, including numbers, text, and logical values
  988.      *
  989.      *    Excel Function:
  990.      *        MAXA(value1[,value2[, ...]])
  991.      *
  992.      *    @access    public
  993.      *    @category Statistical Functions
  994.      *    @param    mixed        $arg,...        Data values
  995.      *    @return    float 
  996.      */
  997.     public static function MAXA({
  998.         // Return value
  999.         $returnValue null;
  1000.  
  1001.         // Loop through arguments
  1002.         $aArgs self::flattenArray(func_get_args());
  1003.         foreach ($aArgs as $arg{
  1004.             // Is it a numeric value?
  1005.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  1006.                 if (is_bool($arg)) {
  1007.                     $arg = (integer) $arg;
  1008.                 elseif (is_string($arg)) {
  1009.                     $arg 0;
  1010.                 }
  1011.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  1012.                     $returnValue $arg;
  1013.                 }
  1014.             }
  1015.         }
  1016.  
  1017.         // Return
  1018.         if(is_null($returnValue)) {
  1019.             return 0;
  1020.         }
  1021.         return $returnValue;
  1022.     }    //    function MAXA()
  1023.  
  1024.  
  1025.     private static function _ifCondition($condition{
  1026.         $condition    self::flattenSingleValue($condition);
  1027.         if (!in_array($condition{0},array('>''<''='))) {
  1028.             if (!is_numeric($condition)) $condition PHPExcel_Calculation::_wrapResult(strtoupper($condition))}
  1029.             return '='.$condition;
  1030.         else {
  1031.             preg_match('/([<>=]+)(.*)/',$condition,$matches);
  1032.             list(,$operator,$operand$matches;
  1033.             if (!is_numeric($operand)) $operand PHPExcel_Calculation::_wrapResult(strtoupper($operand))}
  1034.             return $operator.$operand;
  1035.         }
  1036.     }    //    function _ifCondition()
  1037.  
  1038.     /**
  1039.      *    MAXIF
  1040.      *
  1041.      *    Counts the maximum value within a range of cells that contain numbers within the list of arguments
  1042.      *
  1043.      *    Excel Function:
  1044.      *        MAXIF(value1[,value2[, ...]],condition)
  1045.      *
  1046.      *    @access    public
  1047.      *    @category Mathematical and Trigonometric Functions
  1048.      *    @param    mixed        $arg,...        Data values
  1049.      *    @param    string        $condition        The criteria that defines which cells will be checked.
  1050.      *    @return    float 
  1051.      */
  1052.     public static function MAXIF($aArgs,$condition,$sumArgs array()) {
  1053.         // Return value
  1054.         $returnValue null;
  1055.  
  1056.         $aArgs self::flattenArray($aArgs);
  1057.         $sumArgs self::flattenArray($sumArgs);
  1058.         if (count($sumArgs== 0{
  1059.             $sumArgs $aArgs;
  1060.         }
  1061.         $condition self::_ifCondition($condition);
  1062.         // Loop through arguments
  1063.         foreach ($aArgs as $key => $arg{
  1064.             if (!is_numeric($arg)) $arg PHPExcel_Calculation::_wrapResult(strtoupper($arg))}
  1065.             $testCondition '='.$arg.$condition;
  1066.             if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
  1067.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  1068.                     $returnValue $arg;
  1069.                 }
  1070.             }
  1071.         }
  1072.  
  1073.         // Return
  1074.         return $returnValue;
  1075.     }    //    function MAXIF()
  1076.  
  1077.  
  1078.     /**
  1079.      *    LARGE
  1080.      *
  1081.      *    Returns the nth largest value in a data set. You can use this function to
  1082.      *        select a value based on its relative standing.
  1083.      *
  1084.      *    Excel Function:
  1085.      *        LARGE(value1[,value2[, ...]],entry)
  1086.      *
  1087.      *    @access    public
  1088.      *    @category Statistical Functions
  1089.      *    @param    mixed        $arg,...        Data values
  1090.      *    @param    int            $entry            Position (ordered from the largest) in the array or range of data to return
  1091.      *    @return    float 
  1092.      *
  1093.      */
  1094.     public static function LARGE({
  1095.         $aArgs self::flattenArray(func_get_args());
  1096.  
  1097.         // Calculate
  1098.         $entry floor(array_pop($aArgs));
  1099.  
  1100.         if ((is_numeric($entry)) && (!is_string($entry))) {
  1101.             $mArgs array();
  1102.             foreach ($aArgs as $arg{
  1103.                 // Is it a numeric value?
  1104.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1105.                     $mArgs[$arg;
  1106.                 }
  1107.             }
  1108.             $count self::COUNT($mArgs);
  1109.             $entry floor(--$entry);
  1110.             if (($entry 0|| ($entry >= $count|| ($count == 0)) {
  1111.                 return self::$_errorCodes['num'];
  1112.             }
  1113.             rsort($mArgs);
  1114.             return $mArgs[$entry];
  1115.         }
  1116.         return self::$_errorCodes['value'];
  1117.     }    //    function LARGE()
  1118.  
  1119.  
  1120.     /**
  1121.      *    PERCENTILE
  1122.      *
  1123.      *    Returns the nth percentile of values in a range..
  1124.      *
  1125.      *    Excel Function:
  1126.      *        PERCENTILE(value1[,value2[, ...]],entry)
  1127.      *
  1128.      *    @access    public
  1129.      *    @category Statistical Functions
  1130.      *    @param    mixed        $arg,...        Data values
  1131.      *    @param    float        $entry            Percentile value in the range 0..1, inclusive.
  1132.      *    @return    float 
  1133.      */
  1134.     public static function PERCENTILE({
  1135.         $aArgs self::flattenArray(func_get_args());
  1136.  
  1137.         // Calculate
  1138.         $entry array_pop($aArgs);
  1139.  
  1140.         if ((is_numeric($entry)) && (!is_string($entry))) {
  1141.             if (($entry 0|| ($entry 1)) {
  1142.                 return self::$_errorCodes['num'];
  1143.             }
  1144.             $mArgs array();
  1145.             foreach ($aArgs as $arg{
  1146.                 // Is it a numeric value?
  1147.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1148.                     $mArgs[$arg;
  1149.                 }
  1150.             }
  1151.             $mValueCount count($mArgs);
  1152.             if ($mValueCount 0{
  1153.                 sort($mArgs);
  1154.                 $count self::COUNT($mArgs);
  1155.                 $index $entry ($count-1);
  1156.                 $iBase floor($index);
  1157.                 if ($index == $iBase{
  1158.                     return $mArgs[$index];
  1159.                 else {
  1160.                     $iNext $iBase 1;
  1161.                     $iProportion $index $iBase;
  1162.                     return $mArgs[$iBase(($mArgs[$iNext$mArgs[$iBase]$iProportion;
  1163.                 }
  1164.             }
  1165.         }
  1166.         return self::$_errorCodes['value'];
  1167.     }    //    function PERCENTILE()
  1168.  
  1169.  
  1170.     /**
  1171.      *    QUARTILE
  1172.      *
  1173.      *    Returns the quartile of a data set.
  1174.      *
  1175.      *    Excel Function:
  1176.      *        QUARTILE(value1[,value2[, ...]],entry)
  1177.      *
  1178.      *    @access    public
  1179.      *    @category Statistical Functions
  1180.      *    @param    mixed        $arg,...        Data values
  1181.      *    @param    int            $entry            Quartile value in the range 1..3, inclusive.
  1182.      *    @return    float 
  1183.      */
  1184.     public static function QUARTILE({
  1185.         $aArgs self::flattenArray(func_get_args());
  1186.  
  1187.         // Calculate
  1188.         $entry floor(array_pop($aArgs));
  1189.  
  1190.         if ((is_numeric($entry)) && (!is_string($entry))) {
  1191.             $entry /= 4;
  1192.             if (($entry 0|| ($entry 1)) {
  1193.                 return self::$_errorCodes['num'];
  1194.             }
  1195.             return self::PERCENTILE($aArgs,$entry);
  1196.         }
  1197.         return self::$_errorCodes['value'];
  1198.     }    //    function QUARTILE()
  1199.  
  1200.  
  1201.     /**
  1202.      *    COUNT
  1203.      *
  1204.      *    Counts the number of cells that contain numbers within the list of arguments
  1205.      *
  1206.      *    Excel Function:
  1207.      *        COUNT(value1[,value2[, ...]])
  1208.      *
  1209.      *    @access    public
  1210.      *    @category Statistical Functions
  1211.      *    @param    mixed        $arg,...        Data values
  1212.      *    @return    int 
  1213.      */
  1214.     public static function COUNT({
  1215.         // Return value
  1216.         $returnValue 0;
  1217.  
  1218.         // Loop through arguments
  1219.         $aArgs self::flattenArrayIndexed(func_get_args());
  1220.         foreach ($aArgs as $k => $arg{
  1221.             if ((is_bool($arg)) &&
  1222.                 ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1223.                 $arg = (integer) $arg;
  1224.             }
  1225.             // Is it a numeric value?
  1226.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1227.                 ++$returnValue;
  1228.             }
  1229.         }
  1230.  
  1231.         // Return
  1232.         return $returnValue;
  1233.     }    //    function COUNT()
  1234.  
  1235.  
  1236.     /**
  1237.      *    COUNTBLANK
  1238.      *
  1239.      *    Counts the number of empty cells within the list of arguments
  1240.      *
  1241.      *    Excel Function:
  1242.      *        COUNTBLANK(value1[,value2[, ...]])
  1243.      *
  1244.      *    @access    public
  1245.      *    @category Statistical Functions
  1246.      *    @param    mixed        $arg,...        Data values
  1247.      *    @return    int 
  1248.      */
  1249.     public static function COUNTBLANK({
  1250.         // Return value
  1251.         $returnValue 0;
  1252.  
  1253.         // Loop through arguments
  1254.         $aArgs self::flattenArray(func_get_args());
  1255.         foreach ($aArgs as $arg{
  1256.             // Is it a blank cell?
  1257.             if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) {
  1258.                 ++$returnValue;
  1259.             }
  1260.         }
  1261.  
  1262.         // Return
  1263.         return $returnValue;
  1264.     }    //    function COUNTBLANK()
  1265.  
  1266.  
  1267.     /**
  1268.      *    COUNTA
  1269.      *
  1270.      *    Counts the number of cells that are not empty within the list of arguments
  1271.      *
  1272.      *    Excel Function:
  1273.      *        COUNTA(value1[,value2[, ...]])
  1274.      *
  1275.      *    @access    public
  1276.      *    @category Statistical Functions
  1277.      *    @param    mixed        $arg,...        Data values
  1278.      *    @return    int 
  1279.      */
  1280.     public static function COUNTA({
  1281.         // Return value
  1282.         $returnValue 0;
  1283.  
  1284.         // Loop through arguments
  1285.         $aArgs self::flattenArray(func_get_args());
  1286.         foreach ($aArgs as $arg{
  1287.             // Is it a numeric, boolean or string value?
  1288.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  1289.                 ++$returnValue;
  1290.             }
  1291.         }
  1292.  
  1293.         // Return
  1294.         return $returnValue;
  1295.     }    //    function COUNTA()
  1296.  
  1297.  
  1298.     /**
  1299.      *    COUNTIF
  1300.      *
  1301.      *    Counts the number of cells that contain numbers within the list of arguments
  1302.      *
  1303.      *    Excel Function:
  1304.      *        COUNTIF(value1[,value2[, ...]],condition)
  1305.      *
  1306.      *    @access    public
  1307.      *    @category Statistical Functions
  1308.      *    @param    mixed        $arg,...        Data values
  1309.      *    @param    string        $condition        The criteria that defines which cells will be counted.
  1310.      *    @return    int 
  1311.      */
  1312.     public static function COUNTIF($aArgs,$condition{
  1313.         // Return value
  1314.         $returnValue 0;
  1315.  
  1316.         $aArgs self::flattenArray($aArgs);
  1317.         $condition self::_ifCondition($condition);
  1318.         // Loop through arguments
  1319.         foreach ($aArgs as $arg{
  1320.             if (!is_numeric($arg)) $arg PHPExcel_Calculation::_wrapResult(strtoupper($arg))}
  1321.             $testCondition '='.$arg.$condition;
  1322.             if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
  1323.                 // Is it a value within our criteria
  1324.                 ++$returnValue;
  1325.             }
  1326.         }
  1327.  
  1328.         // Return
  1329.         return $returnValue;
  1330.     }    //    function COUNTIF()
  1331.  
  1332.  
  1333.     /**
  1334.      *    SUMIF
  1335.      *
  1336.      *    Counts the number of cells that contain numbers within the list of arguments
  1337.      *
  1338.      *    Excel Function:
  1339.      *        SUMIF(value1[,value2[, ...]],condition)
  1340.      *
  1341.      *    @access    public
  1342.      *    @category Mathematical and Trigonometric Functions
  1343.      *    @param    mixed        $arg,...        Data values
  1344.      *    @param    string        $condition        The criteria that defines which cells will be summed.
  1345.      *    @return    float 
  1346.      */
  1347.     public static function SUMIF($aArgs,$condition,$sumArgs array()) {
  1348.         // Return value
  1349.         $returnValue 0;
  1350.  
  1351.         $aArgs self::flattenArray($aArgs);
  1352.         $sumArgs self::flattenArray($sumArgs);
  1353.         if (count($sumArgs== 0{
  1354.             $sumArgs $aArgs;
  1355.         }
  1356.         $condition self::_ifCondition($condition);
  1357.         // Loop through arguments
  1358.         foreach ($aArgs as $key => $arg{
  1359.             if (!is_numeric($arg)) $arg PHPExcel_Calculation::_wrapResult(strtoupper($arg))}
  1360.             $testCondition '='.$arg.$condition;
  1361.             if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
  1362.                 // Is it a value within our criteria
  1363.                 $returnValue += $sumArgs[$key];
  1364.             }
  1365.         }
  1366.  
  1367.         // Return
  1368.         return $returnValue;
  1369.     }    //    function SUMIF()
  1370.  
  1371.  
  1372.     /**
  1373.      *    AVERAGE
  1374.      *
  1375.      *    Returns the average (arithmetic mean) of the arguments
  1376.      *
  1377.      *    Excel Function:
  1378.      *        AVERAGE(value1[,value2[, ...]])
  1379.      *
  1380.      *    @access    public
  1381.      *    @category Statistical Functions
  1382.      *    @param    mixed        $arg,...        Data values
  1383.      *    @return    float 
  1384.      */
  1385.     public static function AVERAGE({
  1386.         $aArgs self::flattenArrayIndexed(func_get_args());
  1387.  
  1388.         $returnValue $aCount 0;
  1389.         // Loop through arguments
  1390.         foreach ($aArgs as $k => $arg{
  1391.             if ((is_bool($arg)) &&
  1392.                 ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1393.                 $arg = (integer) $arg;
  1394.             }
  1395.             // Is it a numeric value?
  1396.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1397.                 if (is_null($returnValue)) {
  1398.                     $returnValue $arg;
  1399.                 else {
  1400.                     $returnValue += $arg;
  1401.                 }
  1402.                 ++$aCount;
  1403.             }
  1404.         }
  1405.  
  1406.         // Return
  1407.         if ($aCount 0{
  1408.             return $returnValue $aCount;
  1409.         else {
  1410.             return self::$_errorCodes['divisionbyzero'];
  1411.         }
  1412.     }    //    function AVERAGE()
  1413.  
  1414.  
  1415.     /**
  1416.      *    AVERAGEA
  1417.      *
  1418.      *    Returns the average of its arguments, including numbers, text, and logical values
  1419.      *
  1420.      *    Excel Function:
  1421.      *        AVERAGEA(value1[,value2[, ...]])
  1422.      *
  1423.      *    @access    public
  1424.      *    @category Statistical Functions
  1425.      *    @param    mixed        $arg,...        Data values
  1426.      *    @return    float 
  1427.      */
  1428.     public static function AVERAGEA({
  1429.         // Return value
  1430.         $returnValue null;
  1431.  
  1432.         // Loop through arguments
  1433.         $aArgs self::flattenArrayIndexed(func_get_args());
  1434.         $aCount 0;
  1435.         foreach ($aArgs as $k => $arg{
  1436.             if ((is_bool($arg)) &&
  1437.                 (!self::isMatrixValue($k))) {
  1438.             else {
  1439.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  1440.                     if (is_bool($arg)) {
  1441.                         $arg = (integer) $arg;
  1442.                     elseif (is_string($arg)) {
  1443.                         $arg 0;
  1444.                     }
  1445.                     if (is_null($returnValue)) {
  1446.                         $returnValue $arg;
  1447.                     else {
  1448.                         $returnValue += $arg;
  1449.                     }
  1450.                     ++$aCount;
  1451.                 }
  1452.             }
  1453.         }
  1454.  
  1455.         // Return
  1456.         if ($aCount 0{
  1457.             return $returnValue $aCount;
  1458.         else {
  1459.             return self::$_errorCodes['divisionbyzero'];
  1460.         }
  1461.     }    //    function AVERAGEA()
  1462.  
  1463.  
  1464.     /**
  1465.      *    AVERAGEIF
  1466.      *
  1467.      *    Returns the average value from a range of cells that contain numbers within the list of arguments
  1468.      *
  1469.      *    Excel Function:
  1470.      *        AVERAGEIF(value1[,value2[, ...]],condition)
  1471.      *
  1472.      *    @access    public
  1473.      *    @category Mathematical and Trigonometric Functions
  1474.      *    @param    mixed        $arg,...        Data values
  1475.      *    @param    string        $condition        The criteria that defines which cells will be checked.
  1476.      *    @return    float 
  1477.      */
  1478.     public static function AVERAGEIF($aArgs,$condition,$averageArgs array()) {
  1479.         // Return value
  1480.         $returnValue 0;
  1481.  
  1482.         $aArgs self::flattenArray($aArgs);
  1483.         $averageArgs self::flattenArray($averageArgs);
  1484.         if (count($averageArgs== 0{
  1485.             $averageArgs $aArgs;
  1486.         }
  1487.         $condition self::_ifCondition($condition);
  1488.         // Loop through arguments
  1489.         $aCount 0;
  1490.         foreach ($aArgs as $key => $arg{
  1491.             if (!is_numeric($arg)) $arg PHPExcel_Calculation::_wrapResult(strtoupper($arg))}
  1492.             $testCondition '='.$arg.$condition;
  1493.             if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
  1494.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  1495.                     $returnValue += $arg;
  1496.                     ++$aCount;
  1497.                 }
  1498.             }
  1499.         }
  1500.  
  1501.         // Return
  1502.         if ($aCount 0{
  1503.             return $returnValue $aCount;
  1504.         else {
  1505.             return self::$_errorCodes['divisionbyzero'];
  1506.         }
  1507.     }    //    function AVERAGEIF()
  1508.  
  1509.  
  1510.     /**
  1511.      *    MEDIAN
  1512.      *
  1513.      *    Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
  1514.      *
  1515.      *    Excel Function:
  1516.      *        MEDIAN(value1[,value2[, ...]])
  1517.      *
  1518.      *    @access    public
  1519.      *    @category Statistical Functions
  1520.      *    @param    mixed        $arg,...        Data values
  1521.      *    @return    float 
  1522.      */
  1523.     public static function MEDIAN({
  1524.         // Return value
  1525.         $returnValue self::$_errorCodes['num'];
  1526.  
  1527.         $mArgs array();
  1528.         // Loop through arguments
  1529.         $aArgs self::flattenArray(func_get_args());
  1530.         foreach ($aArgs as $arg{
  1531.             // Is it a numeric value?
  1532.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1533.                 $mArgs[$arg;
  1534.             }
  1535.         }
  1536.  
  1537.         $mValueCount count($mArgs);
  1538.         if ($mValueCount 0{
  1539.             sort($mArgs,SORT_NUMERIC);
  1540.             $mValueCount $mValueCount 2;
  1541.             if ($mValueCount == floor($mValueCount)) {
  1542.                 $returnValue ($mArgs[$mValueCount--$mArgs[$mValueCount]2;
  1543.             else {
  1544.                 $mValueCount == floor($mValueCount);
  1545.                 $returnValue $mArgs[$mValueCount];
  1546.             }
  1547.         }
  1548.  
  1549.         // Return
  1550.         return $returnValue;
  1551.     }    //    function MEDIAN()
  1552.  
  1553.  
  1554.     //
  1555.     //    Special variant of array_count_values that isn't limited to strings and integers,
  1556.     //        but can work with floating point numbers as values
  1557.     //
  1558.     private static function _modeCalc($data{
  1559.         $frequencyArray array();
  1560.         foreach($data as $datum{
  1561.             $found False;
  1562.             foreach($frequencyArray as $key => $value{
  1563.                 if ((string) $value['value'== (string) $datum{
  1564.                     ++$frequencyArray[$key]['frequency'];
  1565.                     $found True;
  1566.                     break;
  1567.                 }
  1568.             }
  1569.             if (!$found{
  1570.                 $frequencyArray[array('value'        => $datum,
  1571.                                           'frequency'    =>    );
  1572.             }
  1573.         }
  1574.  
  1575.         foreach($frequencyArray as $key => $value{
  1576.             $frequencyList[$key$value['frequency'];
  1577.             $valueList[$key$value['value'];
  1578.         }
  1579.         array_multisort($frequencyListSORT_DESC$valueListSORT_ASCSORT_NUMERIC$frequencyArray);
  1580.  
  1581.         if ($frequencyArray[0]['frequency'== 1{
  1582.             return self::NA();
  1583.         }
  1584.         return $frequencyArray[0]['value'];
  1585.     }    //    function _modeCalc()
  1586.  
  1587.  
  1588.     /**
  1589.      *    MODE
  1590.      *
  1591.      *    Returns the most frequently occurring, or repetitive, value in an array or range of data
  1592.      *
  1593.      *    Excel Function:
  1594.      *        MODE(value1[,value2[, ...]])
  1595.      *
  1596.      *    @access    public
  1597.      *    @category Statistical Functions
  1598.      *    @param    mixed        $arg,...        Data values
  1599.      *    @return    float 
  1600.      */
  1601.     public static function MODE({
  1602.         // Return value
  1603.         $returnValue self::NA();
  1604.  
  1605.         // Loop through arguments
  1606.         $aArgs self::flattenArray(func_get_args());
  1607.  
  1608.         $mArgs array();
  1609.         foreach ($aArgs as $arg{
  1610.             // Is it a numeric value?
  1611.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1612.                 $mArgs[$arg;
  1613.             }
  1614.         }
  1615.  
  1616.         if (count($mArgs0{
  1617.             return self::_modeCalc($mArgs);
  1618.         }
  1619.  
  1620.         // Return
  1621.         return $returnValue;
  1622.     }    //    function MODE()
  1623.  
  1624.  
  1625.     /**
  1626.      *    DEVSQ
  1627.      *
  1628.      *    Returns the sum of squares of deviations of data points from their sample mean.
  1629.      *
  1630.      *    Excel Function:
  1631.      *        DEVSQ(value1[,value2[, ...]])
  1632.      *
  1633.      *    @access    public
  1634.      *    @category Statistical Functions
  1635.      *    @param    mixed        $arg,...        Data values
  1636.      *    @return    float 
  1637.      */
  1638.     public static function DEVSQ({
  1639.         $aArgs self::flattenArrayIndexed(func_get_args());
  1640.  
  1641.         // Return value
  1642.         $returnValue null;
  1643.  
  1644.         $aMean self::AVERAGE($aArgs);
  1645.         if ($aMean != self::$_errorCodes['divisionbyzero']{
  1646.             $aCount = -1;
  1647.             foreach ($aArgs as $k => $arg{
  1648.                 // Is it a numeric value?
  1649.                 if ((is_bool($arg)) &&
  1650.                     ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1651.                     $arg = (integer) $arg;
  1652.                 }
  1653.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1654.                     if (is_null($returnValue)) {
  1655.                         $returnValue pow(($arg $aMean),2);
  1656.                     else {
  1657.                         $returnValue += pow(($arg $aMean),2);
  1658.                     }
  1659.                     ++$aCount;
  1660.                 }
  1661.             }
  1662.  
  1663.             // Return
  1664.             if (is_null($returnValue)) {
  1665.                 return self::$_errorCodes['num'];
  1666.             else {
  1667.                 return $returnValue;
  1668.             }
  1669.         }
  1670.         return self::NA();
  1671.     }    //    function DEVSQ()
  1672.  
  1673.  
  1674.     /**
  1675.      *    AVEDEV
  1676.      *
  1677.      *    Returns the average of the absolute deviations of data points from their mean.
  1678.      *    AVEDEV is a measure of the variability in a data set.
  1679.      *
  1680.      *    Excel Function:
  1681.      *        AVEDEV(value1[,value2[, ...]])
  1682.      *
  1683.      *    @access    public
  1684.      *    @category Statistical Functions
  1685.      *    @param    mixed        $arg,...        Data values
  1686.      *    @return    float 
  1687.      */
  1688.     public static function AVEDEV({
  1689.         $aArgs self::flattenArrayIndexed(func_get_args());
  1690.  
  1691.         // Return value
  1692.         $returnValue null;
  1693.  
  1694.         $aMean self::AVERAGE($aArgs);
  1695.         if ($aMean != self::$_errorCodes['divisionbyzero']{
  1696.             $aCount 0;
  1697.             foreach ($aArgs as $k => $arg{
  1698.                 if ((is_bool($arg)) &&
  1699.                     ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1700.                     $arg = (integer) $arg;
  1701.                 }
  1702.                 // Is it a numeric value?
  1703.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1704.                     if (is_null($returnValue)) {
  1705.                         $returnValue abs($arg $aMean);
  1706.                     else {
  1707.                         $returnValue += abs($arg $aMean);
  1708.                     }
  1709.                     ++$aCount;
  1710.                 }
  1711.             }
  1712.  
  1713.             // Return
  1714.             if ($aCount == 0{
  1715.                 return self::$_errorCodes['divisionbyzero'];
  1716.             }
  1717.             return $returnValue $aCount;
  1718.         }
  1719.         return self::$_errorCodes['num'];
  1720.     }    //    function AVEDEV()
  1721.  
  1722.  
  1723.     /**
  1724.      *    GEOMEAN
  1725.      *
  1726.      *    Returns the geometric mean of an array or range of positive data. For example, you
  1727.      *        can use GEOMEAN to calculate average growth rate given compound interest with
  1728.      *        variable rates.
  1729.      *
  1730.      *    Excel Function:
  1731.      *        GEOMEAN(value1[,value2[, ...]])
  1732.      *
  1733.      *    @access    public
  1734.      *    @category Statistical Functions
  1735.      *    @param    mixed        $arg,...        Data values
  1736.      *    @return    float 
  1737.      */
  1738.     public static function GEOMEAN({
  1739.         $aArgs self::flattenArray(func_get_args());
  1740.  
  1741.         $aMean self::PRODUCT($aArgs);
  1742.         if (is_numeric($aMean&& ($aMean 0)) {
  1743.             $aCount self::COUNT($aArgs;
  1744.             if (self::MIN($aArgs0{
  1745.                 return pow($aMean($aCount));
  1746.             }
  1747.         }
  1748.         return self::$_errorCodes['num'];
  1749.     }    //    GEOMEAN()
  1750.  
  1751.  
  1752.     /**
  1753.      *    HARMEAN
  1754.      *
  1755.      *    Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the
  1756.      *        arithmetic mean of reciprocals.
  1757.      *
  1758.      *    Excel Function:
  1759.      *        HARMEAN(value1[,value2[, ...]])
  1760.      *
  1761.      *    @access    public
  1762.      *    @category Statistical Functions
  1763.      *    @param    mixed        $arg,...        Data values
  1764.      *    @return    float 
  1765.      */
  1766.     public static function HARMEAN({
  1767.         // Return value
  1768.         $returnValue self::NA();
  1769.  
  1770.         // Loop through arguments
  1771.         $aArgs self::flattenArray(func_get_args());
  1772.         if (self::MIN($aArgs0{
  1773.             return self::$_errorCodes['num'];
  1774.         }
  1775.         $aCount 0;
  1776.         foreach ($aArgs as $arg{
  1777.             // Is it a numeric value?
  1778.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1779.                 if ($arg <= 0{
  1780.                     return self::$_errorCodes['num'];
  1781.                 }
  1782.                 if (is_null($returnValue)) {
  1783.                     $returnValue ($arg);
  1784.                 else {
  1785.                     $returnValue += ($arg);
  1786.                 }
  1787.                 ++$aCount;
  1788.             }
  1789.         }
  1790.  
  1791.         // Return
  1792.         if ($aCount 0{
  1793.             return ($returnValue $aCount);
  1794.         else {
  1795.             return $returnValue;
  1796.         }
  1797.     }    //    function HARMEAN()
  1798.  
  1799.  
  1800.     /**
  1801.      *    TRIMMEAN
  1802.      *
  1803.      *    Returns the mean of the interior of a data set. TRIMMEAN calculates the mean
  1804.      *    taken by excluding a percentage of data points from the top and bottom tails
  1805.      *    of a data set.
  1806.      *
  1807.      *    Excel Function:
  1808.      *        TRIMEAN(value1[,value2[, ...]],$discard)
  1809.      *
  1810.      *    @access    public
  1811.      *    @category Statistical Functions
  1812.      *    @param    mixed        $arg,...        Data values
  1813.      *    @param    float        $discard        Percentage to discard
  1814.      *    @return    float 
  1815.      */
  1816.     public static function TRIMMEAN({
  1817.         $aArgs self::flattenArray(func_get_args());
  1818.  
  1819.         // Calculate
  1820.         $percent array_pop($aArgs);
  1821.  
  1822.         if ((is_numeric($percent)) && (!is_string($percent))) {
  1823.             if (($percent 0|| ($percent 1)) {
  1824.                 return self::$_errorCodes['num'];
  1825.             }
  1826.             $mArgs array();
  1827.             foreach ($aArgs as $arg{
  1828.                 // Is it a numeric value?
  1829.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1830.                     $mArgs[$arg;
  1831.                 }
  1832.             }
  1833.             $discard floor(self::COUNT($mArgs$percent 2);
  1834.             sort($mArgs);
  1835.             for ($i=0$i $discard++$i{
  1836.                 array_pop($mArgs);
  1837.                 array_shift($mArgs);
  1838.             }
  1839.             return self::AVERAGE($mArgs);
  1840.         }
  1841.         return self::$_errorCodes['value'];
  1842.     }    //    function TRIMMEAN()
  1843.  
  1844.  
  1845.     /**
  1846.      *    STDEV
  1847.      *
  1848.      *    Estimates standard deviation based on a sample. The standard deviation is a measure of how
  1849.      *    widely values are dispersed from the average value (the mean).
  1850.      *
  1851.      *    Excel Function:
  1852.      *        STDEV(value1[,value2[, ...]])
  1853.      *
  1854.      *    @access    public
  1855.      *    @category Statistical Functions
  1856.      *    @param    mixed        $arg,...        Data values
  1857.      *    @return    float 
  1858.      */
  1859.     public static function STDEV({
  1860.         $aArgs self::flattenArrayIndexed(func_get_args());
  1861.  
  1862.         // Return value
  1863.         $returnValue null;
  1864.  
  1865.         $aMean self::AVERAGE($aArgs);
  1866.         if (!is_null($aMean)) {
  1867.             $aCount = -1;
  1868.             foreach ($aArgs as $k => $arg{
  1869.                 if ((is_bool($arg)) &&
  1870.                     ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1871.                     $arg = (integer) $arg;
  1872.                 }
  1873.                 // Is it a numeric value?
  1874.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1875.                     if (is_null($returnValue)) {
  1876.                         $returnValue pow(($arg $aMean),2);
  1877.                     else {
  1878.                         $returnValue += pow(($arg $aMean),2);
  1879.                     }
  1880.                     ++$aCount;
  1881.                 }
  1882.             }
  1883.  
  1884.             // Return
  1885.             if (($aCount 0&& ($returnValue >= 0)) {
  1886.                 return sqrt($returnValue $aCount);
  1887.             }
  1888.         }
  1889.         return self::$_errorCodes['divisionbyzero'];
  1890.     }    //    function STDEV()
  1891.  
  1892.  
  1893.     /**
  1894.      *    STDEVA
  1895.      *
  1896.      *    Estimates standard deviation based on a sample, including numbers, text, and logical values
  1897.      *
  1898.      *    Excel Function:
  1899.      *        STDEVA(value1[,value2[, ...]])
  1900.      *
  1901.      *    @access    public
  1902.      *    @category Statistical Functions
  1903.      *    @param    mixed        $arg,...        Data values
  1904.      *    @return    float 
  1905.      */
  1906.     public static function STDEVA({
  1907.         $aArgs self::flattenArrayIndexed(func_get_args());
  1908.  
  1909.         // Return value
  1910.         $returnValue null;
  1911.  
  1912.         $aMean self::AVERAGEA($aArgs);
  1913.         if (!is_null($aMean)) {
  1914.             $aCount = -1;
  1915.             foreach ($aArgs as $k => $arg{
  1916.                 if ((is_bool($arg)) &&
  1917.                     (!self::isMatrixValue($k))) {
  1918.                 else {
  1919.                     // Is it a numeric value?
  1920.                     if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1921.                         if (is_bool($arg)) {
  1922.                             $arg = (integer) $arg;
  1923.                         elseif (is_string($arg)) {
  1924.                             $arg 0;
  1925.                         }
  1926.                         if (is_null($returnValue)) {
  1927.                             $returnValue pow(($arg $aMean),2);
  1928.                         else {
  1929.                             $returnValue += pow(($arg $aMean),2);
  1930.                         }
  1931.                         ++$aCount;
  1932.                     }
  1933.                 }
  1934.             }
  1935.  
  1936.             // Return
  1937.             if (($aCount 0&& ($returnValue >= 0)) {
  1938.                 return sqrt($returnValue $aCount);
  1939.             }
  1940.         }
  1941.         return self::$_errorCodes['divisionbyzero'];
  1942.     }    //    function STDEVA()
  1943.  
  1944.  
  1945.     /**
  1946.      *    STDEVP
  1947.      *
  1948.      *    Calculates standard deviation based on the entire population
  1949.      *
  1950.      *    Excel Function:
  1951.      *        STDEVP(value1[,value2[, ...]])
  1952.      *
  1953.      *    @access    public
  1954.      *    @category Statistical Functions
  1955.      *    @param    mixed        $arg,...        Data values
  1956.      *    @return    float 
  1957.      */
  1958.     public static function STDEVP({
  1959.         $aArgs self::flattenArrayIndexed(func_get_args());
  1960.  
  1961.         // Return value
  1962.         $returnValue null;
  1963.  
  1964.         $aMean self::AVERAGE($aArgs);
  1965.         if (!is_null($aMean)) {
  1966.             $aCount 0;
  1967.             foreach ($aArgs as $k => $arg{
  1968.                 if ((is_bool($arg)) &&
  1969.                     ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1970.                     $arg = (integer) $arg;
  1971.                 }
  1972.                 // Is it a numeric value?
  1973.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1974.                     if (is_null($returnValue)) {
  1975.                         $returnValue pow(($arg $aMean),2);
  1976.                     else {
  1977.                         $returnValue += pow(($arg $aMean),2);
  1978.                     }
  1979.                     ++$aCount;
  1980.                 }
  1981.             }
  1982.  
  1983.             // Return
  1984.             if (($aCount 0&& ($returnValue >= 0)) {
  1985.                 return sqrt($returnValue $aCount);
  1986.             }
  1987.         }
  1988.         return self::$_errorCodes['divisionbyzero'];
  1989.     }    //    function STDEVP()
  1990.  
  1991.  
  1992.     /**
  1993.      *    STDEVPA
  1994.      *
  1995.      *    Calculates standard deviation based on the entire population, including numbers, text, and logical values
  1996.      *
  1997.      *    Excel Function:
  1998.      *        STDEVPA(value1[,value2[, ...]])
  1999.      *
  2000.      *    @access    public
  2001.      *    @category Statistical Functions
  2002.      *    @param    mixed        $arg,...        Data values
  2003.      *    @return    float 
  2004.      */
  2005.     public static function STDEVPA({
  2006.         $aArgs self::flattenArrayIndexed(func_get_args());
  2007.  
  2008.         // Return value
  2009.         $returnValue null;
  2010.  
  2011.         $aMean self::AVERAGEA($aArgs);
  2012.         if (!is_null($aMean)) {
  2013.             $aCount 0;
  2014.             foreach ($aArgs as $k => $arg{
  2015.                 if ((is_bool($arg)) &&
  2016.                     (!self::isMatrixValue($k))) {
  2017.                 else {
  2018.                     // Is it a numeric value?
  2019.                     if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  2020.                         if (is_bool($arg)) {
  2021.                             $arg = (integer) $arg;
  2022.                         elseif (is_string($arg)) {
  2023.                             $arg 0;
  2024.                         }
  2025.                         if (is_null($returnValue)) {
  2026.                             $returnValue pow(($arg $aMean),2);
  2027.                         else {
  2028.                             $returnValue += pow(($arg $aMean),2);
  2029.                         }
  2030.                         ++$aCount;
  2031.                     }
  2032.                 }
  2033.             }
  2034.  
  2035.             // Return
  2036.             if (($aCount 0&& ($returnValue >= 0)) {
  2037.                 return sqrt($returnValue $aCount);
  2038.             }
  2039.         }
  2040.         return self::$_errorCodes['divisionbyzero'];
  2041.     }    //    function STDEVPA()
  2042.  
  2043.  
  2044.     /**
  2045.      *    VARFunc
  2046.      *
  2047.      *    Estimates variance based on a sample.
  2048.      *
  2049.      *    Excel Function:
  2050.      *        VAR(value1[,value2[, ...]])
  2051.      *
  2052.      *    @access    public
  2053.      *    @category Statistical Functions
  2054.      *    @param    mixed        $arg,...        Data values
  2055.      *    @return    float 
  2056.      */
  2057.     public static function VARFunc({
  2058.         // Return value
  2059.         $returnValue self::$_errorCodes['divisionbyzero'];
  2060.  
  2061.         $summerA $summerB 0;
  2062.  
  2063.         // Loop through arguments
  2064.         $aArgs self::flattenArray(func_get_args());
  2065.         $aCount 0;
  2066.         foreach ($aArgs as $arg{
  2067.             if (is_bool($arg)) $arg = (integer) $arg}
  2068.             // Is it a numeric value?
  2069.             if ((is_numeric($arg)) && (!is_string($arg))) {
  2070.                 $summerA += ($arg $arg);
  2071.                 $summerB += $arg;
  2072.                 ++$aCount;
  2073.             }
  2074.         }
  2075.  
  2076.         // Return
  2077.         if ($aCount 1{
  2078.             $summerA *= $aCount;
  2079.             $summerB *= $summerB;
  2080.             $returnValue ($summerA $summerB($aCount ($aCount 1));
  2081.         }
  2082.         return $returnValue;
  2083.     }    //    function VARFunc()
  2084.  
  2085.  
  2086.     /**
  2087.      *    VARA
  2088.      *
  2089.      *    Estimates variance based on a sample, including numbers, text, and logical values
  2090.      *
  2091.      *    Excel Function:
  2092.      *        VARA(value1[,value2[, ...]])
  2093.      *
  2094.      *    @access    public
  2095.      *    @category Statistical Functions
  2096.      *    @param    mixed        $arg,...        Data values
  2097.      *    @return    float 
  2098.      */
  2099.     public static function VARA({
  2100.         // Return value
  2101.         $returnValue self::$_errorCodes['divisionbyzero'];
  2102.  
  2103.         $summerA $summerB 0;
  2104.  
  2105.         // Loop through arguments
  2106.         $aArgs self::flattenArrayIndexed(func_get_args());
  2107.         $aCount 0;
  2108.         foreach ($aArgs as $k => $arg{
  2109.             if ((is_string($arg)) &&
  2110.                 (self::isValue($k))) {
  2111.                 return self::$_errorCodes['value'];
  2112.             elseif ((is_string($arg)) &&
  2113.                 (!self::isMatrixValue($k))) {
  2114.             else {
  2115.                 // Is it a numeric value?
  2116.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  2117.                     if (is_bool($arg)) {
  2118.                         $arg = (integer) $arg;
  2119.                     elseif (is_string($arg)) {
  2120.                         $arg 0;
  2121.                     }
  2122.                     $summerA += ($arg $arg);
  2123.                     $summerB += $arg;
  2124.                     ++$aCount;
  2125.                 }
  2126.             }
  2127.         }
  2128.  
  2129.         // Return
  2130.         if ($aCount 1{
  2131.             $summerA *= $aCount;
  2132.             $summerB *= $summerB;
  2133.             $returnValue ($summerA $summerB($aCount ($aCount 1));
  2134.         }
  2135.         return $returnValue;
  2136.     }    //    function VARA()
  2137.  
  2138.  
  2139.     /**
  2140.      *    VARP
  2141.      *
  2142.      *    Calculates variance based on the entire population
  2143.      *
  2144.      *    Excel Function:
  2145.      *        VARP(value1[,value2[, ...]])
  2146.      *
  2147.      *    @access    public
  2148.      *    @category Statistical Functions
  2149.      *    @param    mixed        $arg,...        Data values
  2150.      *    @return    float 
  2151.      */
  2152.     public static function VARP({
  2153.         // Return value
  2154.         $returnValue self::$_errorCodes['divisionbyzero'];
  2155.  
  2156.         $summerA $summerB 0;
  2157.  
  2158.         // Loop through arguments
  2159.         $aArgs self::flattenArray(func_get_args());
  2160.         $aCount 0;
  2161.         foreach ($aArgs as $arg{
  2162.             if (is_bool($arg)) $arg = (integer) $arg}
  2163.             // Is it a numeric value?
  2164.             if ((is_numeric($arg)) && (!is_string($arg))) {
  2165.                 $summerA += ($arg $arg);
  2166.                 $summerB += $arg;
  2167.                 ++$aCount;
  2168.             }
  2169.         }
  2170.  
  2171.         // Return
  2172.         if ($aCount 0{
  2173.             $summerA *= $aCount;
  2174.             $summerB *= $summerB;
  2175.             $returnValue ($summerA $summerB($aCount $aCount);
  2176.         }
  2177.         return $returnValue;
  2178.     }    //    function VARP()
  2179.  
  2180.  
  2181.     /**
  2182.      *    VARPA
  2183.      *
  2184.      *    Calculates variance based on the entire population, including numbers, text, and logical values
  2185.      *
  2186.      *    Excel Function:
  2187.      *        VARPA(value1[,value2[, ...]])
  2188.      *
  2189.      *    @access    public
  2190.      *    @category Statistical Functions
  2191.      *    @param    mixed        $arg,...        Data values
  2192.      *    @return    float 
  2193.      */
  2194.     public static function VARPA({
  2195.         // Return value
  2196.         $returnValue self::$_errorCodes['divisionbyzero'];
  2197.  
  2198.         $summerA $summerB 0;
  2199.  
  2200.         // Loop through arguments
  2201.         $aArgs self::flattenArrayIndexed(func_get_args());
  2202.         $aCount 0;
  2203.         foreach ($aArgs as $k => $arg{
  2204.             if ((is_string($arg)) &&
  2205.                 (self::isValue($k))) {
  2206.                 return self::$_errorCodes['value'];
  2207.             elseif ((is_string($arg)) &&
  2208.                 (!self::isMatrixValue($k))) {
  2209.             else {
  2210.                 // Is it a numeric value?
  2211.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  2212.                     if (is_bool($arg)) {
  2213.                         $arg = (integer) $arg;
  2214.                     elseif (is_string($arg)) {
  2215.                         $arg 0;
  2216.                     }
  2217.                     $summerA += ($arg $arg);
  2218.                     $summerB += $arg;
  2219.                     ++$aCount;
  2220.                 }
  2221.             }
  2222.         }
  2223.  
  2224.         // Return
  2225.         if ($aCount 0{
  2226.             $summerA *= $aCount;
  2227.             $summerB *= $summerB;
  2228.             $returnValue ($summerA $summerB($aCount $aCount);
  2229.         }
  2230.         return $returnValue;
  2231.     }    //    function VARPA()
  2232.  
  2233.  
  2234.     /**
  2235.      *    RANK
  2236.      *
  2237.      *    Returns the rank of a number in a list of numbers.
  2238.      *
  2239.      *    @param    number                The number whose rank you want to find.
  2240.      *    @param    array of number        An array of, or a reference to, a list of numbers.
  2241.      *    @param    mixed                Order to sort the values in the value set
  2242.      *    @return    float 
  2243.      */
  2244.     public static function RANK($value,$valueSet,$order=0{
  2245.         $value self::flattenSingleValue($value);
  2246.         $valueSet self::flattenArray($valueSet);
  2247.         $order    (is_null($order))    :    (integer) self::flattenSingleValue($order);
  2248.  
  2249.         foreach($valueSet as $key => $valueEntry{
  2250.             if (!is_numeric($valueEntry)) {
  2251.                 unset($valueSet[$key]);
  2252.             }
  2253.         }
  2254.  
  2255.         if ($order == 0{
  2256.             rsort($valueSet,SORT_NUMERIC);
  2257.         else {
  2258.             sort($valueSet,SORT_NUMERIC);
  2259.         }
  2260.         $pos array_search($value,$valueSet);
  2261.         if ($pos === False{
  2262.             return self::$_errorCodes['na'];
  2263.         }
  2264.  
  2265.         return ++$pos;
  2266.     }    //    function RANK()
  2267.  
  2268.  
  2269.     /**
  2270.      *    PERCENTRANK
  2271.      *
  2272.      *    Returns the rank of a value in a data set as a percentage of the data set.
  2273.      *
  2274.      *    @param    array of number        An array of, or a reference to, a list of numbers.
  2275.      *    @param    number                The number whose rank you want to find.
  2276.      *    @param    number                The number of significant digits for the returned percentage value.
  2277.      *    @return    float 
  2278.      */
  2279.     public static function PERCENTRANK($valueSet,$value,$significance=3{
  2280.         $valueSet    self::flattenArray($valueSet);
  2281.         $value        self::flattenSingleValue($value);
  2282.         $significance    (is_null($significance))    :    (integer) self::flattenSingleValue($significance);
  2283.  
  2284.         foreach($valueSet as $key => $valueEntry{
  2285.             if (!is_numeric($valueEntry)) {
  2286.                 unset($valueSet[$key]);
  2287.             }
  2288.         }
  2289.         sort($valueSet,SORT_NUMERIC);
  2290.         $valueCount count($valueSet);
  2291.         if ($valueCount == 0{
  2292.             return self::$_errorCodes['num'];
  2293.         }
  2294.  
  2295.         $valueAdjustor $valueCount 1;
  2296.         if (($value $valueSet[0]|| ($value $valueSet[$valueAdjustor])) {
  2297.             return self::$_errorCodes['na'];
  2298.         }
  2299.  
  2300.         $pos array_search($value,$valueSet);
  2301.         if ($pos === False{
  2302.             $pos 0;
  2303.             $testValue $valueSet[0];
  2304.             while ($testValue $value{
  2305.                 $testValue $valueSet[++$pos];
  2306.             }
  2307.             --$pos;
  2308.             $pos += (($value $valueSet[$pos]($testValue $valueSet[$pos]));
  2309.         }
  2310.  
  2311.         return round($pos $valueAdjustor,$significance);
  2312.     }    //    function PERCENTRANK()
  2313.  
  2314.  
  2315.     private static function _checkTrendArrays(&$array1,&$array2{
  2316.         if (!is_array($array1)) $array1 array($array1)}
  2317.         if (!is_array($array2)) $array2 array($array2)}
  2318.  
  2319.         $array1 self::flattenArray($array1);
  2320.         $array2 self::flattenArray($array2);
  2321.         foreach($array1 as $key => $value{
  2322.             if ((is_bool($value)) || (is_string($value)) || (is_null($value))) {
  2323.                 unset($array1[$key]);
  2324.                 unset($array2[$key]);
  2325.             }
  2326.         }
  2327.         foreach($array2 as $key => $value{
  2328.             if ((is_bool($value)) || (is_string($value)) || (is_null($value))) {
  2329.                 unset($array1[$key]);
  2330.                 unset($array2[$key]);
  2331.             }
  2332.         }
  2333.         $array1 array_merge($array1);
  2334.         $array2 array_merge($array2);
  2335.  
  2336.         return True;
  2337.     }    //    function _checkTrendArrays()
  2338.  
  2339.  
  2340.     /**
  2341.      *    INTERCEPT
  2342.      *
  2343.      *    Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values.
  2344.      *
  2345.      *    @param    array of mixed        Data Series Y
  2346.      *    @param    array of mixed        Data Series X
  2347.      *    @return    float 
  2348.      */
  2349.     public static function INTERCEPT($yValues,$xValues{
  2350.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2351.             return self::$_errorCodes['value'];
  2352.         }
  2353.         $yValueCount count($yValues);
  2354.         $xValueCount count($xValues);
  2355.  
  2356.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2357.             return self::$_errorCodes['na'];
  2358.         elseif ($yValueCount == 1{
  2359.             return self::$_errorCodes['divisionbyzero'];
  2360.         }
  2361.  
  2362.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2363.         return $bestFitLinear->getIntersect();
  2364.     }    //    function INTERCEPT()
  2365.  
  2366.  
  2367.     /**
  2368.      *    RSQ
  2369.      *
  2370.      *    Returns the square of the Pearson product moment correlation coefficient through data points in known_y's and known_x's.
  2371.      *
  2372.      *    @param    array of mixed        Data Series Y
  2373.      *    @param    array of mixed        Data Series X
  2374.      *    @return    float 
  2375.      */
  2376.     public static function RSQ($yValues,$xValues{
  2377.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2378.             return self::$_errorCodes['value'];
  2379.         }
  2380.         $yValueCount count($yValues);
  2381.         $xValueCount count($xValues);
  2382.  
  2383.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2384.             return self::$_errorCodes['na'];
  2385.         elseif ($yValueCount == 1{
  2386.             return self::$_errorCodes['divisionbyzero'];
  2387.         }
  2388.  
  2389.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2390.         return $bestFitLinear->getGoodnessOfFit();
  2391.     }    //    function RSQ()
  2392.  
  2393.  
  2394.     /**
  2395.      *    SLOPE
  2396.      *
  2397.      *    Returns the slope of the linear regression line through data points in known_y's and known_x's.
  2398.      *
  2399.      *    @param    array of mixed        Data Series Y
  2400.      *    @param    array of mixed        Data Series X
  2401.      *    @return    float 
  2402.      */
  2403.     public static function SLOPE($yValues,$xValues{
  2404.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2405.             return self::$_errorCodes['value'];
  2406.         }
  2407.         $yValueCount count($yValues);
  2408.         $xValueCount count($xValues);
  2409.  
  2410.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2411.             return self::$_errorCodes['na'];
  2412.         elseif ($yValueCount == 1{
  2413.             return self::$_errorCodes['divisionbyzero'];
  2414.         }
  2415.  
  2416.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2417.         return $bestFitLinear->getSlope();
  2418.     }    //    function SLOPE()
  2419.  
  2420.  
  2421.     /**
  2422.      *    STEYX
  2423.      *
  2424.      *    Returns the standard error of the predicted y-value for each x in the regression.
  2425.      *
  2426.      *    @param    array of mixed        Data Series Y
  2427.      *    @param    array of mixed        Data Series X
  2428.      *    @return    float 
  2429.      */
  2430.     public static function STEYX($yValues,$xValues{
  2431.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2432.             return self::$_errorCodes['value'];
  2433.         }
  2434.         $yValueCount count($yValues);
  2435.         $xValueCount count($xValues);
  2436.  
  2437.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2438.             return self::$_errorCodes['na'];
  2439.         elseif ($yValueCount == 1{
  2440.             return self::$_errorCodes['divisionbyzero'];
  2441.         }
  2442.  
  2443.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2444.         return $bestFitLinear->getStdevOfResiduals();
  2445.     }    //    function STEYX()
  2446.  
  2447.  
  2448.     /**
  2449.      *    COVAR
  2450.      *
  2451.      *    Returns covariance, the average of the products of deviations for each data point pair.
  2452.      *
  2453.      *    @param    array of mixed        Data Series Y
  2454.      *    @param    array of mixed        Data Series X
  2455.      *    @return    float 
  2456.      */
  2457.     public static function COVAR($yValues,$xValues{
  2458.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2459.             return self::$_errorCodes['value'];
  2460.         }
  2461.         $yValueCount count($yValues);
  2462.         $xValueCount count($xValues);
  2463.  
  2464.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2465.             return self::$_errorCodes['na'];
  2466.         elseif ($yValueCount == 1{
  2467.             return self::$_errorCodes['divisionbyzero'];
  2468.         }
  2469.  
  2470.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2471.         return $bestFitLinear->getCovariance();
  2472.     }    //    function COVAR()
  2473.  
  2474.  
  2475.     /**
  2476.      *    CORREL
  2477.      *
  2478.      *    Returns covariance, the average of the products of deviations for each data point pair.
  2479.      *
  2480.      *    @param    array of mixed        Data Series Y
  2481.      *    @param    array of mixed        Data Series X
  2482.      *    @return    float 
  2483.      */
  2484.     public static function CORREL($yValues,$xValues=null{
  2485.         if ((is_null($xValues)) || (!is_array($yValues)) || (!is_array($xValues))) {
  2486.             return self::$_errorCodes['value'];
  2487.         }
  2488.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2489.             return self::$_errorCodes['value'];
  2490.         }
  2491.         $yValueCount count($yValues);
  2492.         $xValueCount count($xValues);
  2493.  
  2494.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2495.             return self::$_errorCodes['na'];
  2496.         elseif ($yValueCount == 1{
  2497.             return self::$_errorCodes['divisionbyzero'];
  2498.         }
  2499.  
  2500.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2501.         return $bestFitLinear->getCorrelation();
  2502.     }    //    function CORREL()
  2503.  
  2504.  
  2505.     /**
  2506.      *    LINEST
  2507.      *
  2508.      *    Calculates the statistics for a line by using the "least squares" method to calculate a straight line that best fits your data,
  2509.      *        and then returns an array that describes the line.
  2510.      *
  2511.      *    @param    array of mixed        Data Series Y
  2512.      *    @param    array of mixed        Data Series X
  2513.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2514.      *    @param    boolean                A logical value specifying whether to return additional regression statistics.
  2515.      *    @return    array 
  2516.      */
  2517.     public static function LINEST($yValues,$xValues=null,$const=True,$stats=False{
  2518.         $const    (is_null($const))    True :    (boolean) self::flattenSingleValue($const);
  2519.         $stats    (is_null($stats))    False :    (boolean) self::flattenSingleValue($stats);
  2520.         if (is_null($xValues)) $xValues range(1,count(self::flattenArray($yValues)));
  2521.  
  2522.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2523.             return self::$_errorCodes['value'];
  2524.         }
  2525.         $yValueCount count($yValues);
  2526.         $xValueCount count($xValues);
  2527.  
  2528.  
  2529.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2530.             return self::$_errorCodes['na'];
  2531.         elseif ($yValueCount == 1{
  2532.             return 0;
  2533.         }
  2534.  
  2535.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const);
  2536.         if ($stats{
  2537.             return arrayarray$bestFitLinear->getSlope(),
  2538.                                   $bestFitLinear->getSlopeSE(),
  2539.                                   $bestFitLinear->getGoodnessOfFit(),
  2540.                                   $bestFitLinear->getF(),
  2541.                                   $bestFitLinear->getSSRegression(),
  2542.                                ),
  2543.                           array$bestFitLinear->getIntersect(),
  2544.                                  $bestFitLinear->getIntersectSE(),
  2545.                                  $bestFitLinear->getStdevOfResiduals(),
  2546.                                  $bestFitLinear->getDFResiduals(),
  2547.                                  $bestFitLinear->getSSResiduals()
  2548.                                )
  2549.                         );
  2550.         else {
  2551.             return array$bestFitLinear->getSlope(),
  2552.                           $bestFitLinear->getIntersect()
  2553.                         );
  2554.         }
  2555.     }    //    function LINEST()
  2556.  
  2557.  
  2558.     /**
  2559.      *    LOGEST
  2560.      *
  2561.      *    Calculates an exponential curve that best fits the X and Y data series,
  2562.      *        and then returns an array that describes the line.
  2563.      *
  2564.      *    @param    array of mixed        Data Series Y
  2565.      *    @param    array of mixed        Data Series X
  2566.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2567.      *    @param    boolean                A logical value specifying whether to return additional regression statistics.
  2568.      *    @return    array 
  2569.      */
  2570.     public static function LOGEST($yValues,$xValues=null,$const=True,$stats=False{
  2571.         $const    (is_null($const))    True :    (boolean) self::flattenSingleValue($const);
  2572.         $stats    (is_null($stats))    False :    (boolean) self::flattenSingleValue($stats);
  2573.         if (is_null($xValues)) $xValues range(1,count(self::flattenArray($yValues)));
  2574.  
  2575.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2576.             return self::$_errorCodes['value'];
  2577.         }
  2578.         $yValueCount count($yValues);
  2579.         $xValueCount count($xValues);
  2580.  
  2581.         foreach($yValues as $value{
  2582.             if ($value <= 0.0{
  2583.                 return self::$_errorCodes['num'];
  2584.             }
  2585.         }
  2586.  
  2587.  
  2588.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2589.             return self::$_errorCodes['na'];
  2590.         elseif ($yValueCount == 1{
  2591.             return 1;
  2592.         }
  2593.  
  2594.         $bestFitExponential trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const);
  2595.         if ($stats{
  2596.             return arrayarray$bestFitExponential->getSlope(),
  2597.                                   $bestFitExponential->getSlopeSE(),
  2598.                                   $bestFitExponential->getGoodnessOfFit(),
  2599.                                   $bestFitExponential->getF(),
  2600.                                   $bestFitExponential->getSSRegression(),
  2601.                                ),
  2602.                           array$bestFitExponential->getIntersect(),
  2603.                                  $bestFitExponential->getIntersectSE(),
  2604.                                  $bestFitExponential->getStdevOfResiduals(),
  2605.                                  $bestFitExponential->getDFResiduals(),
  2606.                                  $bestFitExponential->getSSResiduals()
  2607.                                )
  2608.                         );
  2609.         else {
  2610.             return array$bestFitExponential->getSlope(),
  2611.                           $bestFitExponential->getIntersect()
  2612.                         );
  2613.         }
  2614.     }    //    function LOGEST()
  2615.  
  2616.  
  2617.     /**
  2618.      *    FORECAST
  2619.      *
  2620.      *    Calculates, or predicts, a future value by using existing values. The predicted value is a y-value for a given x-value.
  2621.      *
  2622.      *    @param    float                Value of X for which we want to find Y
  2623.      *    @param    array of mixed        Data Series Y
  2624.      *    @param    array of mixed        Data Series X
  2625.      *    @return    float 
  2626.      */
  2627.     public static function FORECAST($xValue,$yValues,$xValues{
  2628.         $xValue    self::flattenSingleValue($xValue);
  2629.         if (!is_numeric($xValue)) {
  2630.             return self::$_errorCodes['value'];
  2631.         }
  2632.  
  2633.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2634.             return self::$_errorCodes['value'];
  2635.         }
  2636.         $yValueCount count($yValues);
  2637.         $xValueCount count($xValues);
  2638.  
  2639.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2640.             return self::$_errorCodes['na'];
  2641.         elseif ($yValueCount == 1{
  2642.             return self::$_errorCodes['divisionbyzero'];
  2643.         }
  2644.  
  2645.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2646.         return $bestFitLinear->getValueOfYForX($xValue);
  2647.     }    //    function FORECAST()
  2648.  
  2649.  
  2650.     /**
  2651.      *    TREND
  2652.      *
  2653.      *    Returns values along a linear trend
  2654.      *
  2655.      *    @param    array of mixed        Data Series Y
  2656.      *    @param    array of mixed        Data Series X
  2657.      *    @param    array of mixed        Values of X for which we want to find Y
  2658.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2659.      *    @return    array of float
  2660.      */
  2661.     public static function TREND($yValues,$xValues=array(),$newValues=array(),$const=True{
  2662.         $yValues self::flattenArray($yValues);
  2663.         $xValues self::flattenArray($xValues);
  2664.         $newValues self::flattenArray($newValues);
  2665.         $const    (is_null($const))    True :    (boolean) self::flattenSingleValue($const);
  2666.  
  2667.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const);
  2668.         if (count($newValues== 0{
  2669.             $newValues $bestFitLinear->getXValues();
  2670.         }
  2671.  
  2672.         $returnArray array();
  2673.         foreach($newValues as $xValue{
  2674.             $returnArray[0][$bestFitLinear->getValueOfYForX($xValue);
  2675.         }
  2676.  
  2677.         return $returnArray;
  2678.     }    //    function TREND()
  2679.  
  2680.  
  2681.     /**
  2682.      *    GROWTH
  2683.      *
  2684.      *    Returns values along a predicted emponential trend
  2685.      *
  2686.      *    @param    array of mixed        Data Series Y
  2687.      *    @param    array of mixed        Data Series X
  2688.      *    @param    array of mixed        Values of X for which we want to find Y
  2689.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2690.      *    @return    array of float
  2691.      */
  2692.     public static function GROWTH($yValues,$xValues=array(),$newValues=array(),$const=True{
  2693.         $yValues self::flattenArray($yValues);
  2694.         $xValues self::flattenArray($xValues);
  2695.         $newValues self::flattenArray($newValues);
  2696.         $const    (is_null($const))    True :    (boolean) self::flattenSingleValue($const);
  2697.  
  2698.         $bestFitExponential trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const);
  2699.         if (count($newValues== 0{
  2700.             $newValues $bestFitExponential->getXValues();
  2701.         }
  2702.  
  2703.         $returnArray array();
  2704.         foreach($newValues as $xValue{
  2705.             $returnArray[0][$bestFitExponential->getValueOfYForX($xValue);
  2706.         }
  2707.  
  2708.         return $returnArray;
  2709.     }    //    function GROWTH()
  2710.  
  2711.  
  2712.     private static function _romanCut($num$n{
  2713.         return ($num ($num $n ) ) $n;
  2714.     }    //    function _romanCut()
  2715.  
  2716.  
  2717.     public static function ROMAN($aValue$style=0{
  2718.         $aValue    = (integer) self::flattenSingleValue($aValue);
  2719.         $style    (is_null($style))    :    (integer) self::flattenSingleValue($style);
  2720.         if ((!is_numeric($aValue)) || ($aValue 0|| ($aValue >= 4000)) {
  2721.             return self::$_errorCodes['value'];
  2722.         }
  2723.         if ($aValue == 0{
  2724.             return '';
  2725.         }
  2726.  
  2727.         $mill Array('''M''MM''MMM''MMMM''MMMMM');
  2728.         $cent Array('''C''CC''CCC''CD''D''DC''DCC''DCCC''CM');
  2729.         $tens Array('''X''XX''XXX''XL''L''LX''LXX''LXXX''XC');
  2730.         $ones Array('''I''II''III''IV''V''VI''VII''VIII''IX');
  2731.  
  2732.         $roman '';
  2733.         while ($aValue 5999{
  2734.             $roman .= 'M';
  2735.             $aValue -= 1000;
  2736.         }
  2737.         $m self::_romanCut($aValue1000);    $aValue %= 1000;
  2738.         $c self::_romanCut($aValue100);        $aValue %= 100;
  2739.         $t self::_romanCut($aValue10);        $aValue %= 10;
  2740.  
  2741.         return $roman.$mill[$m].$cent[$c].$tens[$t].$ones[$aValue];
  2742.     }    //    function ROMAN()
  2743.  
  2744.  
  2745.     /**
  2746.      *    SUBTOTAL
  2747.      *
  2748.      *    Returns a subtotal in a list or database.
  2749.      *
  2750.      *    @param    int        the number 1 to 11 that specifies which function to
  2751.      *                     use in calculating subtotals within a list.
  2752.      *    @param    array of mixed        Data Series
  2753.      *    @return    float 
  2754.      */
  2755.     public static function SUBTOTAL({
  2756.         $aArgs self::flattenArray(func_get_args());
  2757.  
  2758.         // Calculate
  2759.         $subtotal array_shift($aArgs);
  2760.  
  2761.         if ((is_numeric($subtotal)) && (!is_string($subtotal))) {
  2762.             switch($subtotal{
  2763.                 case 1    :
  2764.                     return self::AVERAGE($aArgs);
  2765.                     break;
  2766.                 case 2    :
  2767.                     return self::COUNT($aArgs);
  2768.                     break;
  2769.                 case 3    :
  2770.                     return self::COUNTA($aArgs);
  2771.                     break;
  2772.                 case 4    :
  2773.                     return self::MAX($aArgs);
  2774.                     break;
  2775.                 case 5    :
  2776.                     return self::MIN($aArgs);
  2777.                     break;
  2778.                 case 6    :
  2779.                     return self::PRODUCT($aArgs);
  2780.                     break;
  2781.                 case 7    :
  2782.                     return self::STDEV($aArgs);
  2783.                     break;
  2784.                 case 8    :
  2785.                     return self::STDEVP($aArgs);
  2786.                     break;
  2787.                 case 9    :
  2788.                     return self::SUM($aArgs);
  2789.                     break;
  2790.                 case 10    :
  2791.                     return self::VARFunc($aArgs);
  2792.                     break;
  2793.                 case 11    :
  2794.                     return self::VARP($aArgs);
  2795.                     break;
  2796.             }
  2797.         }
  2798.         return self::$_errorCodes['value'];
  2799.     }    //    function SUBTOTAL()
  2800.  
  2801.  
  2802.     /**
  2803.      *    SQRTPI
  2804.      *
  2805.      *    Returns the square root of (number * pi).
  2806.      *
  2807.      *    @param    float    $number        Number
  2808.      *    @return    float    Square Root of Number * Pi
  2809.      */
  2810.     public static function SQRTPI($number{
  2811.         $number    self::flattenSingleValue($number);
  2812.  
  2813.         if (is_numeric($number)) {
  2814.             if ($number 0{
  2815.                 return self::$_errorCodes['num'];
  2816.             }
  2817.             return sqrt($number M_PI;
  2818.         }
  2819.         return self::$_errorCodes['value'];
  2820.     }    //    function SQRTPI()
  2821.  
  2822.  
  2823.     /**
  2824.      *    FACT
  2825.      *
  2826.      *    Returns the factorial of a number.
  2827.      *
  2828.      *    @param    float    $factVal    Factorial Value
  2829.      *    @return    int        Factorial
  2830.      */
  2831.     public static function FACT($factVal{
  2832.         $factVal    self::flattenSingleValue($factVal);
  2833.  
  2834.         if (is_numeric($factVal)) {
  2835.             if ($factVal 0{
  2836.                 return self::$_errorCodes['num'];
  2837.             }
  2838.             $factLoop floor($factVal);
  2839.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  2840.                 if ($factVal $factLoop{
  2841.                     return self::$_errorCodes['num'];
  2842.                 }
  2843.             }
  2844.  
  2845.             $factorial 1;
  2846.             while ($factLoop 1{
  2847.                 $factorial *= $factLoop--;
  2848.             }
  2849.             return $factorial ;
  2850.         }
  2851.         return self::$_errorCodes['value'];
  2852.     }    //    function FACT()
  2853.  
  2854.  
  2855.     /**
  2856.      *    FACTDOUBLE
  2857.      *
  2858.      *    Returns the double factorial of a number.
  2859.      *
  2860.      *    @param    float    $factVal    Factorial Value
  2861.      *    @return    int        Double Factorial
  2862.      */
  2863.     public static function FACTDOUBLE($factVal{
  2864.         $factLoop    floor(self::flattenSingleValue($factVal));
  2865.  
  2866.         if (is_numeric($factLoop)) {
  2867.             if ($factVal 0{
  2868.                 return self::$_errorCodes['num'];
  2869.             }
  2870.             $factorial 1;
  2871.             while ($factLoop 1{
  2872.                 $factorial *= $factLoop--;
  2873.                 --$factLoop;
  2874.             }
  2875.             return $factorial ;
  2876.         }
  2877.         return self::$_errorCodes['value'];
  2878.     }    //    function FACTDOUBLE()
  2879.  
  2880.  
  2881.     /**
  2882.      *    MULTINOMIAL
  2883.      *
  2884.      *    Returns the ratio of the factorial of a sum of values to the product of factorials.
  2885.      *
  2886.      *    @param    array of mixed        Data Series
  2887.      *    @return    float 
  2888.      */
  2889.     public static function MULTINOMIAL({
  2890.         // Loop through arguments
  2891.         $aArgs self::flattenArray(func_get_args());
  2892.         $summer 0;
  2893.         $divisor 1;
  2894.         foreach ($aArgs as $arg{
  2895.             // Is it a numeric value?
  2896.             if (is_numeric($arg)) {
  2897.                 if ($arg 1{
  2898.                     return self::$_errorCodes['num'];
  2899.                 }
  2900.                 $summer += floor($arg);
  2901.                 $divisor *= self::FACT($arg);
  2902.             else {
  2903.                 return self::$_errorCodes['value'];
  2904.             }
  2905.         }
  2906.  
  2907.         // Return
  2908.         if ($summer 0{
  2909.             $summer self::FACT($summer);
  2910.             return $summer $divisor;
  2911.         }
  2912.         return 0;
  2913.     }    //    function MULTINOMIAL()
  2914.  
  2915.  
  2916.     /**
  2917.      *    CEILING
  2918.      *
  2919.      *    Returns number rounded up, away from zero, to the nearest multiple of significance.
  2920.      *
  2921.      *    @param    float    $number            Number to round
  2922.      *    @param    float    $significance    Significance
  2923.      *    @return    float    Rounded Number
  2924.      */
  2925.     public static function CEILING($number,$significance=null{
  2926.         $number            self::flattenSingleValue($number);
  2927.         $significance    self::flattenSingleValue($significance);
  2928.  
  2929.         if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  2930.             $significance $number/abs($number);
  2931.         }
  2932.  
  2933.         if ((is_numeric($number)) && (is_numeric($significance))) {
  2934.             if (self::SIGN($number== self::SIGN($significance)) {
  2935.                 if ($significance == 0.0{
  2936.                     return 0;
  2937.                 }
  2938.                 return ceil($number $significance$significance;
  2939.             else {
  2940.                 return self::$_errorCodes['num'];
  2941.             }
  2942.         }
  2943.         return self::$_errorCodes['value'];
  2944.     }    //    function CEILING()
  2945.  
  2946.  
  2947.     /**
  2948.      *    EVEN
  2949.      *
  2950.      *    Returns number rounded up to the nearest even integer.
  2951.      *
  2952.      *    @param    float    $number            Number to round
  2953.      *    @return    int        Rounded Number
  2954.      */
  2955.     public static function EVEN($number{
  2956.         $number    self::flattenSingleValue($number);
  2957.  
  2958.         if (is_numeric($number)) {
  2959.             $significance self::SIGN($number);
  2960.             return self::CEILING($number,$significance);
  2961.         }
  2962.         return self::$_errorCodes['value'];
  2963.     }    //    function EVEN()
  2964.  
  2965.  
  2966.     /**
  2967.      *    ODD
  2968.      *
  2969.      *    Returns number rounded up to the nearest odd integer.
  2970.      *
  2971.      *    @param    float    $number            Number to round
  2972.      *    @return    int        Rounded Number
  2973.      */
  2974.     public static function ODD($number{
  2975.         $number    self::flattenSingleValue($number);
  2976.  
  2977.         if (is_numeric($number)) {
  2978.             $significance self::SIGN($number);
  2979.             if ($significance == 0{
  2980.                 return 1;
  2981.             }
  2982.             $result self::CEILING($number,$significance);
  2983.             if (self::IS_EVEN($result)) {
  2984.                 $result += $significance;
  2985.             }
  2986.             return $result;
  2987.         }
  2988.         return self::$_errorCodes['value'];
  2989.     }    //    function ODD()
  2990.  
  2991.  
  2992.     /**
  2993.      *    INTVALUE
  2994.      *
  2995.      *    Casts a floating point value to an integer
  2996.      *
  2997.      *    @param    float    $number            Number to cast to an integer
  2998.      *    @return    integer    Integer value
  2999.      */
  3000.     public static function INTVALUE($number{
  3001.         $number    self::flattenSingleValue($number);
  3002.  
  3003.         if (is_numeric($number)) {
  3004.             return (int) floor($number);
  3005.         }
  3006.         return self::$_errorCodes['value'];
  3007.     }    //    function INTVALUE()
  3008.  
  3009.  
  3010.     /**
  3011.      *    ROUNDUP
  3012.      *
  3013.      *    Rounds a number up to a specified number of decimal places
  3014.      *
  3015.      *    @param    float    $number            Number to round
  3016.      *    @param    int        $digits            Number of digits to which you want to round $number
  3017.      *    @return    float    Rounded Number
  3018.      */
  3019.     public static function ROUNDUP($number,$digits{
  3020.         $number    self::flattenSingleValue($number);
  3021.         $digits    self::flattenSingleValue($digits);
  3022.  
  3023.         if ((is_numeric($number)) && (is_numeric($digits))) {
  3024.             $significance pow(10,$digits);
  3025.             if ($number 0.0{
  3026.                 return floor($number $significance$significance;
  3027.             else {
  3028.                 return ceil($number $significance$significance;
  3029.             }
  3030.         }
  3031.         return self::$_errorCodes['value'];
  3032.     }    //    function ROUNDUP()
  3033.  
  3034.  
  3035.     /**
  3036.      *    ROUNDDOWN
  3037.      *
  3038.      *    Rounds a number down to a specified number of decimal places
  3039.      *
  3040.      *    @param    float    $number            Number to round
  3041.      *    @param    int        $digits            Number of digits to which you want to round $number
  3042.      *    @return    float    Rounded Number
  3043.      */
  3044.     public static function ROUNDDOWN($number,$digits{
  3045.         $number    self::flattenSingleValue($number);
  3046.         $digits    self::flattenSingleValue($digits);
  3047.  
  3048.         if ((is_numeric($number)) && (is_numeric($digits))) {
  3049.             $significance pow(10,$digits);
  3050.             if ($number 0.0{
  3051.                 return ceil($number $significance$significance;
  3052.             else {
  3053.                 return floor($number $significance$significance;
  3054.             }
  3055.         }
  3056.         return self::$_errorCodes['value'];
  3057.     }    //    function ROUNDDOWN()
  3058.  
  3059.  
  3060.     /**
  3061.      *    MROUND
  3062.      *
  3063.      *    Rounds a number to the nearest multiple of a specified value
  3064.      *
  3065.      *    @param    float    $number            Number to round
  3066.      *    @param    int        $multiple        Multiple to which you want to round $number
  3067.      *    @return    float    Rounded Number
  3068.      */
  3069.     public static function MROUND($number,$multiple{
  3070.         $number        self::flattenSingleValue($number);
  3071.         $multiple    self::flattenSingleValue($multiple);
  3072.  
  3073.         if ((is_numeric($number)) && (is_numeric($multiple))) {
  3074.             if ($multiple == 0{
  3075.                 return 0;
  3076.             }
  3077.             if ((self::SIGN($number)) == (self::SIGN($multiple))) {
  3078.                 $multiplier $multiple;
  3079.                 return round($number $multiplier$multiplier;
  3080.             }
  3081.             return self::$_errorCodes['num'];
  3082.         }
  3083.         return self::$_errorCodes['value'];
  3084.     }    //    function MROUND()
  3085.  
  3086.  
  3087.     /**
  3088.      *    SIGN
  3089.      *
  3090.      *    Determines the sign of a number. Returns 1 if the number is positive, zero (0)
  3091.      *    if the number is 0, and -1 if the number is negative.
  3092.      *
  3093.      *    @param    float    $number            Number to round
  3094.      *    @return    int        sign value
  3095.      */
  3096.     public static function SIGN($number{
  3097.         $number    self::flattenSingleValue($number);
  3098.  
  3099.         if (is_numeric($number)) {
  3100.             if ($number == 0.0{
  3101.                 return 0;
  3102.             }
  3103.             return $number abs($number);
  3104.         }
  3105.         return self::$_errorCodes['value'];
  3106.     }    //    function SIGN()
  3107.  
  3108.  
  3109.     /**
  3110.      *    FLOOR
  3111.      *
  3112.      *    Rounds number down, toward zero, to the nearest multiple of significance.
  3113.      *
  3114.      *    @param    float    $number            Number to round
  3115.      *    @param    float    $significance    Significance
  3116.      *    @return    float    Rounded Number
  3117.      */
  3118.     public static function FLOOR($number,$significance=null{
  3119.         $number            self::flattenSingleValue($number);
  3120.         $significance    self::flattenSingleValue($significance);
  3121.  
  3122.         if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  3123.             $significance $number/abs($number);
  3124.         }
  3125.  
  3126.         if ((is_numeric($number)) && (is_numeric($significance))) {
  3127.             if ((float) $significance == 0.0{
  3128.                 return self::$_errorCodes['divisionbyzero'];
  3129.             }
  3130.             if (self::SIGN($number== self::SIGN($significance)) {
  3131.                 return floor($number $significance$significance;
  3132.             else {
  3133.                 return self::$_errorCodes['num'];
  3134.             }
  3135.         }
  3136.         return self::$_errorCodes['value'];
  3137.     }    //    function FLOOR()
  3138.  
  3139.  
  3140.     /**
  3141.      *    PERMUT
  3142.      *
  3143.      *    Returns the number of permutations for a given number of objects that can be
  3144.      *    selected from number objects. A permutation is any set or subset of objects or
  3145.      *    events where internal order is significant. Permutations are different from
  3146.      *    combinations, for which the internal order is not significant. Use this function
  3147.      *    for lottery-style probability calculations.
  3148.      *
  3149.      *    @param    int        $numObjs    Number of different objects
  3150.      *    @param    int        $numInSet    Number of objects in each permutation
  3151.      *    @return    int        Number of permutations
  3152.      */
  3153.     public static function PERMUT($numObjs,$numInSet{
  3154.         $numObjs    self::flattenSingleValue($numObjs);
  3155.         $numInSet    self::flattenSingleValue($numInSet);
  3156.  
  3157.         if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
  3158.             $numInSet floor($numInSet);
  3159.             if ($numObjs $numInSet{
  3160.                 return self::$_errorCodes['num'];
  3161.             }
  3162.             return round(self::FACT($numObjsself::FACT($numObjs $numInSet));
  3163.         }
  3164.         return self::$_errorCodes['value'];
  3165.     }    //    function PERMUT()
  3166.  
  3167.  
  3168.     /**
  3169.      *    COMBIN
  3170.      *
  3171.      *    Returns the number of combinations for a given number of items. Use COMBIN to
  3172.      *    determine the total possible number of groups for a given number of items.
  3173.      *
  3174.      *    @param    int        $numObjs    Number of different objects
  3175.      *    @param    int        $numInSet    Number of objects in each combination
  3176.      *    @return    int        Number of combinations
  3177.      */
  3178.     public static function COMBIN($numObjs,$numInSet{
  3179.         $numObjs    self::flattenSingleValue($numObjs);
  3180.         $numInSet    self::flattenSingleValue($numInSet);
  3181.  
  3182.         if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
  3183.             if ($numObjs $numInSet{
  3184.                 return self::$_errorCodes['num'];
  3185.             elseif ($numInSet 0{
  3186.                 return self::$_errorCodes['num'];
  3187.             }
  3188.             return round(self::FACT($numObjsself::FACT($numObjs $numInSet)) self::FACT($numInSet);
  3189.         }
  3190.         return self::$_errorCodes['value'];
  3191.     }    //    function COMBIN()
  3192.  
  3193.  
  3194.     /**
  3195.      *    SERIESSUM
  3196.      *
  3197.      *    Returns the sum of a power series
  3198.      *
  3199.      *    @param    float            $x    Input value to the power series
  3200.      *    @param    float            $n    Initial power to which you want to raise $x
  3201.      *    @param    float            $m    Step by which to increase $n for each term in the series
  3202.      *    @param    array of mixed        Data Series
  3203.      *    @return    float 
  3204.      */
  3205.     public static function SERIESSUM({
  3206.         // Return value
  3207.         $returnValue 0;
  3208.  
  3209.         // Loop through arguments
  3210.         $aArgs self::flattenArray(func_get_args());
  3211.  
  3212.         $x array_shift($aArgs);
  3213.         $n array_shift($aArgs);
  3214.         $m array_shift($aArgs);
  3215.  
  3216.         if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) {
  3217.             // Calculate
  3218.             $i 0;
  3219.             foreach($aArgs as $arg{
  3220.                 // Is it a numeric value?
  3221.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  3222.                     $returnValue += $arg pow($x,$n ($m $i++));
  3223.                 else {
  3224.                     return self::$_errorCodes['value'];
  3225.                 }
  3226.             }
  3227.             // Return
  3228.             return $returnValue;
  3229.         }
  3230.         return self::$_errorCodes['value'];
  3231.     }    //    function SERIESSUM()
  3232.  
  3233.  
  3234.     /**
  3235.      *    STANDARDIZE
  3236.      *
  3237.      *    Returns a normalized value from a distribution characterized by mean and standard_dev.
  3238.      *
  3239.      *    @param    float    $value        Value to normalize
  3240.      *    @param    float    $mean        Mean Value
  3241.      *    @param    float    $stdDev        Standard Deviation
  3242.      *    @return    float    Standardized value
  3243.      */
  3244.     public static function STANDARDIZE($value,$mean,$stdDev{
  3245.         $value    self::flattenSingleValue($value);
  3246.         $mean    self::flattenSingleValue($mean);
  3247.         $stdDev    self::flattenSingleValue($stdDev);
  3248.  
  3249.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  3250.             if ($stdDev <= 0{
  3251.                 return self::$_errorCodes['num'];
  3252.             }
  3253.             return ($value $mean$stdDev ;
  3254.         }
  3255.         return self::$_errorCodes['value'];
  3256.     }    //    function STANDARDIZE()
  3257.  
  3258.  
  3259.     //
  3260.     //    Private method to return an array of the factors of the input value
  3261.     //
  3262.     private static function _factors($value{
  3263.         $startVal floor(sqrt($value));
  3264.  
  3265.         $factorArray array();
  3266.         for ($i $startVal$i 1--$i{
  3267.             if (($value $i== 0{
  3268.                 $factorArray array_merge($factorArray,self::_factors($value $i));
  3269.                 $factorArray array_merge($factorArray,self::_factors($i));
  3270.                 if ($i <= sqrt($value)) {
  3271.                     break;
  3272.                 }
  3273.             }
  3274.         }
  3275.         if (count($factorArray0{
  3276.             rsort($factorArray);
  3277.             return $factorArray;
  3278.         else {
  3279.             return array((integer) $value);
  3280.         }
  3281.     }    //    function _factors()
  3282.  
  3283.  
  3284.     /**
  3285.      *    LCM
  3286.      *
  3287.      *    Returns the lowest common multiplier of a series of numbers
  3288.      *
  3289.      *    @param    $array    Values to calculate the Lowest Common Multiplier
  3290.      *    @return    int        Lowest Common Multiplier
  3291.      */
  3292.     public static function LCM({
  3293.         $aArgs self::flattenArray(func_get_args());
  3294.  
  3295.         $returnValue 1;
  3296.         $allPoweredFactors array();
  3297.         foreach($aArgs as $value{
  3298.             if (!is_numeric($value)) {
  3299.                 return self::$_errorCodes['value'];
  3300.             }
  3301.             if ($value == 0{
  3302.                 return 0;
  3303.             elseif ($value 0{
  3304.                 return self::$_errorCodes['num'];
  3305.             }
  3306.             $myFactors self::_factors(floor($value));
  3307.             $myCountedFactors array_count_values($myFactors);
  3308.             $myPoweredFactors array();
  3309.             foreach($myCountedFactors as $myCountedFactor => $myCountedPower{
  3310.                 $myPoweredFactors[$myCountedFactorpow($myCountedFactor,$myCountedPower);
  3311.             }
  3312.             foreach($myPoweredFactors as $myPoweredValue => $myPoweredFactor{
  3313.                 if (array_key_exists($myPoweredValue,$allPoweredFactors)) {
  3314.                     if ($allPoweredFactors[$myPoweredValue$myPoweredFactor{
  3315.                         $allPoweredFactors[$myPoweredValue$myPoweredFactor;
  3316.                     }
  3317.                 else {
  3318.                     $allPoweredFactors[$myPoweredValue$myPoweredFactor;
  3319.                 }
  3320.             }
  3321.         }
  3322.         foreach($allPoweredFactors as $allPoweredFactor{
  3323.             $returnValue *= (integer) $allPoweredFactor;
  3324.         }
  3325.         return $returnValue;
  3326.     }    //    function LCM()
  3327.  
  3328.  
  3329.     /**
  3330.      *    GCD
  3331.      *
  3332.      *    Returns the greatest common divisor of a series of numbers
  3333.      *
  3334.      *    @param    $array    Values to calculate the Greatest Common Divisor
  3335.      *    @return    int        Greatest Common Divisor
  3336.      */
  3337.     public static function GCD({
  3338.         $aArgs self::flattenArray(func_get_args());
  3339.  
  3340.         $returnValue 1;
  3341.         $allPoweredFactors array();
  3342.         foreach($aArgs as $value{
  3343.             if ($value == 0{
  3344.                 break;
  3345.             }
  3346.             $myFactors self::_factors($value);
  3347.             $myCountedFactors array_count_values($myFactors);
  3348.             $allValuesFactors[$myCountedFactors;
  3349.         }
  3350.         $allValuesCount count($allValuesFactors);
  3351.         $mergedArray $allValuesFactors[0];
  3352.         for ($i=1;$i $allValuesCount++$i{
  3353.             $mergedArray array_intersect_key($mergedArray,$allValuesFactors[$i]);
  3354.         }
  3355.         $mergedArrayValues count($mergedArray);
  3356.         if ($mergedArrayValues == 0{
  3357.             return $returnValue;
  3358.         elseif ($mergedArrayValues 1{
  3359.             foreach($mergedArray as $mergedKey => $mergedValue{
  3360.                 foreach($allValuesFactors as $highestPowerTest{
  3361.                     foreach($highestPowerTest as $testKey => $testValue{
  3362.                         if (($testKey == $mergedKey&& ($testValue $mergedValue)) {
  3363.                             $mergedArray[$mergedKey$testValue;
  3364.                             $mergedValue $testValue;
  3365.                         }
  3366.                     }
  3367.                 }
  3368.             }
  3369.  
  3370.             $returnValue 1;
  3371.             foreach($mergedArray as $key => $value{
  3372.                 $returnValue *= pow($key,$value);
  3373.             }
  3374.             return $returnValue;
  3375.         else {
  3376.             $keys array_keys($mergedArray);
  3377.             $key $keys[0];
  3378.             $value $mergedArray[$key];
  3379.             foreach($allValuesFactors as $testValue{
  3380.                 foreach($testValue as $mergedKey => $mergedValue{
  3381.                     if (($mergedKey == $key&& ($mergedValue $value)) {
  3382.                         $value $mergedValue;
  3383.                     }
  3384.                 }
  3385.             }
  3386.             return pow($key,$value);
  3387.         }
  3388.     }    //    function GCD()
  3389.  
  3390.  
  3391.     /**
  3392.      *    BINOMDIST
  3393.      *
  3394.      *    Returns the individual term binomial distribution probability. Use BINOMDIST in problems with
  3395.      *    a fixed number of tests or trials, when the outcomes of any trial are only success or failure,
  3396.      *    when trials are independent, and when the probability of success is constant throughout the
  3397.      *    experiment. For example, BINOMDIST can calculate the probability that two of the next three
  3398.      *    babies born are male.
  3399.      *
  3400.      *    @param    float        $value            Number of successes in trials
  3401.      *    @param    float        $trials            Number of trials
  3402.      *    @param    float        $probability    Probability of success on each trial
  3403.      *    @param    boolean        $cumulative 
  3404.      *    @return    float 
  3405.      *
  3406.      *    @todo    Cumulative distribution function
  3407.      *
  3408.      */
  3409.     public static function BINOMDIST($value$trials$probability$cumulative{
  3410.         $value            floor(self::flattenSingleValue($value));
  3411.         $trials            floor(self::flattenSingleValue($trials));
  3412.         $probability    self::flattenSingleValue($probability);
  3413.  
  3414.         if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) {
  3415.             if (($value 0|| ($value $trials)) {
  3416.                 return self::$_errorCodes['num'];
  3417.             }
  3418.             if (($probability 0|| ($probability 1)) {
  3419.                 return self::$_errorCodes['num'];
  3420.             }
  3421.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  3422.                 if ($cumulative{
  3423.                     $summer 0;
  3424.                     for ($i 0$i <= $value++$i{
  3425.                         $summer += self::COMBIN($trials,$ipow($probability,$ipow($probability,$trials $i);
  3426.                     }
  3427.                     return $summer;
  3428.                 else {
  3429.                     return self::COMBIN($trials,$valuepow($probability,$valuepow($probability,$trials $value;
  3430.                 }
  3431.             }
  3432.         }
  3433.         return self::$_errorCodes['value'];
  3434.     }    //    function BINOMDIST()
  3435.  
  3436.  
  3437.     /**
  3438.      *    NEGBINOMDIST
  3439.      *
  3440.      *    Returns the negative binomial distribution. NEGBINOMDIST returns the probability that
  3441.      *    there will be number_f failures before the number_s-th success, when the constant
  3442.      *    probability of a success is probability_s. This function is similar to the binomial
  3443.      *    distribution, except that the number of successes is fixed, and the number of trials is
  3444.      *    variable. Like the binomial, trials are assumed to be independent.
  3445.      *
  3446.      *    @param    float        $failures        Number of Failures
  3447.      *    @param    float        $successes        Threshold number of Successes
  3448.      *    @param    float        $probability    Probability of success on each trial
  3449.      *    @return    float 
  3450.      *
  3451.      */
  3452.     public static function NEGBINOMDIST($failures$successes$probability{
  3453.         $failures        floor(self::flattenSingleValue($failures));
  3454.         $successes        floor(self::flattenSingleValue($successes));
  3455.         $probability    self::flattenSingleValue($probability);
  3456.  
  3457.         if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) {
  3458.             if (($failures 0|| ($successes 1)) {
  3459.                 return self::$_errorCodes['num'];
  3460.             }
  3461.             if (($probability 0|| ($probability 1)) {
  3462.                 return self::$_errorCodes['num'];
  3463.             }
  3464.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  3465.                 if (($failures $successes 1<= 0{
  3466.                     return self::$_errorCodes['num'];
  3467.                 }
  3468.             }
  3469.             return (self::COMBIN($failures $successes 1,$successes 1)) (pow($probability,$successes)) (pow($probability,$failures)) ;
  3470.         }
  3471.         return self::$_errorCodes['value'];
  3472.     }    //    function NEGBINOMDIST()
  3473.  
  3474.  
  3475.     /**
  3476.      *    CRITBINOM
  3477.      *
  3478.      *    Returns the smallest value for which the cumulative binomial distribution is greater
  3479.      *    than or equal to a criterion value
  3480.      *
  3481.      *    See http://support.microsoft.com/kb/828117/ for details of the algorithm used
  3482.      *
  3483.      *    @param    float        $trials            number of Bernoulli trials
  3484.      *    @param    float        $probability    probability of a success on each trial
  3485.      *    @param    float        $alpha            criterion value
  3486.      *    @return    int 
  3487.      *
  3488.      *    @todo    Warning. This implementation differs from the algorithm detailed on the MS
  3489.      *             web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess
  3490.      *             This eliminates a potential endless loop error, but may have an adverse affect on the
  3491.      *             accuracy of the function (although all my tests have so far returned correct results).
  3492.      *
  3493.      */
  3494.     public static function CRITBINOM($trials$probability$alpha{
  3495.         $trials            floor(self::flattenSingleValue($trials));
  3496.         $probability    self::flattenSingleValue($probability);
  3497.         $alpha            self::flattenSingleValue($alpha);
  3498.  
  3499.         if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) {
  3500.             if ($trials 0{
  3501.                 return self::$_errorCodes['num'];
  3502.             }
  3503.             if (($probability 0|| ($probability 1)) {
  3504.                 return self::$_errorCodes['num'];
  3505.             }
  3506.             if (($alpha 0|| ($alpha 1)) {
  3507.                 return self::$_errorCodes['num'];
  3508.             }
  3509.             if ($alpha <= 0.5{
  3510.                 $t sqrt(log(($alpha $alpha)));
  3511.                 $trialsApprox ($t (2.515517 0.802853 $t 0.010328 $t $t(1.432788 $t 0.189269 $t $t 0.001308 $t $t $t));
  3512.             else {
  3513.                 $t sqrt(log(pow($alpha,2)));
  3514.                 $trialsApprox $t (2.515517 0.802853 $t 0.010328 $t $t(1.432788 $t 0.189269 $t $t 0.001308 $t $t $t);
  3515.             }
  3516.             $Guess floor($trials $probability $trialsApprox sqrt($trials $probability ($probability)));
  3517.             if ($Guess 0{
  3518.                 $Guess 0;
  3519.             elseif ($Guess $trials{
  3520.                 $Guess $trials;
  3521.             }
  3522.  
  3523.             $TotalUnscaledProbability $UnscaledPGuess $UnscaledCumPGuess 0.0;
  3524.             $EssentiallyZero 10e-12;
  3525.  
  3526.             $m floor($trials $probability);
  3527.             ++$TotalUnscaledProbability;
  3528.             if ($m == $Guess++$UnscaledPGuess}
  3529.             if ($m <= $Guess++$UnscaledCumPGuess}
  3530.  
  3531.             $PreviousValue 1;
  3532.             $Done False;
  3533.             $k $m 1;
  3534.             while ((!$Done&& ($k <= $trials)) {
  3535.                 $CurrentValue $PreviousValue ($trials $k 1$probability ($k ($probability));
  3536.                 $TotalUnscaledProbability += $CurrentValue;
  3537.                 if ($k == $Guess$UnscaledPGuess += $CurrentValue}
  3538.                 if ($k <= $Guess$UnscaledCumPGuess += $CurrentValue}
  3539.                 if ($CurrentValue <= $EssentiallyZero$Done True}
  3540.                 $PreviousValue $CurrentValue;
  3541.                 ++$k;
  3542.             }
  3543.  
  3544.             $PreviousValue 1;
  3545.             $Done False;
  3546.             $k $m 1;
  3547.             while ((!$Done&& ($k >= 0)) {
  3548.                 $CurrentValue $PreviousValue $k ($probability(($trials $k$probability);
  3549.                 $TotalUnscaledProbability += $CurrentValue;
  3550.                 if ($k == $Guess$UnscaledPGuess += $CurrentValue}
  3551.                 if ($k <= $Guess$UnscaledCumPGuess += $CurrentValue}
  3552.                 if ($CurrentValue <= $EssentiallyZero$Done True}
  3553.                 $PreviousValue $CurrentValue;
  3554.                 --$k;
  3555.             }
  3556.  
  3557.             $PGuess $UnscaledPGuess $TotalUnscaledProbability;
  3558.             $CumPGuess $UnscaledCumPGuess $TotalUnscaledProbability;
  3559.  
  3560. //            $CumPGuessMinus1 = $CumPGuess - $PGuess;
  3561.             $CumPGuessMinus1 $CumPGuess 1;
  3562.  
  3563.             while (True{
  3564.                 if (($CumPGuessMinus1 $alpha&& ($CumPGuess >= $alpha)) {
  3565.                     return $Guess;
  3566.                 elseif (($CumPGuessMinus1 $alpha&& ($CumPGuess $alpha)) {
  3567.                     $PGuessPlus1 $PGuess ($trials $Guess$probability $Guess ($probability);
  3568.                     $CumPGuessMinus1 $CumPGuess;
  3569.                     $CumPGuess $CumPGuess $PGuessPlus1;
  3570.                     $PGuess $PGuessPlus1;
  3571.                     ++$Guess;
  3572.                 elseif (($CumPGuessMinus1 >= $alpha&& ($CumPGuess >= $alpha)) {
  3573.                     $PGuessMinus1 $PGuess $Guess ($probability($trials $Guess 1$probability;
  3574.                     $CumPGuess $CumPGuessMinus1;
  3575.                     $CumPGuessMinus1 $CumPGuessMinus1 $PGuess;
  3576.                     $PGuess $PGuessMinus1;
  3577.                     --$Guess;
  3578.                 }
  3579.             }
  3580.         }
  3581.         return self::$_errorCodes['value'];
  3582.     }    //    function CRITBINOM()
  3583.  
  3584.  
  3585.     /**
  3586.      *    CHIDIST
  3587.      *
  3588.      *    Returns the one-tailed probability of the chi-squared distribution.
  3589.      *
  3590.      *    @param    float        $value            Value for the function
  3591.      *    @param    float        $degrees        degrees of freedom
  3592.      *    @return    float 
  3593.      */
  3594.     public static function CHIDIST($value$degrees{
  3595.         $value        self::flattenSingleValue($value);
  3596.         $degrees    floor(self::flattenSingleValue($degrees));
  3597.  
  3598.         if ((is_numeric($value)) && (is_numeric($degrees))) {
  3599.             if ($degrees 1{
  3600.                 return self::$_errorCodes['num'];
  3601.             }
  3602.             if ($value 0{
  3603.                 if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  3604.                     return 1;
  3605.                 }
  3606.                 return self::$_errorCodes['num'];
  3607.             }
  3608.             return (self::_incompleteGamma($degrees/2,$value/2self::_gamma($degrees/2));
  3609.         }
  3610.         return self::$_errorCodes['value'];
  3611.     }    //    function CHIDIST()
  3612.  
  3613.  
  3614.     /**
  3615.      *    CHIINV
  3616.      *
  3617.      *    Returns the one-tailed probability of the chi-squared distribution.
  3618.      *
  3619.      *    @param    float        $probability    Probability for the function
  3620.      *    @param    float        $degrees        degrees of freedom
  3621.      *    @return    float 
  3622.      */
  3623.     public static function CHIINV($probability$degrees{
  3624.         $probability    self::flattenSingleValue($probability);
  3625.         $degrees        floor(self::flattenSingleValue($degrees));
  3626.  
  3627.         if ((is_numeric($probability)) && (is_numeric($degrees))) {
  3628.  
  3629.             $xLo 100;
  3630.             $xHi 0;
  3631.  
  3632.             $x $xNew 1;
  3633.             $dx    1;
  3634.             $i 0;
  3635.  
  3636.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  3637.                 // Apply Newton-Raphson step
  3638.                 $result self::CHIDIST($x$degrees);
  3639.                 $error $result $probability;
  3640.                 if ($error == 0.0{
  3641.                     $dx 0;
  3642.                 elseif ($error 0.0{
  3643.                     $xLo $x;
  3644.                 else {
  3645.                     $xHi $x;
  3646.                 }
  3647.                 // Avoid division by zero
  3648.                 if ($result != 0.0{
  3649.                     $dx $error $result;
  3650.                     $xNew $x $dx;
  3651.                 }
  3652.                 // If the NR fails to converge (which for example may be the
  3653.                 // case if the initial guess is too rough) we apply a bisection
  3654.                 // step to determine a more narrow interval around the root.
  3655.                 if (($xNew $xLo|| ($xNew $xHi|| ($result == 0.0)) {
  3656.                     $xNew ($xLo $xHi2;
  3657.                     $dx $xNew $x;
  3658.                 }
  3659.                 $x $xNew;
  3660.             }
  3661.             if ($i == MAX_ITERATIONS{
  3662.                 return self::$_errorCodes['na'];
  3663.             }
  3664.             return round($x,12);
  3665.         }
  3666.         return self::$_errorCodes['value'];
  3667.     }    //    function CHIINV()
  3668.  
  3669.  
  3670.     /**
  3671.      *    EXPONDIST
  3672.      *
  3673.      *    Returns the exponential distribution. Use EXPONDIST to model the time between events,
  3674.      *    such as how long an automated bank teller takes to deliver cash. For example, you can
  3675.      *    use EXPONDIST to determine the probability that the process takes at most 1 minute.
  3676.      *
  3677.      *    @param    float        $value            Value of the function
  3678.      *    @param    float        $lambda            The parameter value
  3679.      *    @param    boolean        $cumulative 
  3680.      *    @return    float 
  3681.      */
  3682.     public static function EXPONDIST($value$lambda$cumulative{
  3683.         $value    self::flattenSingleValue($value);
  3684.         $lambda    self::flattenSingleValue($lambda);
  3685.         $cumulative    self::flattenSingleValue($cumulative);
  3686.  
  3687.         if ((is_numeric($value)) && (is_numeric($lambda))) {
  3688.             if (($value 0|| ($lambda 0)) {
  3689.                 return self::$_errorCodes['num'];
  3690.             }
  3691.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  3692.                 if ($cumulative{
  3693.                     return exp(0-$value*$lambda);
  3694.                 else {
  3695.                     return $lambda exp(0-$value*$lambda);
  3696.                 }
  3697.             }
  3698.         }
  3699.         return self::$_errorCodes['value'];
  3700.     }    //    function EXPONDIST()
  3701.  
  3702.  
  3703.     /**
  3704.      *    FISHER
  3705.      *
  3706.      *    Returns the Fisher transformation at x. This transformation produces a function that
  3707.      *    is normally distributed rather than skewed. Use this function to perform hypothesis
  3708.      *    testing on the correlation coefficient.
  3709.      *
  3710.      *    @param    float        $value 
  3711.      *    @return    float 
  3712.      */
  3713.     public static function FISHER($value{
  3714.         $value    self::flattenSingleValue($value);
  3715.  
  3716.         if (is_numeric($value)) {
  3717.             if (($value <= -1|| ($value >= 1)) {
  3718.                 return self::$_errorCodes['num'];
  3719.             }
  3720.             return 0.5 log((1+$value)/(1-$value));
  3721.         }
  3722.         return self::$_errorCodes['value'];
  3723.     }    //    function FISHER()
  3724.  
  3725.  
  3726.     /**
  3727.      *    FISHERINV
  3728.      *
  3729.      *    Returns the inverse of the Fisher transformation. Use this transformation when
  3730.      *    analyzing correlations between ranges or arrays of data. If y = FISHER(x), then
  3731.      *    FISHERINV(y) = x.
  3732.      *
  3733.      *    @param    float        $value 
  3734.      *    @return    float 
  3735.      */
  3736.     public static function FISHERINV($value{
  3737.         $value    self::flattenSingleValue($value);
  3738.  
  3739.         if (is_numeric($value)) {
  3740.             return (exp($value1(exp($value1);
  3741.         }
  3742.         return self::$_errorCodes['value'];
  3743.     }    //    function FISHERINV()
  3744.  
  3745.  
  3746.     // Function cache for _logBeta function
  3747.     private static $_logBetaCache_p            0.0;
  3748.     private static $_logBetaCache_q            0.0;
  3749.     private static $_logBetaCache_result    0.0;
  3750.  
  3751.     /**
  3752.      *    The natural logarithm of the beta function.
  3753.      *    @param require p>0
  3754.      *    @param require q>0
  3755.      *    @return if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
  3756.      *    @author Jaco van Kooten
  3757.      */
  3758.     private static function _logBeta($p$q{
  3759.         if ($p != self::$_logBetaCache_p || $q != self::$_logBetaCache_q{
  3760.             self::$_logBetaCache_p $p;
  3761.             self::$_logBetaCache_q $q;
  3762.             if (($p <= 0.0|| ($q <= 0.0|| (($p $qLOG_GAMMA_X_MAX_VALUE)) {
  3763.                 self::$_logBetaCache_result 0.0;
  3764.             else {
  3765.                 self::$_logBetaCache_result self::_logGamma($pself::_logGamma($qself::_logGamma($p $q);
  3766.             }
  3767.         }
  3768.         return self::$_logBetaCache_result;
  3769.     }    //    function _logBeta()
  3770.  
  3771.  
  3772.     /**
  3773.      *    Evaluates of continued fraction part of incomplete beta function.
  3774.      *    Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
  3775.      *    @author Jaco van Kooten
  3776.      */
  3777.     private static function _betaFraction($x$p$q{
  3778.         $c 1.0;
  3779.         $sum_pq $p $q;
  3780.         $p_plus $p 1.0;
  3781.         $p_minus $p 1.0;
  3782.         $h 1.0 $sum_pq $x $p_plus;
  3783.         if (abs($hXMININ{
  3784.             $h XMININ;
  3785.         }
  3786.         $h 1.0 $h;
  3787.         $frac $h;
  3788.         $m     1;
  3789.         $delta 0.0;
  3790.         while ($m <= MAX_ITERATIONS && abs($delta-1.0PRECISION {
  3791.             $m2 $m;
  3792.             // even index for d
  3793.             $d $m ($q $m$x ( ($p_minus $m2($p $m2));
  3794.             $h 1.0 $d $h;
  3795.             if (abs($hXMININ{
  3796.                 $h XMININ;
  3797.             }
  3798.             $h 1.0 $h;
  3799.             $c 1.0 $d $c;
  3800.             if (abs($cXMININ{
  3801.                 $c XMININ;
  3802.             }
  3803.             $frac *= $h $c;
  3804.             // odd index for d
  3805.             $d = -($p $m($sum_pq $m$x (($p $m2($p_plus $m2));
  3806.             $h 1.0 $d $h;
  3807.             if (abs($hXMININ{
  3808.                 $h XMININ;
  3809.             }
  3810.             $h 1.0 $h;
  3811.             $c 1.0 $d $c;
  3812.             if (abs($cXMININ{
  3813.                 $c XMININ;
  3814.             }
  3815.             $delta $h $c;
  3816.             $frac *= $delta;
  3817.             ++$m;
  3818.         }
  3819.         return $frac;
  3820.     }    //    function _betaFraction()
  3821.  
  3822.  
  3823.     /**
  3824.      * logGamma function
  3825.      *
  3826.      * @version 1.1
  3827.      * @author Jaco van Kooten
  3828.      *
  3829.      *  Original author was Jaco van Kooten. Ported to PHP by Paul Meagher.
  3830.      *
  3831.      *  The natural logarithm of the gamma function. <br />
  3832.      *  Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz <br />
  3833.      *  Applied Mathematics Division <br />
  3834.      *  Argonne National Laboratory <br />
  3835.      *  Argonne, IL 60439 <br />
  3836.      *  <p>
  3837.      *  References:
  3838.      *  <ol>
  3839.      *  <li>W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural
  3840.      *      Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.</li>
  3841.      *  <li>K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.</li>
  3842.      *  <li>Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.</li>
  3843.      *  </ol>
  3844.      *  </p>
  3845.      *  <p>
  3846.      *  From the original documentation:
  3847.      *  </p>
  3848.      *  <p>
  3849.      *  This routine calculates the LOG(GAMMA) function for a positive real argument X.
  3850.      *  Computation is based on an algorithm outlined in references 1 and 2.
  3851.      *  The program uses rational functions that theoretically approximate LOG(GAMMA)
  3852.      *  to at least 18 significant decimal digits. The approximation for X > 12 is from
  3853.      *  reference 3, while approximations for X < 12.0 are similar to those in reference
  3854.      *  1, but are unpublished. The accuracy achieved depends on the arithmetic system,
  3855.      *  the compiler, the intrinsic functions, and proper selection of the
  3856.      *  machine-dependent constants.
  3857.      *  </p>
  3858.      *  <p>
  3859.      *  Error returns: <br />
  3860.      *  The program returns the value XINF for X .LE. 0.0 or when overflow would occur.
  3861.      *  The computation is believed to be free of underflow and overflow.
  3862.      *  </p>
  3863.      * @return MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305
  3864.      */
  3865.  
  3866.     // Function cache for logGamma
  3867.     private static $_logGammaCache_result    0.0;
  3868.     private static $_logGammaCache_x        0.0;
  3869.  
  3870.     private static function _logGamma($x{
  3871.         // Log Gamma related constants
  3872.         static $lg_d1 = -0.5772156649015328605195174;
  3873.         static $lg_d2 0.4227843350984671393993777;
  3874.         static $lg_d4 1.791759469228055000094023;
  3875.  
  3876.         static $lg_p1 array(    4.945235359296727046734888,
  3877.                                 201.8112620856775083915565,
  3878.                                 2290.838373831346393026739,
  3879.                                 11319.67205903380828685045,
  3880.                                 28557.24635671635335736389,
  3881.                                 38484.96228443793359990269,
  3882.                                 26377.48787624195437963534,
  3883.                                 7225.813979700288197698961 );
  3884.         static $lg_p2 array(    4.974607845568932035012064,
  3885.                                 542.4138599891070494101986,
  3886.                                 15506.93864978364947665077,
  3887.                                 184793.2904445632425417223,
  3888.                                 1088204.76946882876749847,
  3889.                                 3338152.967987029735917223,
  3890.                                 5106661.678927352456275255,
  3891.                                 3074109.054850539556250927 );
  3892.         static $lg_p4 array(    14745.02166059939948905062,
  3893.                                 2426813.369486704502836312,
  3894.                                 121475557.4045093227939592,
  3895.                                 2663432449.630976949898078,
  3896.                                 29403789566.34553899906876,
  3897.                                 170266573776.5398868392998,
  3898.                                 492612579337.743088758812,
  3899.                                 560625185622.3951465078242 );
  3900.  
  3901.         static $lg_q1 array(    67.48212550303777196073036,
  3902.                                 1113.332393857199323513008,
  3903.                                 7738.757056935398733233834,
  3904.                                 27639.87074403340708898585,
  3905.                                 54993.10206226157329794414,
  3906.                                 61611.22180066002127833352,
  3907.                                 36351.27591501940507276287,
  3908.                                 8785.536302431013170870835 );
  3909.         static $lg_q2 array(    183.0328399370592604055942,
  3910.                                 7765.049321445005871323047,
  3911.                                 133190.3827966074194402448,
  3912.                                 1136705.821321969608938755,
  3913.                                 5267964.117437946917577538,
  3914.                                 13467014.54311101692290052,
  3915.                                 17827365.30353274213975932,
  3916.                                 9533095.591844353613395747 );
  3917.         static $lg_q4 array(    2690.530175870899333379843,
  3918.                                 639388.5654300092398984238,
  3919.                                 41355999.30241388052042842,
  3920.                                 1120872109.61614794137657,
  3921.                                 14886137286.78813811542398,
  3922.                                 101680358627.2438228077304,
  3923.                                 341747634550.7377132798597,
  3924.                                 446315818741.9713286462081 );
  3925.  
  3926.         static $lg_c  array(    -0.001910444077728,
  3927.                                 8.4171387781295e-4,
  3928.                                 -5.952379913043012e-4,
  3929.                                 7.93650793500350248e-4,
  3930.                                 -0.002777777777777681622553,
  3931.                                 0.08333333333333333331554247,
  3932.                                 0.0057083835261 );
  3933.  
  3934.     // Rough estimate of the fourth root of logGamma_xBig
  3935.     static $lg_frtbig 2.25e76;
  3936.     static $pnt68     0.6796875;
  3937.  
  3938.  
  3939.     if ($x == self::$_logGammaCache_x{
  3940.         return self::$_logGammaCache_result;
  3941.     }
  3942.     $y $x;
  3943.     if ($y 0.0 && $y <= LOG_GAMMA_X_MAX_VALUE{
  3944.         if ($y <= EPS{
  3945.             $res = -log(y);
  3946.         elseif ($y <= 1.5{
  3947.             // ---------------------
  3948.             //    EPS .LT. X .LE. 1.5
  3949.             // ---------------------
  3950.             if ($y $pnt68{
  3951.                 $corr = -log($y);
  3952.                 $xm1 $y;
  3953.             else {
  3954.                 $corr 0.0;
  3955.                 $xm1 $y 1.0;
  3956.             }
  3957.             if ($y <= 0.5 || $y >= $pnt68{
  3958.                 $xden 1.0;
  3959.                 $xnum 0.0;
  3960.                 for ($i 0$i 8++$i{
  3961.                     $xnum $xnum $xm1 $lg_p1[$i];
  3962.                     $xden $xden $xm1 $lg_q1[$i];
  3963.                 }
  3964.                 $res $corr $xm1 ($lg_d1 $xm1 ($xnum $xden));
  3965.             else {
  3966.                 $xm2 $y 1.0;
  3967.                 $xden 1.0;
  3968.                 $xnum 0.0;
  3969.                 for ($i 0$i 8++$i{
  3970.                     $xnum $xnum $xm2 $lg_p2[$i];
  3971.                     $xden $xden $xm2 $lg_q2[$i];
  3972.                 }
  3973.                 $res $corr $xm2 ($lg_d2 $xm2 ($xnum $xden));
  3974.             }
  3975.         elseif ($y <= 4.0{
  3976.             // ---------------------
  3977.             //    1.5 .LT. X .LE. 4.0
  3978.             // ---------------------
  3979.             $xm2 $y 2.0;
  3980.             $xden 1.0;
  3981.             $xnum 0.0;
  3982.             for ($i 0$i 8++$i{
  3983.                 $xnum $xnum $xm2 $lg_p2[$i];
  3984.                 $xden $xden $xm2 $lg_q2[$i];
  3985.             }
  3986.             $res $xm2 ($lg_d2 $xm2 ($xnum $xden));
  3987.         elseif ($y <= 12.0{
  3988.             // ----------------------
  3989.             //    4.0 .LT. X .LE. 12.0
  3990.             // ----------------------
  3991.             $xm4 $y 4.0;
  3992.             $xden = -1.0;
  3993.             $xnum 0.0;
  3994.             for ($i 0$i 8++$i{
  3995.                 $xnum $xnum $xm4 $lg_p4[$i];
  3996.                 $xden $xden $xm4 $lg_q4[$i];
  3997.             }
  3998.             $res $lg_d4 $xm4 ($xnum $xden);
  3999.         else {
  4000.             // ---------------------------------
  4001.             //    Evaluate for argument .GE. 12.0
  4002.             // ---------------------------------
  4003.             $res 0.0;
  4004.             if ($y <= $lg_frtbig{
  4005.                 $res $lg_c[6];
  4006.                 $ysq $y $y;
  4007.                 for ($i 0$i 6++$i)
  4008.                     $res $res $ysq $lg_c[$i];
  4009.                 }
  4010.                 $res /= $y;
  4011.                 $corr log($y);
  4012.                 $res $res log(SQRT2PI0.5 $corr;
  4013.                 $res += $y ($corr 1.0);
  4014.             }
  4015.         else {
  4016.             // --------------------------
  4017.             //    Return for bad arguments
  4018.             // --------------------------
  4019.             $res MAX_VALUE;
  4020.         }
  4021.         // ------------------------------
  4022.         //    Final adjustments and return
  4023.         // ------------------------------
  4024.         self::$_logGammaCache_x $x;
  4025.         self::$_logGammaCache_result $res;
  4026.         return $res;
  4027.     }    //    function _logGamma()
  4028.  
  4029.  
  4030.     /**
  4031.      * Beta function.
  4032.      *
  4033.      * @author Jaco van Kooten
  4034.      *
  4035.      * @param require p>0
  4036.      * @param require q>0
  4037.      * @return if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
  4038.      */
  4039.     private static function _beta($p$q{
  4040.         if ($p <= 0.0 || $q <= 0.0 || ($p $qLOG_GAMMA_X_MAX_VALUE{
  4041.             return 0.0;
  4042.         else {
  4043.             return exp(self::_logBeta($p$q));
  4044.         }
  4045.     }    //    function _beta()
  4046.  
  4047.  
  4048.     /**
  4049.      * Incomplete beta function
  4050.      *
  4051.      * @author Jaco van Kooten
  4052.      * @author Paul Meagher
  4053.      *
  4054.      *  The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992).
  4055.      * @param require 0<=x<=1
  4056.      * @param require p>0
  4057.      * @param require q>0
  4058.      * @return if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow
  4059.      */
  4060.     private static function _incompleteBeta($x$p$q{
  4061.         if ($x <= 0.0{
  4062.             return 0.0;
  4063.         elseif ($x >= 1.0{
  4064.             return 1.0;
  4065.         elseif (($p <= 0.0|| ($q <= 0.0|| (($p $qLOG_GAMMA_X_MAX_VALUE)) {
  4066.             return 0.0;
  4067.         }
  4068.         $beta_gam exp((self::_logBeta($p$q)) $p log($x$q log(1.0 $x));
  4069.         if ($x ($p 1.0($p $q 2.0)) {
  4070.             return $beta_gam self::_betaFraction($x$p$q$p;
  4071.         else {
  4072.             return 1.0 ($beta_gam self::_betaFraction($x$q$p$q);
  4073.         }
  4074.     }    //    function _incompleteBeta()
  4075.  
  4076.  
  4077.     /**
  4078.      * BETADIST
  4079.      *
  4080.      * Returns the beta distribution.
  4081.      *
  4082.      * @param    float        $value            Value at which you want to evaluate the distribution
  4083.      * @param    float        $alpha            Parameter to the distribution
  4084.      * @param    float        $beta            Parameter to the distribution
  4085.      * @param    boolean        $cumulative 
  4086.      * @return    float 
  4087.      *
  4088.      */
  4089.     public static function BETADIST($value,$alpha,$beta,$rMin=0,$rMax=1{
  4090.         $value    self::flattenSingleValue($value);
  4091.         $alpha    self::flattenSingleValue($alpha);
  4092.         $beta    self::flattenSingleValue($beta);
  4093.         $rMin    self::flattenSingleValue($rMin);
  4094.         $rMax    self::flattenSingleValue($rMax);
  4095.  
  4096.         if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
  4097.             if (($value $rMin|| ($value $rMax|| ($alpha <= 0|| ($beta <= 0|| ($rMin == $rMax)) {
  4098.                 return self::$_errorCodes['num'];
  4099.             }
  4100.             if ($rMin $rMax{
  4101.                 $tmp $rMin;
  4102.                 $rMin $rMax;
  4103.                 $rMax $tmp;
  4104.             }
  4105.             $value -= $rMin;
  4106.             $value /= ($rMax $rMin);
  4107.             return self::_incompleteBeta($value,$alpha,$beta);
  4108.         }
  4109.         return self::$_errorCodes['value'];
  4110.     }    //    function BETADIST()
  4111.  
  4112.  
  4113.     /**
  4114.      * BETAINV
  4115.      *
  4116.      * Returns the inverse of the beta distribution.
  4117.      *
  4118.      * @param    float        $probability    Probability at which you want to evaluate the distribution
  4119.      * @param    float        $alpha            Parameter to the distribution
  4120.      * @param    float        $beta            Parameter to the distribution
  4121.      * @param    boolean        $cumulative 
  4122.      * @return    float 
  4123.      *
  4124.      */
  4125.     public static function BETAINV($probability,$alpha,$beta,$rMin=0,$rMax=1{
  4126.         $probability    self::flattenSingleValue($probability);
  4127.         $alpha            self::flattenSingleValue($alpha);
  4128.         $beta            self::flattenSingleValue($beta);
  4129.         $rMin            self::flattenSingleValue($rMin);
  4130.         $rMax            self::flattenSingleValue($rMax);
  4131.  
  4132.         if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
  4133.             if (($alpha <= 0|| ($beta <= 0|| ($rMin == $rMax|| ($probability <= 0|| ($probability 1)) {
  4134.                 return self::$_errorCodes['num'];
  4135.             }
  4136.             if ($rMin $rMax{
  4137.                 $tmp $rMin;
  4138.                 $rMin $rMax;
  4139.                 $rMax $tmp;
  4140.             }
  4141.             $a 0;
  4142.             $b 2;
  4143.  
  4144.             $i 0;
  4145.             while ((($b $aPRECISION&& ($i++ < MAX_ITERATIONS)) {
  4146.                 $guess ($a $b2;
  4147.                 $result self::BETADIST($guess$alpha$beta);
  4148.                 if (($result == $probability|| ($result == 0)) {
  4149.                     $b $a;
  4150.                 elseif ($result $probability{
  4151.                     $b $guess;
  4152.                 else {
  4153.                     $a $guess;
  4154.                 }
  4155.             }
  4156.             if ($i == MAX_ITERATIONS{
  4157.                 return self::$_errorCodes['na'];
  4158.             }
  4159.             return round($rMin $guess ($rMax $rMin),12);
  4160.         }
  4161.         return self::$_errorCodes['value'];
  4162.     }    //    function BETAINV()
  4163.  
  4164.  
  4165.     //
  4166.     //    Private implementation of the incomplete Gamma function
  4167.     //
  4168.     private static function _incompleteGamma($a,$x{
  4169.         static $max 32;
  4170.         $summer 0;
  4171.         for ($n=0$n<=$max++$n{
  4172.             $divisor $a;
  4173.             for ($i=1$i<=$n++$i{
  4174.                 $divisor *= ($a $i);
  4175.             }
  4176.             $summer += (pow($x,$n$divisor);
  4177.         }
  4178.         return pow($x,$aexp(0-$x$summer;
  4179.     }    //    function _incompleteGamma()
  4180.  
  4181.  
  4182.     //
  4183.     //    Private implementation of the Gamma function
  4184.     //
  4185.     private static function _gamma($data{
  4186.         if ($data == 0.0return 0;
  4187.  
  4188.         static $p0 1.000000000190015;
  4189.         static $p array => 76.18009172947146,
  4190.                             => -86.50532032941677,
  4191.                             => 24.01409824083091,
  4192.                             => -1.231739572450155,
  4193.                             => 1.208650973866179e-3,
  4194.                             => -5.395239384953e-6
  4195.                           );
  4196.  
  4197.         $y $x $data;
  4198.         $tmp $x 5.5;
  4199.         $tmp -= ($x 0.5log($tmp);
  4200.  
  4201.         $summer $p0;
  4202.         for ($j=1;$j<=6;++$j{
  4203.             $summer += ($p[$j/ ++$y);
  4204.         }
  4205.         return exp($tmp log(SQRT2PI $summer $x));
  4206.     }    //    function _gamma()
  4207.  
  4208.  
  4209.     /**
  4210.      * GAMMADIST
  4211.      *
  4212.      * Returns the gamma distribution.
  4213.      *
  4214.      * @param    float        $value            Value at which you want to evaluate the distribution
  4215.      * @param    float        $a                Parameter to the distribution
  4216.      * @param    float        $b                Parameter to the distribution
  4217.      * @param    boolean        $cumulative 
  4218.      * @return    float 
  4219.      *
  4220.      */
  4221.     public static function GAMMADIST($value,$a,$b,$cumulative{
  4222.         $value    self::flattenSingleValue($value);
  4223.         $a        self::flattenSingleValue($a);
  4224.         $b        self::flattenSingleValue($b);
  4225.  
  4226.         if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) {
  4227.             if (($value 0|| ($a <= 0|| ($b <= 0)) {
  4228.                 return self::$_errorCodes['num'];
  4229.             }
  4230.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4231.                 if ($cumulative{
  4232.                     return self::_incompleteGamma($a,$value $bself::_gamma($a);
  4233.                 else {
  4234.                     return ((pow($b,$aself::_gamma($a))) pow($value,$a-1exp(0-($value $b));
  4235.                 }
  4236.             }
  4237.         }
  4238.         return self::$_errorCodes['value'];
  4239.     }    //    function GAMMADIST()
  4240.  
  4241.  
  4242.     /**
  4243.      * GAMMAINV
  4244.      *
  4245.      * Returns the inverse of the beta distribution.
  4246.      *
  4247.      * @param    float        $probability    Probability at which you want to evaluate the distribution
  4248.      * @param    float        $alpha            Parameter to the distribution
  4249.      * @param    float        $beta            Parameter to the distribution
  4250.      * @return    float 
  4251.      *
  4252.      */
  4253.     public static function GAMMAINV($probability,$alpha,$beta{
  4254.         $probability    self::flattenSingleValue($probability);
  4255.         $alpha            self::flattenSingleValue($alpha);
  4256.         $beta            self::flattenSingleValue($beta);
  4257.  
  4258.         if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) {
  4259.             if (($alpha <= 0|| ($beta <= 0|| ($probability 0|| ($probability 1)) {
  4260.                 return self::$_errorCodes['num'];
  4261.             }
  4262.  
  4263.             $xLo 0;
  4264.             $xHi $alpha $beta 5;
  4265.  
  4266.             $x $xNew 1;
  4267.             $error $pdf 0;
  4268.             $dx    1024;
  4269.             $i 0;
  4270.  
  4271.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  4272.                 // Apply Newton-Raphson step
  4273.                 $error self::GAMMADIST($x$alpha$betaTrue$probability;
  4274.                 if ($error 0.0{
  4275.                     $xLo $x;
  4276.                 else {
  4277.                     $xHi $x;
  4278.                 }
  4279.                 $pdf self::GAMMADIST($x$alpha$betaFalse);
  4280.                 // Avoid division by zero
  4281.                 if ($pdf != 0.0{
  4282.                     $dx $error $pdf;
  4283.                     $xNew $x $dx;
  4284.                 }
  4285.                 // If the NR fails to converge (which for example may be the
  4286.                 // case if the initial guess is too rough) we apply a bisection
  4287.                 // step to determine a more narrow interval around the root.
  4288.                 if (($xNew $xLo|| ($xNew $xHi|| ($pdf == 0.0)) {
  4289.                     $xNew ($xLo $xHi2;
  4290.                     $dx $xNew $x;
  4291.                 }
  4292.                 $x $xNew;
  4293.             }
  4294.             if ($i == MAX_ITERATIONS{
  4295.                 return self::$_errorCodes['na'];
  4296.             }
  4297.             return $x;
  4298.         }
  4299.         return self::$_errorCodes['value'];
  4300.     }    //    function GAMMAINV()
  4301.  
  4302.  
  4303.     /**
  4304.      * GAMMALN
  4305.      *
  4306.      * Returns the natural logarithm of the gamma function.
  4307.      *
  4308.      * @param    float        $value 
  4309.      * @return    float 
  4310.      */
  4311.     public static function GAMMALN($value{
  4312.         $value    self::flattenSingleValue($value);
  4313.  
  4314.         if (is_numeric($value)) {
  4315.             if ($value <= 0{
  4316.                 return self::$_errorCodes['num'];
  4317.             }
  4318.             return log(self::_gamma($value));
  4319.         }
  4320.         return self::$_errorCodes['value'];
  4321.     }    //    function GAMMALN()
  4322.  
  4323.  
  4324.     /**
  4325.      * NORMDIST
  4326.      *
  4327.      * Returns the normal distribution for the specified mean and standard deviation. This
  4328.      * function has a very wide range of applications in statistics, including hypothesis
  4329.      * testing.
  4330.      *
  4331.      * @param    float        $value 
  4332.      * @param    float        $mean        Mean Value
  4333.      * @param    float        $stdDev        Standard Deviation
  4334.      * @param    boolean        $cumulative 
  4335.      * @return    float 
  4336.      *
  4337.      */
  4338.     public static function NORMDIST($value$mean$stdDev$cumulative{
  4339.         $value    self::flattenSingleValue($value);
  4340.         $mean    self::flattenSingleValue($mean);
  4341.         $stdDev    self::flattenSingleValue($stdDev);
  4342.  
  4343.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4344.             if ($stdDev 0{
  4345.                 return self::$_errorCodes['num'];
  4346.             }
  4347.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4348.                 if ($cumulative{
  4349.                     return 0.5 (self::_erfVal(($value $mean($stdDev sqrt(2))));
  4350.                 else {
  4351.                     return ((SQRT2PI $stdDev)) exp((pow($value $mean,2(($stdDev $stdDev))));
  4352.                 }
  4353.             }
  4354.         }
  4355.         return self::$_errorCodes['value'];
  4356.     }    //    function NORMDIST()
  4357.  
  4358.  
  4359.     /**
  4360.      * NORMSDIST
  4361.      *
  4362.      * Returns the standard normal cumulative distribution function. The distribution has
  4363.      * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a
  4364.      * table of standard normal curve areas.
  4365.      *
  4366.      * @param    float        $value 
  4367.      * @return    float 
  4368.      */
  4369.     public static function NORMSDIST($value{
  4370.         $value    self::flattenSingleValue($value);
  4371.  
  4372.         return self::NORMDIST($value01True);
  4373.     }    //    function NORMSDIST()
  4374.  
  4375.  
  4376.     /**
  4377.      * LOGNORMDIST
  4378.      *
  4379.      * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed
  4380.      * with parameters mean and standard_dev.
  4381.      *
  4382.      * @param    float        $value 
  4383.      * @return    float 
  4384.      */
  4385.     public static function LOGNORMDIST($value$mean$stdDev{
  4386.         $value    self::flattenSingleValue($value);
  4387.         $mean    self::flattenSingleValue($mean);
  4388.         $stdDev    self::flattenSingleValue($stdDev);
  4389.  
  4390.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4391.             if (($value <= 0|| ($stdDev <= 0)) {
  4392.                 return self::$_errorCodes['num'];
  4393.             }
  4394.             return self::NORMSDIST((log($value$mean$stdDev);
  4395.         }
  4396.         return self::$_errorCodes['value'];
  4397.     }    //    function LOGNORMDIST()
  4398.  
  4399.  
  4400.     /***************************************************************************
  4401.      *                                inverse_ncdf.php
  4402.      *                            -------------------
  4403.      *    begin                : Friday, January 16, 2004
  4404.      *    copyright            : (C) 2004 Michael Nickerson
  4405.      *    email                : [email protected]
  4406.      *
  4407.      ***************************************************************************/
  4408.     private static function _inverse_ncdf($p{
  4409.         //    Inverse ncdf approximation by Peter J. Acklam, implementation adapted to
  4410.         //    PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
  4411.         //    a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html
  4412.         //    I have not checked the accuracy of this implementation. Be aware that PHP
  4413.         //    will truncate the coeficcients to 14 digits.
  4414.  
  4415.         //    You have permission to use and distribute this function freely for
  4416.         //    whatever purpose you want, but please show common courtesy and give credit
  4417.         //    where credit is due.
  4418.  
  4419.         //    Input paramater is $p - probability - where 0 < p < 1.
  4420.  
  4421.         //    Coefficients in rational approximations
  4422.         static $a array(    => -3.969683028665376e+01,
  4423.                             => 2.209460984245205e+02,
  4424.                             => -2.759285104469687e+02,
  4425.                             => 1.383577518672690e+02,
  4426.                             => -3.066479806614716e+01,
  4427.                             => 2.506628277459239e+00
  4428.                          );
  4429.  
  4430.         static $b array(    => -5.447609879822406e+01,
  4431.                             => 1.615858368580409e+02,
  4432.                             => -1.556989798598866e+02,
  4433.                             => 6.680131188771972e+01,
  4434.                             => -1.328068155288572e+01
  4435.                          );
  4436.  
  4437.         static $c array(    => -7.784894002430293e-03,
  4438.                             => -3.223964580411365e-01,
  4439.                             => -2.400758277161838e+00,
  4440.                             => -2.549732539343734e+00,
  4441.                             => 4.374664141464968e+00,
  4442.                             => 2.938163982698783e+00
  4443.                          );
  4444.  
  4445.         static $d array(    => 7.784695709041462e-03,
  4446.                             => 3.224671290700398e-01,
  4447.                             => 2.445134137142996e+00,
  4448.                             => 3.754408661907416e+00
  4449.                          );
  4450.  
  4451.         //    Define lower and upper region break-points.
  4452.         $p_low 0.02425;            //Use lower region approx. below this
  4453.         $p_high $p_low;        //Use upper region approx. above this
  4454.  
  4455.         if ($p && $p $p_low{
  4456.             //    Rational approximation for lower region.
  4457.             $q sqrt(-log($p));
  4458.             return ((((($c[1$q $c[2]$q $c[3]$q $c[4]$q $c[5]$q $c[6]/
  4459.                     (((($d[1$q $d[2]$q $d[3]$q $d[4]$q 1);
  4460.         elseif ($p_low <= $p && $p <= $p_high{
  4461.             //    Rational approximation for central region.
  4462.             $q $p 0.5;
  4463.             $r $q $q;
  4464.             return ((((($a[1$r $a[2]$r $a[3]$r $a[4]$r $a[5]$r $a[6]$q /
  4465.                    ((((($b[1$r $b[2]$r $b[3]$r $b[4]$r $b[5]$r 1);
  4466.         elseif ($p_high $p && $p 1{
  4467.             //    Rational approximation for upper region.
  4468.             $q sqrt(-log($p));
  4469.             return -((((($c[1$q $c[2]$q $c[3]$q $c[4]$q $c[5]$q $c[6]/
  4470.                      (((($d[1$q $d[2]$q $d[3]$q $d[4]$q 1);
  4471.         }
  4472.         //    If 0 < p < 1, return a null value
  4473.         return self::$_errorCodes['null'];
  4474.     }    //    function _inverse_ncdf()
  4475.  
  4476.  
  4477.     private static function _inverse_ncdf2($prob{
  4478.         //    Approximation of inverse standard normal CDF developed by
  4479.         //    B. Moro, "The Full Monte," Risk 8(2), Feb 1995, 57-58.
  4480.  
  4481.         $a1 2.50662823884;
  4482.         $a2 = -18.61500062529;
  4483.         $a3 41.39119773534;
  4484.         $a4 = -25.44106049637;
  4485.  
  4486.         $b1 = -8.4735109309;
  4487.         $b2 23.08336743743;
  4488.         $b3 = -21.06224101826;
  4489.         $b4 3.13082909833;
  4490.  
  4491.         $c1 0.337475482272615;
  4492.         $c2 0.976169019091719;
  4493.         $c3 0.160797971491821;
  4494.         $c4 2.76438810333863E-02;
  4495.         $c5 3.8405729373609E-03;
  4496.         $c6 3.951896511919E-04;
  4497.         $c7 3.21767881768E-05;
  4498.         $c8 2.888167364E-07;
  4499.         $c9 3.960315187E-07;
  4500.  
  4501.         $y $prob 0.5;
  4502.         if (abs($y0.42{
  4503.             $z ($y $y);
  4504.             $z $y ((($a4 $z $a3$z $a2$z $a1(((($b4 $z $b3$z $b2$z $b1$z 1);
  4505.         else {
  4506.             if ($y 0{
  4507.                 $z log(-log($prob));
  4508.             else {
  4509.                 $z log(-log($prob));
  4510.             }
  4511.             $z $c1 $z ($c2 $z ($c3 $z ($c4 $z ($c5 $z ($c6 $z ($c7 $z ($c8 $z $c9)))))));
  4512.             if ($y 0{
  4513.                 $z = -$z;
  4514.             }
  4515.         }
  4516.         return $z;
  4517.     }    //    function _inverse_ncdf2()
  4518.  
  4519.  
  4520.     private static function _inverse_ncdf3($p{
  4521.         //    ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3.
  4522.         //    Produces the normal deviate Z corresponding to a given lower
  4523.         //    tail area of P; Z is accurate to about 1 part in 10**16.
  4524.         //
  4525.         //    This is a PHP version of the original FORTRAN code that can
  4526.         //    be found at http://lib.stat.cmu.edu/apstat/
  4527.         $split1 0.425;
  4528.         $split2 5;
  4529.         $const1 0.180625;
  4530.         $const2 1.6;
  4531.  
  4532.         //    coefficients for p close to 0.5
  4533.         $a0 3.3871328727963666080;
  4534.         $a1 1.3314166789178437745E+2;
  4535.         $a2 1.9715909503065514427E+3;
  4536.         $a3 1.3731693765509461125E+4;
  4537.         $a4 4.5921953931549871457E+4;
  4538.         $a5 6.7265770927008700853E+4;
  4539.         $a6 3.3430575583588128105E+4;
  4540.         $a7 2.5090809287301226727E+3;
  4541.  
  4542.         $b1 4.2313330701600911252E+1;
  4543.         $b2 6.8718700749205790830E+2;
  4544.         $b3 5.3941960214247511077E+3;
  4545.         $b4 2.1213794301586595867E+4;
  4546.         $b5 3.9307895800092710610E+4;
  4547.         $b6 2.8729085735721942674E+4;
  4548.         $b7 5.2264952788528545610E+3;
  4549.  
  4550.         //    coefficients for p not close to 0, 0.5 or 1.
  4551.         $c0 1.42343711074968357734;
  4552.         $c1 4.63033784615654529590;
  4553.         $c2 5.76949722146069140550;
  4554.         $c3 3.64784832476320460504;
  4555.         $c4 1.27045825245236838258;
  4556.         $c5 2.41780725177450611770E-1;
  4557.         $c6 2.27238449892691845833E-2;
  4558.         $c7 7.74545014278341407640E-4;
  4559.  
  4560.         $d1 2.05319162663775882187;
  4561.         $d2 1.67638483018380384940;
  4562.         $d3 6.89767334985100004550E-1;
  4563.         $d4 1.48103976427480074590E-1;
  4564.         $d5 1.51986665636164571966E-2;
  4565.         $d6 5.47593808499534494600E-4;
  4566.         $d7 1.05075007164441684324E-9;
  4567.  
  4568.         //    coefficients for p near 0 or 1.
  4569.         $e0 6.65790464350110377720;
  4570.         $e1 5.46378491116411436990;
  4571.         $e2 1.78482653991729133580;
  4572.         $e3 2.96560571828504891230E-1;
  4573.         $e4 2.65321895265761230930E-2;
  4574.         $e5 1.24266094738807843860E-3;
  4575.         $e6 2.71155556874348757815E-5;
  4576.         $e7 2.01033439929228813265E-7;
  4577.  
  4578.         $f1 5.99832206555887937690E-1;
  4579.         $f2 1.36929880922735805310E-1;
  4580.         $f3 1.48753612908506148525E-2;
  4581.         $f4 7.86869131145613259100E-4;
  4582.         $f5 1.84631831751005468180E-5;
  4583.         $f6 1.42151175831644588870E-7;
  4584.         $f7 2.04426310338993978564E-15;
  4585.  
  4586.         $q $p 0.5;
  4587.  
  4588.         //    computation for p close to 0.5
  4589.         if (abs($q<= split1{
  4590.             $R $const1 $q $q;
  4591.             $z $q ((((((($a7 $R $a6$R $a5$R $a4$R $a3$R $a2$R $a1$R $a0/
  4592.                       ((((((($b7 $R $b6$R $b5$R $b4$R $b3$R $b2$R $b1$R 1);
  4593.         else {
  4594.             if ($q 0{
  4595.                 $R $p;
  4596.             else {
  4597.                 $R $p;
  4598.             }
  4599.             $R pow(-log($R),2);
  4600.  
  4601.             //    computation for p not close to 0, 0.5 or 1.
  4602.             If ($R <= $split2{
  4603.                 $R $R $const2;
  4604.                 $z ((((((($c7 $R $c6$R $c5$R $c4$R $c3$R $c2$R $c1$R $c0/
  4605.                      ((((((($d7 $R $d6$R $d5$R $d4$R $d3$R $d2$R $d1$R 1);
  4606.             else {
  4607.             //    computation for p near 0 or 1.
  4608.                 $R $R $split2;
  4609.                 $z ((((((($e7 $R $e6$R $e5$R $e4$R $e3$R $e2$R $e1$R $e0/
  4610.                      ((((((($f7 $R $f6$R $f5$R $f4$R $f3$R $f2$R $f1$R 1);
  4611.             }
  4612.             if ($q 0{
  4613.                 $z = -$z;
  4614.             }
  4615.         }
  4616.         return $z;
  4617.     }    //    function _inverse_ncdf3()
  4618.  
  4619.  
  4620.     /**
  4621.      * NORMINV
  4622.      *
  4623.      * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation.
  4624.      *
  4625.      * @param    float        $value 
  4626.      * @param    float        $mean        Mean Value
  4627.      * @param    float        $stdDev        Standard Deviation
  4628.      * @return    float 
  4629.      *
  4630.      */
  4631.     public static function NORMINV($probability,$mean,$stdDev{
  4632.         $probability    self::flattenSingleValue($probability);
  4633.         $mean            self::flattenSingleValue($mean);
  4634.         $stdDev            self::flattenSingleValue($stdDev);
  4635.  
  4636.         if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4637.             if (($probability 0|| ($probability 1)) {
  4638.                 return self::$_errorCodes['num'];
  4639.             }
  4640.             if ($stdDev 0{
  4641.                 return self::$_errorCodes['num'];
  4642.             }
  4643.             return (self::_inverse_ncdf($probability$stdDev$mean;
  4644.         }
  4645.         return self::$_errorCodes['value'];
  4646.     }    //    function NORMINV()
  4647.  
  4648.  
  4649.     /**
  4650.      * NORMSINV
  4651.      *
  4652.      * Returns the inverse of the standard normal cumulative distribution
  4653.      *
  4654.      * @param    float        $value 
  4655.      * @return    float 
  4656.      */
  4657.     public static function NORMSINV($value{
  4658.         return self::NORMINV($value01);
  4659.     }    //    function NORMSINV()
  4660.  
  4661.  
  4662.     /**
  4663.      * LOGINV
  4664.      *
  4665.      * Returns the inverse of the normal cumulative distribution
  4666.      *
  4667.      * @param    float        $value 
  4668.      * @return    float 
  4669.      *
  4670.      * @todo    Try implementing P J Acklam's refinement algorithm for greater
  4671.      *             accuracy if I can get my head round the mathematics
  4672.      *             (as described at) http://home.online.no/~pjacklam/notes/invnorm/
  4673.      */
  4674.     public static function LOGINV($probability$mean$stdDev{
  4675.         $probability    self::flattenSingleValue($probability);
  4676.         $mean            self::flattenSingleValue($mean);
  4677.         $stdDev            self::flattenSingleValue($stdDev);
  4678.  
  4679.         if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4680.             if (($probability 0|| ($probability 1|| ($stdDev <= 0)) {
  4681.                 return self::$_errorCodes['num'];
  4682.             }
  4683.             return exp($mean $stdDev self::NORMSINV($probability));
  4684.         }
  4685.         return self::$_errorCodes['value'];
  4686.     }    //    function LOGINV()
  4687.  
  4688.  
  4689.     /**
  4690.      * HYPGEOMDIST
  4691.      *
  4692.      * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of
  4693.      * sample successes, given the sample size, population successes, and population size.
  4694.      *
  4695.      * @param    float        $sampleSuccesses        Number of successes in the sample
  4696.      * @param    float        $sampleNumber            Size of the sample
  4697.      * @param    float        $populationSuccesses    Number of successes in the population
  4698.      * @param    float        $populationNumber        Population size
  4699.      * @return    float 
  4700.      *
  4701.      */
  4702.     public static function HYPGEOMDIST($sampleSuccesses$sampleNumber$populationSuccesses$populationNumber{
  4703.         $sampleSuccesses        floor(self::flattenSingleValue($sampleSuccesses));
  4704.         $sampleNumber            floor(self::flattenSingleValue($sampleNumber));
  4705.         $populationSuccesses    floor(self::flattenSingleValue($populationSuccesses));
  4706.         $populationNumber        floor(self::flattenSingleValue($populationNumber));
  4707.  
  4708.         if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) {
  4709.             if (($sampleSuccesses 0|| ($sampleSuccesses $sampleNumber|| ($sampleSuccesses $populationSuccesses)) {
  4710.                 return self::$_errorCodes['num'];
  4711.             }
  4712.             if (($sampleNumber <= 0|| ($sampleNumber $populationNumber)) {
  4713.                 return self::$_errorCodes['num'];
  4714.             }
  4715.             if (($populationSuccesses <= 0|| ($populationSuccesses $populationNumber)) {
  4716.                 return self::$_errorCodes['num'];
  4717.             }
  4718.             return self::COMBIN($populationSuccesses,$sampleSuccesses*
  4719.                    self::COMBIN($populationNumber $populationSuccesses,$sampleNumber $sampleSuccesses/
  4720.                    self::COMBIN($populationNumber,$sampleNumber);
  4721.         }
  4722.         return self::$_errorCodes['value'];
  4723.     }    //    function HYPGEOMDIST()
  4724.  
  4725.  
  4726.     /**
  4727.      * TDIST
  4728.      *
  4729.      * Returns the probability of Student's T distribution.
  4730.      *
  4731.      * @param    float        $value            Value for the function
  4732.      * @param    float        $degrees        degrees of freedom
  4733.      * @param    float        $tails            number of tails (1 or 2)
  4734.      * @return    float 
  4735.      */
  4736.     public static function TDIST($value$degrees$tails{
  4737.         $value        self::flattenSingleValue($value);
  4738.         $degrees    floor(self::flattenSingleValue($degrees));
  4739.         $tails        floor(self::flattenSingleValue($tails));
  4740.  
  4741.         if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) {
  4742.             if (($value 0|| ($degrees 1|| ($tails 1|| ($tails 2)) {
  4743.                 return self::$_errorCodes['num'];
  4744.             }
  4745.             //    tdist, which finds the probability that corresponds to a given value
  4746.             //    of t with k degrees of freedom. This algorithm is translated from a
  4747.             //    pascal function on p81 of "Statistical Computing in Pascal" by D
  4748.             //    Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd:
  4749.             //    London). The above Pascal algorithm is itself a translation of the
  4750.             //    fortran algoritm "AS 3" by B E Cooper of the Atlas Computer
  4751.             //    Laboratory as reported in (among other places) "Applied Statistics
  4752.             //    Algorithms", editied by P Griffiths and I D Hill (1985; Ellis
  4753.             //    Horwood Ltd.; W. Sussex, England).
  4754.             $tterm $degrees;
  4755.             $ttheta atan2($value,sqrt($tterm));
  4756.             $tc cos($ttheta);
  4757.             $ts sin($ttheta);
  4758.             $tsum 0;
  4759.  
  4760.             if (($degrees 2== 1{
  4761.                 $ti 3;
  4762.                 $tterm $tc;
  4763.             else {
  4764.                 $ti 2;
  4765.                 $tterm 1;
  4766.             }
  4767.  
  4768.             $tsum $tterm;
  4769.             while ($ti $degrees{
  4770.                 $tterm *= $tc $tc ($ti 1$ti;
  4771.                 $tsum += $tterm;
  4772.                 $ti += 2;
  4773.             }
  4774.             $tsum *= $ts;
  4775.             if (($degrees 2== 1$tsum M_2DIVPI ($tsum $ttheta)}
  4776.             $tValue 0.5 ($tsum);
  4777.             if ($tails == 1{
  4778.                 return abs($tValue);
  4779.             else {
  4780.                 return abs(($tValue$tValue);
  4781.             }
  4782.         }
  4783.         return self::$_errorCodes['value'];
  4784.     }    //    function TDIST()
  4785.  
  4786.  
  4787.     /**
  4788.      * TINV
  4789.      *
  4790.      * Returns the one-tailed probability of the chi-squared distribution.
  4791.      *
  4792.      * @param    float        $probability    Probability for the function
  4793.      * @param    float        $degrees        degrees of freedom
  4794.      * @return    float 
  4795.      */
  4796.     public static function TINV($probability$degrees{
  4797.         $probability    self::flattenSingleValue($probability);
  4798.         $degrees        floor(self::flattenSingleValue($degrees));
  4799.  
  4800.         if ((is_numeric($probability)) && (is_numeric($degrees))) {
  4801.             $xLo 100;
  4802.             $xHi 0;
  4803.  
  4804.             $x $xNew 1;
  4805.             $dx    1;
  4806.             $i 0;
  4807.  
  4808.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  4809.                 // Apply Newton-Raphson step
  4810.                 $result self::TDIST($x$degrees2);
  4811.                 $error $result $probability;
  4812.                 if ($error == 0.0{
  4813.                     $dx 0;
  4814.                 elseif ($error 0.0{
  4815.                     $xLo $x;
  4816.                 else {
  4817.                     $xHi $x;
  4818.                 }
  4819.                 // Avoid division by zero
  4820.                 if ($result != 0.0{
  4821.                     $dx $error $result;
  4822.                     $xNew $x $dx;
  4823.                 }
  4824.                 // If the NR fails to converge (which for example may be the
  4825.                 // case if the initial guess is too rough) we apply a bisection
  4826.                 // step to determine a more narrow interval around the root.
  4827.                 if (($xNew $xLo|| ($xNew $xHi|| ($result == 0.0)) {
  4828.                     $xNew ($xLo $xHi2;
  4829.                     $dx $xNew $x;
  4830.                 }
  4831.                 $x $xNew;
  4832.             }
  4833.             if ($i == MAX_ITERATIONS{
  4834.                 return self::$_errorCodes['na'];
  4835.             }
  4836.             return round($x,12);
  4837.         }
  4838.         return self::$_errorCodes['value'];
  4839.     }    //    function TINV()
  4840.  
  4841.  
  4842.     /**
  4843.      * CONFIDENCE
  4844.      *
  4845.      * Returns the confidence interval for a population mean
  4846.      *
  4847.      * @param    float        $alpha 
  4848.      * @param    float        $stdDev        Standard Deviation
  4849.      * @param    float        $size 
  4850.      * @return    float 
  4851.      *
  4852.      */
  4853.     public static function CONFIDENCE($alpha,$stdDev,$size{
  4854.         $alpha    self::flattenSingleValue($alpha);
  4855.         $stdDev    self::flattenSingleValue($stdDev);
  4856.         $size    floor(self::flattenSingleValue($size));
  4857.  
  4858.         if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) {
  4859.             if (($alpha <= 0|| ($alpha >= 1)) {
  4860.                 return self::$_errorCodes['num'];
  4861.             }
  4862.             if (($stdDev <= 0|| ($size 1)) {
  4863.                 return self::$_errorCodes['num'];
  4864.             }
  4865.             return self::NORMSINV($alpha 2$stdDev sqrt($size);
  4866.         }
  4867.         return self::$_errorCodes['value'];
  4868.     }    //    function CONFIDENCE()
  4869.  
  4870.  
  4871.     /**
  4872.      * POISSON
  4873.      *
  4874.      * Returns the Poisson distribution. A common application of the Poisson distribution
  4875.      * is predicting the number of events over a specific time, such as the number of
  4876.      * cars arriving at a toll plaza in 1 minute.
  4877.      *
  4878.      * @param    float        $value 
  4879.      * @param    float        $mean        Mean Value
  4880.      * @param    boolean        $cumulative 
  4881.      * @return    float 
  4882.      *
  4883.      */
  4884.     public static function POISSON($value$mean$cumulative{
  4885.         $value    self::flattenSingleValue($value);
  4886.         $mean    self::flattenSingleValue($mean);
  4887.  
  4888.         if ((is_numeric($value)) && (is_numeric($mean))) {
  4889.             if (($value <= 0|| ($mean <= 0)) {
  4890.                 return self::$_errorCodes['num'];
  4891.             }
  4892.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4893.                 if ($cumulative{
  4894.                     $summer 0;
  4895.                     for ($i 0$i <= floor($value)++$i{
  4896.                         $summer += pow($mean,$iself::FACT($i);
  4897.                     }
  4898.                     return exp(0-$mean$summer;
  4899.                 else {
  4900.                     return (exp(0-$meanpow($mean,$value)) self::FACT($value);
  4901.                 }
  4902.             }
  4903.         }
  4904.         return self::$_errorCodes['value'];
  4905.     }    //    function POISSON()
  4906.  
  4907.  
  4908.     /**
  4909.      * WEIBULL
  4910.      *
  4911.      * Returns the Weibull distribution. Use this distribution in reliability
  4912.      * analysis, such as calculating a device's mean time to failure.
  4913.      *
  4914.      * @param    float        $value 
  4915.      * @param    float        $alpha        Alpha Parameter
  4916.      * @param    float        $beta        Beta Parameter
  4917.      * @param    boolean        $cumulative 
  4918.      * @return    float 
  4919.      *
  4920.      */
  4921.     public static function WEIBULL($value$alpha$beta$cumulative{
  4922.         $value    self::flattenSingleValue($value);
  4923.         $alpha    self::flattenSingleValue($alpha);
  4924.         $beta    self::flattenSingleValue($beta);
  4925.  
  4926.         if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) {
  4927.             if (($value 0|| ($alpha <= 0|| ($beta <= 0)) {
  4928.                 return self::$_errorCodes['num'];
  4929.             }
  4930.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4931.                 if ($cumulative{
  4932.                     return exp(pow($value $beta,$alpha));
  4933.                 else {
  4934.                     return ($alpha pow($beta,$alpha)) pow($value,$alpha 1exp(pow($value $beta,$alpha));
  4935.                 }
  4936.             }
  4937.         }
  4938.         return self::$_errorCodes['value'];
  4939.     }    //    function WEIBULL()
  4940.  
  4941.  
  4942.     /**
  4943.      * ZTEST
  4944.      *
  4945.      * Returns the Weibull distribution. Use this distribution in reliability
  4946.      * analysis, such as calculating a device's mean time to failure.
  4947.      *
  4948.      * @param    float        $value 
  4949.      * @param    float        $alpha        Alpha Parameter
  4950.      * @param    float        $beta        Beta Parameter
  4951.      * @param    boolean        $cumulative 
  4952.      * @return    float 
  4953.      *
  4954.      */
  4955.     public static function ZTEST($dataSet$m0$sigma=null{
  4956.         $dataSet    self::flattenArrayIndexed($dataSet);
  4957.         $m0            self::flattenSingleValue($m0);
  4958.         $sigma        self::flattenSingleValue($sigma);
  4959.  
  4960.         if (is_null($sigma)) {
  4961.             $sigma self::STDEV($dataSet);
  4962.         }
  4963.         $n count($dataSet);
  4964.  
  4965.         return self::NORMSDIST((self::AVERAGE($dataSet$m0)/($sigma/SQRT($n)));
  4966.     }    //    function ZTEST()
  4967.  
  4968.  
  4969.     /**
  4970.      * SKEW
  4971.      *
  4972.      * Returns the skewness of a distribution. Skewness characterizes the degree of asymmetry
  4973.      * of a distribution around its mean. Positive skewness indicates a distribution with an
  4974.      * asymmetric tail extending toward more positive values. Negative skewness indicates a
  4975.      * distribution with an asymmetric tail extending toward more negative values.
  4976.      *
  4977.      * @param    array    Data Series
  4978.      * @return    float 
  4979.      */
  4980.     public static function SKEW({
  4981.         $aArgs self::flattenArrayIndexed(func_get_args());
  4982.         $mean self::AVERAGE($aArgs);
  4983.         $stdDev self::STDEV($aArgs);
  4984.  
  4985.         $count $summer 0;
  4986.         // Loop through arguments
  4987.         foreach ($aArgs as $k => $arg{
  4988.             if ((is_bool($arg)) &&
  4989.                 (!self::isMatrixValue($k))) {
  4990.             else {
  4991.                 // Is it a numeric value?
  4992.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  4993.                     $summer += pow((($arg $mean$stdDev),3;
  4994.                     ++$count;
  4995.                 }
  4996.             }
  4997.         }
  4998.  
  4999.         // Return
  5000.         if ($count 2{
  5001.             return $summer ($count (($count-1($count-2)));
  5002.         }
  5003.         return self::$_errorCodes['divisionbyzero'];
  5004.     }    //    function SKEW()
  5005.  
  5006.  
  5007.     /**
  5008.      * KURT
  5009.      *
  5010.      * Returns the kurtosis of a data set. Kurtosis characterizes the relative peakedness
  5011.      * or flatness of a distribution compared with the normal distribution. Positive
  5012.      * kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a
  5013.      * relatively flat distribution.
  5014.      *
  5015.      * @param    array    Data Series
  5016.      * @return    float 
  5017.      */
  5018.     public static function KURT({
  5019.         $aArgs self::flattenArrayIndexed(func_get_args());
  5020.         $mean self::AVERAGE($aArgs);
  5021.         $stdDev self::STDEV($aArgs);
  5022.  
  5023.         if ($stdDev 0{
  5024.             $count $summer 0;
  5025.             // Loop through arguments
  5026.             foreach ($aArgs as $k => $arg{
  5027.                 if ((is_bool($arg)) &&
  5028.                     (!self::isMatrixValue($k))) {
  5029.                 else {
  5030.                     // Is it a numeric value?
  5031.                     if ((is_numeric($arg)) && (!is_string($arg))) {
  5032.                         $summer += pow((($arg $mean$stdDev),4;
  5033.                         ++$count;
  5034.                     }
  5035.                 }
  5036.             }
  5037.  
  5038.             // Return
  5039.             if ($count 3{
  5040.                 return $summer ($count ($count+1(($count-1($count-2($count-3))) (pow($count-1,2(($count-2($count-3)));
  5041.             }
  5042.         }
  5043.         return self::$_errorCodes['divisionbyzero'];
  5044.     }    //    function KURT()
  5045.  
  5046.  
  5047.     /**
  5048.      * RAND
  5049.      *
  5050.      * @param    int        $min    Minimal value
  5051.      * @param    int        $max    Maximal value
  5052.      * @return    int        Random number
  5053.      */
  5054.     public static function RAND($min 0$max 0{
  5055.         $min        self::flattenSingleValue($min);
  5056.         $max        self::flattenSingleValue($max);
  5057.  
  5058.         if ($min == && $max == 0{
  5059.             return (rand(0,10000000)) 10000000;
  5060.         else {
  5061.             return rand($min$max);
  5062.         }
  5063.     }    //    function RAND()
  5064.  
  5065.  
  5066.     /**
  5067.      * MOD
  5068.      *
  5069.      * @param    int        $a        Dividend
  5070.      * @param    int        $b        Divisor
  5071.      * @return    int        Remainder
  5072.      */
  5073.     public static function MOD($a 1$b 1{
  5074.         $a        self::flattenSingleValue($a);
  5075.         $b        self::flattenSingleValue($b);
  5076.  
  5077.         if ($b == 0.0{
  5078.             return self::$_errorCodes['divisionbyzero'];
  5079.         elseif (($a 0.0&& ($b 0.0)) {
  5080.             return $b fmod(abs($a),$b);
  5081.         elseif (($a 0.0&& ($b 0.0)) {
  5082.             return $b fmod($a,abs($b));
  5083.         }
  5084.  
  5085.         return fmod($a,$b);
  5086.     }    //    function MOD()
  5087.  
  5088.  
  5089.     /**
  5090.      * CHARACTER
  5091.      *
  5092.      * @param    string    $character    Value
  5093.      * @return    int 
  5094.      */
  5095.     public static function CHARACTER($character{
  5096.         $character    self::flattenSingleValue($character);
  5097.  
  5098.         if ((!is_numeric($character)) || ($character 0)) {
  5099.             return self::$_errorCodes['value'];
  5100.         }
  5101.  
  5102.         if (function_exists('mb_convert_encoding')) {
  5103.             return mb_convert_encoding('&#'.intval($character).';''UTF-8''HTML-ENTITIES');
  5104.         else {
  5105.             return chr(intval($character));
  5106.         }
  5107.     }
  5108.  
  5109.  
  5110.     private static function _uniord($c{
  5111.         if (ord($c{0}>=&& ord($c{0}<= 127)
  5112.             return ord($c{0});
  5113.         if (ord($c{0}>= 192 && ord($c{0}<= 223)
  5114.             return (ord($c{0})-192)*64 (ord($c{1})-128);
  5115.         if (ord($c{0}>= 224 && ord($c{0}<= 239)
  5116.             return (ord($c{0})-224)*4096 (ord($c{1})-128)*64 (ord($c{2})-128);
  5117.         if (ord($c{0}>= 240 && ord($c{0}<= 247)
  5118.             return (ord($c{0})-240)*262144 (ord($c{1})-128)*4096 (ord($c{2})-128)*64 (ord($c{3})-128);
  5119.         if (ord($c{0}>= 248 && ord($c{0}<= 251)
  5120.             return (ord($c{0})-248)*16777216 (ord($c{1})-128)*262144 (ord($c{2})-128)*4096 (ord($c{3})-128)*64 (ord($c{4})-128);
  5121.         if (ord($c{0}>= 252 && ord($c{0}<= 253)
  5122.             return (ord($c{0})-252)*1073741824 (ord($c{1})-128)*16777216 (ord($c{2})-128)*262144 (ord($c{3})-128)*4096 (ord($c{4})-128)*64 (ord($c{5})-128);
  5123.         if (ord($c{0}>= 254 && ord($c{0}<= 255//error
  5124.             return self::$_errorCodes['value'];
  5125.         return 0;
  5126.     }    //    function _uniord()
  5127.  
  5128.     /**
  5129.      * ASCIICODE
  5130.      *
  5131.      * @param    string    $character    Value
  5132.      * @return    int 
  5133.      */
  5134.     public static function ASCIICODE($characters{
  5135.         $characters    self::flattenSingleValue($characters);
  5136.         if (is_bool($characters)) {
  5137.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5138.                 $characters = (int) $characters;
  5139.             else {
  5140.                 if ($characters{
  5141.                     $characters 'True';
  5142.                 else {
  5143.                     $characters 'False';
  5144.                 }
  5145.             }
  5146.         }
  5147.  
  5148.         $character $characters;
  5149.         if ((function_exists('mb_strlen')) && (function_exists('mb_substr'))) {
  5150.             if (mb_strlen($characters'UTF-8'1$character mb_substr($characters01'UTF-8')}
  5151.             return self::_uniord($character);
  5152.         else {
  5153.             if (strlen($characters0$character substr($characters01)}
  5154.             return ord($character);
  5155.         }
  5156.     }    //    function ASCIICODE()
  5157.  
  5158.  
  5159.     /**
  5160.      * CONCATENATE
  5161.      *
  5162.      * @return    string 
  5163.      */
  5164.     public static function CONCATENATE({
  5165.         // Return value
  5166.         $returnValue '';
  5167.  
  5168.         // Loop through arguments
  5169.         $aArgs self::flattenArray(func_get_args());
  5170.         foreach ($aArgs as $arg{
  5171.             if (is_bool($arg)) {
  5172.                 if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5173.                     $arg = (int) $arg;
  5174.                 else {
  5175.                     if ($arg{
  5176.                         $arg 'TRUE';
  5177.                     else {
  5178.                         $arg 'FALSE';
  5179.                     }
  5180.                 }
  5181.             }
  5182.             $returnValue .= $arg;
  5183.         }
  5184.  
  5185.         // Return
  5186.         return $returnValue;
  5187.     }    //    function CONCATENATE()
  5188.  
  5189.  
  5190.     /**
  5191.      * STRINGLENGTH
  5192.      *
  5193.      * @param    string    $value    Value
  5194.      * @param    int        $chars    Number of characters
  5195.      * @return    string 
  5196.      */
  5197.     public static function STRINGLENGTH($value ''{
  5198.         $value        self::flattenSingleValue($value);
  5199.  
  5200.         if (is_bool($value)) {
  5201.             $value ($value'TRUE' 'FALSE';
  5202.         }
  5203.  
  5204.         if (function_exists('mb_strlen')) {
  5205.             return mb_strlen($value'UTF-8');
  5206.         else {
  5207.             return strlen($value);
  5208.         }
  5209.     }    //    function STRINGLENGTH()
  5210.  
  5211.  
  5212.     /**
  5213.      * SEARCHSENSITIVE
  5214.      *
  5215.      * @param    string    $needle        The string to look for
  5216.      * @param    string    $haystack    The string in which to look
  5217.      * @param    int        $offset        Offset within $haystack
  5218.      * @return    string 
  5219.      */
  5220.     public static function SEARCHSENSITIVE($needle,$haystack,$offset=1{
  5221.         $needle        self::flattenSingleValue($needle);
  5222.         $haystack    self::flattenSingleValue($haystack);
  5223.         $offset        self::flattenSingleValue($offset);
  5224.  
  5225.         if (!is_bool($needle)) {
  5226.             if (is_bool($haystack)) {
  5227.                 $haystack ($haystack'TRUE' 'FALSE';
  5228.             }
  5229.  
  5230.             if (($offset 0&& (strlen($haystack$offset)) {
  5231.                 if (function_exists('mb_strpos')) {
  5232.                     $pos mb_strpos($haystack$needle--$offset,'UTF-8');
  5233.                 else {
  5234.                     $pos strpos($haystack$needle--$offset);
  5235.                 }
  5236.                 if ($pos !== false{
  5237.                     return ++$pos;
  5238.                 }
  5239.             }
  5240.         }
  5241.         return self::$_errorCodes['value'];
  5242.     }    //    function SEARCHSENSITIVE()
  5243.  
  5244.  
  5245.     /**
  5246.      * SEARCHINSENSITIVE
  5247.      *
  5248.      * @param    string    $needle        The string to look for
  5249.      * @param    string    $haystack    The string in which to look
  5250.      * @param    int        $offset        Offset within $haystack
  5251.      * @return    string 
  5252.      */
  5253.     public static function SEARCHINSENSITIVE($needle,$haystack,$offset=1{
  5254.         $needle        self::flattenSingleValue($needle);
  5255.         $haystack    self::flattenSingleValue($haystack);
  5256.         $offset        self::flattenSingleValue($offset);
  5257.  
  5258.         if (!is_bool($needle)) {
  5259.             if (is_bool($haystack)) {
  5260.                 $haystack ($haystack'TRUE' 'FALSE';
  5261.             }
  5262.  
  5263.             if (($offset 0&& (strlen($haystack$offset)) {
  5264.                 if (function_exists('mb_stripos')) {
  5265.                     $pos mb_stripos($haystack$needle--$offset,'UTF-8');
  5266.                 else {
  5267.                     $pos stripos($haystack$needle--$offset);
  5268.                 }
  5269.                 if ($pos !== false{
  5270.                     return ++$pos;
  5271.                 }
  5272.             }
  5273.         }
  5274.         return self::$_errorCodes['value'];
  5275.     }    //    function SEARCHINSENSITIVE()
  5276.  
  5277.  
  5278.     /**
  5279.      * LEFT
  5280.      *
  5281.      * @param    string    $value    Value
  5282.      * @param    int        $chars    Number of characters
  5283.      * @return    string 
  5284.      */
  5285.     public static function LEFT($value ''$chars 1{
  5286.         $value        self::flattenSingleValue($value);
  5287.         $chars        self::flattenSingleValue($chars);
  5288.  
  5289.         if ($chars 0{
  5290.             return self::$_errorCodes['value'];
  5291.         }
  5292.  
  5293.         if (is_bool($value)) {
  5294.             $value ($value'TRUE' 'FALSE';
  5295.         }
  5296.  
  5297.         if (function_exists('mb_substr')) {
  5298.             return mb_substr($value0$chars'UTF-8');
  5299.         else {
  5300.             return substr($value0$chars);
  5301.         }
  5302.     }    //    function LEFT()
  5303.  
  5304.  
  5305.     /**
  5306.      *    RIGHT
  5307.      *
  5308.      *    @param    string    $value    Value
  5309.      *    @param    int        $chars    Number of characters
  5310.      *    @return    string 
  5311.      */
  5312.     public static function RIGHT($value ''$chars 1{
  5313.         $value        self::flattenSingleValue($value);
  5314.         $chars        self::flattenSingleValue($chars);
  5315.  
  5316.         if ($chars 0{
  5317.             return self::$_errorCodes['value'];
  5318.         }
  5319.  
  5320.         if (is_bool($value)) {
  5321.             $value ($value'TRUE' 'FALSE';
  5322.         }
  5323.  
  5324.         if ((function_exists('mb_substr')) && (function_exists('mb_strlen'))) {
  5325.             return mb_substr($valuemb_strlen($value'UTF-8'$chars$chars'UTF-8');
  5326.         else {
  5327.             return substr($valuestrlen($value$chars);
  5328.         }
  5329.     }    //    function RIGHT()
  5330.  
  5331.  
  5332.     /**
  5333.      *    MID
  5334.      *
  5335.      *    @param    string    $value    Value
  5336.      *    @param    int        $start    Start character
  5337.      *    @param    int        $chars    Number of characters
  5338.      *    @return    string 
  5339.      */
  5340.     public static function MID($value ''$start 1$chars null{
  5341.         $value        self::flattenSingleValue($value);
  5342.         $start        self::flattenSingleValue($start);
  5343.         $chars        self::flattenSingleValue($chars);
  5344.  
  5345.         if (($start 1|| ($chars 0)) {
  5346.             return self::$_errorCodes['value'];
  5347.         }
  5348.  
  5349.         if (is_bool($value)) {
  5350.             $value ($value'TRUE' 'FALSE';
  5351.         }
  5352.  
  5353.         if (function_exists('mb_substr')) {
  5354.             return mb_substr($value--$start$chars'UTF-8');
  5355.         else {
  5356.             return substr($value--$start$chars);
  5357.         }
  5358.     }    //    function MID()
  5359.  
  5360.  
  5361.     /**
  5362.      *    REPLACE
  5363.      *
  5364.      *    @param    string    $value    Value
  5365.      *    @param    int        $start    Start character
  5366.      *    @param    int        $chars    Number of characters
  5367.      *    @return    string 
  5368.      */
  5369.     public static function REPLACE($oldText ''$start 1$chars null$newText{
  5370.         $oldText    self::flattenSingleValue($oldText);
  5371.         $start        self::flattenSingleValue($start);
  5372.         $chars        self::flattenSingleValue($chars);
  5373.         $newText    self::flattenSingleValue($newText);
  5374.  
  5375.         $left self::LEFT($oldText,$start-1);
  5376.         $right self::RIGHT($oldText,self::STRINGLENGTH($oldText)-($start+$chars)+1);
  5377.  
  5378.         return $left.$newText.$right;
  5379.     }    //    function REPLACE()
  5380.  
  5381.  
  5382.     /**
  5383.      *    SUBSTITUTE
  5384.      *
  5385.      *    @param    string    $text        Value
  5386.      *    @param    string    $fromText    From Value
  5387.      *    @param    string    $toText        To Value
  5388.      *    @param    integer    $instance    Instance Number
  5389.      *    @return    string 
  5390.      */
  5391.     public static function SUBSTITUTE($text ''$fromText ''$toText ''$instance 0{
  5392.         $text        self::flattenSingleValue($text);
  5393.         $fromText    self::flattenSingleValue($fromText);
  5394.         $toText        self::flattenSingleValue($toText);
  5395.         $instance    floor(self::flattenSingleValue($instance));
  5396.  
  5397.         if ($instance == 0{
  5398.             if(function_exists('mb_str_replace')) {
  5399.                 return mb_str_replace($fromText,$toText,$text);
  5400.             else {
  5401.                 return str_replace($fromText,$toText,$text);
  5402.             }
  5403.         else {
  5404.             $pos = -1;
  5405.             while($instance 0{
  5406.                 if (function_exists('mb_strpos')) {
  5407.                     $pos mb_strpos($text$fromText$pos+1'UTF-8');
  5408.                 else {
  5409.                     $pos strpos($text$fromText$pos+1);
  5410.                 }
  5411.                 if ($pos === false{
  5412.                     break;
  5413.                 }
  5414.                 --$instance;
  5415.             }
  5416.             if ($pos !== false{
  5417.                 if (function_exists('mb_strlen')) {
  5418.                     return self::REPLACE($text,++$pos,mb_strlen($fromText'UTF-8'),$toText);
  5419.                 else {
  5420.                     return self::REPLACE($text,++$pos,strlen($fromText),$toText);
  5421.                 }
  5422.             }
  5423.         }
  5424.  
  5425.         return $left.$newText.$right;
  5426.     }    //    function SUBSTITUTE()
  5427.  
  5428.  
  5429.     /**
  5430.      *    RETURNSTRING
  5431.      *
  5432.      *    @param    mixed    $value    Value to check
  5433.      *    @return    boolean 
  5434.      */
  5435.     public static function RETURNSTRING($testValue ''{
  5436.         $testValue    self::flattenSingleValue($testValue);
  5437.  
  5438.         if (is_string($testValue)) {
  5439.             return $testValue;
  5440.         }
  5441.         return Null;
  5442.     }    //    function RETURNSTRING()
  5443.  
  5444.  
  5445.     /**
  5446.      *    FIXEDFORMAT
  5447.      *
  5448.      *    @param    mixed    $value    Value to check
  5449.      *    @return    boolean 
  5450.      */
  5451.     public static function FIXEDFORMAT($value,$decimals=2,$no_commas=false{
  5452.         $value        self::flattenSingleValue($value);
  5453.         $decimals    self::flattenSingleValue($decimals);
  5454.         $no_commas        self::flattenSingleValue($no_commas);
  5455.  
  5456.         $valueResult round($value,$decimals);
  5457.         if ($decimals 0$decimals 0}
  5458.         if (!$no_commas{
  5459.             $valueResult number_format($valueResult,$decimals);
  5460.         }
  5461.  
  5462.         return (string) $valueResult;
  5463.     }    //    function FIXEDFORMAT()
  5464.  
  5465.  
  5466.     /**
  5467.      *    TEXTFORMAT
  5468.      *
  5469.      *    @param    mixed    $value    Value to check
  5470.      *    @return    boolean 
  5471.      */
  5472.     public static function TEXTFORMAT($value,$format{
  5473.         $value    self::flattenSingleValue($value);
  5474.         $format    self::flattenSingleValue($format);
  5475.  
  5476.         if ((is_string($value)) && (!is_numeric($value)) && PHPExcel_Shared_Date::isDateTimeFormatCode($format)) {
  5477.             $value self::DATEVALUE($value);
  5478.         }
  5479.  
  5480.         return (string) PHPExcel_Style_NumberFormat::toFormattedString($value,$format);
  5481.     }    //    function TEXTFORMAT()
  5482.  
  5483.  
  5484.     /**
  5485.      *    TRIMSPACES
  5486.      *
  5487.      *    @param    mixed    $value    Value to check
  5488.      *    @return    string 
  5489.      */
  5490.     public static function TRIMSPACES($stringValue ''{
  5491.         $stringValue    self::flattenSingleValue($stringValue);
  5492.  
  5493.         if (is_string($stringValue|| is_numeric($stringValue)) {
  5494.             return trim(preg_replace('/  +/',' ',$stringValue));
  5495.         }
  5496.         return Null;
  5497.     }    //    function TRIMSPACES()
  5498.  
  5499.  
  5500.     private static $_invalidChars Null;
  5501.  
  5502.     /**
  5503.      *    TRIMNONPRINTABLE
  5504.      *
  5505.      *    @param    mixed    $value    Value to check
  5506.      *    @return    string 
  5507.      */
  5508.     public static function TRIMNONPRINTABLE($stringValue ''{
  5509.         $stringValue    self::flattenSingleValue($stringValue);
  5510.  
  5511.         if (is_bool($stringValue)) {
  5512.             $stringValue ($stringValue'TRUE' 'FALSE';
  5513.         }
  5514.  
  5515.         if (self::$_invalidChars == Null{
  5516.             self::$_invalidChars range(chr(0),chr(31));
  5517.         }
  5518.  
  5519.         if (is_string($stringValue|| is_numeric($stringValue)) {
  5520.             return str_replace(self::$_invalidChars,'',trim($stringValue,"\x00..\x1F"));
  5521.         }
  5522.         return Null;
  5523.     }    //    function TRIMNONPRINTABLE()
  5524.  
  5525.  
  5526.     /**
  5527.      *    ERROR_TYPE
  5528.      *
  5529.      *    @param    mixed    $value    Value to check
  5530.      *    @return    boolean 
  5531.      */
  5532.     public static function ERROR_TYPE($value ''{
  5533.         $value    self::flattenSingleValue($value);
  5534.  
  5535.         $i 1;
  5536.         foreach(self::$_errorCodes as $errorCode{
  5537.             if ($value == $errorCode{
  5538.                 return $i;
  5539.             }
  5540.             ++$i;
  5541.         }
  5542.         return self::$_errorCodes['na'];
  5543.     }    //    function ERROR_TYPE()
  5544.  
  5545.  
  5546.     /**
  5547.      *    IS_BLANK
  5548.      *
  5549.      *    @param    mixed    $value    Value to check
  5550.      *    @return    boolean 
  5551.      */
  5552.     public static function IS_BLANK($value=null{
  5553.         if (!is_null($value)) {
  5554.             $value    self::flattenSingleValue($value);
  5555.         }
  5556.  
  5557.         return is_null($value);
  5558.     }    //    function IS_BLANK()
  5559.  
  5560.  
  5561.     /**
  5562.      *    IS_ERR
  5563.      *
  5564.      *    @param    mixed    $value    Value to check
  5565.      *    @return    boolean 
  5566.      */
  5567.     public static function IS_ERR($value ''{
  5568.         $value        self::flattenSingleValue($value);
  5569.  
  5570.         return self::IS_ERROR($value&& (!self::IS_NA($value));
  5571.     }    //    function IS_ERR()
  5572.  
  5573.  
  5574.     /**
  5575.      *    IS_ERROR
  5576.      *
  5577.      *    @param    mixed    $value    Value to check
  5578.      *    @return    boolean 
  5579.      */
  5580.     public static function IS_ERROR($value ''{
  5581.         $value        self::flattenSingleValue($value);
  5582.  
  5583.         return in_array($valuearray_values(self::$_errorCodes));
  5584.     }    //    function IS_ERROR()
  5585.  
  5586.  
  5587.     /**
  5588.      *    IS_NA
  5589.      *
  5590.      *    @param    mixed    $value    Value to check
  5591.      *    @return    boolean 
  5592.      */
  5593.     public static function IS_NA($value ''{
  5594.         $value        self::flattenSingleValue($value);
  5595.  
  5596.         return ($value === self::$_errorCodes['na']);
  5597.     }    //    function IS_NA()
  5598.  
  5599.  
  5600.     /**
  5601.      *    IS_EVEN
  5602.      *
  5603.      *    @param    mixed    $value    Value to check
  5604.      *    @return    boolean 
  5605.      */
  5606.     public static function IS_EVEN($value 0{
  5607.         $value        self::flattenSingleValue($value);
  5608.  
  5609.         if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
  5610.             return self::$_errorCodes['value'];
  5611.         }
  5612.         return ($value == 0);
  5613.     }    //    function IS_EVEN()
  5614.  
  5615.  
  5616.     /**
  5617.      *    IS_ODD
  5618.      *
  5619.      *    @param    mixed    $value    Value to check
  5620.      *    @return    boolean 
  5621.      */
  5622.     public static function IS_ODD($value null{
  5623.         $value        self::flattenSingleValue($value);
  5624.  
  5625.         if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
  5626.             return self::$_errorCodes['value'];
  5627.         }
  5628.         return (abs($value== 1);
  5629.     }    //    function IS_ODD()
  5630.  
  5631.  
  5632.     /**
  5633.      *    IS_NUMBER
  5634.      *
  5635.      *    @param    mixed    $value        Value to check
  5636.      *    @return    boolean 
  5637.      */
  5638.     public static function IS_NUMBER($value 0{
  5639.         $value        self::flattenSingleValue($value);
  5640.  
  5641.         if (is_string($value)) {
  5642.             return False;
  5643.         }
  5644.         return is_numeric($value);
  5645.     }    //    function IS_NUMBER()
  5646.  
  5647.  
  5648.     /**
  5649.      *    IS_LOGICAL
  5650.      *
  5651.      *    @param    mixed    $value        Value to check
  5652.      *    @return    boolean 
  5653.      */
  5654.     public static function IS_LOGICAL($value true{
  5655.         $value        self::flattenSingleValue($value);
  5656.  
  5657.         return is_bool($value);
  5658.     }    //    function IS_LOGICAL()
  5659.  
  5660.  
  5661.     /**
  5662.      *    IS_TEXT
  5663.      *
  5664.      *    @param    mixed    $value        Value to check
  5665.      *    @return    boolean 
  5666.      */
  5667.     public static function IS_TEXT($value ''{
  5668.         $value        self::flattenSingleValue($value);
  5669.  
  5670.         return is_string($value);
  5671.     }    //    function IS_TEXT()
  5672.  
  5673.  
  5674.     /**
  5675.      *    IS_NONTEXT
  5676.      *
  5677.      *    @param    mixed    $value        Value to check
  5678.      *    @return    boolean 
  5679.      */
  5680.     public static function IS_NONTEXT($value ''{
  5681.         return !self::IS_TEXT($value);
  5682.     }    //    function IS_NONTEXT()
  5683.  
  5684.  
  5685.     /**
  5686.      *    VERSION
  5687.      *
  5688.      *    @return    string    Version information
  5689.      */
  5690.     public static function VERSION({
  5691.         return 'PHPExcel 1.7.4, 2010-08-26';
  5692.     }    //    function VERSION()
  5693.  
  5694.  
  5695.     /**
  5696.      * DATE
  5697.      *
  5698.      * @param    long    $year 
  5699.      * @param    long    $month 
  5700.      * @param    long    $day 
  5701.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5702.      *                         depending on the value of the ReturnDateType flag
  5703.      */
  5704.     public static function DATE($year 0$month 1$day 1{
  5705.         $year    = (integer) self::flattenSingleValue($year);
  5706.         $month    = (integer) self::flattenSingleValue($month);
  5707.         $day    = (integer) self::flattenSingleValue($day);
  5708.  
  5709.         $baseYear PHPExcel_Shared_Date::getExcelCalendar();
  5710.         // Validate parameters
  5711.         if ($year ($baseYear-1900)) {
  5712.             return self::$_errorCodes['num'];
  5713.         }
  5714.         if ((($baseYear-1900!= 0&& ($year $baseYear&& ($year >= 1900)) {
  5715.             return self::$_errorCodes['num'];
  5716.         }
  5717.  
  5718.         if (($year $baseYear&& ($year >= ($baseYear-1900))) {
  5719.             $year += 1900;
  5720.         }
  5721.  
  5722.         if ($month 1{
  5723.             //    Handle year/month adjustment if month < 1
  5724.             --$month;
  5725.             $year += ceil($month 121;
  5726.             $month 13 abs($month 12);
  5727.         elseif ($month 12{
  5728.             //    Handle year/month adjustment if month > 12
  5729.             $year += floor($month 12);
  5730.             $month ($month 12);
  5731.         }
  5732.  
  5733.         // Re-validate the year parameter after adjustments
  5734.         if (($year $baseYear|| ($year >= 10000)) {
  5735.             return self::$_errorCodes['num'];
  5736.         }
  5737.  
  5738.         // Execute function
  5739.         $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel($year$month$day);
  5740.         switch (self::getReturnDateType()) {
  5741.             case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  5742.                                                   break;
  5743.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
  5744.                                                   break;
  5745.             case self::RETURNDATE_PHP_OBJECT    return PHPExcel_Shared_Date::ExcelToPHPObject($excelDateValue);
  5746.                                                   break;
  5747.         }
  5748.     }    //    function DATE()
  5749.  
  5750.  
  5751.     /**
  5752.      * TIME
  5753.      *
  5754.      * @param    long    $hour 
  5755.      * @param    long    $minute 
  5756.      * @param    long    $second 
  5757.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5758.      *                         depending on the value of the ReturnDateType flag
  5759.      */
  5760.     public static function TIME($hour 0$minute 0$second 0{
  5761.         $hour    self::flattenSingleValue($hour);
  5762.         $minute    self::flattenSingleValue($minute);
  5763.         $second    self::flattenSingleValue($second);
  5764.  
  5765.         if ($hour == ''$hour 0}
  5766.         if ($minute == ''$minute 0}
  5767.         if ($second == ''$second 0}
  5768.  
  5769.         if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) {
  5770.             return self::$_errorCodes['value'];
  5771.         }
  5772.         $hour    = (integer) $hour;
  5773.         $minute    = (integer) $minute;
  5774.         $second    = (integer) $second;
  5775.  
  5776.         if ($second 0{
  5777.             $minute += floor($second 60);
  5778.             $second 60 abs($second 60);
  5779.             if ($second == 60$second 0}
  5780.         elseif ($second >= 60{
  5781.             $minute += floor($second 60);
  5782.             $second $second 60;
  5783.         }
  5784.         if ($minute 0{
  5785.             $hour += floor($minute 60);
  5786.             $minute 60 abs($minute 60);
  5787.             if ($minute == 60$minute 0}
  5788.         elseif ($minute >= 60{
  5789.             $hour += floor($minute 60);
  5790.             $minute $minute 60;
  5791.         }
  5792.  
  5793.         if ($hour 23{
  5794.             $hour $hour 24;
  5795.         elseif ($hour 0{
  5796.             return self::$_errorCodes['num'];
  5797.         }
  5798.  
  5799.         // Execute function
  5800.         switch (self::getReturnDateType()) {
  5801.             case self::RETURNDATE_EXCEL            $date 0;
  5802.                                                   $calendar PHPExcel_Shared_Date::getExcelCalendar();
  5803.                                                   if ($calendar != PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900{
  5804.                                                      $date 1;
  5805.                                                   }
  5806.                                                   return (float) PHPExcel_Shared_Date::FormattedPHPToExcel($calendar1$date$hour$minute$second);
  5807.                                                   break;
  5808.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(197011$hour-1$minute$second));    // -2147468400; //    -2147472000 + 3600
  5809.                                                   break;
  5810.             case self::RETURNDATE_PHP_OBJECT    $dayAdjust 0;
  5811.                                                   if ($hour 0{
  5812.                                                      $dayAdjust floor($hour 24);
  5813.                                                      $hour 24 abs($hour 24);
  5814.                                                      if ($hour == 24$hour 0}
  5815.                                                   elseif ($hour >= 24{
  5816.                                                      $dayAdjust floor($hour 24);
  5817.                                                      $hour $hour 24;
  5818.                                                   }
  5819.                                                   $phpDateObject new DateTime('1900-01-01 '.$hour.':'.$minute.':'.$second);
  5820.                                                   if ($dayAdjust != 0{
  5821.                                                      $phpDateObject->modify($dayAdjust.' days');
  5822.                                                   }
  5823.                                                   return $phpDateObject;
  5824.                                                   break;
  5825.         }
  5826.     }    //    function TIME()
  5827.  
  5828.  
  5829.     /**
  5830.      * DATEVALUE
  5831.      *
  5832.      * @param    string    $dateValue 
  5833.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5834.      *                         depending on the value of the ReturnDateType flag
  5835.      */
  5836.     public static function DATEVALUE($dateValue 1{
  5837.         $dateValue trim(self::flattenSingleValue($dateValue),'"');
  5838.         //    Strip any ordinals because they're allowed in Excel (English only)
  5839.         $dateValue preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui','$1$3',$dateValue);
  5840.         //    Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany)
  5841.         $dateValue    str_replace(array('/','.','-','  '),array(' ',' ',' ',' '),$dateValue);
  5842.  
  5843.         $yearFound false;
  5844.         $t1 explode(' ',$dateValue);
  5845.         foreach($t1 as &$t{
  5846.             if ((is_numeric($t)) && ($t 31)) {
  5847.                 if ($yearFound{
  5848.                     return self::$_errorCodes['value'];
  5849.                 else {
  5850.                     if ($t 100$t += 1900}
  5851.                     $yearFound true;
  5852.                 }
  5853.             }
  5854.         }
  5855.         if ((count($t1== 1&& (strpos($t,':'!= false)) {
  5856.             //    We've been fed a time value without any date
  5857.             return 0.0;
  5858.         elseif (count($t1== 2{
  5859.             //    We only have two parts of the date: either day/month or month/year
  5860.             if ($yearFound{
  5861.                 array_unshift($t1,1);
  5862.             else {
  5863.                 array_push($t1,date('Y'));
  5864.             }
  5865.         }
  5866.         unset($t);
  5867.         $dateValue implode(' ',$t1);
  5868.  
  5869.         $PHPDateArray date_parse($dateValue);
  5870.         if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  5871.             $testVal1 strtok($dateValue,'- ');
  5872.             if ($testVal1 !== False{
  5873.                 $testVal2 strtok('- ');
  5874.                 if ($testVal2 !== False{
  5875.                     $testVal3 strtok('- ');
  5876.                     if ($testVal3 === False{
  5877.                         $testVal3 strftime('%Y');
  5878.                     }
  5879.                 else {
  5880.                     return self::$_errorCodes['value'];
  5881.                 }
  5882.             else {
  5883.                 return self::$_errorCodes['value'];
  5884.             }
  5885.             $PHPDateArray date_parse($testVal1.'-'.$testVal2.'-'.$testVal3);
  5886.             if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  5887.                 $PHPDateArray date_parse($testVal2.'-'.$testVal1.'-'.$testVal3);
  5888.                 if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  5889.                     return self::$_errorCodes['value'];
  5890.                 }
  5891.             }
  5892.         }
  5893.  
  5894.         if (($PHPDateArray !== False&& ($PHPDateArray['error_count'== 0)) {
  5895.             // Execute function
  5896.             if ($PHPDateArray['year'== '')    $PHPDateArray['year'strftime('%Y')}
  5897.             if ($PHPDateArray['month'== '')    $PHPDateArray['month'strftime('%m')}
  5898.             if ($PHPDateArray['day'== '')        $PHPDateArray['day'strftime('%d')}
  5899.             $excelDateValue floor(PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']));
  5900.  
  5901.             switch (self::getReturnDateType()) {
  5902.                 case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  5903.                                                       break;
  5904.                 case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
  5905.                                                       break;
  5906.                 case self::RETURNDATE_PHP_OBJECT    return new DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00');
  5907.                                                       break;
  5908.             }
  5909.         }
  5910.         return self::$_errorCodes['value'];
  5911.     }    //    function DATEVALUE()
  5912.  
  5913.  
  5914.     /**
  5915.      * _getDateValue
  5916.      *
  5917.      * @param    string    $dateValue 
  5918.      * @return    mixed    Excel date/time serial value, or string if error
  5919.      */
  5920.     private static function _getDateValue($dateValue{
  5921.         if (!is_numeric($dateValue)) {
  5922.             if ((is_string($dateValue)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  5923.                 return self::$_errorCodes['value'];
  5924.             }
  5925.             if ((is_object($dateValue)) && ($dateValue instanceof PHPExcel_Shared_Date::$dateTimeObjectType)) {
  5926.                 $dateValue PHPExcel_Shared_Date::PHPToExcel($dateValue);
  5927.             else {
  5928.                 $saveReturnDateType self::getReturnDateType();
  5929.                 self::setReturnDateType(self::RETURNDATE_EXCEL);
  5930.                 $dateValue self::DATEVALUE($dateValue);
  5931.                 self::setReturnDateType($saveReturnDateType);
  5932.             }
  5933.         }
  5934.         return $dateValue;
  5935.     }    //    function _getDateValue()
  5936.  
  5937.  
  5938.     /**
  5939.      * TIMEVALUE
  5940.      *
  5941.      * @param    string    $timeValue 
  5942.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5943.      *                         depending on the value of the ReturnDateType flag
  5944.      */
  5945.     public static function TIMEVALUE($timeValue{
  5946.         $timeValue trim(self::flattenSingleValue($timeValue),'"');
  5947.         $timeValue    str_replace(array('/','.'),array('-','-'),$timeValue);
  5948.  
  5949.         $PHPDateArray date_parse($timeValue);
  5950.         if (($PHPDateArray !== False&& ($PHPDateArray['error_count'== 0)) {
  5951.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5952.                 $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']);
  5953.             else {
  5954.                 $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel(1900,1,1,$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']1;
  5955.             }
  5956.  
  5957.             switch (self::getReturnDateType()) {
  5958.                 case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  5959.                                                       break;
  5960.                 case self::RETURNDATE_PHP_NUMERIC    return (integer) $phpDateValue PHPExcel_Shared_Date::ExcelToPHP($excelDateValue+255693600;;
  5961.                                                       break;
  5962.                 case self::RETURNDATE_PHP_OBJECT    return new DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']);
  5963.                                                       break;
  5964.             }
  5965.         }
  5966.         return self::$_errorCodes['value'];
  5967.     }    //    function TIMEVALUE()
  5968.  
  5969.  
  5970.     /**
  5971.      * _getTimeValue
  5972.      *
  5973.      * @param    string    $timeValue 
  5974.      * @return    mixed    Excel date/time serial value, or string if error
  5975.      */
  5976.     private static function _getTimeValue($timeValue{
  5977.         $saveReturnDateType self::getReturnDateType();
  5978.         self::setReturnDateType(self::RETURNDATE_EXCEL);
  5979.         $timeValue self::TIMEVALUE($timeValue);
  5980.         self::setReturnDateType($saveReturnDateType);
  5981.         return $timeValue;
  5982.     }    //    function _getTimeValue()
  5983.  
  5984.  
  5985.     /**
  5986.      * DATETIMENOW
  5987.      *
  5988.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5989.      *                         depending on the value of the ReturnDateType flag
  5990.      */
  5991.     public static function DATETIMENOW({
  5992.         $saveTimeZone date_default_timezone_get();
  5993.         date_default_timezone_set('UTC');
  5994.         $retValue False;
  5995.         switch (self::getReturnDateType()) {
  5996.             case self::RETURNDATE_EXCEL            $retValue = (float) PHPExcel_Shared_Date::PHPToExcel(time());
  5997.                                                   break;
  5998.             case self::RETURNDATE_PHP_NUMERIC    $retValue = (integer) time();
  5999.                                                   break;
  6000.             case self::RETURNDATE_PHP_OBJECT    $retValue new DateTime();
  6001.                                                   break;
  6002.         }
  6003.         date_default_timezone_set($saveTimeZone);
  6004.  
  6005.         return $retValue;
  6006.     }    //    function DATETIMENOW()
  6007.  
  6008.  
  6009.     /**
  6010.      * DATENOW
  6011.      *
  6012.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  6013.      *                         depending on the value of the ReturnDateType flag
  6014.      */
  6015.     public static function DATENOW({
  6016.         $saveTimeZone date_default_timezone_get();
  6017.         date_default_timezone_set('UTC');
  6018.         $retValue False;
  6019.         $excelDateTime floor(PHPExcel_Shared_Date::PHPToExcel(time()));
  6020.         switch (self::getReturnDateType()) {
  6021.             case self::RETURNDATE_EXCEL            $retValue = (float) $excelDateTime;
  6022.                                                   break;
  6023.             case self::RETURNDATE_PHP_NUMERIC    $retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime3600;
  6024.                                                   break;
  6025.             case self::RETURNDATE_PHP_OBJECT    $retValue PHPExcel_Shared_Date::ExcelToPHPObject($excelDateTime);
  6026.                                                   break;
  6027.         }
  6028.         date_default_timezone_set($saveTimeZone);
  6029.  
  6030.         return $retValue;
  6031.     }    //    function DATENOW()
  6032.  
  6033.  
  6034.     private static function _isLeapYear($year{
  6035.         return ((($year 4== 0&& (($year 100!= 0|| (($year 400== 0));
  6036.     }    //    function _isLeapYear()
  6037.  
  6038.  
  6039.     private static function _dateDiff360($startDay$startMonth$startYear$endDay$endMonth$endYear$methodUS{
  6040.         if ($startDay == 31{
  6041.             --$startDay;
  6042.         elseif ($methodUS && ($startMonth == && ($startDay == 29 || ($startDay == 28 && !self::_isLeapYear($startYear))))) {
  6043.             $startDay 30;
  6044.         }
  6045.         if ($endDay == 31{
  6046.             if ($methodUS && $startDay != 30{
  6047.                 $endDay 1;
  6048.                 if ($endMonth == 12{
  6049.                     ++$endYear;
  6050.                     $endMonth 1;
  6051.                 else {
  6052.                     ++$endMonth;
  6053.                 }
  6054.             else {
  6055.                 $endDay 30;
  6056.             }
  6057.         }
  6058.  
  6059.         return $endDay $endMonth 30 $endYear 360 $startDay $startMonth 30 $startYear 360;
  6060.     }    //    function _dateDiff360()
  6061.  
  6062.  
  6063.     /**
  6064.      * DAYS360
  6065.      *
  6066.      * @param    long    $startDate        Excel date serial value or a standard date string
  6067.      * @param    long    $endDate        Excel date serial value or a standard date string
  6068.      * @param    boolean    $method            US or European Method
  6069.      * @return    long    PHP date/time serial
  6070.      */
  6071.     public static function DAYS360($startDate 0$endDate 0$method false{
  6072.         $startDate    self::flattenSingleValue($startDate);
  6073.         $endDate    self::flattenSingleValue($endDate);
  6074.  
  6075.         if (is_string($startDate self::_getDateValue($startDate))) {
  6076.             return self::$_errorCodes['value'];
  6077.         }
  6078.         if (is_string($endDate self::_getDateValue($endDate))) {
  6079.             return self::$_errorCodes['value'];
  6080.         }
  6081.  
  6082.         // Execute function
  6083.         $PHPStartDateObject PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
  6084.         $startDay $PHPStartDateObject->format('j');
  6085.         $startMonth $PHPStartDateObject->format('n');
  6086.         $startYear $PHPStartDateObject->format('Y');
  6087.  
  6088.         $PHPEndDateObject PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  6089.         $endDay $PHPEndDateObject->format('j');
  6090.         $endMonth $PHPEndDateObject->format('n');
  6091.         $endYear $PHPEndDateObject->format('Y');
  6092.  
  6093.         return self::_dateDiff360($startDay$startMonth$startYear$endDay$endMonth$endYear!$method);
  6094.     }    //    function DAYS360()
  6095.  
  6096.  
  6097.     /**
  6098.      * DATEDIF
  6099.      *
  6100.      * @param    long    $startDate        Excel date serial value or a standard date string
  6101.      * @param    long    $endDate        Excel date serial value or a standard date string
  6102.      * @param    string    $unit 
  6103.      * @return    long    Interval between the dates
  6104.      */
  6105.     public static function DATEDIF($startDate 0$endDate 0$unit 'D'{
  6106.         $startDate    self::flattenSingleValue($startDate);
  6107.         $endDate    self::flattenSingleValue($endDate);
  6108.         $unit        strtoupper(self::flattenSingleValue($unit));
  6109.  
  6110.         if (is_string($startDate self::_getDateValue($startDate))) {
  6111.             return self::$_errorCodes['value'];
  6112.         }
  6113.         if (is_string($endDate self::_getDateValue($endDate))) {
  6114.             return self::$_errorCodes['value'];
  6115.         }
  6116.  
  6117.         // Validate parameters
  6118.         if ($startDate >= $endDate{
  6119.             return self::$_errorCodes['num'];
  6120.         }
  6121.  
  6122.         // Execute function
  6123.         $difference $endDate $startDate;
  6124.  
  6125.         $PHPStartDateObject PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
  6126.         $startDays $PHPStartDateObject->format('j');
  6127.         $startMonths $PHPStartDateObject->format('n');
  6128.         $startYears $PHPStartDateObject->format('Y');
  6129.  
  6130.         $PHPEndDateObject PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  6131.         $endDays $PHPEndDateObject->format('j');
  6132.         $endMonths $PHPEndDateObject->format('n');
  6133.         $endYears $PHPEndDateObject->format('Y');
  6134.  
  6135.         $retVal self::$_errorCodes['num'];
  6136.         switch ($unit{
  6137.             case 'D':
  6138.                 $retVal intval($difference);
  6139.                 break;
  6140.             case 'M':
  6141.                 $retVal intval($endMonths $startMonths(intval($endYears $startYears12);
  6142.                 //    We're only interested in full months
  6143.                 if ($endDays $startDays{
  6144.                     --$retVal;
  6145.                 }
  6146.                 break;
  6147.             case 'Y':
  6148.                 $retVal intval($endYears $startYears);
  6149.                 //    We're only interested in full months
  6150.                 if ($endMonths $startMonths{
  6151.                     --$retVal;
  6152.                 elseif (($endMonths == $startMonths&& ($endDays $startDays)) {
  6153.                     --$retVal;
  6154.                 }
  6155.                 break;
  6156.             case 'MD':
  6157.                 if ($endDays $startDays{
  6158.                     $retVal $endDays;
  6159.                     $PHPEndDateObject->modify('-'.$endDays.' days');
  6160.                     $adjustDays $PHPEndDateObject->format('j');
  6161.                     if ($adjustDays $startDays{
  6162.                         $retVal += ($adjustDays $startDays);
  6163.                     }
  6164.                 else {
  6165.                     $retVal $endDays $startDays;
  6166.                 }
  6167.                 break;
  6168.             case 'YM':
  6169.                 $retVal intval($endMonths $startMonths);
  6170.                 if ($retVal 0$retVal 12 $retVal;
  6171.                 //    We're only interested in full months
  6172.                 if ($endDays $startDays{
  6173.                     --$retVal;
  6174.                 }
  6175.                 break;
  6176.             case 'YD':
  6177.                 $retVal intval($difference);
  6178.                 if ($endYears $startYears{
  6179.                     while ($endYears $startYears{
  6180.                         $PHPEndDateObject->modify('-1 year');
  6181.                         $endYears $PHPEndDateObject->format('Y');
  6182.                     }
  6183.                     $retVal $PHPEndDateObject->format('z'$PHPStartDateObject->format('z');
  6184.                     if ($retVal 0$retVal += 365}
  6185.                 }
  6186.                 break;
  6187.         }
  6188.         return $retVal;
  6189.     }    //    function DATEDIF()
  6190.  
  6191.  
  6192.     /**
  6193.      *    YEARFRAC
  6194.      *
  6195.      *    Calculates the fraction of the year represented by the number of whole days between two dates (the start_date and the
  6196.      *    end_date). Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or obligations
  6197.      *    to assign to a specific term.
  6198.      *
  6199.      *    @param    mixed    $startDate        Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string
  6200.      *    @param    mixed    $endDate        Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string
  6201.      *    @param    integer    $method            Method used for the calculation
  6202.      *                                         0 or omitted    US (NASD) 30/360
  6203.      *                                         1                Actual/actual
  6204.      *                                         2                Actual/360
  6205.      *                                         3                Actual/365
  6206.      *                                         4                European 30/360
  6207.      *    @return    float    fraction of the year
  6208.      */
  6209.     public static function YEARFRAC($startDate 0$endDate 0$method 0{
  6210.         $startDate    self::flattenSingleValue($startDate);
  6211.         $endDate    self::flattenSingleValue($endDate);
  6212.         $method        self::flattenSingleValue($method);
  6213.  
  6214.         if (is_string($startDate self::_getDateValue($startDate))) {
  6215.             return self::$_errorCodes['value'];
  6216.         }
  6217.         if (is_string($endDate self::_getDateValue($endDate))) {
  6218.             return self::$_errorCodes['value'];
  6219.         }
  6220.  
  6221.         if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) {
  6222.             switch($method{
  6223.                 case 0    :
  6224.                     return self::DAYS360($startDate,$endDate360;
  6225.                     break;
  6226.                 case 1    :
  6227.                     $days self::DATEDIF($startDate,$endDate);
  6228.                     $startYear self::YEAR($startDate);
  6229.                     $endYear self::YEAR($endDate);
  6230.                     $years $endYear $startYear 1;
  6231.                     $leapDays 0;
  6232.                     if ($years == 1{
  6233.                         if (self::_isLeapYear($endYear)) {
  6234.                             $startMonth self::MONTHOFYEAR($startDate);
  6235.                             $endMonth self::MONTHOFYEAR($endDate);
  6236.                             $endDay self::DAYOFMONTH($endDate);
  6237.                             if (($startMonth 3||
  6238.                                 (($endMonth 100 $endDay>= (100 29))) {
  6239.                                  $leapDays += 1;
  6240.                             }
  6241.                         }
  6242.                     else {
  6243.                         for($year $startYear$year <= $endYear++$year{
  6244.                             if ($year == $startYear{
  6245.                                 $startMonth self::MONTHOFYEAR($startDate);
  6246.                                 $startDay self::DAYOFMONTH($startDate);
  6247.                                 if ($startMonth 3{
  6248.                                     $leapDays += (self::_isLeapYear($year)) 0;
  6249.                                 }
  6250.                             elseif($year == $endYear{
  6251.                                 $endMonth self::MONTHOFYEAR($endDate);
  6252.                                 $endDay self::DAYOFMONTH($endDate);
  6253.                                 if (($endMonth 100 $endDay>= (100 29)) {
  6254.                                     $leapDays += (self::_isLeapYear($year)) 0;
  6255.                                 }
  6256.                             else {
  6257.                                 $leapDays += (self::_isLeapYear($year)) 0;
  6258.                             }
  6259.                         }
  6260.                         if ($years == 2{
  6261.                             if (($leapDays == 0&& (self::_isLeapYear($startYear)) && ($days 365)) {
  6262.                                 $leapDays 1;
  6263.                             elseif ($days 366{
  6264.                                 $years 1;
  6265.                             }
  6266.                         }
  6267.                         $leapDays /= $years;
  6268.                     }
  6269.                     return $days (365 $leapDays);
  6270.                     break;
  6271.                 case 2    :
  6272.                     return self::DATEDIF($startDate,$endDate360;
  6273.                     break;
  6274.                 case 3    :
  6275.                     return self::DATEDIF($startDate,$endDate365;
  6276.                     break;
  6277.                 case 4    :
  6278.                     return self::DAYS360($startDate,$endDate,True360;
  6279.                     break;
  6280.             }
  6281.         }
  6282.         return self::$_errorCodes['value'];
  6283.     }    //    function YEARFRAC()
  6284.  
  6285.  
  6286.     /**
  6287.      * NETWORKDAYS
  6288.      *
  6289.      * @param    mixed                Start date
  6290.      * @param    mixed                End date
  6291.      * @param    array of mixed        Optional Date Series
  6292.      * @return    long    Interval between the dates
  6293.      */
  6294.     public static function NETWORKDAYS($startDate,$endDate{
  6295.         //    Retrieve the mandatory start and end date that are referenced in the function definition
  6296.         $startDate    self::flattenSingleValue($startDate);
  6297.         $endDate    self::flattenSingleValue($endDate);
  6298.         //    Flush the mandatory start and end date that are referenced in the function definition, and get the optional days
  6299.         $dateArgs self::flattenArray(func_get_args());
  6300.         array_shift($dateArgs);
  6301.         array_shift($dateArgs);
  6302.  
  6303.         //    Validate the start and end dates
  6304.         if (is_string($startDate $sDate self::_getDateValue($startDate))) {
  6305.             return self::$_errorCodes['value'];
  6306.         }
  6307.         $startDate = (float) floor($startDate);
  6308.         if (is_string($endDate $eDate self::_getDateValue($endDate))) {
  6309.             return self::$_errorCodes['value'];
  6310.         }
  6311.         $endDate = (float) floor($endDate);
  6312.  
  6313.         if ($sDate $eDate{
  6314.             $startDate $eDate;
  6315.             $endDate $sDate;
  6316.         }
  6317.  
  6318.         // Execute function
  6319.         $startDoW self::DAYOFWEEK($startDate,2);
  6320.         if ($startDoW 0$startDoW 0}
  6321.         $endDoW self::DAYOFWEEK($endDate,2);
  6322.         if ($endDoW >= 6$endDoW 0}
  6323.  
  6324.         $wholeWeekDays floor(($endDate $startDate75;
  6325.         $partWeekDays $endDoW $startDoW;
  6326.         if ($partWeekDays 5{
  6327.             $partWeekDays -= 5;
  6328.         }
  6329.  
  6330.         //    Test any extra holiday parameters
  6331.         $holidayCountedArray array();
  6332.         foreach ($dateArgs as $holidayDate{
  6333.             if (is_string($holidayDate self::_getDateValue($holidayDate))) {
  6334.                 return self::$_errorCodes['value'];
  6335.             }
  6336.             if (($holidayDate >= $startDate&& ($holidayDate <= $endDate)) {
  6337.                 if ((self::DAYOFWEEK($holidayDate,26&& (!in_array($holidayDate,$holidayCountedArray))) {
  6338.                     --$partWeekDays;
  6339.                     $holidayCountedArray[$holidayDate;
  6340.                 }
  6341.             }
  6342.         }
  6343.  
  6344.         if ($sDate $eDate{
  6345.             return ($wholeWeekDays $partWeekDays);
  6346.         }
  6347.         return $wholeWeekDays $partWeekDays;
  6348.     }    //    function NETWORKDAYS()
  6349.  
  6350.  
  6351.     /**
  6352.      * WORKDAY
  6353.      *
  6354.      * @param    mixed                Start date
  6355.      * @param    mixed                number of days for adjustment
  6356.      * @param    array of mixed        Optional Date Series
  6357.      * @return    long    Interval between the dates
  6358.      */
  6359.     public static function WORKDAY($startDate,$endDays{
  6360.         //    Retrieve the mandatory start date and days that are referenced in the function definition
  6361.         $startDate    self::flattenSingleValue($startDate);
  6362.         $endDays    = (int) self::flattenSingleValue($endDays);
  6363.         //    Flush the mandatory start date and days that are referenced in the function definition, and get the optional days
  6364.         $dateArgs self::flattenArray(func_get_args());
  6365.         array_shift($dateArgs);
  6366.         array_shift($dateArgs);
  6367.  
  6368.         if ((is_string($startDate self::_getDateValue($startDate))) || (!is_numeric($endDays))) {
  6369.             return self::$_errorCodes['value'];
  6370.         }
  6371.         $startDate = (float) floor($startDate);
  6372.         //    If endDays is 0, we always return startDate
  6373.         if ($endDays == 0return $startDate}
  6374.  
  6375.         $decrementing ($endDays 0True False;
  6376.  
  6377.         //    Adjust the start date if it falls over a weekend
  6378.  
  6379.         $startDoW self::DAYOFWEEK($startDate,3);
  6380.         if (self::DAYOFWEEK($startDate,3>= 5{
  6381.             $startDate += ($decrementing? -$startDoW 4$startDoW;
  6382.             ($decrementing$endDays++ : $endDays--;
  6383.         }
  6384.  
  6385.         //    Add endDays
  6386.         $endDate = (float) $startDate (intval($endDays 57($endDays 5);
  6387.  
  6388.         //    Adjust the calculated end date if it falls over a weekend
  6389.         $endDoW self::DAYOFWEEK($endDate,3);
  6390.         if ($endDoW >= 5{
  6391.             $endDate += ($decrementing? -$endDoW 4$endDoW;
  6392.         }
  6393.  
  6394.         //    Test any extra holiday parameters
  6395.         if (count($dateArgs0{
  6396.             $holidayCountedArray $holidayDates array();
  6397.             foreach ($dateArgs as $holidayDate{
  6398.                 if ((!is_null($holidayDate)) && (trim($holidayDate'')) {
  6399.                     if (is_string($holidayDate self::_getDateValue($holidayDate))) {
  6400.                         return self::$_errorCodes['value'];
  6401.                     }
  6402.                     if (self::DAYOFWEEK($holidayDate,35{
  6403.                         $holidayDates[$holidayDate;
  6404.                     }
  6405.                 }
  6406.             }
  6407.             if ($decrementing{
  6408.                 rsort($holidayDatesSORT_NUMERIC);
  6409.             else {
  6410.                 sort($holidayDatesSORT_NUMERIC);
  6411.             }
  6412.             foreach ($holidayDates as $holidayDate{
  6413.                 if ($decrementing{
  6414.                     if (($holidayDate <= $startDate&& ($holidayDate >= $endDate)) {
  6415.                         if (!in_array($holidayDate,$holidayCountedArray)) {
  6416.                             --$endDate;
  6417.                             $holidayCountedArray[$holidayDate;
  6418.                         }
  6419.                     }
  6420.                 else {
  6421.                     if (($holidayDate >= $startDate&& ($holidayDate <= $endDate)) {
  6422.                         if (!in_array($holidayDate,$holidayCountedArray)) {
  6423.                             ++$endDate;
  6424.                             $holidayCountedArray[$holidayDate;
  6425.                         }
  6426.                     }
  6427.                 }
  6428.                 //    Adjust the calculated end date if it falls over a weekend
  6429.                 $endDoW self::DAYOFWEEK($endDate,3);
  6430.                 if ($endDoW >= 5{
  6431.                     $endDate += ($decrementing? -$endDoW 4$endDoW;
  6432.                 }
  6433.  
  6434.             }
  6435.         }
  6436.  
  6437.         switch (self::getReturnDateType()) {
  6438.             case self::RETURNDATE_EXCEL            return (float) $endDate;
  6439.                                                   break;
  6440.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($endDate);
  6441.                                                   break;
  6442.             case self::RETURNDATE_PHP_OBJECT    return PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  6443.                                                   break;
  6444.         }
  6445.     }    //    function WORKDAY()
  6446.  
  6447.  
  6448.     /**
  6449.      * DAYOFMONTH
  6450.      *
  6451.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6452.      * @return    int        Day
  6453.      */
  6454.     public static function DAYOFMONTH($dateValue 1{
  6455.         $dateValue    self::flattenSingleValue($dateValue);
  6456.  
  6457.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6458.             return self::$_errorCodes['value'];
  6459.         elseif ($dateValue == 0.0{
  6460.             return 0;
  6461.         elseif ($dateValue 0.0{
  6462.             return self::$_errorCodes['num'];
  6463.         }
  6464.  
  6465.         // Execute function
  6466.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6467.  
  6468.         return (int) $PHPDateObject->format('j');
  6469.     }    //    function DAYOFMONTH()
  6470.  
  6471.  
  6472.     /**
  6473.      * DAYOFWEEK
  6474.      *
  6475.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6476.      * @return    int        Day
  6477.      */
  6478.     public static function DAYOFWEEK($dateValue 1$style 1{
  6479.         $dateValue    self::flattenSingleValue($dateValue);
  6480.         $style        floor(self::flattenSingleValue($style));
  6481.  
  6482.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6483.             return self::$_errorCodes['value'];
  6484.         elseif ($dateValue 0.0{
  6485.             return self::$_errorCodes['num'];
  6486.         }
  6487.  
  6488.         // Execute function
  6489.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6490.         $DoW $PHPDateObject->format('w');
  6491.  
  6492.         $firstDay 1;
  6493.         switch ($style{
  6494.             case 1: ++$DoW;
  6495.                     break;
  6496.             case 2if ($DoW == 0$DoW 7}
  6497.                     break;
  6498.             case 3if ($DoW == 0$DoW 7}
  6499.                     $firstDay 0;
  6500.                     --$DoW;
  6501.                     break;
  6502.             default:
  6503.         }
  6504.         if (self::$compatibilityMode == self::COMPATIBILITY_EXCEL{
  6505.             //    Test for Excel's 1900 leap year, and introduce the error as required
  6506.             if (($PHPDateObject->format('Y'== 1900&& ($PHPDateObject->format('n'<= 2)) {
  6507.                 --$DoW;
  6508.                 if ($DoW $firstDay{
  6509.                     $DoW += 7;
  6510.                 }
  6511.             }
  6512.         }
  6513.  
  6514.         return (int) $DoW;
  6515.     }    //    function DAYOFWEEK()
  6516.  
  6517.  
  6518.     /**
  6519.      * WEEKOFYEAR
  6520.      *
  6521.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6522.      * @param    boolean    $method            Week begins on Sunday or Monday
  6523.      * @return    int        Week Number
  6524.      */
  6525.     public static function WEEKOFYEAR($dateValue 1$method 1{
  6526.         $dateValue    self::flattenSingleValue($dateValue);
  6527.         $method        floor(self::flattenSingleValue($method));
  6528.  
  6529.         if (!is_numeric($method)) {
  6530.             return self::$_errorCodes['value'];
  6531.         elseif (($method 1|| ($method 2)) {
  6532.             return self::$_errorCodes['num'];
  6533.         }
  6534.  
  6535.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6536.             return self::$_errorCodes['value'];
  6537.         elseif ($dateValue 0.0{
  6538.             return self::$_errorCodes['num'];
  6539.         }
  6540.  
  6541.         // Execute function
  6542.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6543.         $dayOfYear $PHPDateObject->format('z');
  6544.         $dow $PHPDateObject->format('w');
  6545.         $PHPDateObject->modify('-'.$dayOfYear.' days');
  6546.         $dow $PHPDateObject->format('w');
  6547.         $daysInFirstWeek (($dow ($method)) 7);
  6548.         $dayOfYear -= $daysInFirstWeek;
  6549.         $weekOfYear ceil($dayOfYear 71;
  6550.  
  6551.         return (int) $weekOfYear;
  6552.     }    //    function WEEKOFYEAR()
  6553.  
  6554.  
  6555.     /**
  6556.      * MONTHOFYEAR
  6557.      *
  6558.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6559.      * @return    int        Month
  6560.      */
  6561.     public static function MONTHOFYEAR($dateValue 1{
  6562.         $dateValue    self::flattenSingleValue($dateValue);
  6563.  
  6564.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6565.             return self::$_errorCodes['value'];
  6566.         elseif ($dateValue 0.0{
  6567.             return self::$_errorCodes['num'];
  6568.         }
  6569.  
  6570.         // Execute function
  6571.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6572.  
  6573.         return (int) $PHPDateObject->format('n');
  6574.     }    //    function MONTHOFYEAR()
  6575.  
  6576.  
  6577.     /**
  6578.      * YEAR
  6579.      *
  6580.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6581.      * @return    int        Year
  6582.      */
  6583.     public static function YEAR($dateValue 1{
  6584.         $dateValue    self::flattenSingleValue($dateValue);
  6585.  
  6586.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6587.             return self::$_errorCodes['value'];
  6588.         elseif ($dateValue 0.0{
  6589.             return self::$_errorCodes['num'];
  6590.         }
  6591.  
  6592.         // Execute function
  6593.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6594.  
  6595.         return (int) $PHPDateObject->format('Y');
  6596.     }    //    function YEAR()
  6597.  
  6598.  
  6599.     /**
  6600.      * HOUROFDAY
  6601.      *
  6602.      * @param    mixed    $timeValue        Excel time serial value or a standard time string
  6603.      * @return    int        Hour
  6604.      */
  6605.     public static function HOUROFDAY($timeValue 0{
  6606.         $timeValue    self::flattenSingleValue($timeValue);
  6607.  
  6608.         if (!is_numeric($timeValue)) {
  6609.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6610.                 $testVal strtok($timeValue,'/-: ');
  6611.                 if (strlen($testValstrlen($timeValue)) {
  6612.                     return self::$_errorCodes['value'];
  6613.                 }
  6614.             }
  6615.             $timeValue self::_getTimeValue($timeValue);
  6616.             if (is_string($timeValue)) {
  6617.                 return self::$_errorCodes['value'];
  6618.             }
  6619.         }
  6620.         // Execute function
  6621.         if ($timeValue >= 1{
  6622.             $timeValue fmod($timeValue,1);
  6623.         elseif ($timeValue 0.0{
  6624.             return self::$_errorCodes['num'];
  6625.         }
  6626.         $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  6627.  
  6628.         return (int) gmdate('G',$timeValue);
  6629.     }    //    function HOUROFDAY()
  6630.  
  6631.  
  6632.     /**
  6633.      * MINUTEOFHOUR
  6634.      *
  6635.      * @param    long    $timeValue        Excel time serial value or a standard time string
  6636.      * @return    int        Minute
  6637.      */
  6638.     public static function MINUTEOFHOUR($timeValue 0{
  6639.         $timeValue $timeTester    self::flattenSingleValue($timeValue);
  6640.  
  6641.         if (!is_numeric($timeValue)) {
  6642.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6643.                 $testVal strtok($timeValue,'/-: ');
  6644.                 if (strlen($testValstrlen($timeValue)) {
  6645.                     return self::$_errorCodes['value'];
  6646.                 }
  6647.             }
  6648.             $timeValue self::_getTimeValue($timeValue);
  6649.             if (is_string($timeValue)) {
  6650.                 return self::$_errorCodes['value'];
  6651.             }
  6652.         }
  6653.         // Execute function
  6654.         if ($timeValue >= 1{
  6655.             $timeValue fmod($timeValue,1);
  6656.         elseif ($timeValue 0.0{
  6657.             return self::$_errorCodes['num'];
  6658.         }
  6659.         $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  6660.  
  6661.         return (int) gmdate('i',$timeValue);
  6662.     }    //    function MINUTEOFHOUR()
  6663.  
  6664.  
  6665.     /**
  6666.      * SECONDOFMINUTE
  6667.      *
  6668.      * @param    long    $timeValue        Excel time serial value or a standard time string
  6669.      * @return    int        Second
  6670.      */
  6671.     public static function SECONDOFMINUTE($timeValue 0{
  6672.         $timeValue    self::flattenSingleValue($timeValue);
  6673.  
  6674.         if (!is_numeric($timeValue)) {
  6675.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6676.                 $testVal strtok($timeValue,'/-: ');
  6677.                 if (strlen($testValstrlen($timeValue)) {
  6678.                     return self::$_errorCodes['value'];
  6679.                 }
  6680.             }
  6681.             $timeValue self::_getTimeValue($timeValue);
  6682.             if (is_string($timeValue)) {
  6683.                 return self::$_errorCodes['value'];
  6684.             }
  6685.         }
  6686.         // Execute function
  6687.         if ($timeValue >= 1{
  6688.             $timeValue fmod($timeValue,1);
  6689.         elseif ($timeValue 0.0{
  6690.             return self::$_errorCodes['num'];
  6691.         }
  6692.         $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  6693.  
  6694.         return (int) gmdate('s',$timeValue);
  6695.     }    //    function SECONDOFMINUTE()
  6696.  
  6697.  
  6698.     private static function _adjustDateByMonths($dateValue 0$adjustmentMonths 0{
  6699.         // Execute function
  6700.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6701.         $oMonth = (int) $PHPDateObject->format('m');
  6702.         $oYear = (int) $PHPDateObject->format('Y');
  6703.  
  6704.         $adjustmentMonthsString = (string) $adjustmentMonths;
  6705.         if ($adjustmentMonths 0{
  6706.             $adjustmentMonthsString '+'.$adjustmentMonths;
  6707.         }
  6708.         if ($adjustmentMonths != 0{
  6709.             $PHPDateObject->modify($adjustmentMonthsString.' months');
  6710.         }
  6711.         $nMonth = (int) $PHPDateObject->format('m');
  6712.         $nYear = (int) $PHPDateObject->format('Y');
  6713.  
  6714.         $monthDiff ($nMonth $oMonth(($nYear $oYear12);
  6715.         if ($monthDiff != $adjustmentMonths{
  6716.             $adjustDays = (int) $PHPDateObject->format('d');
  6717.             $adjustDaysString '-'.$adjustDays.' days';
  6718.             $PHPDateObject->modify($adjustDaysString);
  6719.         }
  6720.         return $PHPDateObject;
  6721.     }    //    function _adjustDateByMonths()
  6722.  
  6723.  
  6724.     /**
  6725.      * EDATE
  6726.      *
  6727.      * Returns the serial number that represents the date that is the indicated number of months before or after a specified date
  6728.      * (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.
  6729.      *
  6730.      * @param    long    $dateValue                Excel date serial value or a standard date string
  6731.      * @param    int        $adjustmentMonths        Number of months to adjust by
  6732.      * @return    long    Excel date serial value
  6733.      */
  6734.     public static function EDATE($dateValue 1$adjustmentMonths 0{
  6735.         $dateValue            self::flattenSingleValue($dateValue);
  6736.         $adjustmentMonths    floor(self::flattenSingleValue($adjustmentMonths));
  6737.  
  6738.         if (!is_numeric($adjustmentMonths)) {
  6739.             return self::$_errorCodes['value'];
  6740.         }
  6741.  
  6742.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6743.             return self::$_errorCodes['value'];
  6744.         }
  6745.  
  6746.         // Execute function
  6747.         $PHPDateObject self::_adjustDateByMonths($dateValue,$adjustmentMonths);
  6748.  
  6749.         switch (self::getReturnDateType()) {
  6750.             case self::RETURNDATE_EXCEL            return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
  6751.                                                   break;
  6752.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
  6753.                                                   break;
  6754.             case self::RETURNDATE_PHP_OBJECT    return $PHPDateObject;
  6755.                                                   break;
  6756.         }
  6757.     }    //    function EDATE()
  6758.  
  6759.  
  6760.     /**
  6761.      * EOMONTH
  6762.      *
  6763.      * Returns the serial number for the last day of the month that is the indicated number of months before or after start_date.
  6764.      * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
  6765.      *
  6766.      * @param    long    $dateValue            Excel date serial value or a standard date string
  6767.      * @param    int        $adjustmentMonths    Number of months to adjust by
  6768.      * @return    long    Excel date serial value
  6769.      */
  6770.     public static function EOMONTH($dateValue 1$adjustmentMonths 0{
  6771.         $dateValue            self::flattenSingleValue($dateValue);
  6772.         $adjustmentMonths    floor(self::flattenSingleValue($adjustmentMonths));
  6773.  
  6774.         if (!is_numeric($adjustmentMonths)) {
  6775.             return self::$_errorCodes['value'];
  6776.         }
  6777.  
  6778.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6779.             return self::$_errorCodes['value'];
  6780.         }
  6781.  
  6782.         // Execute function
  6783.         $PHPDateObject self::_adjustDateByMonths($dateValue,$adjustmentMonths+1);
  6784.         $adjustDays = (int) $PHPDateObject->format('d');
  6785.         $adjustDaysString '-'.$adjustDays.' days';
  6786.         $PHPDateObject->modify($adjustDaysString);
  6787.  
  6788.         switch (self::getReturnDateType()) {
  6789.             case self::RETURNDATE_EXCEL            return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
  6790.                                                   break;
  6791.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
  6792.                                                   break;
  6793.             case self::RETURNDATE_PHP_OBJECT    return $PHPDateObject;
  6794.                                                   break;
  6795.         }
  6796.     }    //    function EOMONTH()
  6797.  
  6798.  
  6799.     /**
  6800.      *    TRUNC
  6801.      *
  6802.      *    Truncates value to the number of fractional digits by number_digits.
  6803.      *
  6804.      *    @param    float        $value 
  6805.      *    @param    int            $number_digits 
  6806.      *    @return    float        Truncated value
  6807.      */
  6808.     public static function TRUNC($value 0$number_digits 0{
  6809.         $value            self::flattenSingleValue($value);
  6810.         $number_digits    self::flattenSingleValue($number_digits);
  6811.  
  6812.         // Validate parameters
  6813.         if ($number_digits 0{
  6814.             return self::$_errorCodes['value'];
  6815.         }
  6816.  
  6817.         // Truncate
  6818.         if ($number_digits 0{
  6819.             $value $value pow(10$number_digits);
  6820.         }
  6821.         $value intval($value);
  6822.         if ($number_digits 0{
  6823.             $value $value pow(10$number_digits);
  6824.         }
  6825.  
  6826.         // Return
  6827.         return $value;
  6828.     }    //    function TRUNC()
  6829.  
  6830.     /**
  6831.      *    POWER
  6832.      *
  6833.      *    Computes x raised to the power y.
  6834.      *
  6835.      *    @param    float        $x 
  6836.      *    @param    float        $y 
  6837.      *    @return    float 
  6838.      */
  6839.     public static function POWER($x 0$y 2{
  6840.         $x    self::flattenSingleValue($x);
  6841.         $y    self::flattenSingleValue($y);
  6842.  
  6843.         // Validate parameters
  6844.         if ($x == && $y <= 0{
  6845.             return self::$_errorCodes['divisionbyzero'];
  6846.         }
  6847.  
  6848.         // Return
  6849.         return pow($x$y);
  6850.     }    //    function POWER()
  6851.  
  6852.  
  6853.     private static function _nbrConversionFormat($xVal,$places{
  6854.         if (!is_null($places)) {
  6855.             if (strlen($xVal<= $places{
  6856.                 return substr(str_pad($xVal,$places,'0',STR_PAD_LEFT),-10);
  6857.             else {
  6858.                 return self::$_errorCodes['num'];
  6859.             }
  6860.         }
  6861.  
  6862.         return substr($xVal,-10);
  6863.     }    //    function _nbrConversionFormat()
  6864.  
  6865.  
  6866.     /**
  6867.      * BINTODEC
  6868.      *
  6869.      * Return a binary value as Decimal.
  6870.      *
  6871.      * @param    string        $x 
  6872.      * @return    string 
  6873.      */
  6874.     public static function BINTODEC($x{
  6875.         $x    self::flattenSingleValue($x);
  6876.  
  6877.         if (is_bool($x)) {
  6878.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6879.                 $x = (int) $x;
  6880.             else {
  6881.                 return self::$_errorCodes['value'];
  6882.             }
  6883.         }
  6884.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6885.             $x floor($x);
  6886.         }
  6887.         $x = (string) $x;
  6888.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  6889.             return self::$_errorCodes['num'];
  6890.         }
  6891.         if (strlen($x10{
  6892.             return self::$_errorCodes['num'];
  6893.         elseif (strlen($x== 10{
  6894.             //    Two's Complement
  6895.             $x substr($x,-9);
  6896.             return '-'.(512-bindec($x));
  6897.         }
  6898.         return bindec($x);
  6899.     }    //    function BINTODEC()
  6900.  
  6901.  
  6902.     /**
  6903.      * BINTOHEX
  6904.      *
  6905.      * Return a binary value as Hex.
  6906.      *
  6907.      * @param    string        $x 
  6908.      * @return    string 
  6909.      */
  6910.     public static function BINTOHEX($x$places=null{
  6911.         $x    floor(self::flattenSingleValue($x));
  6912.         $places    self::flattenSingleValue($places);
  6913.  
  6914.         if (is_bool($x)) {
  6915.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6916.                 $x = (int) $x;
  6917.             else {
  6918.                 return self::$_errorCodes['value'];
  6919.             }
  6920.         }
  6921.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6922.             $x floor($x);
  6923.         }
  6924.         $x = (string) $x;
  6925.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  6926.             return self::$_errorCodes['num'];
  6927.         }
  6928.         if (strlen($x10{
  6929.             return self::$_errorCodes['num'];
  6930.         elseif (strlen($x== 10{
  6931.             //    Two's Complement
  6932.             return str_repeat('F',8).substr(strtoupper(dechex(bindec(substr($x,-9)))),-2);
  6933.         }
  6934.         $hexVal = (string) strtoupper(dechex(bindec($x)));
  6935.  
  6936.         return self::_nbrConversionFormat($hexVal,$places);
  6937.     }    //    function BINTOHEX()
  6938.  
  6939.  
  6940.     /**
  6941.      * BINTOOCT
  6942.      *
  6943.      * Return a binary value as Octal.
  6944.      *
  6945.      * @param    string        $x 
  6946.      * @return    string 
  6947.      */
  6948.     public static function BINTOOCT($x$places=null{
  6949.         $x    floor(self::flattenSingleValue($x));
  6950.         $places    self::flattenSingleValue($places);
  6951.  
  6952.         if (is_bool($x)) {
  6953.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6954.                 $x = (int) $x;
  6955.             else {
  6956.                 return self::$_errorCodes['value'];
  6957.             }
  6958.         }
  6959.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6960.             $x floor($x);
  6961.         }
  6962.         $x = (string) $x;
  6963.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  6964.             return self::$_errorCodes['num'];
  6965.         }
  6966.         if (strlen($x10{
  6967.             return self::$_errorCodes['num'];
  6968.         elseif (strlen($x== 10{
  6969.             //    Two's Complement
  6970.             return str_repeat('7',7).substr(strtoupper(decoct(bindec(substr($x,-9)))),-3);
  6971.         }
  6972.         $octVal = (string) decoct(bindec($x));
  6973.  
  6974.         return self::_nbrConversionFormat($octVal,$places);
  6975.     }    //    function BINTOOCT()
  6976.  
  6977.  
  6978.     /**
  6979.      * DECTOBIN
  6980.      *
  6981.      * Return an octal value as binary.
  6982.      *
  6983.      * @param    string        $x 
  6984.      * @return    string 
  6985.      */
  6986.     public static function DECTOBIN($x$places=null{
  6987.         $x    self::flattenSingleValue($x);
  6988.         $places    self::flattenSingleValue($places);
  6989.  
  6990.         if (is_bool($x)) {
  6991.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6992.                 $x = (int) $x;
  6993.             else {
  6994.                 return self::$_errorCodes['value'];
  6995.             }
  6996.         }
  6997.         $x = (string) $x;
  6998.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  6999.             return self::$_errorCodes['value'];
  7000.         }
  7001.         $x = (string) floor($x);
  7002.         $r decbin($x);
  7003.         if (strlen($r== 32{
  7004.             //    Two's Complement
  7005.             $r substr($r,-10);
  7006.         elseif (strlen($r11{
  7007.             return self::$_errorCodes['num'];
  7008.         }
  7009.  
  7010.         return self::_nbrConversionFormat($r,$places);
  7011.     }    //    function DECTOBIN()
  7012.  
  7013.  
  7014.     /**
  7015.      * DECTOOCT
  7016.      *
  7017.      * Return an octal value as binary.
  7018.      *
  7019.      * @param    string        $x 
  7020.      * @return    string 
  7021.      */
  7022.     public static function DECTOOCT($x$places=null{
  7023.         $x    self::flattenSingleValue($x);
  7024.         $places    self::flattenSingleValue($places);
  7025.  
  7026.         if (is_bool($x)) {
  7027.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  7028.                 $x = (int) $x;
  7029.             else {
  7030.                 return self::$_errorCodes['value'];
  7031.             }
  7032.         }
  7033.         $x = (string) $x;
  7034.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  7035.             return self::$_errorCodes['value'];
  7036.         }
  7037.         $x = (string) floor($x);
  7038.         $r decoct($x);
  7039.         if (strlen($r== 11{
  7040.             //    Two's Complement
  7041.             $r substr($r,-10);
  7042.         }
  7043.  
  7044.         return self::_nbrConversionFormat($r,$places);
  7045.     }    //    function DECTOOCT()
  7046.  
  7047.  
  7048.     /**
  7049.      * DECTOHEX
  7050.      *
  7051.      * Return an octal value as binary.
  7052.      *
  7053.      * @param    string        $x 
  7054.      * @return    string 
  7055.      */
  7056.     public static function DECTOHEX($x$places=null{
  7057.         $x    self::flattenSingleValue($x);
  7058.         $places    self::flattenSingleValue($places);
  7059.  
  7060.         if (is_bool($x)) {
  7061.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  7062.                 $x = (int) $x;
  7063.             else {
  7064.                 return self::$_errorCodes['value'];
  7065.             }
  7066.         }
  7067.         $x = (string) $x;
  7068.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  7069.             return self::$_errorCodes['value'];
  7070.         }
  7071.         $x = (string) floor($x);
  7072.         $r strtoupper(dechex($x));
  7073.         if (strlen($r== 8{
  7074.             //    Two's Complement
  7075.             $r 'FF'.$r;
  7076.         }
  7077.  
  7078.         return self::_nbrConversionFormat($r,$places);
  7079.     }    //    function DECTOHEX()
  7080.  
  7081.  
  7082.     /**
  7083.      * HEXTOBIN
  7084.      *
  7085.      * Return a hex value as binary.
  7086.      *
  7087.      * @param    string        $x 
  7088.      * @return    string 
  7089.      */
  7090.     public static function HEXTOBIN($x$places=null{
  7091.         $x    self::flattenSingleValue($x);
  7092.         $places    self::flattenSingleValue($places);
  7093.  
  7094.         if (is_bool($x)) {
  7095.             return self::$_errorCodes['value'];
  7096.         }
  7097.         $x = (string) $x;
  7098.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  7099.             return self::$_errorCodes['num'];
  7100.         }
  7101.         $binVal decbin(hexdec($x));
  7102.  
  7103.         return substr(self::_nbrConversionFormat($binVal,$places),-10);
  7104.     }    //    function HEXTOBIN()
  7105.  
  7106.  
  7107.     /**
  7108.      * HEXTOOCT
  7109.      *
  7110.      * Return a hex value as octal.
  7111.      *
  7112.      * @param    string        $x 
  7113.      * @return    string 
  7114.      */
  7115.     public static function HEXTOOCT($x$places=null{
  7116.         $x    self::flattenSingleValue($x);
  7117.         $places    self::flattenSingleValue($places);
  7118.  
  7119.         if (is_bool($x)) {
  7120.             return self::$_errorCodes['value'];
  7121.         }
  7122.         $x = (string) $x;
  7123.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  7124.             return self::$_errorCodes['num'];
  7125.         }
  7126.         $octVal decoct(hexdec($x));
  7127.  
  7128.         return self::_nbrConversionFormat($octVal,$places);
  7129.     }    //    function HEXTOOCT()
  7130.  
  7131.  
  7132.     /**
  7133.      * HEXTODEC
  7134.      *
  7135.      * Return a hex value as octal.
  7136.      *
  7137.      * @param    string        $x 
  7138.      * @return    string 
  7139.      */
  7140.     public static function HEXTODEC($x{
  7141.         $x    self::flattenSingleValue($x);
  7142.  
  7143.         if (is_bool($x)) {
  7144.             return self::$_errorCodes['value'];
  7145.         }
  7146.         $x = (string) $x;
  7147.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  7148.             return self::$_errorCodes['num'];
  7149.         }
  7150.         return hexdec($x);
  7151.     }    //    function HEXTODEC()
  7152.  
  7153.  
  7154.     /**
  7155.      * OCTTOBIN
  7156.      *
  7157.      * Return an octal value as binary.
  7158.      *
  7159.      * @param    string        $x 
  7160.      * @return    string 
  7161.      */
  7162.     public static function OCTTOBIN($x$places=null{
  7163.         $x    self::flattenSingleValue($x);
  7164.         $places    self::flattenSingleValue($places);
  7165.  
  7166.         if (is_bool($x)) {
  7167.             return self::$_errorCodes['value'];
  7168.         }
  7169.         $x = (string) $x;
  7170.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  7171.             return self::$_errorCodes['num'];
  7172.         }
  7173.         $r decbin(octdec($x));
  7174.  
  7175.         return self::_nbrConversionFormat($r,$places);
  7176.     }    //    function OCTTOBIN()
  7177.  
  7178.  
  7179.     /**
  7180.      * OCTTODEC
  7181.      *
  7182.      * Return an octal value as binary.
  7183.      *
  7184.      * @param    string        $x 
  7185.      * @return    string 
  7186.      */
  7187.     public static function OCTTODEC($x{
  7188.         $x    self::flattenSingleValue($x);
  7189.  
  7190.         if (is_bool($x)) {
  7191.             return self::$_errorCodes['value'];
  7192.         }
  7193.         $x = (string) $x;
  7194.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  7195.             return self::$_errorCodes['num'];
  7196.         }
  7197.         return octdec($x);
  7198.     }    //    function OCTTODEC()
  7199.  
  7200.  
  7201.     /**
  7202.      * OCTTOHEX
  7203.      *
  7204.      * Return an octal value as hex.
  7205.      *
  7206.      * @param    string        $x 
  7207.      * @return    string 
  7208.      */
  7209.     public static function OCTTOHEX($x$places=null{
  7210.         $x    self::flattenSingleValue($x);
  7211.         $places    self::flattenSingleValue($places);
  7212.  
  7213.         if (is_bool($x)) {
  7214.             return self::$_errorCodes['value'];
  7215.         }
  7216.         $x = (string) $x;
  7217.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  7218.             return self::$_errorCodes['num'];
  7219.         }
  7220.         $hexVal strtoupper(dechex(octdec($x)));
  7221.  
  7222.         return self::_nbrConversionFormat($hexVal,$places);
  7223.     }    //    function OCTTOHEX()
  7224.  
  7225.  
  7226.     public static function _parseComplex($complexNumber{
  7227.         $workString = (string) $complexNumber;
  7228.  
  7229.         $realNumber $imaginary 0;
  7230.         //    Extract the suffix, if there is one
  7231.         $suffix substr($workString,-1);
  7232.         if (!is_numeric($suffix)) {
  7233.             $workString substr($workString,0,-1);
  7234.         else {
  7235.             $suffix '';
  7236.         }
  7237.  
  7238.         //    Split the input into its Real and Imaginary components
  7239.         $leadingSign 0;
  7240.         if (strlen($workString0{
  7241.             $leadingSign (($workString{0== '+'|| ($workString{0== '-')) 0;
  7242.         }
  7243.         $power '';
  7244.         $realNumber strtok($workString'+-');
  7245.         if (strtoupper(substr($realNumber,-1)) == 'E'{
  7246.             $power strtok('+-');
  7247.             ++$leadingSign;
  7248.         }
  7249.  
  7250.         $realNumber substr($workString,0,strlen($realNumber)+strlen($power)+$leadingSign);
  7251.  
  7252.         if ($suffix != ''{
  7253.             $imaginary substr($workString,strlen($realNumber));
  7254.  
  7255.             if (($imaginary == ''&& (($realNumber == ''|| ($realNumber == '+'|| ($realNumber == '-'))) {
  7256.                 $imaginary $realNumber.'1';
  7257.                 $realNumber '0';
  7258.             else if ($imaginary == ''{
  7259.                 $imaginary $realNumber;
  7260.                 $realNumber '0';
  7261.             elseif (($imaginary == '+'|| ($imaginary == '-')) {
  7262.                 $imaginary .= '1';
  7263.             }
  7264.         }
  7265.  
  7266.         $complexArray array'real'        => $realNumber,
  7267.                                'imaginary'    => $imaginary,
  7268.                                'suffix'        => $suffix
  7269.                              );
  7270.  
  7271.         return $complexArray;
  7272.     }    //    function _parseComplex()
  7273.  
  7274.  
  7275.     private static function _cleanComplex($complexNumber{
  7276.         if ($complexNumber{0== '+'$complexNumber substr($complexNumber,1);
  7277.         if ($complexNumber{0== '0'$complexNumber substr($complexNumber,1);
  7278.         if ($complexNumber{0== '.'$complexNumber '0'.$complexNumber;
  7279.         if ($complexNumber{0== '+'$complexNumber substr($complexNumber,1);
  7280.         return $complexNumber;
  7281.     }
  7282.  
  7283.  
  7284.     /**
  7285.      * COMPLEX
  7286.      *
  7287.      * returns a complex number of the form x + yi or x + yj.
  7288.      *
  7289.      * @param    float        $realNumber 
  7290.      * @param    float        $imaginary 
  7291.      * @param    string        $suffix 
  7292.      * @return    string 
  7293.      */
  7294.     public static function COMPLEX($realNumber=0.0$imaginary=0.0$suffix='i'{
  7295.         $realNumber    (is_null($realNumber))    0.0 :    (float) self::flattenSingleValue($realNumber);
  7296.         $imaginary    (is_null($imaginary))        0.0 :    (float) self::flattenSingleValue($imaginary);
  7297.         $suffix        (is_null($suffix))        'i' :    self::flattenSingleValue($suffix);
  7298.  
  7299.         if (((is_numeric($realNumber)) && (is_numeric($imaginary))) &&
  7300.             (($suffix == 'i'|| ($suffix == 'j'|| ($suffix == ''))) {
  7301.             if ($suffix == ''$suffix 'i';
  7302.             if ($realNumber == 0.0{
  7303.                 if ($imaginary == 0.0{
  7304.                     return (string) '0';
  7305.                 elseif ($imaginary == 1.0{
  7306.                     return (string) $suffix;
  7307.                 elseif ($imaginary == -1.0{
  7308.                     return (string) '-'.$suffix;
  7309.                 }
  7310.                 return (string) $imaginary.$suffix;
  7311.             elseif ($imaginary == 0.0{
  7312.                 return (string) $realNumber;
  7313.             elseif ($imaginary == 1.0{
  7314.                 return (string) $realNumber.'+'.$suffix;
  7315.             elseif ($imaginary == -1.0{
  7316.                 return (string) $realNumber.'-'.$suffix;
  7317.             }
  7318.             if ($imaginary 0$imaginary = (string) '+'.$imaginary}
  7319.             return (string) $realNumber.$imaginary.$suffix;
  7320.         }
  7321.         return self::$_errorCodes['value'];
  7322.     }    //    function COMPLEX()
  7323.  
  7324.  
  7325.     /**
  7326.      * IMAGINARY
  7327.      *
  7328.      * Returns the imaginary coefficient of a complex number in x + yi or x + yj text format.
  7329.      *
  7330.      * @param    string        $complexNumber 
  7331.      * @return    real 
  7332.      */
  7333.     public static function IMAGINARY($complexNumber{
  7334.         $complexNumber    self::flattenSingleValue($complexNumber);
  7335.  
  7336.         $parsedComplex self::_parseComplex($complexNumber);
  7337.         if (!is_array($parsedComplex)) {
  7338.             return $parsedComplex;
  7339.         }
  7340.         return $parsedComplex['imaginary'];
  7341.     }    //    function IMAGINARY()
  7342.  
  7343.  
  7344.     /**
  7345.      * IMREAL
  7346.      *
  7347.      * Returns the real coefficient of a complex number in x + yi or x + yj text format.
  7348.      *
  7349.      * @param    string        $complexNumber 
  7350.      * @return    real 
  7351.      */
  7352.     public static function IMREAL($complexNumber{
  7353.         $complexNumber    self::flattenSingleValue($complexNumber);
  7354.  
  7355.         $parsedComplex self::_parseComplex($complexNumber);
  7356.         if (!is_array($parsedComplex)) {
  7357.             return $parsedComplex;
  7358.         }
  7359.         return $parsedComplex['real'];
  7360.     }    //    function IMREAL()
  7361.  
  7362.  
  7363.     /**
  7364.      * IMABS
  7365.      *
  7366.      * Returns the absolute value (modulus) of a complex number in x + yi or x + yj text format.
  7367.      *
  7368.      * @param    string        $complexNumber 
  7369.      * @return    real 
  7370.      */
  7371.     public static function IMABS($complexNumber{
  7372.         $complexNumber    self::flattenSingleValue($complexNumber);
  7373.  
  7374.         $parsedComplex self::_parseComplex($complexNumber);
  7375.         if (!is_array($parsedComplex)) {
  7376.             return $parsedComplex;
  7377.         }
  7378.         return sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary']));
  7379.     }    //    function IMABS()
  7380.  
  7381.  
  7382.     /**
  7383.      * IMARGUMENT
  7384.      *
  7385.      * 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.
  7386.      *
  7387.      * @param    string        $complexNumber 
  7388.      * @return    string 
  7389.      */
  7390.     public static function IMARGUMENT($complexNumber{
  7391.         $complexNumber    self::flattenSingleValue($complexNumber);
  7392.  
  7393.         $parsedComplex self::_parseComplex($complexNumber);
  7394.         if (!is_array($parsedComplex)) {
  7395.             return $parsedComplex;
  7396.         }
  7397.  
  7398.         if ($parsedComplex['real'== 0.0{
  7399.             if ($parsedComplex['imaginary'== 0.0{
  7400.                 return 0.0;
  7401.             elseif($parsedComplex['imaginary'0.0{
  7402.                 return M_PI / -2;
  7403.             else {
  7404.                 return M_PI 2;
  7405.             }
  7406.         elseif ($parsedComplex['real'0.0{
  7407.             return atan($parsedComplex['imaginary'$parsedComplex['real']);
  7408.         elseif ($parsedComplex['imaginary'0.0{
  7409.             return (M_PI atan(abs($parsedComplex['imaginary']abs($parsedComplex['real'])));
  7410.         else {
  7411.             return M_PI atan($parsedComplex['imaginary'abs($parsedComplex['real']));
  7412.         }
  7413.     }    //    function IMARGUMENT()
  7414.  
  7415.  
  7416.     /**
  7417.      * IMCONJUGATE
  7418.      *
  7419.      * Returns the complex conjugate of a complex number in x + yi or x + yj text format.
  7420.      *
  7421.      * @param    string        $complexNumber 
  7422.      * @return    string 
  7423.      */
  7424.     public static function IMCONJUGATE($complexNumber{
  7425.         $complexNumber    self::flattenSingleValue($complexNumber);
  7426.  
  7427.         $parsedComplex self::_parseComplex($complexNumber);
  7428.  
  7429.         if (!is_array($parsedComplex)) {
  7430.             return $parsedComplex;
  7431.         }
  7432.  
  7433.         if ($parsedComplex['imaginary'== 0.0{
  7434.             return $parsedComplex['real'];
  7435.         else {
  7436.             return self::_cleanComplex(self::COMPLEX($parsedComplex['real']$parsedComplex['imaginary']$parsedComplex['suffix']));
  7437.         }
  7438.     }    //    function IMCONJUGATE()
  7439.  
  7440.  
  7441.     /**
  7442.      * IMCOS
  7443.      *
  7444.      * Returns the cosine of a complex number in x + yi or x + yj text format.
  7445.      *
  7446.      * @param    string        $complexNumber 
  7447.      * @return    string 
  7448.      */
  7449.     public static function IMCOS($complexNumber{
  7450.         $complexNumber    self::flattenSingleValue($complexNumber);
  7451.  
  7452.         $parsedComplex self::_parseComplex($complexNumber);
  7453.         if (!is_array($parsedComplex)) {
  7454.             return $parsedComplex;
  7455.         }
  7456.  
  7457.         if ($parsedComplex['imaginary'== 0.0{
  7458.             return cos($parsedComplex['real']);
  7459.         else {
  7460.             return self::IMCONJUGATE(self::COMPLEX(cos($parsedComplex['real']cosh($parsedComplex['imaginary']),sin($parsedComplex['real']sinh($parsedComplex['imaginary']),$parsedComplex['suffix']));
  7461.         }
  7462.     }    //    function IMCOS()
  7463.  
  7464.  
  7465.     /**
  7466.      * IMSIN
  7467.      *
  7468.      * Returns the sine of a complex number in x + yi or x + yj text format.
  7469.      *
  7470.      * @param    string        $complexNumber 
  7471.      * @return    string 
  7472.      */
  7473.     public static function IMSIN($complexNumber{
  7474.         $complexNumber    self::flattenSingleValue($complexNumber);
  7475.  
  7476.         $parsedComplex self::_parseComplex($complexNumber);
  7477.         if (!is_array($parsedComplex)) {
  7478.             return $parsedComplex;
  7479.         }
  7480.  
  7481.         if ($parsedComplex['imaginary'== 0.0{
  7482.             return sin($parsedComplex['real']);
  7483.         else {
  7484.             return self::COMPLEX(sin($parsedComplex['real']cosh($parsedComplex['imaginary']),cos($parsedComplex['real']sinh($parsedComplex['imaginary']),$parsedComplex['suffix']);
  7485.         }
  7486.     }    //    function IMSIN()
  7487.  
  7488.  
  7489.     /**
  7490.      * IMSQRT
  7491.      *
  7492.      * Returns the square root of a complex number in x + yi or x + yj text format.
  7493.      *
  7494.      * @param    string        $complexNumber 
  7495.      * @return    string 
  7496.      */
  7497.     public static function IMSQRT($complexNumber{
  7498.         $complexNumber    self::flattenSingleValue($complexNumber);
  7499.  
  7500.         $parsedComplex self::_parseComplex($complexNumber);
  7501.         if (!is_array($parsedComplex)) {
  7502.             return $parsedComplex;
  7503.         }
  7504.  
  7505.         $theta self::IMARGUMENT($complexNumber);
  7506.         $d1 cos($theta 2);
  7507.         $d2 sin($theta 2);
  7508.         $r sqrt(sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary'])));
  7509.  
  7510.         if ($parsedComplex['suffix'== ''{
  7511.             return self::COMPLEX($d1 $r,$d2 $r);
  7512.         else {
  7513.             return self::COMPLEX($d1 $r,$d2 $r,$parsedComplex['suffix']);
  7514.         }
  7515.     }    //    function IMSQRT()
  7516.  
  7517.  
  7518.     /**
  7519.      * IMLN
  7520.      *
  7521.      * Returns the natural logarithm of a complex number in x + yi or x + yj text format.
  7522.      *
  7523.      * @param    string        $complexNumber 
  7524.      * @return    string 
  7525.      */
  7526.     public static function IMLN($complexNumber{
  7527.         $complexNumber    self::flattenSingleValue($complexNumber);
  7528.  
  7529.         $parsedComplex self::_parseComplex($complexNumber);
  7530.         if (!is_array($parsedComplex)) {
  7531.             return $parsedComplex;
  7532.         }
  7533.  
  7534.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7535.             return self::$_errorCodes['num'];
  7536.         }
  7537.  
  7538.         $logR log(sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary'])));
  7539.         $t self::IMARGUMENT($complexNumber);
  7540.  
  7541.         if ($parsedComplex['suffix'== ''{
  7542.             return self::COMPLEX($logR,$t);
  7543.         else {
  7544.             return self::COMPLEX($logR,$t,$parsedComplex['suffix']);
  7545.         }
  7546.     }    //    function IMLN()
  7547.  
  7548.  
  7549.     /**
  7550.      * IMLOG10
  7551.      *
  7552.      * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
  7553.      *
  7554.      * @param    string        $complexNumber 
  7555.      * @return    string 
  7556.      */
  7557.     public static function IMLOG10($complexNumber{
  7558.         $complexNumber    self::flattenSingleValue($complexNumber);
  7559.  
  7560.         $parsedComplex self::_parseComplex($complexNumber);
  7561.         if (!is_array($parsedComplex)) {
  7562.             return $parsedComplex;
  7563.         }
  7564.  
  7565.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7566.             return self::$_errorCodes['num'];
  7567.         elseif (($parsedComplex['real'0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7568.             return log10($parsedComplex['real']);
  7569.         }
  7570.  
  7571.         return self::IMPRODUCT(log10(EULER),self::IMLN($complexNumber));
  7572.     }    //    function IMLOG10()
  7573.  
  7574.  
  7575.     /**
  7576.      * IMLOG2
  7577.      *
  7578.      * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
  7579.      *
  7580.      * @param    string        $complexNumber 
  7581.      * @return    string 
  7582.      */
  7583.     public static function IMLOG2($complexNumber{
  7584.         $complexNumber    self::flattenSingleValue($complexNumber);
  7585.  
  7586.         $parsedComplex self::_parseComplex($complexNumber);
  7587.         if (!is_array($parsedComplex)) {
  7588.             return $parsedComplex;
  7589.         }
  7590.  
  7591.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7592.             return self::$_errorCodes['num'];
  7593.         elseif (($parsedComplex['real'0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7594.             return log($parsedComplex['real'],2);
  7595.         }
  7596.  
  7597.         return self::IMPRODUCT(log(EULER,2),self::IMLN($complexNumber));
  7598.     }    //    function IMLOG2()
  7599.  
  7600.  
  7601.     /**
  7602.      * IMEXP
  7603.      *
  7604.      * Returns the exponential of a complex number in x + yi or x + yj text format.
  7605.      *
  7606.      * @param    string        $complexNumber 
  7607.      * @return    string 
  7608.      */
  7609.     public static function IMEXP($complexNumber{
  7610.         $complexNumber    self::flattenSingleValue($complexNumber);
  7611.  
  7612.         $parsedComplex self::_parseComplex($complexNumber);
  7613.         if (!is_array($parsedComplex)) {
  7614.             return $parsedComplex;
  7615.         }
  7616.  
  7617.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7618.             return '1';
  7619.         }
  7620.  
  7621.         $e exp($parsedComplex['real']);
  7622.         $eX $e cos($parsedComplex['imaginary']);
  7623.         $eY $e sin($parsedComplex['imaginary']);
  7624.  
  7625.         if ($parsedComplex['suffix'== ''{
  7626.             return self::COMPLEX($eX,$eY);
  7627.         else {
  7628.             return self::COMPLEX($eX,$eY,$parsedComplex['suffix']);
  7629.         }
  7630.     }    //    function IMEXP()
  7631.  
  7632.  
  7633.     /**
  7634.      * IMPOWER
  7635.      *
  7636.      * Returns a complex number in x + yi or x + yj text format raised to a power.
  7637.      *
  7638.      * @param    string        $complexNumber 
  7639.      * @return    string 
  7640.      */
  7641.     public static function IMPOWER($complexNumber,$realNumber{
  7642.         $complexNumber    self::flattenSingleValue($complexNumber);
  7643.         $realNumber        self::flattenSingleValue($realNumber);
  7644.  
  7645.         if (!is_numeric($realNumber)) {
  7646.             return self::$_errorCodes['value'];
  7647.         }
  7648.  
  7649.         $parsedComplex self::_parseComplex($complexNumber);
  7650.         if (!is_array($parsedComplex)) {
  7651.             return $parsedComplex;
  7652.         }
  7653.  
  7654.         $r sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary']));
  7655.         $rPower pow($r,$realNumber);
  7656.         $theta self::IMARGUMENT($complexNumber$realNumber;
  7657.         if ($theta == 0{
  7658.             return 1;
  7659.         elseif ($parsedComplex['imaginary'== 0.0{
  7660.             return self::COMPLEX($rPower cos($theta),$rPower sin($theta),$parsedComplex['suffix']);
  7661.         else {
  7662.             return self::COMPLEX($rPower cos($theta),$rPower sin($theta),$parsedComplex['suffix']);
  7663.         }
  7664.     }    //    function IMPOWER()
  7665.  
  7666.  
  7667.     /**
  7668.      * IMDIV
  7669.      *
  7670.      * Returns the quotient of two complex numbers in x + yi or x + yj text format.
  7671.      *
  7672.      * @param    string        $complexDividend 
  7673.      * @param    string        $complexDivisor 
  7674.      * @return    real 
  7675.      */
  7676.     public static function IMDIV($complexDividend,$complexDivisor{
  7677.         $complexDividend    self::flattenSingleValue($complexDividend);
  7678.         $complexDivisor    self::flattenSingleValue($complexDivisor);
  7679.  
  7680.         $parsedComplexDividend self::_parseComplex($complexDividend);
  7681.         if (!is_array($parsedComplexDividend)) {
  7682.             return $parsedComplexDividend;
  7683.         }
  7684.  
  7685.         $parsedComplexDivisor self::_parseComplex($complexDivisor);
  7686.         if (!is_array($parsedComplexDivisor)) {
  7687.             return $parsedComplexDividend;
  7688.         }
  7689.  
  7690.         if (($parsedComplexDividend['suffix'!= ''&& ($parsedComplexDivisor['suffix'!= ''&&
  7691.             ($parsedComplexDividend['suffix'!= $parsedComplexDivisor['suffix'])) {
  7692.             return self::$_errorCodes['num'];
  7693.         }
  7694.         if (($parsedComplexDividend['suffix'!= ''&& ($parsedComplexDivisor['suffix'== '')) {
  7695.             $parsedComplexDivisor['suffix'$parsedComplexDividend['suffix'];
  7696.         }
  7697.  
  7698.         $d1 ($parsedComplexDividend['real'$parsedComplexDivisor['real']($parsedComplexDividend['imaginary'$parsedComplexDivisor['imaginary']);
  7699.         $d2 ($parsedComplexDividend['imaginary'$parsedComplexDivisor['real']($parsedComplexDividend['real'$parsedComplexDivisor['imaginary']);
  7700.         $d3 ($parsedComplexDivisor['real'$parsedComplexDivisor['real']($parsedComplexDivisor['imaginary'$parsedComplexDivisor['imaginary']);
  7701.  
  7702.         $r $d1/$d3;
  7703.         $i $d2/$d3;
  7704.  
  7705.         if ($i 0.0{
  7706.             return self::_cleanComplex($r.'+'.$i.$parsedComplexDivisor['suffix']);
  7707.         elseif ($i 0.0{
  7708.             return self::_cleanComplex($r.$i.$parsedComplexDivisor['suffix']);
  7709.         else {
  7710.             return $r;
  7711.         }
  7712.     }    //    function IMDIV()
  7713.  
  7714.  
  7715.     /**
  7716.      * IMSUB
  7717.      *
  7718.      * Returns the difference of two complex numbers in x + yi or x + yj text format.
  7719.      *
  7720.      * @param    string        $complexNumber1 
  7721.      * @param    string        $complexNumber2 
  7722.      * @return    real 
  7723.      */
  7724.     public static function IMSUB($complexNumber1,$complexNumber2{
  7725.         $complexNumber1    self::flattenSingleValue($complexNumber1);
  7726.         $complexNumber2    self::flattenSingleValue($complexNumber2);
  7727.  
  7728.         $parsedComplex1 self::_parseComplex($complexNumber1);
  7729.         if (!is_array($parsedComplex1)) {
  7730.             return $parsedComplex1;
  7731.         }
  7732.  
  7733.         $parsedComplex2 self::_parseComplex($complexNumber2);
  7734.         if (!is_array($parsedComplex2)) {
  7735.             return $parsedComplex2;
  7736.         }
  7737.  
  7738.         if ((($parsedComplex1['suffix'!= ''&& ($parsedComplex2['suffix'!= '')) &&
  7739.             ($parsedComplex1['suffix'!= $parsedComplex2['suffix'])) {
  7740.             return self::$_errorCodes['num'];
  7741.         elseif (($parsedComplex1['suffix'== ''&& ($parsedComplex2['suffix'!= '')) {
  7742.             $parsedComplex1['suffix'$parsedComplex2['suffix'];
  7743.         }
  7744.  
  7745.         $d1 $parsedComplex1['real'$parsedComplex2['real'];
  7746.         $d2 $parsedComplex1['imaginary'$parsedComplex2['imaginary'];
  7747.  
  7748.         return self::COMPLEX($d1,$d2,$parsedComplex1['suffix']);
  7749.     }    //    function IMSUB()
  7750.  
  7751.  
  7752.     /**
  7753.      * IMSUM
  7754.      *
  7755.      * Returns the sum of two or more complex numbers in x + yi or x + yj text format.
  7756.      *
  7757.      * @param    array of mixed        Data Series
  7758.      * @return    real 
  7759.      */
  7760.     public static function IMSUM({
  7761.         // Return value
  7762.         $returnValue self::_parseComplex('0');
  7763.         $activeSuffix '';
  7764.  
  7765.         // Loop through the arguments
  7766.         $aArgs self::flattenArray(func_get_args());
  7767.         foreach ($aArgs as $arg{
  7768.             $parsedComplex self::_parseComplex($arg);
  7769.             if (!is_array($parsedComplex)) {
  7770.                 return $parsedComplex;
  7771.             }
  7772.  
  7773.             if ($activeSuffix == ''{
  7774.                 $activeSuffix $parsedComplex['suffix'];
  7775.             elseif (($parsedComplex['suffix'!= ''&& ($activeSuffix != $parsedComplex['suffix'])) {
  7776.                 return self::$_errorCodes['value'];
  7777.             }
  7778.  
  7779.             $returnValue['real'+= $parsedComplex['real'];
  7780.             $returnValue['imaginary'+= $parsedComplex['imaginary'];
  7781.         }
  7782.  
  7783.         if ($returnValue['imaginary'== 0.0$activeSuffix ''}
  7784.         return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix);
  7785.     }    //    function IMSUM()
  7786.  
  7787.  
  7788.     /**
  7789.      * IMPRODUCT
  7790.      *
  7791.      * Returns the product of two or more complex numbers in x + yi or x + yj text format.
  7792.      *
  7793.      * @param    array of mixed        Data Series
  7794.      * @return    real 
  7795.      */
  7796.     public static function IMPRODUCT({
  7797.         // Return value
  7798.         $returnValue self::_parseComplex('1');
  7799.         $activeSuffix '';
  7800.  
  7801.         // Loop through the arguments
  7802.         $aArgs self::flattenArray(func_get_args());
  7803.         foreach ($aArgs as $arg{
  7804.             $parsedComplex self::_parseComplex($arg);
  7805.             if (!is_array($parsedComplex)) {
  7806.                 return $parsedComplex;
  7807.             }
  7808.             $workValue $returnValue;
  7809.             if (($parsedComplex['suffix'!= ''&& ($activeSuffix == '')) {
  7810.                 $activeSuffix $parsedComplex['suffix'];
  7811.             elseif (($parsedComplex['suffix'!= ''&& ($activeSuffix != $parsedComplex['suffix'])) {
  7812.                 return self::$_errorCodes['num'];
  7813.             }
  7814.             $returnValue['real'($workValue['real'$parsedComplex['real']($workValue['imaginary'$parsedComplex['imaginary']);
  7815.             $returnValue['imaginary'($workValue['real'$parsedComplex['imaginary']($workValue['imaginary'$parsedComplex['real']);
  7816.         }
  7817.  
  7818.         if ($returnValue['imaginary'== 0.0$activeSuffix ''}
  7819.         return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix);
  7820.     }    //    function IMPRODUCT()
  7821.  
  7822.  
  7823.     private static $_conversionUnits array'g'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Gram',                        'AllowPrefix'    => True        ),
  7824.                                               'sg'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Slug',                        'AllowPrefix'    => False    ),
  7825.                                               'lbm'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Pound mass (avoirdupois)',    'AllowPrefix'    => False    ),
  7826.                                               'u'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'U (atomic mass unit)',        'AllowPrefix'    => True        ),
  7827.                                               'ozm'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Ounce mass (avoirdupois)',    'AllowPrefix'    => False    ),
  7828.                                               'm'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Meter',                        'AllowPrefix'    => True        ),
  7829.                                               'mi'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Statute mile',                'AllowPrefix'    => False    ),
  7830.                                               'Nmi'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Nautical mile',                'AllowPrefix'    => False    ),
  7831.                                               'in'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Inch',                        'AllowPrefix'    => False    ),
  7832.                                               'ft'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Foot',                        'AllowPrefix'    => False    ),
  7833.                                               'yd'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Yard',                        'AllowPrefix'    => False    ),
  7834.                                               'ang'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Angstrom',                    'AllowPrefix'    => True        ),
  7835.                                               'Pica'    => array(    'Group'    => 'Distance',        'Unit Name'    => 'Pica (1/72 in)',            'AllowPrefix'    => False    ),
  7836.                                               'yr'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Year',                        'AllowPrefix'    => False    ),
  7837.                                               'day'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Day',                        'AllowPrefix'    => False    ),
  7838.                                               'hr'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Hour',                        'AllowPrefix'    => False    ),
  7839.                                               'mn'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Minute',                    'AllowPrefix'    => False    ),
  7840.                                               'sec'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Second',                    'AllowPrefix'    => True        ),
  7841.                                               'Pa'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Pascal',                    'AllowPrefix'    => True        ),
  7842.                                               'p'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Pascal',                    'AllowPrefix'    => True        ),
  7843.                                               'atm'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Atmosphere',                'AllowPrefix'    => True        ),
  7844.                                               'at'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Atmosphere',                'AllowPrefix'    => True        ),
  7845.                                               'mmHg'    => array(    'Group'    => 'Pressure',        'Unit Name'    => 'mm of Mercury',                'AllowPrefix'    => True        ),
  7846.                                               'N'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Newton',                    'AllowPrefix'    => True        ),
  7847.                                               'dyn'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Dyne',                        'AllowPrefix'    => True        ),
  7848.                                               'dy'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Dyne',                        'AllowPrefix'    => True        ),
  7849.                                               'lbf'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Pound force',                'AllowPrefix'    => False    ),
  7850.                                               'J'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Joule',                        'AllowPrefix'    => True        ),
  7851.                                               'e'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Erg',                        'AllowPrefix'    => True        ),
  7852.                                               'c'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Thermodynamic calorie',        'AllowPrefix'    => True        ),
  7853.                                               'cal'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'IT calorie',                'AllowPrefix'    => True        ),
  7854.                                               'eV'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Electron volt',                'AllowPrefix'    => True        ),
  7855.                                               'ev'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Electron volt',                'AllowPrefix'    => True        ),
  7856.                                               'HPh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Horsepower-hour',            'AllowPrefix'    => False    ),
  7857.                                               'hh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Horsepower-hour',            'AllowPrefix'    => False    ),
  7858.                                               'Wh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Watt-hour',                    'AllowPrefix'    => True        ),
  7859.                                               'wh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Watt-hour',                    'AllowPrefix'    => True        ),
  7860.                                               'flb'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Foot-pound',                'AllowPrefix'    => False    ),
  7861.                                               'BTU'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'BTU',                        'AllowPrefix'    => False    ),
  7862.                                               'btu'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'BTU',                        'AllowPrefix'    => False    ),
  7863.                                               'HP'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Horsepower',                'AllowPrefix'    => False    ),
  7864.                                               'h'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Horsepower',                'AllowPrefix'    => False    ),
  7865.                                               'W'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Watt',                        'AllowPrefix'    => True        ),
  7866.                                               'w'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Watt',                        'AllowPrefix'    => True        ),
  7867.                                               'T'        => array(    'Group'    => 'Magnetism',        'Unit Name'    => 'Tesla',                        'AllowPrefix'    => True        ),
  7868.                                               'ga'        => array(    'Group'    => 'Magnetism',        'Unit Name'    => 'Gauss',                        'AllowPrefix'    => True        ),
  7869.                                               'C'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Celsius',                    'AllowPrefix'    => False    ),
  7870.                                               'cel'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Celsius',                    'AllowPrefix'    => False    ),
  7871.                                               'F'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Fahrenheit',                'AllowPrefix'    => False    ),
  7872.                                               'fah'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Fahrenheit',                'AllowPrefix'    => False    ),
  7873.                                               'K'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Kelvin',                    'AllowPrefix'    => False    ),
  7874.                                               'kel'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Kelvin',                    'AllowPrefix'    => False    ),
  7875.                                               'tsp'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Teaspoon',                    'AllowPrefix'    => False    ),
  7876.                                               'tbs'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Tablespoon',                'AllowPrefix'    => False    ),
  7877.                                               'oz'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Fluid Ounce',                'AllowPrefix'    => False    ),
  7878.                                               'cup'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Cup',                        'AllowPrefix'    => False    ),
  7879.                                               'pt'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'U.S. Pint',                    'AllowPrefix'    => False    ),
  7880.                                               'us_pt'    => array(    'Group'    => 'Liquid',        'Unit Name'    => 'U.S. Pint',                    'AllowPrefix'    => False    ),
  7881.                                               'uk_pt'    => array(    'Group'    => 'Liquid',        'Unit Name'    => 'U.K. Pint',                    'AllowPrefix'    => False    ),
  7882.                                               'qt'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Quart',                        'AllowPrefix'    => False    ),
  7883.                                               'gal'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Gallon',                    'AllowPrefix'    => False    ),
  7884.                                               'l'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Litre',                        'AllowPrefix'    => True        ),
  7885.                                               'lt'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Litre',                        'AllowPrefix'    => True        )
  7886.                                             );
  7887.  
  7888.     private static $_conversionMultipliers array(    'Y'    => array(    'multiplier'    => 1E24,    'name'    => 'yotta'    ),
  7889.                                                     'Z'    => array(    'multiplier'    => 1E21,    'name'    => 'zetta'    ),
  7890.                                                     'E'    => array(    'multiplier'    => 1E18,    'name'    => 'exa'    ),
  7891.                                                     'P'    => array(    'multiplier'    => 1E15,    'name'    => 'peta'    ),
  7892.                                                     'T'    => array(    'multiplier'    => 1E12,    'name'    => 'tera'    ),
  7893.                                                     'G'    => array(    'multiplier'    => 1E9,        'name'    => 'giga'    ),
  7894.                                                     'M'    => array(    'multiplier'    => 1E6,        'name'    => 'mega'    ),
  7895.                                                     'k'    => array(    'multiplier'    => 1E3,        'name'    => 'kilo'    ),
  7896.                                                     'h'    => array(    'multiplier'    => 1E2,        'name'    => 'hecto'    ),
  7897.                                                     'e'    => array(    'multiplier'    => 1E1,        'name'    => 'deka'    ),
  7898.                                                     'd'    => array(    'multiplier'    => 1E-1,    'name'    => 'deci'    ),
  7899.                                                     'c'    => array(    'multiplier'    => 1E-2,    'name'    => 'centi'    ),
  7900.                                                     'm'    => array(    'multiplier'    => 1E-3,    'name'    => 'milli'    ),
  7901.                                                     'u'    => array(    'multiplier'    => 1E-6,    'name'    => 'micro'    ),
  7902.                                                     'n'    => array(    'multiplier'    => 1E-9,    'name'    => 'nano'    ),
  7903.                                                     'p'    => array(    'multiplier'    => 1E-12,    'name'    => 'pico'    ),
  7904.                                                     'f'    => array(    'multiplier'    => 1E-15,    'name'    => 'femto'    ),
  7905.                                                     'a'    => array(    'multiplier'    => 1E-18,    'name'    => 'atto'    ),
  7906.                                                     'z'    => array(    'multiplier'    => 1E-21,    'name'    => 'zepto'    ),
  7907.                                                     'y'    => array(    'multiplier'    => 1E-24,    'name'    => 'yocto'    )
  7908.                                                  );
  7909.  
  7910.     private static $_unitConversions array(    'Mass'        => array(    'g'        => array(    'g'        => 1.0,
  7911.                                                                                             'sg'    => 6.85220500053478E-05,
  7912.                                                                                             'lbm'    => 2.20462291469134E-03,
  7913.                                                                                             'u'        => 6.02217000000000E+23,
  7914.                                                                                             'ozm'    => 3.52739718003627E-02
  7915.                                                                                         ),
  7916.                                                                         'sg'    => array(    'g'        => 1.45938424189287E+04,
  7917.                                                                                             'sg'    => 1.0,
  7918.                                                                                             'lbm'    => 3.21739194101647E+01,
  7919.                                                                                             'u'        => 8.78866000000000E+27,
  7920.                                                                                             'ozm'    => 5.14782785944229E+02
  7921.                                                                                         ),
  7922.                                                                         'lbm'    => array(    'g'        => 4.5359230974881148E+02,
  7923.                                                                                             'sg'    => 3.10810749306493E-02,
  7924.                                                                                             'lbm'    => 1.0,
  7925.                                                                                             'u'        => 2.73161000000000E+26,
  7926.                                                                                             'ozm'    => 1.60000023429410E+01
  7927.                                                                                         ),
  7928.                                                                         'u'        => array(    'g'        => 1.66053100460465E-24,
  7929.                                                                                             'sg'    => 1.13782988532950E-28,
  7930.                                                                                             'lbm'    => 3.66084470330684E-27,
  7931.                                                                                             'u'        => 1.0,
  7932.                                                                                             'ozm'    => 5.85735238300524E-26
  7933.                                                                                         ),
  7934.                                                                         'ozm'    => array(    'g'        => 2.83495152079732E+01,
  7935.                                                                                             'sg'    => 1.94256689870811E-03,
  7936.                                                                                             'lbm'    => 6.24999908478882E-02,
  7937.                                                                                             'u'        => 1.70725600000000E+25,
  7938.                                                                                             'ozm'    => 1.0
  7939.                                                                                         )
  7940.                                                                     ),
  7941.                                                 'Distance'    => array(    'm'        => array(    'm'        => 1.0,
  7942.                                                                                             'mi'    => 6.21371192237334E-04,
  7943.                                                                                             'Nmi'    => 5.39956803455724E-04,
  7944.                                                                                             'in'    => 3.93700787401575E+01,
  7945.                                                                                             'ft'    => 3.28083989501312E+00,
  7946.                                                                                             'yd'    => 1.09361329797891E+00,
  7947.                                                                                             'ang'    => 1.00000000000000E+10,
  7948.                                                                                             'Pica'    => 2.83464566929116E+03
  7949.                                                                                         ),
  7950.                                                                         'mi'    => array(    'm'        => 1.60934400000000E+03,
  7951.                                                                                             'mi'    => 1.0,
  7952.                                                                                             'Nmi'    => 8.68976241900648E-01,
  7953.                                                                                             'in'    => 6.33600000000000E+04,
  7954.                                                                                             'ft'    => 5.28000000000000E+03,
  7955.                                                                                             'yd'    => 1.76000000000000E+03,
  7956.                                                                                             'ang'    => 1.60934400000000E+13,
  7957.                                                                                             'Pica'    => 4.56191999999971E+06
  7958.                                                                                         ),
  7959.                                                                         'Nmi'    => array(    'm'        => 1.85200000000000E+03,
  7960.                                                                                             'mi'    => 1.15077944802354E+00,
  7961.                                                                                             'Nmi'    => 1.0,
  7962.                                                                                             'in'    => 7.29133858267717E+04,
  7963.                                                                                             'ft'    => 6.07611548556430E+03,
  7964.                                                                                             'yd'    => 2.02537182785694E+03,
  7965.                                                                                             'ang'    => 1.85200000000000E+13,
  7966.                                                                                             'Pica'    => 5.24976377952723E+06
  7967.                                                                                         ),
  7968.                                                                         'in'    => array(    'm'        => 2.54000000000000E-02,
  7969.                                                                                             'mi'    => 1.57828282828283E-05,
  7970.                                                                                             'Nmi'    => 1.37149028077754E-05,
  7971.                                                                                             'in'    => 1.0,
  7972.                                                                                             'ft'    => 8.33333333333333E-02,
  7973.                                                                                             'yd'    => 2.77777777686643E-02,
  7974.                                                                                             'ang'    => 2.54000000000000E+08,
  7975.                                                                                             'Pica'    => 7.19999999999955E+01
  7976.                                                                                         ),
  7977.                                                                         'ft'    => array(    'm'        => 3.04800000000000E-01,
  7978.                                                                                             'mi'    => 1.89393939393939E-04,
  7979.                                                                                             'Nmi'    => 1.64578833693305E-04,
  7980.                                                                                             'in'    => 1.20000000000000E+01,
  7981.                                                                                             'ft'    => 1.0,
  7982.                                                                                             'yd'    => 3.33333333223972E-01,
  7983.                                                                                             'ang'    => 3.04800000000000E+09,
  7984.                                                                                             'Pica'    => 8.63999999999946E+02
  7985.                                                                                         ),
  7986.                                                                         'yd'    => array(    'm'        => 9.14400000300000E-01,
  7987.                                                                                             'mi'    => 5.68181818368230E-04,
  7988.                                                                                             'Nmi'    => 4.93736501241901E-04,
  7989.                                                                                             'in'    => 3.60000000118110E+01,
  7990.                                                                                             'ft'    => 3.00000000000000E+00,
  7991.                                                                                             'yd'    => 1.0,
  7992.                                                                                             'ang'    => 9.14400000300000E+09,
  7993.                                                                                             'Pica'    => 2.59200000085023E+03
  7994.                                                                                         ),
  7995.                                                                         'ang'    => array(    'm'        => 1.00000000000000E-10,
  7996.                                                                                             'mi'    => 6.21371192237334E-14,
  7997.                                                                                             'Nmi'    => 5.39956803455724E-14,
  7998.                                                                                             'in'    => 3.93700787401575E-09,
  7999.                                                                                             'ft'    => 3.28083989501312E-10,
  8000.                                                                                             'yd'    => 1.09361329797891E-10,
  8001.                                                                                             'ang'    => 1.0,
  8002.                                                                                             'Pica'    => 2.83464566929116E-07
  8003.                                                                                         ),
  8004.                                                                         'Pica'    => array(    'm'        => 3.52777777777800E-04,
  8005.                                                                                             'mi'    => 2.19205948372629E-07,
  8006.                                                                                             'Nmi'    => 1.90484761219114E-07,
  8007.                                                                                             'in'    => 1.38888888888898E-02,
  8008.                                                                                             'ft'    => 1.15740740740748E-03,
  8009.                                                                                             'yd'    => 3.85802469009251E-04,
  8010.                                                                                             'ang'    => 3.52777777777800E+06,
  8011.                                                                                             'Pica'    => 1.0
  8012.                                                                                         )
  8013.                                                                     ),
  8014.                                                 'Time'        => array(    'yr'    => array(    'yr'        => 1.0,
  8015.                                                                                             'day'        => 365.25,
  8016.                                                                                             'hr'        => 8766.0,
  8017.                                                                                             'mn'        => 525960.0,
  8018.                                                                                             'sec'        => 31557600.0
  8019.                                                                                         ),
  8020.                                                                         'day'    => array(    'yr'        => 2.73785078713210E-03,
  8021.                                                                                             'day'        => 1.0,
  8022.                                                                                             'hr'        => 24.0,
  8023.                                                                                             'mn'        => 1440.0,
  8024.                                                                                             'sec'        => 86400.0
  8025.                                                                                         ),
  8026.                                                                         'hr'    => array(    'yr'        => 1.14077116130504E-04,
  8027.                                                                                             'day'        => 4.16666666666667E-02,
  8028.                                                                                             'hr'        => 1.0,
  8029.                                                                                             'mn'        => 60.0,
  8030.                                                                                             'sec'        => 3600.0
  8031.                                                                                         ),
  8032.                                                                         'mn'    => array(    'yr'        => 1.90128526884174E-06,
  8033.                                                                                             'day'        => 6.94444444444444E-04,
  8034.                                                                                             'hr'        => 1.66666666666667E-02,
  8035.                                                                                             'mn'        => 1.0,
  8036.                                                                                             'sec'        => 60.0
  8037.                                                                                         ),
  8038.                                                                         'sec'    => array(    'yr'        => 3.16880878140289E-08,
  8039.                                                                                             'day'        => 1.15740740740741E-05,
  8040.                                                                                             'hr'        => 2.77777777777778E-04,
  8041.                                                                                             'mn'        => 1.66666666666667E-02,
  8042.                                                                                             'sec'        => 1.0
  8043.                                                                                         )
  8044.                                                                     ),
  8045.                                                 'Pressure'    => array(    'Pa'    => array(    'Pa'        => 1.0,
  8046.                                                                                             'p'            => 1.0,
  8047.                                                                                             'atm'        => 9.86923299998193E-06,
  8048.                                                                                             'at'        => 9.86923299998193E-06,
  8049.                                                                                             'mmHg'        => 7.50061707998627E-03
  8050.                                                                                         ),
  8051.                                                                         'p'        => array(    'Pa'        => 1.0,
  8052.                                                                                             'p'            => 1.0,
  8053.                                                                                             'atm'        => 9.86923299998193E-06,
  8054.                                                                                             'at'        => 9.86923299998193E-06,
  8055.                                                                                             'mmHg'        => 7.50061707998627E-03
  8056.                                                                                         ),
  8057.                                                                         'atm'    => array(    'Pa'        => 1.01324996583000E+05,
  8058.                                                                                             'p'            => 1.01324996583000E+05,
  8059.                                                                                             'atm'        => 1.0,
  8060.                                                                                             'at'        => 1.0,
  8061.                                                                                             'mmHg'        => 760.0
  8062.                                                                                         ),
  8063.                                                                         'at'    => array(    'Pa'        => 1.01324996583000E+05,
  8064.                                                                                             'p'            => 1.01324996583000E+05,
  8065.                                                                                             'atm'        => 1.0,
  8066.                                                                                             'at'        => 1.0,
  8067.                                                                                             'mmHg'        => 760.0
  8068.                                                                                         ),
  8069.                                                                         'mmHg'    => array(    'Pa'        => 1.33322363925000E+02,
  8070.                                                                                             'p'            => 1.33322363925000E+02,
  8071.                                                                                             'atm'        => 1.31578947368421E-03,
  8072.                                                                                             'at'        => 1.31578947368421E-03,
  8073.                                                                                             'mmHg'        => 1.0
  8074.                                                                                         )
  8075.                                                                     ),
  8076.                                                 'Force'        => array(    'N'        => array(    'N'            => 1.0,
  8077.                                                                                             'dyn'        => 1.0E+5,
  8078.                                                                                             'dy'        => 1.0E+5,
  8079.                                                                                             'lbf'        => 2.24808923655339E-01
  8080.                                                                                         ),
  8081.                                                                         'dyn'    => array(    'N'            => 1.0E-5,
  8082.                                                                                             'dyn'        => 1.0,
  8083.                                                                                             'dy'        => 1.0,
  8084.                                                                                             'lbf'        => 2.24808923655339E-06
  8085.                                                                                         ),
  8086.                                                                         'dy'    => array(    'N'            => 1.0E-5,
  8087.                                                                                             'dyn'        => 1.0,
  8088.                                                                                             'dy'        => 1.0,
  8089.                                                                                             'lbf'        => 2.24808923655339E-06
  8090.                                                                                         ),
  8091.                                                                         'lbf'    => array(    'N'            => 4.448222,
  8092.                                                                                             'dyn'        => 4.448222E+5,
  8093.                                                                                             'dy'        => 4.448222E+5,
  8094.                                                                                             'lbf'        => 1.0
  8095.                                                                                         )
  8096.                                                                     ),
  8097.                                                 'Energy'    => array(    'J'        => array(    'J'            => 1.0,
  8098.                                                                                             'e'            => 9.99999519343231E+06,
  8099.                                                                                             'c'            => 2.39006249473467E-01,
  8100.                                                                                             'cal'        => 2.38846190642017E-01,
  8101.                                                                                             'eV'        => 6.24145700000000E+18,
  8102.                                                                                             'ev'        => 6.24145700000000E+18,
  8103.                                                                                             'HPh'        => 3.72506430801000E-07,
  8104.                                                                                             'hh'        => 3.72506430801000E-07,
  8105.                                                                                             'Wh'        => 2.77777916238711E-04,
  8106.                                                                                             'wh'        => 2.77777916238711E-04,
  8107.                                                                                             'flb'        => 2.37304222192651E+01,
  8108.                                                                                             'BTU'        => 9.47815067349015E-04,
  8109.                                                                                             'btu'        => 9.47815067349015E-04
  8110.                                                                                         ),
  8111.                                                                         'e'        => array(    'J'            => 1.00000048065700E-07,
  8112.                                                                                             'e'            => 1.0,
  8113.                                                                                             'c'            => 2.39006364353494E-08,
  8114.                                                                                             'cal'        => 2.38846305445111E-08,
  8115.                                                                                             'eV'        => 6.24146000000000E+11,
  8116.                                                                                             'ev'        => 6.24146000000000E+11,
  8117.                                                                                             'HPh'        => 3.72506609848824E-14,
  8118.                                                                                             'hh'        => 3.72506609848824E-14,
  8119.                                                                                             'Wh'        => 2.77778049754611E-11,
  8120.                                                                                             'wh'        => 2.77778049754611E-11,
  8121.                                                                                             'flb'        => 2.37304336254586E-06,
  8122.                                                                                             'BTU'        => 9.47815522922962E-11,
  8123.                                                                                             'btu'        => 9.47815522922962E-11
  8124.                                                                                         ),
  8125.                                                                         'c'        => array(    'J'            => 4.18399101363672E+00,
  8126.                                                                                             'e'            => 4.18398900257312E+07,
  8127.                                                                                             'c'            => 1.0,
  8128.                                                                                             'cal'        => 9.99330315287563E-01,
  8129.                                                                                             'eV'        => 2.61142000000000E+19,
  8130.                                                                                             'ev'        => 2.61142000000000E+19,
  8131.                                                                                             'HPh'        => 1.55856355899327E-06,
  8132.                                                                                             'hh'        => 1.55856355899327E-06,
  8133.                                                                                             'Wh'        => 1.16222030532950E-03,
  8134.                                                                                             'wh'        => 1.16222030532950E-03,
  8135.                                                                                             'flb'        => 9.92878733152102E+01,
  8136.                                                                                             'BTU'        => 3.96564972437776E-03,
  8137.                                                                                             'btu'        => 3.96564972437776E-03
  8138.                                                                                         ),
  8139.                                                                         'cal'    => array(    'J'            => 4.18679484613929E+00,
  8140.                                                                                             'e'            => 4.18679283372801E+07,
  8141.                                                                                             'c'            => 1.00067013349059E+00,
  8142.                                                                                             'cal'        => 1.0,
  8143.                                                                                             'eV'        => 2.61317000000000E+19,
  8144.                                                                                             'ev'        => 2.61317000000000E+19,
  8145.                                                                                             'HPh'        => 1.55960800463137E-06,
  8146.                                                                                             'hh'        => 1.55960800463137E-06,
  8147.                                                                                             'Wh'        => 1.16299914807955E-03,
  8148.                                                                                             'wh'        => 1.16299914807955E-03,
  8149.                                                                                             'flb'        => 9.93544094443283E+01,
  8150.                                                                                             'BTU'        => 3.96830723907002E-03,
  8151.                                                                                             'btu'        => 3.96830723907002E-03
  8152.                                                                                         ),
  8153.                                                                         'eV'    => array(    'J'            => 1.60219000146921E-19,
  8154.                                                                                             'e'            => 1.60218923136574E-12,
  8155.                                                                                             'c'            => 3.82933423195043E-20,
  8156.                                                                                             'cal'        => 3.82676978535648E-20,
  8157.                                                                                             'eV'        => 1.0,
  8158.                                                                                             'ev'        => 1.0,
  8159.                                                                                             'HPh'        => 5.96826078912344E-26,
  8160.                                                                                             'hh'        => 5.96826078912344E-26,
  8161.                                                                                             'Wh'        => 4.45053000026614E-23,
  8162.                                                                                             'wh'        => 4.45053000026614E-23,
  8163.                                                                                             'flb'        => 3.80206452103492E-18,
  8164.                                                                                             'BTU'        => 1.51857982414846E-22,
  8165.                                                                                             'btu'        => 1.51857982414846E-22
  8166.                                                                                         ),
  8167.                                                                         'ev'    => array(    'J'            => 1.60219000146921E-19,
  8168.                                                                                             'e'            => 1.60218923136574E-12,
  8169.                                                                                             'c'            => 3.82933423195043E-20,
  8170.                                                                                             'cal'        => 3.82676978535648E-20,
  8171.                                                                                             'eV'        => 1.0,
  8172.                                                                                             'ev'        => 1.0,
  8173.                                                                                             'HPh'        => 5.96826078912344E-26,
  8174.                                                                                             'hh'        => 5.96826078912344E-26,
  8175.                                                                                             'Wh'        => 4.45053000026614E-23,
  8176.                                                                                             'wh'        => 4.45053000026614E-23,
  8177.                                                                                             'flb'        => 3.80206452103492E-18,
  8178.                                                                                             'BTU'        => 1.51857982414846E-22,
  8179.                                                                                             'btu'        => 1.51857982414846E-22
  8180.                                                                                         ),
  8181.                                                                         'HPh'    => array(    'J'            => 2.68451741316170E+06,
  8182.                                                                                             'e'            => 2.68451612283024E+13,
  8183.                                                                                             'c'            => 6.41616438565991E+05,
  8184.                                                                                             'cal'        => 6.41186757845835E+05,
  8185.                                                                                             'eV'        => 1.67553000000000E+25,
  8186.                                                                                             'ev'        => 1.67553000000000E+25,
  8187.                                                                                             'HPh'        => 1.0,
  8188.                                                                                             'hh'        => 1.0,
  8189.                                                                                             'Wh'        => 7.45699653134593E+02,
  8190.                                                                                             'wh'        => 7.45699653134593E+02,
  8191.                                                                                             'flb'        => 6.37047316692964E+07,
  8192.                                                                                             'BTU'        => 2.54442605275546E+03,
  8193.                                                                                             'btu'        => 2.54442605275546E+03
  8194.                                                                                         ),
  8195.                                                                         'hh'    => array(    'J'            => 2.68451741316170E+06,
  8196.                                                                                             'e'            => 2.68451612283024E+13,
  8197.                                                                                             'c'            => 6.41616438565991E+05,
  8198.                                                                                             'cal'        => 6.41186757845835E+05,
  8199.                                                                                             'eV'        => 1.67553000000000E+25,
  8200.                                                                                             'ev'        => 1.67553000000000E+25,
  8201.                                                                                             'HPh'        => 1.0,
  8202.                                                                                             'hh'        => 1.0,
  8203.                                                                                             'Wh'        => 7.45699653134593E+02,
  8204.                                                                                             'wh'        => 7.45699653134593E+02,
  8205.                                                                                             'flb'        => 6.37047316692964E+07,
  8206.                                                                                             'BTU'        => 2.54442605275546E+03,
  8207.                                                                                             'btu'        => 2.54442605275546E+03
  8208.                                                                                         ),
  8209.                                                                         'Wh'    => array(    'J'            => 3.59999820554720E+03,
  8210.                                                                                             'e'            => 3.59999647518369E+10,
  8211.                                                                                             'c'            => 8.60422069219046E+02,
  8212.                                                                                             'cal'        => 8.59845857713046E+02,
  8213.                                                                                             'eV'        => 2.24692340000000E+22,
  8214.                                                                                             'ev'        => 2.24692340000000E+22,
  8215.                                                                                             'HPh'        => 1.34102248243839E-03,
  8216.                                                                                             'hh'        => 1.34102248243839E-03,
  8217.                                                                                             'Wh'        => 1.0,
  8218.                                                                                             'wh'        => 1.0,
  8219.                                                                                             'flb'        => 8.54294774062316E+04,
  8220.                                                                                             'BTU'        => 3.41213254164705E+00,
  8221.                                                                                             'btu'        => 3.41213254164705E+00
  8222.                                                                                         ),
  8223.                                                                         'wh'    => array(    'J'            => 3.59999820554720E+03,
  8224.                                                                                             'e'            => 3.59999647518369E+10,
  8225.                                                                                             'c'            => 8.60422069219046E+02,
  8226.                                                                                             'cal'        => 8.59845857713046E+02,
  8227.                                                                                             'eV'        => 2.24692340000000E+22,
  8228.                                                                                             'ev'        => 2.24692340000000E+22,
  8229.                                                                                             'HPh'        => 1.34102248243839E-03,
  8230.                                                                                             'hh'        => 1.34102248243839E-03,
  8231.                                                                                             'Wh'        => 1.0,
  8232.                                                                                             'wh'        => 1.0,
  8233.                                                                                             'flb'        => 8.54294774062316E+04,
  8234.                                                                                             'BTU'        => 3.41213254164705E+00,
  8235.                                                                                             'btu'        => 3.41213254164705E+00
  8236.                                                                                         ),
  8237.                                                                         'flb'    => array(    'J'            => 4.21400003236424E-02,
  8238.                                                                                             'e'            => 4.21399800687660E+05,
  8239.                                                                                             'c'            => 1.00717234301644E-02,
  8240.                                                                                             'cal'        => 1.00649785509554E-02,
  8241.                                                                                             'eV'        => 2.63015000000000E+17,
  8242.                                                                                             'ev'        => 2.63015000000000E+17,
  8243.                                                                                             'HPh'        => 1.56974211145130E-08,
  8244.                                                                                             'hh'        => 1.56974211145130E-08,
  8245.                                                                                             'Wh'        => 1.17055614802000E-05,
  8246.                                                                                             'wh'        => 1.17055614802000E-05,
  8247.                                                                                             'flb'        => 1.0,
  8248.                                                                                             'BTU'        => 3.99409272448406E-05,
  8249.                                                                                             'btu'        => 3.99409272448406E-05
  8250.                                                                                         ),
  8251.                                                                         'BTU'    => array(    'J'            => 1.05505813786749E+03,
  8252.                                                                                             'e'            => 1.05505763074665E+10,
  8253.                                                                                             'c'            => 2.52165488508168E+02,
  8254.                                                                                             'cal'        => 2.51996617135510E+02,
  8255.                                                                                             'eV'        => 6.58510000000000E+21,
  8256.                                                                                             'ev'        => 6.58510000000000E+21,
  8257.                                                                                             'HPh'        => 3.93015941224568E-04,
  8258.                                                                                             'hh'        => 3.93015941224568E-04,
  8259.                                                                                             'Wh'        => 2.93071851047526E-01,
  8260.                                                                                             'wh'        => 2.93071851047526E-01,
  8261.                                                                                             'flb'        => 2.50369750774671E+04,
  8262.                                                                                             'BTU'        => 1.0,
  8263.                                                                                             'btu'        => 1.0,
  8264.                                                                                         ),
  8265.                                                                         'btu'    => array(    'J'            => 1.05505813786749E+03,
  8266.                                                                                             'e'            => 1.05505763074665E+10,
  8267.                                                                                             'c'            => 2.52165488508168E+02,
  8268.                                                                                             'cal'        => 2.51996617135510E+02,
  8269.                                                                                             'eV'        => 6.58510000000000E+21,
  8270.                                                                                             'ev'        => 6.58510000000000E+21,
  8271.                                                                                             'HPh'        => 3.93015941224568E-04,
  8272.                                                                                             'hh'        => 3.93015941224568E-04,
  8273.                                                                                             'Wh'        => 2.93071851047526E-01,
  8274.                                                                                             'wh'        => 2.93071851047526E-01,
  8275.                                                                                             'flb'        => 2.50369750774671E+04,
  8276.                                                                                             'BTU'        => 1.0,
  8277.                                                                                             'btu'        => 1.0,
  8278.                                                                                         )
  8279.                                                                     ),
  8280.                                                 'Power'        => array(    'HP'    => array(    'HP'        => 1.0,
  8281.                                                                                             'h'            => 1.0,
  8282.                                                                                             'W'            => 7.45701000000000E+02,
  8283.                                                                                             'w'            => 7.45701000000000E+02
  8284.                                                                                         ),
  8285.                                                                         'h'        => array(    'HP'        => 1.0,
  8286.                                                                                             'h'            => 1.0,
  8287.                                                                                             'W'            => 7.45701000000000E+02,
  8288.                                                                                             'w'            => 7.45701000000000E+02
  8289.                                                                                         ),
  8290.                                                                         'W'        => array(    'HP'        => 1.34102006031908E-03,
  8291.                                                                                             'h'            => 1.34102006031908E-03,
  8292.                                                                                             'W'            => 1.0,
  8293.                                                                                             'w'            => 1.0
  8294.                                                                                         ),
  8295.                                                                         'w'        => array(    'HP'        => 1.34102006031908E-03,
  8296.                                                                                             'h'            => 1.34102006031908E-03,
  8297.                                                                                             'W'            => 1.0,
  8298.                                                                                             'w'            => 1.0
  8299.                                                                                         )
  8300.                                                                     ),
  8301.                                                 'Magnetism'    => array(    'T'        => array(    'T'            => 1.0,
  8302.                                                                                             'ga'        => 10000.0
  8303.                                                                                         ),
  8304.                                                                         'ga'    => array(    'T'            => 0.0001,
  8305.                                                                                             'ga'        => 1.0
  8306.                                                                                         )
  8307.                                                                     ),
  8308.                                                 'Liquid'    => array(    'tsp'    => array(    'tsp'        => 1.0,
  8309.                                                                                             'tbs'        => 3.33333333333333E-01,
  8310.                                                                                             'oz'        => 1.66666666666667E-01,
  8311.                                                                                             'cup'        => 2.08333333333333E-02,
  8312.                                                                                             'pt'        => 1.04166666666667E-02,
  8313.                                                                                             'us_pt'        => 1.04166666666667E-02,
  8314.                                                                                             'uk_pt'        => 8.67558516821960E-03,
  8315.                                                                                             'qt'        => 5.20833333333333E-03,
  8316.                                                                                             'gal'        => 1.30208333333333E-03,
  8317.                                                                                             'l'            => 4.92999408400710E-03,
  8318.                                                                                             'lt'        => 4.92999408400710E-03
  8319.                                                                                         ),
  8320.                                                                         'tbs'    => array(    'tsp'        => 3.00000000000000E+00,
  8321.                                                                                             'tbs'        => 1.0,
  8322.                                                                                             'oz'        => 5.00000000000000E-01,
  8323.                                                                                             'cup'        => 6.25000000000000E-02,
  8324.                                                                                             'pt'        => 3.12500000000000E-02,
  8325.                                                                                             'us_pt'        => 3.12500000000000E-02,
  8326.                                                                                             'uk_pt'        => 2.60267555046588E-02,
  8327.                                                                                             'qt'        => 1.56250000000000E-02,
  8328.                                                                                             'gal'        => 3.90625000000000E-03,
  8329.                                                                                             'l'            => 1.47899822520213E-02,
  8330.                                                                                             'lt'        => 1.47899822520213E-02
  8331.                                                                                         ),
  8332.                                                                         'oz'    => array(    'tsp'        => 6.00000000000000E+00,
  8333.                                                                                             'tbs'        => 2.00000000000000E+00,
  8334.                                                                                             'oz'        => 1.0,
  8335.                                                                                             'cup'        => 1.25000000000000E-01,
  8336.                                                                                             'pt'        => 6.25000000000000E-02,
  8337.                                                                                             'us_pt'        => 6.25000000000000E-02,
  8338.                                                                                             'uk_pt'        => 5.20535110093176E-02,
  8339.                                                                                             'qt'        => 3.12500000000000E-02,
  8340.                                                                                             'gal'        => 7.81250000000000E-03,
  8341.                                                                                             'l'            => 2.95799645040426E-02,
  8342.                                                                                             'lt'        => 2.95799645040426E-02
  8343.                                                                                         ),
  8344.                                                                         'cup'    => array(    'tsp'        => 4.80000000000000E+01,
  8345.                                                                                             'tbs'        => 1.60000000000000E+01,
  8346.                                                                                             'oz'        => 8.00000000000000E+00,
  8347.                                                                                             'cup'        => 1.0,
  8348.                                                                                             'pt'        => 5.00000000000000E-01,
  8349.                                                                                             'us_pt'        => 5.00000000000000E-01,
  8350.                                                                                             'uk_pt'        => 4.16428088074541E-01,
  8351.                                                                                             'qt'        => 2.50000000000000E-01,
  8352.                                                                                             'gal'        => 6.25000000000000E-02,
  8353.                                                                                             'l'            => 2.36639716032341E-01,
  8354.                                                                                             'lt'        => 2.36639716032341E-01
  8355.                                                                                         ),
  8356.                                                                         'pt'    => array(    'tsp'        => 9.60000000000000E+01,
  8357.                                                                                             'tbs'        => 3.20000000000000E+01,
  8358.                                                                                             'oz'        => 1.60000000000000E+01,
  8359.                                                                                             'cup'        => 2.00000000000000E+00,
  8360.                                                                                             'pt'        => 1.0,
  8361.                                                                                             'us_pt'        => 1.0,
  8362.                                                                                             'uk_pt'        => 8.32856176149081E-01,
  8363.                                                                                             'qt'        => 5.00000000000000E-01,
  8364.                                                                                             'gal'        => 1.25000000000000E-01,
  8365.                                                                                             'l'            => 4.73279432064682E-01,
  8366.                                                                                             'lt'        => 4.73279432064682E-01
  8367.                                                                                         ),
  8368.                                                                         'us_pt'    => array(    'tsp'        => 9.60000000000000E+01,
  8369.                                                                                             'tbs'        => 3.20000000000000E+01,
  8370.                                                                                             'oz'        => 1.60000000000000E+01,
  8371.                                                                                             'cup'        => 2.00000000000000E+00,
  8372.                                                                                             'pt'        => 1.0,
  8373.                                                                                             'us_pt'        => 1.0,
  8374.                                                                                             'uk_pt'        => 8.32856176149081E-01,
  8375.                                                                                             'qt'        => 5.00000000000000E-01,
  8376.                                                                                             'gal'        => 1.25000000000000E-01,
  8377.                                                                                             'l'            => 4.73279432064682E-01,
  8378.                                                                                             'lt'        => 4.73279432064682E-01
  8379.                                                                                         ),
  8380.                                                                         'uk_pt'    => array(    'tsp'        => 1.15266000000000E+02,
  8381.                                                                                             'tbs'        => 3.84220000000000E+01,
  8382.                                                                                             'oz'        => 1.92110000000000E+01,
  8383.                                                                                             'cup'        => 2.40137500000000E+00,
  8384.                                                                                             'pt'        => 1.20068750000000E+00,
  8385.                                                                                             'us_pt'        => 1.20068750000000E+00,
  8386.                                                                                             'uk_pt'        => 1.0,
  8387.                                                                                             'qt'        => 6.00343750000000E-01,
  8388.                                                                                             'gal'        => 1.50085937500000E-01,
  8389.                                                                                             'l'            => 5.68260698087162E-01,
  8390.                                                                                             'lt'        => 5.68260698087162E-01
  8391.                                                                                         ),
  8392.                                                                         'qt'    => array(    'tsp'        => 1.92000000000000E+02,
  8393.                                                                                             'tbs'        => 6.40000000000000E+01,
  8394.                                                                                             'oz'        => 3.20000000000000E+01,
  8395.                                                                                             'cup'        => 4.00000000000000E+00,
  8396.                                                                                             'pt'        => 2.00000000000000E+00,
  8397.                                                                                             'us_pt'        => 2.00000000000000E+00,
  8398.                                                                                             'uk_pt'        => 1.66571235229816E+00,
  8399.                                                                                             'qt'        => 1.0,
  8400.                                                                                             'gal'        => 2.50000000000000E-01,
  8401.                                                                                             'l'            => 9.46558864129363E-01,
  8402.                                                                                             'lt'        => 9.46558864129363E-01
  8403.                                                                                         ),
  8404.                                                                         'gal'    => array(    'tsp'        => 7.68000000000000E+02,
  8405.                                                                                             'tbs'        => 2.56000000000000E+02,
  8406.                                                                                             'oz'        => 1.28000000000000E+02,
  8407.                                                                                             'cup'        => 1.60000000000000E+01,
  8408.                                                                                             'pt'        => 8.00000000000000E+00,
  8409.                                                                                             'us_pt'        => 8.00000000000000E+00,
  8410.                                                                                             'uk_pt'        => 6.66284940919265E+00,
  8411.                                                                                             'qt'        => 4.00000000000000E+00,
  8412.                                                                                             'gal'        => 1.0,
  8413.                                                                                             'l'            => 3.78623545651745E+00,
  8414.                                                                                             'lt'        => 3.78623545651745E+00
  8415.                                                                                         ),
  8416.                                                                         'l'        => array(    'tsp'        => 2.02840000000000E+02,
  8417.                                                                                             'tbs'        => 6.76133333333333E+01,
  8418.                                                                                             'oz'        => 3.38066666666667E+01,
  8419.                                                                                             'cup'        => 4.22583333333333E+00,
  8420.                                                                                             'pt'        => 2.11291666666667E+00,
  8421.                                                                                             'us_pt'        => 2.11291666666667E+00,
  8422.                                                                                             'uk_pt'        => 1.75975569552166E+00,
  8423.                                                                                             'qt'        => 1.05645833333333E+00,
  8424.                                                                                             'gal'        => 2.64114583333333E-01,
  8425.                                                                                             'l'            => 1.0,
  8426.                                                                                             'lt'        => 1.0
  8427.                                                                                         ),
  8428.                                                                         'lt'    => array(    'tsp'        => 2.02840000000000E+02,
  8429.                                                                                             'tbs'        => 6.76133333333333E+01,
  8430.                                                                                             'oz'        => 3.38066666666667E+01,
  8431.                                                                                             'cup'        => 4.22583333333333E+00,
  8432.                                                                                             'pt'        => 2.11291666666667E+00,
  8433.                                                                                             'us_pt'        => 2.11291666666667E+00,
  8434.                                                                                             'uk_pt'        => 1.75975569552166E+00,
  8435.                                                                                             'qt'        => 1.05645833333333E+00,
  8436.                                                                                             'gal'        => 2.64114583333333E-01,
  8437.                                                                                             'l'            => 1.0,
  8438.                                                                                             'lt'        => 1.0
  8439.                                                                                         )
  8440.                                                                     )
  8441.                                             );
  8442.  
  8443.  
  8444.     /**
  8445.      * getConversionGroups
  8446.      *
  8447.      * @return    array 
  8448.      */
  8449.     public static function getConversionGroups({
  8450.         $conversionGroups array();
  8451.         foreach(self::$_conversionUnits as $conversionUnit{
  8452.             $conversionGroups[$conversionUnit['Group'];
  8453.         }
  8454.         return array_merge(array_unique($conversionGroups));
  8455.     }    //    function getConversionGroups()
  8456.  
  8457.  
  8458.     /**
  8459.      * getConversionGroupUnits
  8460.      *
  8461.      * @return    array 
  8462.      */
  8463.     public static function getConversionGroupUnits($group NULL{
  8464.         $conversionGroups array();
  8465.         foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup{
  8466.             if ((is_null($group)) || ($conversionGroup['Group'== $group)) {
  8467.                 $conversionGroups[$conversionGroup['Group']][$conversionUnit;
  8468.             }
  8469.         }
  8470.         return $conversionGroups;
  8471.     }    //    function getConversionGroupUnits()
  8472.  
  8473.  
  8474.     /**
  8475.      * getConversionGroupUnitDetails
  8476.      *
  8477.      * @return    array 
  8478.      */
  8479.     public static function getConversionGroupUnitDetails($group NULL{
  8480.         $conversionGroups array();
  8481.         foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup{
  8482.             if ((is_null($group)) || ($conversionGroup['Group'== $group)) {
  8483.                 $conversionGroups[$conversionGroup['Group']][array(    'unit'            => $conversionUnit,
  8484.                                                                         'description'    => $conversionGroup['Unit Name']
  8485.                                                                       );
  8486.             }
  8487.         }
  8488.         return $conversionGroups;
  8489.     }    //    function getConversionGroupUnitDetails()
  8490.  
  8491.  
  8492.     /**
  8493.      * getConversionGroups
  8494.      *
  8495.      * @return    array 
  8496.      */
  8497.     public static function getConversionMultipliers({
  8498.         return self::$_conversionMultipliers;
  8499.     }    //    function getConversionGroups()
  8500.  
  8501.  
  8502.     /**
  8503.      * CONVERTUOM
  8504.      *
  8505.      * @param    float        $value 
  8506.      * @param    string        $fromUOM 
  8507.      * @param    string        $toUOM 
  8508.      * @return    float 
  8509.      */
  8510.     public static function CONVERTUOM($value$fromUOM$toUOM{
  8511.         $value        self::flattenSingleValue($value);
  8512.         $fromUOM    self::flattenSingleValue($fromUOM);
  8513.         $toUOM        self::flattenSingleValue($toUOM);
  8514.  
  8515.         if (!is_numeric($value)) {
  8516.             return self::$_errorCodes['value'];
  8517.         }
  8518.         $fromMultiplier 1;
  8519.         if (isset(self::$_conversionUnits[$fromUOM])) {
  8520.             $unitGroup1 self::$_conversionUnits[$fromUOM]['Group'];
  8521.         else {
  8522.             $fromMultiplier substr($fromUOM,0,1);
  8523.             $fromUOM substr($fromUOM,1);
  8524.             if (isset(self::$_conversionMultipliers[$fromMultiplier])) {
  8525.                 $fromMultiplier self::$_conversionMultipliers[$fromMultiplier]['multiplier'];
  8526.             else {
  8527.                 return self::$_errorCodes['na'];
  8528.             }
  8529.             if ((isset(self::$_conversionUnits[$fromUOM])) && (self::$_conversionUnits[$fromUOM]['AllowPrefix'])) {
  8530.                 $unitGroup1 self::$_conversionUnits[$fromUOM]['Group'];
  8531.             else {
  8532.                 return self::$_errorCodes['na'];
  8533.             }
  8534.         }
  8535.         $value *= $fromMultiplier;
  8536.  
  8537.         $toMultiplier 1;
  8538.         if (isset(self::$_conversionUnits[$toUOM])) {
  8539.             $unitGroup2 self::$_conversionUnits[$toUOM]['Group'];
  8540.         else {
  8541.             $toMultiplier substr($toUOM,0,1);
  8542.             $toUOM substr($toUOM,1);
  8543.             if (isset(self::$_conversionMultipliers[$toMultiplier])) {
  8544.                 $toMultiplier self::$_conversionMultipliers[$toMultiplier]['multiplier'];
  8545.             else {
  8546.                 return self::$_errorCodes['na'];
  8547.             }
  8548.             if ((isset(self::$_conversionUnits[$toUOM])) && (self::$_conversionUnits[$toUOM]['AllowPrefix'])) {
  8549.                 $unitGroup2 self::$_conversionUnits[$toUOM]['Group'];
  8550.             else {
  8551.                 return self::$_errorCodes['na'];
  8552.             }
  8553.         }
  8554.         if ($unitGroup1 != $unitGroup2{
  8555.             return self::$_errorCodes['na'];
  8556.         }
  8557.  
  8558.         if ($fromUOM == $toUOM{
  8559.             return 1.0;
  8560.         elseif ($unitGroup1 == 'Temperature'{
  8561.             if (($fromUOM == 'F'|| ($fromUOM == 'fah')) {
  8562.                 if (($toUOM == 'F'|| ($toUOM == 'fah')) {
  8563.                     return 1.0;
  8564.                 else {
  8565.                     $value (($value 321.8);
  8566.                     if (($toUOM == 'K'|| ($toUOM == 'kel')) {
  8567.                         $value += 273.15;
  8568.                     }
  8569.                     return $value;
  8570.                 }
  8571.             elseif ((($fromUOM == 'K'|| ($fromUOM == 'kel')) &&
  8572.                       (($toUOM == 'K'|| ($toUOM == 'kel'))) {
  8573.                         return 1.0;
  8574.             elseif ((($fromUOM == 'C'|| ($fromUOM == 'cel')) &&
  8575.                       (($toUOM == 'C'|| ($toUOM == 'cel'))) {
  8576.                     return 1.0;
  8577.             }
  8578.             if (($toUOM == 'F'|| ($toUOM == 'fah')) {
  8579.                 if (($fromUOM == 'K'|| ($fromUOM == 'kel')) {
  8580.                     $value -= 273.15;
  8581.                 }
  8582.                 return ($value 1.832;
  8583.             }
  8584.             if (($toUOM == 'C'|| ($toUOM == 'cel')) {
  8585.                 return $value 273.15;
  8586.             }
  8587.             return $value 273.15;
  8588.         }
  8589.         return ($value self::$_unitConversions[$unitGroup1][$fromUOM][$toUOM]$toMultiplier;
  8590.     }    //    function CONVERTUOM()
  8591.  
  8592.  
  8593.     /**
  8594.      * BESSELI
  8595.      *
  8596.      * Returns the modified Bessel function, which is equivalent to the Bessel function evaluated for purely imaginary arguments
  8597.      *
  8598.      * @param    float        $x 
  8599.      * @param    float        $n 
  8600.      * @return    int 
  8601.      */
  8602.     public static function BESSELI($x$n{
  8603.         $x    (is_null($x))    0.0 :    self::flattenSingleValue($x);
  8604.         $n    (is_null($n))    0.0 :    self::flattenSingleValue($n);
  8605.  
  8606.         if ((is_numeric($x)) && (is_numeric($n))) {
  8607.             $n    floor($n);
  8608.             if ($n 0{
  8609.                 return self::$_errorCodes['num'];
  8610.             }
  8611.             $f_2_PI M_PI;
  8612.  
  8613.             if (abs($x<= 30{
  8614.                 $fTerm pow($x 2$nself::FACT($n);
  8615.                 $nK 1;
  8616.                 $fResult $fTerm;
  8617.                 $fSqrX ($x $x4;
  8618.                 do {
  8619.                     $fTerm *= $fSqrX;
  8620.                     $fTerm /= ($nK ($nK $n));
  8621.                     $fResult += $fTerm;
  8622.                 while ((abs($fTerm1e-10&& (++$nK 100));
  8623.             else {
  8624.                 $fXAbs abs($x);
  8625.                 $fResult exp($fXAbssqrt($f_2_PI $fXAbs);
  8626.                 if (($n && 1&& ($x 0)) {
  8627.                     $fResult = -$fResult;
  8628.                 }
  8629.             }
  8630.             return $fResult;
  8631.         }
  8632.         return self::$_errorCodes['value'];
  8633.     }    //    function BESSELI()
  8634.  
  8635.  
  8636.     /**
  8637.      * BESSELJ
  8638.      *
  8639.      * Returns the Bessel function
  8640.      *
  8641.      * @param    float        $x 
  8642.      * @param    float        $n 
  8643.      * @return    int 
  8644.      */
  8645.     public static function BESSELJ($x$n{
  8646.         $x    (is_null($x))    0.0 :    self::flattenSingleValue($x);
  8647.         $n    (is_null($n))    0.0 :    self::flattenSingleValue($n);
  8648.  
  8649.         if ((is_numeric($x)) && (is_numeric($n))) {
  8650.             $n    floor($n);
  8651.             if ($n 0{
  8652.                 return self::$_errorCodes['num'];
  8653.             }
  8654.             $f_PI_DIV_2 M_PI 2;
  8655.             $f_PI_DIV_4 M_PI 4;
  8656.  
  8657.             $fResult 0;
  8658.             if (abs($x<= 30{
  8659.                 $fTerm pow($x 2$nself::FACT($n);
  8660.                 $nK 1;
  8661.                 $fResult $fTerm;
  8662.                 $fSqrX ($x $x/ -4;
  8663.                 do {
  8664.                     $fTerm *= $fSqrX;
  8665.                     $fTerm /= ($nK ($nK $n));
  8666.                     $fResult += $fTerm;
  8667.                 while ((abs($fTerm1e-10&& (++$nK 100));
  8668.             else {
  8669.                 $fXAbs abs($x);
  8670.                 $fResult sqrt(M_2DIVPI $fXAbscos($fXAbs $n $f_PI_DIV_2 $f_PI_DIV_4);
  8671.                 if (($n && 1&& ($x 0)) {
  8672.                     $fResult = -$fResult;
  8673.                 }
  8674.             }
  8675.             return $fResult;
  8676.         }
  8677.         return self::$_errorCodes['value'];
  8678.     }    //    function BESSELJ()
  8679.  
  8680.  
  8681.     private static function _Besselk0($fNum{
  8682.         if ($fNum <= 2{
  8683.             $fNum2 $fNum 0.5;
  8684.             $y ($fNum2 $fNum2);
  8685.             $fRet = -log($fNum2self::BESSELI($fNum0+
  8686.                     (-0.57721566 $y (0.42278420 $y (0.23069756 $y (0.3488590e-1 $y (0.262698e-2 $y *
  8687.                     (0.10750e-3 $y 0.74e-5))))));
  8688.         else {
  8689.             $y $fNum;
  8690.             $fRet exp(-$fNumsqrt($fNum*
  8691.                     (1.25331414 $y (-0.7832358e-1 $y (0.2189568e-1 $y (-0.1062446e-1 $y *
  8692.                     (0.587872e-2 $y (-0.251540e-2 $y 0.53208e-3))))));
  8693.         }
  8694.         return $fRet;
  8695.     }    //    function _Besselk0()
  8696.  
  8697.  
  8698.     private static function _Besselk1($fNum{
  8699.         if ($fNum <= 2{
  8700.             $fNum2 $fNum 0.5;
  8701.             $y ($fNum2 $fNum2);
  8702.             $fRet log($fNum2self::BESSELI($fNum1+
  8703.                     ($y (0.15443144 $y (-0.67278579 $y (-0.18156897 $y (-0.1919402e-1 $y *
  8704.                     (-0.110404e-2 $y (-0.4686e-4))))))) $fNum;
  8705.         else {
  8706.             $y $fNum;
  8707.             $fRet exp(-$fNumsqrt($fNum*
  8708.                     (1.25331414 $y (0.23498619 $y (-0.3655620e-1 $y (0.1504268e-1 $y (-0.780353e-2 $y *
  8709.                     (0.325614e-2 $y (-0.68245e-3)))))));
  8710.         }
  8711.         return $fRet;
  8712.     }    //    function _Besselk1()
  8713.  
  8714.  
  8715.     /**
  8716.      * BESSELK
  8717.      *
  8718.      * Returns the modified Bessel function, which is equivalent to the Bessel functions evaluated for purely imaginary arguments.
  8719.      *
  8720.      * @param    float        $x 
  8721.      * @param    float        $ord 
  8722.      * @return    float 
  8723.      */
  8724.     public static function BESSELK($x$ord{
  8725.         $x        (is_null($x))        0.0 :    self::flattenSingleValue($x);
  8726.         $ord    (is_null($ord))    0.0 :    self::flattenSingleValue($ord);
  8727.  
  8728.         if ((is_numeric($x)) && (is_numeric($ord))) {
  8729.             if (($ord 0|| ($x == 0.0)) {
  8730.                 return self::$_errorCodes['num'];
  8731.             }
  8732.  
  8733.             switch(floor($ord)) {
  8734.                 case :    return self::_Besselk0($x);
  8735.                             break;
  8736.                 case :    return self::_Besselk1($x);
  8737.                             break;
  8738.                 default :    $fTox    $x;
  8739.                             $fBkm    self::_Besselk0($x);
  8740.                             $fBk    self::_Besselk1($x);
  8741.                             for ($n 1$n $ord++$n{
  8742.                                 $fBkp    $fBkm $n $fTox $fBk;
  8743.                                 $fBkm    $fBk;
  8744.                                 $fBk    $fBkp;
  8745.                             }
  8746.             }
  8747.             return $fBk;
  8748.         }
  8749.         return self::$_errorCodes['value'];
  8750.     }    //    function BESSELK()
  8751.  
  8752.  
  8753.     private static function _Bessely0($fNum{
  8754.         if ($fNum 8.0{
  8755.             $y ($fNum $fNum);
  8756.             $f1 = -2957821389.0 $y (7062834065.0 $y (-512359803.6 $y (10879881.29 $y (-86327.92757 $y 228.4622733))));
  8757.             $f2 40076544269.0 $y (745249964.8 $y (7189466.438 $y (47447.26470 $y (226.1030244 $y))));
  8758.             $fRet $f1 $f2 M_2DIVPI self::BESSELJ($fNum0log($fNum);
  8759.         else {
  8760.             $z 8.0 $fNum;
  8761.             $y ($z $z);
  8762.             $xx $fNum 0.785398164;
  8763.             $f1 $y (-0.1098628627e-2 $y (0.2734510407e-4 $y (-0.2073370639e-5 $y 0.2093887211e-6)));
  8764.             $f2 = -0.1562499995e-1 $y (0.1430488765e-3 $y (-0.6911147651e-5 $y (0.7621095161e-6 $y (-0.934945152e-7))));
  8765.             $fRet sqrt(M_2DIVPI $fNum(sin($xx$f1 $z cos($xx$f2);
  8766.         }
  8767.         return $fRet;
  8768.     }    //    function _Bessely0()
  8769.  
  8770.  
  8771.     private static function _Bessely1($fNum{
  8772.         if ($fNum 8.0{
  8773.             $y ($fNum $fNum);
  8774.             $f1 $fNum (-0.4900604943e13 $y (0.1275274390e13 $y (-0.5153438139e11 $y (0.7349264551e9 $y *
  8775.                 (-0.4237922726e7 $y 0.8511937935e4)))));
  8776.             $f2 0.2499580570e14 $y (0.4244419664e12 $y (0.3733650367e10 $y (0.2245904002e8 $y *
  8777.                 (0.1020426050e6 $y (0.3549632885e3 $y)))));
  8778.             $fRet $f1 $f2 M_2DIVPI self::BESSELJ($fNum1log($fNum$fNum);
  8779.         else {
  8780.             $z 8.0 $fNum;
  8781.             $y ($z $z);
  8782.             $xx $fNum 2.356194491;
  8783.             $f1 $y (0.183105e-2 $y (-0.3516396496e-4 $y (0.2457520174e-5 $y (-0.240337019e6))));
  8784.             $f2 0.04687499995 $y (-0.2002690873e-3 $y (0.8449199096e-5 $y (-0.88228987e-6 $y 0.105787412e-6)));
  8785.             $fRet sqrt(M_2DIVPI $fNum(sin($xx$f1 $z cos($xx$f2);
  8786.             #i12430# ...but this seems to work much better.
  8787. //            $fRet = sqrt(M_2DIVPI / $fNum) * sin($fNum - 2.356194491);
  8788.         }
  8789.         return $fRet;
  8790.     }    //    function _Bessely1()
  8791.  
  8792.  
  8793.     /**
  8794.      * BESSELY
  8795.      *
  8796.      * Returns the Bessel function, which is also called the Weber function or the Neumann function.
  8797.      *
  8798.      * @param    float        $x 
  8799.      * @param    float        $n 
  8800.      * @return    int 
  8801.      */
  8802.     public static function BESSELY($x$ord{
  8803.         $x        (is_null($x))        0.0 :    self::flattenSingleValue($x);
  8804.         $ord    (is_null($ord))    0.0 :    self::flattenSingleValue($ord);
  8805.  
  8806.         if ((is_numeric($x)) && (is_numeric($ord))) {
  8807.             if (($ord 0|| ($x == 0.0)) {
  8808.                 return self::$_errorCodes['num'];
  8809.             }
  8810.  
  8811.             switch(floor($ord)) {
  8812.                 case :    return self::_Bessely0($x);
  8813.                             break;
  8814.                 case :    return self::_Bessely1($x);
  8815.                             break;
  8816.                 default:    $fTox    $x;
  8817.                             $fBym    self::_Bessely0($x);
  8818.                             $fBy    self::_Bessely1($x);
  8819.                             for ($n 1$n $ord++$n{
  8820.                                 $fByp    $n $fTox $fBy $fBym;
  8821.                                 $fBym    $fBy;
  8822.                                 $fBy    $fByp;
  8823.                             }
  8824.             }
  8825.             return $fBy;
  8826.         }
  8827.         return self::$_errorCodes['value'];
  8828.     }    //    function BESSELY()
  8829.  
  8830.  
  8831.     /**
  8832.      * DELTA
  8833.      *
  8834.      * Tests whether two values are equal. Returns 1 if number1 = number2; returns 0 otherwise.
  8835.      *
  8836.      * @param    float        $a 
  8837.      * @param    float        $b 
  8838.      * @return    int 
  8839.      */
  8840.     public static function DELTA($a$b=0{
  8841.         $a    self::flattenSingleValue($a);
  8842.         $b    self::flattenSingleValue($b);
  8843.  
  8844.         return (int) ($a == $b);
  8845.     }    //    function DELTA()
  8846.  
  8847.  
  8848.     /**
  8849.      * GESTEP
  8850.      *
  8851.      * Returns 1 if number = step; returns 0 (zero) otherwise
  8852.      *
  8853.      * @param    float        $number 
  8854.      * @param    float        $step 
  8855.      * @return    int 
  8856.      */
  8857.     public static function GESTEP($number$step=0{
  8858.         $number    self::flattenSingleValue($number);
  8859.         $step    self::flattenSingleValue($step);
  8860.  
  8861.         return (int) ($number >= $step);
  8862.     }    //    function GESTEP()
  8863.  
  8864.  
  8865.     //
  8866.     //    Private method to calculate the erf value
  8867.     //
  8868.     private static $_two_sqrtpi 1.128379167095512574;
  8869.  
  8870.     private static function _erfVal($x{
  8871.         if (abs($x2.2{
  8872.             return self::_erfcVal($x);
  8873.         }
  8874.         $sum $term $x;
  8875.         $xsqr ($x $x);
  8876.         $j 1;
  8877.         do {
  8878.             $term *= $xsqr $j;
  8879.             $sum -= $term ($j 1);
  8880.             ++$j;
  8881.             $term *= $xsqr $j;
  8882.             $sum += $term ($j 1);
  8883.             ++$j;
  8884.             if ($sum == 0.0{
  8885.                 break;
  8886.             }
  8887.         while (abs($term $sumPRECISION);
  8888.         return self::$_two_sqrtpi $sum;
  8889.     }    //    function _erfVal()
  8890.  
  8891.  
  8892.     /**
  8893.      * ERF
  8894.      *
  8895.      * Returns the error function integrated between lower_limit and upper_limit
  8896.      *
  8897.      * @param    float        $lower    lower bound for integrating ERF
  8898.      * @param    float        $upper    upper bound for integrating ERF.
  8899.      *                                 If omitted, ERF integrates between zero and lower_limit
  8900.      * @return    int 
  8901.      */
  8902.     public static function ERF($lower$upper null{
  8903.         $lower    self::flattenSingleValue($lower);
  8904.         $upper    self::flattenSingleValue($upper);
  8905.  
  8906.         if (is_numeric($lower)) {
  8907.             if ($lower 0{
  8908.                 return self::$_errorCodes['num'];
  8909.             }
  8910.             if (is_null($upper)) {
  8911.                 return self::_erfVal($lower);
  8912.             }
  8913.             if (is_numeric($upper)) {
  8914.                 if ($upper 0{
  8915.                     return self::$_errorCodes['num'];
  8916.                 }
  8917.                 return self::_erfVal($upperself::_erfVal($lower);
  8918.             }
  8919.         }
  8920.         return self::$_errorCodes['value'];
  8921.     }    //    function ERF()
  8922.  
  8923.  
  8924.     //
  8925.     //    Private method to calculate the erfc value
  8926.     //
  8927.     private static $_one_sqrtpi 0.564189583547756287;
  8928.  
  8929.     private static function _erfcVal($x{
  8930.         if (abs($x2.2{
  8931.             return self::_erfVal($x);
  8932.         }
  8933.         if ($x 0{
  8934.             return self::erfc(-$x);
  8935.         }
  8936.         $a $n 1;
  8937.         $b $c $x;
  8938.         $d ($x $x0.5;
  8939.         $q1 $q2 $b $d;
  8940.         $t 0;
  8941.         do {
  8942.             $t $a $n $b $x;
  8943.             $a $b;
  8944.             $b $t;
  8945.             $t $c $n $d $x;
  8946.             $c $d;
  8947.             $d $t;
  8948.             $n += 0.5;
  8949.             $q1 $q2;
  8950.             $q2 $b $d;
  8951.         while ((abs($q1 $q2$q2PRECISION);
  8952.         return self::$_one_sqrtpi exp(-$x $x$q2;
  8953.     }    //    function _erfcVal()
  8954.  
  8955.  
  8956.     /**
  8957.      * ERFC
  8958.      *
  8959.      * Returns the complementary ERF function integrated between x and infinity
  8960.      *
  8961.      * @param    float        $x        The lower bound for integrating ERF
  8962.      * @return    int 
  8963.      */
  8964.     public static function ERFC($x{
  8965.         $x    self::flattenSingleValue($x);
  8966.  
  8967.         if (is_numeric($x)) {
  8968.             if ($x 0{
  8969.                 return self::$_errorCodes['num'];
  8970.             }
  8971.             return self::_erfcVal($x);
  8972.         }
  8973.         return self::$_errorCodes['value'];
  8974.     }    //    function ERFC()
  8975.  
  8976.  
  8977.     /**
  8978.      *    LOWERCASE
  8979.      *
  8980.      *    Converts a string value to upper case.
  8981.      *
  8982.      *    @param    string        $mixedCaseString 
  8983.      *    @return    string 
  8984.      */
  8985.     public static function LOWERCASE($mixedCaseString{
  8986.         $mixedCaseString    self::flattenSingleValue($mixedCaseString);
  8987.  
  8988.         if (is_bool($mixedCaseString)) {
  8989.             $mixedCaseString ($mixedCaseString'TRUE' 'FALSE';
  8990.         }
  8991.  
  8992.         if (function_exists('mb_convert_case')) {
  8993.             return mb_convert_case($mixedCaseStringMB_CASE_LOWER'UTF-8');
  8994.         else {
  8995.             return strtoupper($mixedCaseString);
  8996.         }
  8997.     }    //    function LOWERCASE()
  8998.  
  8999.  
  9000.     /**
  9001.      *    UPPERCASE
  9002.      *
  9003.      *    Converts a string value to upper case.
  9004.      *
  9005.      *    @param    string        $mixedCaseString 
  9006.      *    @return    string 
  9007.      */
  9008.     public static function UPPERCASE($mixedCaseString{
  9009.         $mixedCaseString    self::flattenSingleValue($mixedCaseString);
  9010.  
  9011.         if (is_bool($mixedCaseString)) {
  9012.             $mixedCaseString ($mixedCaseString'TRUE' 'FALSE';
  9013.         }
  9014.  
  9015.         if (function_exists('mb_convert_case')) {
  9016.             return mb_convert_case($mixedCaseStringMB_CASE_UPPER'UTF-8');
  9017.         else {
  9018.             return strtoupper($mixedCaseString);
  9019.         }
  9020.     }    //    function UPPERCASE()
  9021.  
  9022.  
  9023.     /**
  9024.      *    PROPERCASE
  9025.      *
  9026.      *    Converts a string value to upper case.
  9027.      *
  9028.      *    @param    string        $mixedCaseString 
  9029.      *    @return    string 
  9030.      */
  9031.     public static function PROPERCASE($mixedCaseString{
  9032.         $mixedCaseString    self::flattenSingleValue($mixedCaseString);
  9033.  
  9034.         if (is_bool($mixedCaseString)) {
  9035.             $mixedCaseString ($mixedCaseString'TRUE' 'FALSE';
  9036.         }
  9037.  
  9038.         if (function_exists('mb_convert_case')) {
  9039.             return mb_convert_case($mixedCaseStringMB_CASE_TITLE'UTF-8');
  9040.         else {
  9041.             return ucwords($mixedCaseString);
  9042.         }
  9043.     }    //    function PROPERCASE()
  9044.  
  9045.  
  9046.     /**
  9047.      *    DOLLAR
  9048.      *
  9049.      *    This function converts a number to text using currency format, with the decimals rounded to the specified place.
  9050.      *    The format used is $#,##0.00_);($#,##0.00)..
  9051.      *
  9052.      *    @param    float    $value            The value to format
  9053.      *    @param    int        $decimals        The number of digits to display to the right of the decimal point.
  9054.      *                                     If decimals is negative, number is rounded to the left of the decimal point.
  9055.      *                                     If you omit decimals, it is assumed to be 2
  9056.      *    @return    string 
  9057.      */
  9058.     public static function DOLLAR($value 0$decimals 2{
  9059.         $value        self::flattenSingleValue($value);
  9060.         $decimals    is_null($decimalsself::flattenSingleValue($decimals);
  9061.  
  9062.         // Validate parameters
  9063.         if (!is_numeric($value|| !is_numeric($decimals)) {
  9064.             return self::$_errorCodes['num'];
  9065.         }
  9066.         $decimals floor($decimals);
  9067.  
  9068.         if ($decimals 0{
  9069.             return money_format('%.'.$decimals.'n',$value);
  9070.         else {
  9071.             $round pow(10,abs($decimals));
  9072.             if ($value 0$round 0-$round}
  9073.             $value self::MROUND($value,$round);
  9074.             //    The implementation of money_format used if the standard PHP function is not available can't handle decimal places of 0,
  9075.             //        so we display to 1 dp and chop off that character and the decimal separator using substr
  9076.             return substr(money_format('%.1n',$value),0,-2);
  9077.         }
  9078.     }    //    function DOLLAR()
  9079.  
  9080.  
  9081.     /**
  9082.      * DOLLARDE
  9083.      *
  9084.      * Converts a dollar price expressed as an integer part and a fraction part into a dollar price expressed as a decimal number.
  9085.      * Fractional dollar numbers are sometimes used for security prices.
  9086.      *
  9087.      * @param    float    $fractional_dollar    Fractional Dollar
  9088.      * @param    int        $fraction            Fraction
  9089.      * @return    float 
  9090.      */
  9091.     public static function DOLLARDE($fractional_dollar Null$fraction 0{
  9092.         $fractional_dollar    self::flattenSingleValue($fractional_dollar);
  9093.         $fraction            = (int)self::flattenSingleValue($fraction);
  9094.  
  9095.         // Validate parameters
  9096.         if (is_null($fractional_dollar|| $fraction 0{
  9097.             return self::$_errorCodes['num'];
  9098.         }
  9099.         if ($fraction == 0{
  9100.             return self::$_errorCodes['divisionbyzero'];
  9101.         }
  9102.  
  9103.         $dollars floor($fractional_dollar);
  9104.         $cents fmod($fractional_dollar,1);
  9105.         $cents /= $fraction;
  9106.         $cents *= pow(10,ceil(log10($fraction)));
  9107.         return $dollars $cents;
  9108.     }    //    function DOLLARDE()
  9109.  
  9110.  
  9111.     /**
  9112.      * DOLLARFR
  9113.      *
  9114.      * Converts a dollar price expressed as a decimal number into a dollar price expressed as a fraction.
  9115.      * Fractional dollar numbers are sometimes used for security prices.
  9116.      *
  9117.      * @param    float    $decimal_dollar        Decimal Dollar
  9118.      * @param    int        $fraction            Fraction
  9119.      * @return    float 
  9120.      */
  9121.     public static function DOLLARFR($decimal_dollar Null$fraction 0{
  9122.         $decimal_dollar    self::flattenSingleValue($decimal_dollar);
  9123.         $fraction        = (int)self::flattenSingleValue($fraction);
  9124.  
  9125.         // Validate parameters
  9126.         if (is_null($decimal_dollar|| $fraction 0{
  9127.             return self::$_errorCodes['num'];
  9128.         }
  9129.         if ($fraction == 0{
  9130.             return self::$_errorCodes['divisionbyzero'];
  9131.         }
  9132.  
  9133.         $dollars floor($decimal_dollar);
  9134.         $cents fmod($decimal_dollar,1);
  9135.         $cents *= $fraction;
  9136.         $cents *= pow(10,-ceil(log10($fraction)));
  9137.         return $dollars $cents;
  9138.     }    //    function DOLLARFR()
  9139.  
  9140.  
  9141.     /**
  9142.      * EFFECT
  9143.      *
  9144.      * Returns the effective interest rate given the nominal rate and the number of compounding payments per year.
  9145.      *
  9146.      * @param    float    $nominal_rate        Nominal interest rate
  9147.      * @param    int        $npery                Number of compounding payments per year
  9148.      * @return    float 
  9149.      */
  9150.     public static function EFFECT($nominal_rate 0$npery 0{
  9151.         $nominal_rate    self::flattenSingleValue($nominal_rate);
  9152.         $npery            = (int)self::flattenSingleValue($npery);
  9153.  
  9154.         // Validate parameters
  9155.         if ($nominal_rate <= || $npery 1{
  9156.             return self::$_errorCodes['num'];
  9157.         }
  9158.  
  9159.         return pow(($nominal_rate $npery)$npery1;
  9160.     }    //    function EFFECT()
  9161.  
  9162.  
  9163.     /**
  9164.      * NOMINAL
  9165.      *
  9166.      * Returns the nominal interest rate given the effective rate and the number of compounding payments per year.
  9167.      *
  9168.      * @param    float    $effect_rate    Effective interest rate
  9169.      * @param    int        $npery            Number of compounding payments per year
  9170.      * @return    float 
  9171.      */
  9172.     public static function NOMINAL($effect_rate 0$npery 0{
  9173.         $effect_rate    self::flattenSingleValue($effect_rate);
  9174.         $npery            = (int)self::flattenSingleValue($npery);
  9175.  
  9176.         // Validate parameters
  9177.         if ($effect_rate <= || $npery 1{
  9178.             return self::$_errorCodes['num'];
  9179.         }
  9180.  
  9181.         // Calculate
  9182.         return $npery (pow($effect_rate 1$npery1);
  9183.     }    //    function NOMINAL()
  9184.  
  9185.  
  9186.     /**
  9187.      * PV
  9188.      *
  9189.      * Returns the Present Value of a cash flow with constant payments and interest rate (annuities).
  9190.      *
  9191.      * @param    float    $rate    Interest rate per period
  9192.      * @param    int        $nper    Number of periods
  9193.      * @param    float    $pmt    Periodic payment (annuity)
  9194.      * @param    float    $fv        Future Value
  9195.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9196.      * @return    float 
  9197.      */
  9198.     public static function PV($rate 0$nper 0$pmt 0$fv 0$type 0{
  9199.         $rate    self::flattenSingleValue($rate);
  9200.         $nper    self::flattenSingleValue($nper);
  9201.         $pmt    self::flattenSingleValue($pmt);
  9202.         $fv        self::flattenSingleValue($fv);
  9203.         $type    self::flattenSingleValue($type);
  9204.  
  9205.         // Validate parameters
  9206.         if ($type != && $type != 1{
  9207.             return self::$_errorCodes['num'];
  9208.         }
  9209.  
  9210.         // Calculate
  9211.         if (!is_null($rate&& $rate != 0{
  9212.             return (-$pmt ($rate $type((pow($rate$nper1$rate$fvpow($rate$nper);
  9213.         else {
  9214.             return -$fv $pmt $nper;
  9215.         }
  9216.     }    //    function PV()
  9217.  
  9218.  
  9219.     /**
  9220.      * FV
  9221.      *
  9222.      * Returns the Future Value of a cash flow with constant payments and interest rate (annuities).
  9223.      *
  9224.      * @param    float    $rate    Interest rate per period
  9225.      * @param    int        $nper    Number of periods
  9226.      * @param    float    $pmt    Periodic payment (annuity)
  9227.      * @param    float    $pv        Present Value
  9228.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9229.      * @return    float 
  9230.      */
  9231.     public static function FV($rate 0$nper 0$pmt 0$pv 0$type 0{
  9232.         $rate    self::flattenSingleValue($rate);
  9233.         $nper    self::flattenSingleValue($nper);
  9234.         $pmt    self::flattenSingleValue($pmt);
  9235.         $pv        self::flattenSingleValue($pv);
  9236.         $type    self::flattenSingleValue($type);
  9237.  
  9238.         // Validate parameters
  9239.         if ($type != && $type != 1{
  9240.             return self::$_errorCodes['num'];
  9241.         }
  9242.  
  9243.         // Calculate
  9244.         if (!is_null($rate&& $rate != 0{
  9245.             return -$pv pow($rate$nper$pmt ($rate $type(pow($rate$nper1$rate;
  9246.         else {
  9247.             return -$pv $pmt $nper;
  9248.         }
  9249.     }    //    function FV()
  9250.  
  9251.  
  9252.     /**
  9253.      * FVSCHEDULE
  9254.      *
  9255.      */
  9256.     public static function FVSCHEDULE($principal$schedule{
  9257.         $principal    self::flattenSingleValue($principal);
  9258.         $schedule    self::flattenArray($schedule);
  9259.  
  9260.         foreach($schedule as $n{
  9261.             $principal *= $n;
  9262.         }
  9263.  
  9264.         return $principal;
  9265.     }    //    function FVSCHEDULE()
  9266.  
  9267.  
  9268.     /**
  9269.      * PMT
  9270.      *
  9271.      * Returns the constant payment (annuity) for a cash flow with a constant interest rate.
  9272.      *
  9273.      * @param    float    $rate    Interest rate per period
  9274.      * @param    int        $nper    Number of periods
  9275.      * @param    float    $pv        Present Value
  9276.      * @param    float    $fv        Future Value
  9277.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9278.      * @return    float 
  9279.      */
  9280.     public static function PMT($rate 0$nper 0$pv 0$fv 0$type 0{
  9281.         $rate    self::flattenSingleValue($rate);
  9282.         $nper    self::flattenSingleValue($nper);
  9283.         $pv        self::flattenSingleValue($pv);
  9284.         $fv        self::flattenSingleValue($fv);
  9285.         $type    self::flattenSingleValue($type);
  9286.  
  9287.         // Validate parameters
  9288.         if ($type != && $type != 1{
  9289.             return self::$_errorCodes['num'];
  9290.         }
  9291.  
  9292.         // Calculate
  9293.         if (!is_null($rate&& $rate != 0{
  9294.             return (-$fv $pv pow($rate$nper)) ($rate $type((pow($rate$nper1$rate);
  9295.         else {
  9296.             return (-$pv $fv$nper;
  9297.         }
  9298.     }    //    function PMT()
  9299.  
  9300.  
  9301.     /**
  9302.      * NPER
  9303.      *
  9304.      * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate.
  9305.      *
  9306.      *    @param    float    $rate    Interest rate per period
  9307.      *    @param    int        $pmt    Periodic payment (annuity)
  9308.      *    @param    float    $pv        Present Value
  9309.      *    @param    float    $fv        Future Value
  9310.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9311.      *    @return    float 
  9312.      */
  9313.     public static function NPER($rate 0$pmt 0$pv 0$fv 0$type 0{
  9314.         $rate    self::flattenSingleValue($rate);
  9315.         $pmt    self::flattenSingleValue($pmt);
  9316.         $pv        self::flattenSingleValue($pv);
  9317.         $fv        self::flattenSingleValue($fv);
  9318.         $type    self::flattenSingleValue($type);
  9319.  
  9320.         // Validate parameters
  9321.         if ($type != && $type != 1{
  9322.             return self::$_errorCodes['num'];
  9323.         }
  9324.  
  9325.         // Calculate
  9326.         if (!is_null($rate&& $rate != 0{
  9327.             if ($pmt == && $pv == 0{
  9328.                 return self::$_errorCodes['num'];
  9329.             }
  9330.             return log(($pmt ($rate $type$rate $fv($pv $pmt ($rate $type$rate)) log($rate);
  9331.         else {
  9332.             if ($pmt == 0{
  9333.                 return self::$_errorCodes['num'];
  9334.             }
  9335.             return (-$pv -$fv$pmt;
  9336.         }
  9337.     }    //    function NPER()
  9338.  
  9339.  
  9340.  
  9341.     private static function _interestAndPrincipal($rate=0$per=0$nper=0$pv=0$fv=0$type=0{
  9342.         $pmt self::PMT($rate$nper$pv$fv$type);
  9343.         $capital $pv;
  9344.         for ($i 1$i<= $per++$i{
  9345.             $interest ($type && $i == 1): -$capital $rate;
  9346.             $principal $pmt $interest;
  9347.             $capital += $principal;
  9348.         }
  9349.         return array($interest$principal);
  9350.     }    //    function _interestAndPrincipal()
  9351.  
  9352.  
  9353.     /**
  9354.      *    IPMT
  9355.      *
  9356.      *    Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
  9357.      *
  9358.      *    @param    float    $rate    Interest rate per period
  9359.      *    @param    int        $per    Period for which we want to find the interest
  9360.      *    @param    int        $nper    Number of periods
  9361.      *    @param    float    $pv        Present Value
  9362.      *    @param    float    $fv        Future Value
  9363.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9364.      *    @return    float 
  9365.      */
  9366.     public static function IPMT($rate$per$nper$pv$fv 0$type 0{
  9367.         $rate    self::flattenSingleValue($rate);
  9368.         $per    = (int) self::flattenSingleValue($per);
  9369.         $nper    = (int) self::flattenSingleValue($nper);
  9370.         $pv        self::flattenSingleValue($pv);
  9371.         $fv        self::flattenSingleValue($fv);
  9372.         $type    = (int) self::flattenSingleValue($type);
  9373.  
  9374.         // Validate parameters
  9375.         if ($type != && $type != 1{
  9376.             return self::$_errorCodes['num'];
  9377.         }
  9378.         if ($per <= || $per $nper{
  9379.             return self::$_errorCodes['value'];
  9380.         }
  9381.  
  9382.         // Calculate
  9383.         $interestAndPrincipal self::_interestAndPrincipal($rate$per$nper$pv$fv$type);
  9384.         return $interestAndPrincipal[0];
  9385.     }    //    function IPMT()
  9386.  
  9387.  
  9388.     /**
  9389.      *    CUMIPMT
  9390.      *
  9391.      *    Returns the cumulative interest paid on a loan between start_period and end_period.
  9392.      *
  9393.      *    @param    float    $rate    Interest rate per period
  9394.      *    @param    int        $nper    Number of periods
  9395.      *    @param    float    $pv        Present Value
  9396.      *    @param    int        start    The first period in the calculation.
  9397.      *                                 Payment periods are numbered beginning with 1.
  9398.      *    @param    int        end        The last period in the calculation.
  9399.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9400.      *    @return    float 
  9401.      */
  9402.     public static function CUMIPMT($rate$nper$pv$start$end$type 0{
  9403.         $rate    self::flattenSingleValue($rate);
  9404.         $nper    = (int) self::flattenSingleValue($nper);
  9405.         $pv        self::flattenSingleValue($pv);
  9406.         $start    = (int) self::flattenSingleValue($start);
  9407.         $end    = (int) self::flattenSingleValue($end);
  9408.         $type    = (int) self::flattenSingleValue($type);
  9409.  
  9410.         // Validate parameters
  9411.         if ($type != && $type != 1{
  9412.             return self::$_errorCodes['num'];
  9413.         }
  9414.         if ($start || $start $end{
  9415.             return self::$_errorCodes['value'];
  9416.         }
  9417.  
  9418.         // Calculate
  9419.         $interest 0;
  9420.         for ($per $start$per <= $end++$per{
  9421.             $interest += self::IPMT($rate$per$nper$pv0$type);
  9422.         }
  9423.  
  9424.         return $interest;
  9425.     }    //    function CUMIPMT()
  9426.  
  9427.  
  9428.     /**
  9429.      *    PPMT
  9430.      *
  9431.      *    Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
  9432.      *
  9433.      *    @param    float    $rate    Interest rate per period
  9434.      *    @param    int        $per    Period for which we want to find the interest
  9435.      *    @param    int        $nper    Number of periods
  9436.      *    @param    float    $pv        Present Value
  9437.      *    @param    float    $fv        Future Value
  9438.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9439.      *    @return    float 
  9440.      */
  9441.     public static function PPMT($rate$per$nper$pv$fv 0$type 0{
  9442.         $rate    self::flattenSingleValue($rate);
  9443.         $per    = (int) self::flattenSingleValue($per);
  9444.         $nper    = (int) self::flattenSingleValue($nper);
  9445.         $pv        self::flattenSingleValue($pv);
  9446.         $fv        self::flattenSingleValue($fv);
  9447.         $type    = (int) self::flattenSingleValue($type);
  9448.  
  9449.         // Validate parameters
  9450.         if ($type != && $type != 1{
  9451.             return self::$_errorCodes['num'];
  9452.         }
  9453.         if ($per <= || $per $nper{
  9454.             return self::$_errorCodes['value'];
  9455.         }
  9456.  
  9457.         // Calculate
  9458.         $interestAndPrincipal self::_interestAndPrincipal($rate$per$nper$pv$fv$type);
  9459.         return $interestAndPrincipal[1];
  9460.     }    //    function PPMT()
  9461.  
  9462.  
  9463.     /**
  9464.      *    CUMPRINC
  9465.      *
  9466.      *    Returns the cumulative principal paid on a loan between start_period and end_period.
  9467.      *
  9468.      *    @param    float    $rate    Interest rate per period
  9469.      *    @param    int        $nper    Number of periods
  9470.      *    @param    float    $pv        Present Value
  9471.      *    @param    int        start    The first period in the calculation.
  9472.      *                                 Payment periods are numbered beginning with 1.
  9473.      *    @param    int        end        The last period in the calculation.
  9474.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9475.      *    @return    float 
  9476.      */
  9477.     public static function CUMPRINC($rate$nper$pv$start$end$type 0{
  9478.         $rate    self::flattenSingleValue($rate);
  9479.         $nper    = (int) self::flattenSingleValue($nper);
  9480.         $pv        self::flattenSingleValue($pv);
  9481.         $start    = (int) self::flattenSingleValue($start);
  9482.         $end    = (int) self::flattenSingleValue($end);
  9483.         $type    = (int) self::flattenSingleValue($type);
  9484.  
  9485.         // Validate parameters
  9486.         if ($type != && $type != 1{
  9487.             return self::$_errorCodes['num'];
  9488.         }
  9489.         if ($start || $start $end{
  9490.             return self::$_errorCodes['value'];
  9491.         }
  9492.  
  9493.         // Calculate
  9494.         $principal 0;
  9495.         for ($per $start$per <= $end++$per{
  9496.             $principal += self::PPMT($rate$per$nper$pv0$type);
  9497.         }
  9498.  
  9499.         return $principal;
  9500.     }    //    function CUMPRINC()
  9501.  
  9502.  
  9503.     /**
  9504.      *      ISPMT
  9505.      *
  9506.      *      Returns the interest payment for an investment based on an interest rate and a constant payment schedule.
  9507.      *
  9508.      *      Excel Function:
  9509.      *          =ISPMT(interest_rate, period, number_payments, PV)
  9510.      *
  9511.      *      interest_rate is the interest rate for the investment
  9512.      *
  9513.      *      period is the period to calculate the interest rate.  It must be betweeen 1 and number_payments.
  9514.      *
  9515.      *      number_payments is the number of payments for the annuity
  9516.      *
  9517.      *      PV is the loan amount or present value of the payments
  9518.      */
  9519.     public static function ISPMT({
  9520.         // Return value
  9521.         $returnValue 0;
  9522.  
  9523.         // Get the parameters
  9524.         $aArgs self::flattenArray(func_get_args());
  9525.         $interestRate array_shift($aArgs);
  9526.         $period array_shift($aArgs);
  9527.         $numberPeriods array_shift($aArgs);
  9528.         $principleRemaining array_shift($aArgs);
  9529.  
  9530.         // Calculate
  9531.         $principlePayment ($principleRemaining 1.0($numberPeriods 1.0);
  9532.         for($i=0$i <= $period++$i{
  9533.             $returnValue $interestRate $principleRemaining * -1;
  9534.             $principleRemaining -= $principlePayment;
  9535.             // principle needs to be 0 after the last payment, don't let floating point screw it up
  9536.             if($i == $numberPeriods{
  9537.                 $returnValue 0;
  9538.             }
  9539.         }
  9540.         return($returnValue);
  9541.     }    //    function ISPMT()
  9542.  
  9543.  
  9544.     /**
  9545.      * NPV
  9546.      *
  9547.      * Returns the Net Present Value of a cash flow series given a discount rate.
  9548.      *
  9549.      * @param    float    Discount interest rate
  9550.      * @param    array    Cash flow series
  9551.      * @return    float 
  9552.      */
  9553.     public static function NPV({
  9554.         // Return value
  9555.         $returnValue 0;
  9556.  
  9557.         // Loop through arguments
  9558.         $aArgs self::flattenArray(func_get_args());
  9559.  
  9560.         // Calculate
  9561.         $rate array_shift($aArgs);
  9562.         for ($i 1$i <= count($aArgs)++$i{
  9563.             // Is it a numeric value?
  9564.             if (is_numeric($aArgs[$i 1])) {
  9565.                 $returnValue += $aArgs[$i 1pow($rate$i);
  9566.             }
  9567.         }
  9568.  
  9569.         // Return
  9570.         return $returnValue;
  9571.     }    //    function NPV()
  9572.  
  9573.  
  9574.     /**
  9575.      *    XNPV
  9576.      *
  9577.      *    Returns the net present value for a schedule of cash flows that is not necessarily periodic.
  9578.      *    To calculate the net present value for a series of cash flows that is periodic, use the NPV function.
  9579.      *
  9580.      *    @param    float    Discount interest rate
  9581.      *    @param    array    Cash flow series
  9582.      *    @return    float 
  9583.      */
  9584.     public static function XNPV($rate$values$dates{
  9585.         if ((!is_array($values)) || (!is_array($dates))) return self::$_errorCodes['value'];
  9586.         $values    self::flattenArray($values);
  9587.         $dates    self::flattenArray($dates);
  9588.         $valCount count($values);
  9589.         if ($valCount != count($dates)) return self::$_errorCodes['num'];
  9590.  
  9591.         $xnpv 0.0;
  9592.         for ($i 0$i $valCount++$i{
  9593.             $xnpv += $values[$ipow($rateself::DATEDIF($dates[0],$dates[$i],'d'365);
  9594.         }
  9595.         return (is_finite($xnpv$xnpv self::$_errorCodes['value']);
  9596.     }    //    function XNPV()
  9597.  
  9598.  
  9599.     public static function IRR($values$guess 0.1{
  9600.         if (!is_array($values)) return self::$_errorCodes['value'];
  9601.         $values self::flattenArray($values);
  9602.         $guess self::flattenSingleValue($guess);
  9603.  
  9604.         // create an initial range, with a root somewhere between 0 and guess
  9605.         $x1 0.0;
  9606.         $x2 $guess;
  9607.         $f1 self::NPV($x1$values);
  9608.         $f2 self::NPV($x2$values);
  9609.         for ($i 0$i FINANCIAL_MAX_ITERATIONS++$i{
  9610.             if (($f1 $f20.0break;
  9611.             if (abs($f1abs($f2)) {
  9612.                 $f1 self::NPV($x1 += 1.6 ($x1 $x2)$values);
  9613.             else {
  9614.                 $f2 self::NPV($x2 += 1.6 ($x2 $x1)$values);
  9615.             }
  9616.         }
  9617.         if (($f1 $f20.0return self::$_errorCodes['value'];
  9618.  
  9619.         $f self::NPV($x1$values);
  9620.         if ($f 0.0{
  9621.             $rtb $x1;
  9622.             $dx $x2 $x1;
  9623.         else {
  9624.             $rtb $x2;
  9625.             $dx $x1 $x2;
  9626.         }
  9627.  
  9628.         for ($i 0;  $i FINANCIAL_MAX_ITERATIONS++$i{
  9629.             $dx *= 0.5;
  9630.             $x_mid $rtb $dx;
  9631.             $f_mid self::NPV($x_mid$values);
  9632.             if ($f_mid <= 0.0$rtb $x_mid;
  9633.             if ((abs($f_midFINANCIAL_PRECISION|| (abs($dxFINANCIAL_PRECISION)) return $x_mid;
  9634.         }
  9635.         return self::$_errorCodes['value'];
  9636.     }    //    function IRR()
  9637.  
  9638.  
  9639.     public static function MIRR($values$finance_rate$reinvestment_rate{
  9640.         if (!is_array($values)) return self::$_errorCodes['value'];
  9641.         $values                self::flattenArray($values);
  9642.         $finance_rate        self::flattenSingleValue($finance_rate);
  9643.         $reinvestment_rate    self::flattenSingleValue($reinvestment_rate);
  9644.         $n count($values);
  9645.  
  9646.         $rr 1.0 $reinvestment_rate;
  9647.         $fr 1.0 $finance_rate;
  9648.  
  9649.         $npv_pos $npv_neg 0.0;
  9650.         foreach($values as $i => $v{
  9651.             if ($v >= 0{
  9652.                 $npv_pos += $v pow($rr$i);
  9653.             else {
  9654.                 $npv_neg += $v pow($fr$i);
  9655.             }
  9656.         }
  9657.  
  9658.         if (($npv_neg == 0|| ($npv_pos == 0|| ($reinvestment_rate <= -1)) {
  9659.             return self::$_errorCodes['value'];
  9660.         }
  9661.  
  9662.         $mirr pow((-$npv_pos pow($rr$n))
  9663.                 / ($npv_neg ($rr))(1.0 ($n 1))) 1.0;
  9664.  
  9665.         return (is_finite($mirr$mirr self::$_errorCodes['value']);
  9666.     }    //    function MIRR()
  9667.  
  9668.  
  9669.     public static function XIRR($values$dates$guess 0.1{
  9670.         if ((!is_array($values)) && (!is_array($dates))) return self::$_errorCodes['value'];
  9671.         $values    self::flattenArray($values);
  9672.         $dates    self::flattenArray($dates);
  9673.         $guess self::flattenSingleValue($guess);
  9674.         if (count($values!= count($dates)) return self::$_errorCodes['num'];
  9675.  
  9676.         // create an initial range, with a root somewhere between 0 and guess
  9677.         $x1 0.0;
  9678.         $x2 $guess;
  9679.         $f1 self::XNPV($x1$values$dates);
  9680.         $f2 self::XNPV($x2$values$dates);
  9681.         for ($i 0$i FINANCIAL_MAX_ITERATIONS++$i{
  9682.             if (($f1 $f20.0break;
  9683.             if (abs($f1abs($f2)) {
  9684.                 $f1 self::XNPV($x1 += 1.6 ($x1 $x2)$values$dates);
  9685.             else {
  9686.                 $f2 self::XNPV($x2 += 1.6 ($x2 $x1)$values$dates);
  9687.             }
  9688.         }
  9689.         if (($f1 $f20.0return self::$_errorCodes['value'];
  9690.  
  9691.         $f self::XNPV($x1$values$dates);
  9692.         if ($f 0.0{
  9693.             $rtb $x1;
  9694.             $dx $x2 $x1;
  9695.         else {
  9696.             $rtb $x2;
  9697.             $dx $x1 $x2;
  9698.         }
  9699.  
  9700.         for ($i 0;  $i FINANCIAL_MAX_ITERATIONS++$i{
  9701.             $dx *= 0.5;
  9702.             $x_mid $rtb $dx;
  9703.             $f_mid self::XNPV($x_mid$values$dates);
  9704.             if ($f_mid <= 0.0$rtb $x_mid;
  9705.             if ((abs($f_midFINANCIAL_PRECISION|| (abs($dxFINANCIAL_PRECISION)) return $x_mid;
  9706.         }
  9707.         return self::$_errorCodes['value'];
  9708.     }
  9709.  
  9710.  
  9711.     /**
  9712.      * RATE
  9713.      *
  9714.      **/
  9715.  
  9716.     public static function RATE($nper$pmt$pv$fv 0.0$type 0$guess 0.1{
  9717.         $nper    = (int) self::flattenSingleValue($nper);
  9718.         $pmt    self::flattenSingleValue($pmt);
  9719.         $pv        self::flattenSingleValue($pv);
  9720.         $fv        (is_null($fv))    0.0    :    self::flattenSingleValue($fv);
  9721.         $type    (is_null($type))    0        :    (int) self::flattenSingleValue($type);
  9722.         $guess    (is_null($guess))    0.1    :    self::flattenSingleValue($guess);
  9723.  
  9724.         $rate $guess;
  9725.         if (abs($rateFINANCIAL_PRECISION{
  9726.             $y $pv ($nper $rate$pmt ($rate $type$nper $fv;
  9727.         else {
  9728.             $f exp($nper log($rate));
  9729.             $y $pv $f $pmt ($rate $type($f 1$fv;
  9730.         }
  9731.         $y0 $pv $pmt $nper $fv;
  9732.         $y1 $pv $f $pmt ($rate $type($f 1$fv;
  9733.  
  9734.         // find root by secant method
  9735.         $i  $x0 0.0;
  9736.         $x1 $rate;
  9737.         while ((abs($y0 $y1FINANCIAL_PRECISION&& ($i FINANCIAL_MAX_ITERATIONS)) {
  9738.             $rate ($y1 $x0 $y0 $x1($y1 $y0);
  9739.             $x0 $x1;
  9740.             $x1 $rate;
  9741.  
  9742.             if (abs($rateFINANCIAL_PRECISION{
  9743.                 $y $pv ($nper $rate$pmt ($rate $type$nper $fv;
  9744.             else {
  9745.                 $f exp($nper log($rate));
  9746.                 $y $pv $f $pmt ($rate $type($f 1$fv;
  9747.             }
  9748.  
  9749.             $y0 $y1;
  9750.             $y1 $y;
  9751.             ++$i;
  9752.         }
  9753.         return $rate;
  9754.     }    //    function RATE()
  9755.  
  9756.  
  9757.     /**
  9758.      *    DB
  9759.      *
  9760.      *    Returns the depreciation of an asset for a specified period using the fixed-declining balance method.
  9761.      *    This form of depreciation is used if you want to get a higher depreciation value at the beginning of the depreciation
  9762.      *        (as opposed to linear depreciation). The depreciation value is reduced with every depreciation period by the
  9763.      *        depreciation already deducted from the initial cost.
  9764.      *
  9765.      *    @param    float    cost        Initial cost of the asset.
  9766.      *    @param    float    salvage        Value at the end of the depreciation. (Sometimes called the salvage value of the asset)
  9767.      *    @param    int        life        Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset)
  9768.      *    @param    int        period        The period for which you want to calculate the depreciation. Period must use the same units as life.
  9769.      *    @param    float    month        Number of months in the first year. If month is omitted, it defaults to 12.
  9770.      *    @return    float 
  9771.      */
  9772.     public static function DB($cost$salvage$life$period$month=12{
  9773.         $cost        = (float) self::flattenSingleValue($cost);
  9774.         $salvage    = (float) self::flattenSingleValue($salvage);
  9775.         $life        = (int) self::flattenSingleValue($life);
  9776.         $period        = (int) self::flattenSingleValue($period);
  9777.         $month        = (int) self::flattenSingleValue($month);
  9778.  
  9779.         //    Validate
  9780.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($month))) {
  9781.             if ($cost == 0{
  9782.                 return 0.0;
  9783.             elseif (($cost 0|| (($salvage $cost0|| ($life <= 0|| ($period 1|| ($month 1)) {
  9784.                 return self::$_errorCodes['num'];
  9785.             }
  9786.             //    Set Fixed Depreciation Rate
  9787.             $fixedDepreciationRate pow(($salvage $cost)($life));
  9788.             $fixedDepreciationRate round($fixedDepreciationRate3);
  9789.  
  9790.             //    Loop through each period calculating the depreciation
  9791.             $previousDepreciation 0;
  9792.             for ($per 1$per <= $period++$per{
  9793.                 if ($per == 1{
  9794.                     $depreciation $cost $fixedDepreciationRate $month 12;
  9795.                 elseif ($per == ($life 1)) {
  9796.                     $depreciation ($cost $previousDepreciation$fixedDepreciationRate (12 $month12;
  9797.                 else {
  9798.                     $depreciation ($cost $previousDepreciation$fixedDepreciationRate;
  9799.                 }
  9800.                 $previousDepreciation += $depreciation;
  9801.             }
  9802.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  9803.                 $depreciation round($depreciation,2);
  9804.             }
  9805.             return $depreciation;
  9806.         }
  9807.         return self::$_errorCodes['value'];
  9808.     }    //    function DB()
  9809.  
  9810.  
  9811.     /**
  9812.      *    DDB
  9813.      *
  9814.      *    Returns the depreciation of an asset for a specified period using the double-declining balance method or some other method you specify.
  9815.      *
  9816.      *    @param    float    cost        Initial cost of the asset.
  9817.      *    @param    float    salvage        Value at the end of the depreciation. (Sometimes called the salvage value of the asset)
  9818.      *    @param    int        life        Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset)
  9819.      *    @param    int        period        The period for which you want to calculate the depreciation. Period must use the same units as life.
  9820.      *    @param    float    factor        The rate at which the balance declines.
  9821.      *                                 If factor is omitted, it is assumed to be 2 (the double-declining balance method).
  9822.      *    @return    float 
  9823.      */
  9824.     public static function DDB($cost$salvage$life$period$factor=2.0{
  9825.         $cost        = (float) self::flattenSingleValue($cost);
  9826.         $salvage    = (float) self::flattenSingleValue($salvage);
  9827.         $life        = (int) self::flattenSingleValue($life);
  9828.         $period        = (int) self::flattenSingleValue($period);
  9829.         $factor        = (float) self::flattenSingleValue($factor);
  9830.  
  9831.         //    Validate
  9832.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($factor))) {
  9833.             if (($cost <= 0|| (($salvage $cost0|| ($life <= 0|| ($period 1|| ($factor <= 0.0|| ($period $life)) {
  9834.                 return self::$_errorCodes['num'];
  9835.             }
  9836.             //    Set Fixed Depreciation Rate
  9837.             $fixedDepreciationRate pow(($salvage $cost)($life));
  9838.             $fixedDepreciationRate round($fixedDepreciationRate3);
  9839.  
  9840.             //    Loop through each period calculating the depreciation
  9841.             $previousDepreciation 0;
  9842.             for ($per 1$per <= $period++$per{
  9843.                 $depreciation min( ($cost $previousDepreciation($factor $life)($cost $salvage $previousDepreciation) );
  9844.                 $previousDepreciation += $depreciation;
  9845.             }
  9846.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  9847.                 $depreciation round($depreciation,2);
  9848.             }
  9849.             return $depreciation;
  9850.         }
  9851.         return self::$_errorCodes['value'];
  9852.     }    //    function DDB()
  9853.  
  9854.  
  9855.     private static function _daysPerYear($year,$basis{
  9856.         switch ($basis{
  9857.             case :
  9858.             case :
  9859.             case :
  9860.                 $daysPerYear 360;
  9861.                 break;
  9862.             case :
  9863.                 $daysPerYear 365;
  9864.                 break;
  9865.             case :
  9866.                 if (self::_isLeapYear($year)) {
  9867.                     $daysPerYear 366;
  9868.                 else {
  9869.                     $daysPerYear 365;
  9870.                 }
  9871.                 break;
  9872.             default    :
  9873.                 return self::$_errorCodes['num'];
  9874.         }
  9875.         return $daysPerYear;
  9876.     }    //    function _daysPerYear()
  9877.  
  9878.  
  9879.     /**
  9880.      *    ACCRINT
  9881.      *
  9882.      *    Returns the discount rate for a security.
  9883.      *
  9884.      *    @param    mixed    issue        The security's issue date.
  9885.      *    @param    mixed    firstinter    The security's first interest date.
  9886.      *    @param    mixed    settlement    The security's settlement date.
  9887.      *    @param    float    rate        The security's annual coupon rate.
  9888.      *    @param    float    par            The security's par value.
  9889.      *    @param    int        basis        The type of day count to use.
  9890.      *                                         0 or omitted    US (NASD) 30/360
  9891.      *                                         1                Actual/actual
  9892.      *                                         2                Actual/360
  9893.      *                                         3                Actual/365
  9894.      *                                         4                European 30/360
  9895.      *    @return    float 
  9896.      */
  9897.     public static function ACCRINT($issue$firstinter$settlement$rate$par=1000$frequency=1$basis=0{
  9898.         $issue        self::flattenSingleValue($issue);
  9899.         $firstinter    self::flattenSingleValue($firstinter);
  9900.         $settlement    self::flattenSingleValue($settlement);
  9901.         $rate        = (float) self::flattenSingleValue($rate);
  9902.         $par        (is_null($par))        1000 :    (float) self::flattenSingleValue($par);
  9903.         $frequency    (is_null($frequency))    1    :         (int) self::flattenSingleValue($frequency);
  9904.         $basis        (is_null($basis))        0    :        (int) self::flattenSingleValue($basis);
  9905.  
  9906.         //    Validate
  9907.         if ((is_numeric($rate)) && (is_numeric($par))) {
  9908.             if (($rate <= 0|| ($par <= 0)) {
  9909.                 return self::$_errorCodes['num'];
  9910.             }
  9911.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  9912.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  9913.                 return $daysBetweenIssueAndSettlement;
  9914.             }
  9915.  
  9916.             return $par $rate $daysBetweenIssueAndSettlement;
  9917.         }
  9918.         return self::$_errorCodes['value'];
  9919.     }    //    function ACCRINT()
  9920.  
  9921.  
  9922.     /**
  9923.      *    ACCRINTM
  9924.      *
  9925.      *    Returns the discount rate for a security.
  9926.      *
  9927.      *    @param    mixed    issue        The security's issue date.
  9928.      *    @param    mixed    settlement    The security's settlement date.
  9929.      *    @param    float    rate        The security's annual coupon rate.
  9930.      *    @param    float    par            The security's par value.
  9931.      *    @param    int        basis        The type of day count to use.
  9932.      *                                         0 or omitted    US (NASD) 30/360
  9933.      *                                         1                Actual/actual
  9934.      *                                         2                Actual/360
  9935.      *                                         3                Actual/365
  9936.      *                                         4                European 30/360
  9937.      *    @return    float 
  9938.      */
  9939.     public static function ACCRINTM($issue$settlement$rate$par=1000$basis=0{
  9940.         $issue        self::flattenSingleValue($issue);
  9941.         $settlement    self::flattenSingleValue($settlement);
  9942.         $rate        = (float) self::flattenSingleValue($rate);
  9943.         $par        (is_null($par))    1000 :    (float) self::flattenSingleValue($par);
  9944.         $basis        (is_null($basis))    :        (int) self::flattenSingleValue($basis);
  9945.  
  9946.         //    Validate
  9947.         if ((is_numeric($rate)) && (is_numeric($par))) {
  9948.             if (($rate <= 0|| ($par <= 0)) {
  9949.                 return self::$_errorCodes['num'];
  9950.             }
  9951.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  9952.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  9953.                 return $daysBetweenIssueAndSettlement;
  9954.             }
  9955.             return $par $rate $daysBetweenIssueAndSettlement;
  9956.         }
  9957.         return self::$_errorCodes['value'];
  9958.     }    //    function ACCRINTM()
  9959.  
  9960.  
  9961.     public static function AMORDEGRC($cost$purchased$firstPeriod$salvage$period$rate$basis=0{
  9962.         $cost            self::flattenSingleValue($cost);
  9963.         $purchased        self::flattenSingleValue($purchased);
  9964.         $firstPeriod    self::flattenSingleValue($firstPeriod);
  9965.         $salvage        self::flattenSingleValue($salvage);
  9966.         $period            floor(self::flattenSingleValue($period));
  9967.         $rate            self::flattenSingleValue($rate);
  9968.         $basis            (is_null($basis))    :    (int) self::flattenSingleValue($basis);
  9969.  
  9970.         $fUsePer 1.0 $rate;
  9971.  
  9972.         if ($fUsePer 3.0{
  9973.             $amortiseCoeff 1.0;
  9974.         elseif ($fUsePer 5.0{
  9975.             $amortiseCoeff 1.5;
  9976.         elseif ($fUsePer <= 6.0{
  9977.             $amortiseCoeff 2.0;
  9978.         else {
  9979.             $amortiseCoeff 2.5;
  9980.         }
  9981.  
  9982.         $rate *= $amortiseCoeff;
  9983. //        $fNRate = floor((self::YEARFRAC($purchased, $firstPeriod, $basis) * $rate * $cost) + 0.5);
  9984.         $fNRate round(self::YEARFRAC($purchased$firstPeriod$basis$rate $cost,0);
  9985.         $cost -= $fNRate;
  9986.         $fRest $cost $salvage;
  9987.  
  9988.         for ($n 0$n $period++$n{
  9989. //            $fNRate = floor(($rate * $cost) + 0.5);
  9990.             $fNRate round($rate $cost,0);
  9991.             $fRest -= $fNRate;
  9992.  
  9993.             if ($fRest 0.0{
  9994.                 switch ($period $n{
  9995.                     case 0    :
  9996.                     case 1    :
  9997. //                              return floor(($cost * 0.5) + 0.5);
  9998.                               return round($cost 0.5,0);
  9999.                               break;
  10000.                     default    return 0.0;
  10001.                               break;
  10002.                 }
  10003.             }
  10004.             $cost -= $fNRate;
  10005.         }
  10006.         return $fNRate;
  10007.     }    //    function AMORDEGRC()
  10008.  
  10009.  
  10010.     public static function AMORLINC($cost$purchased$firstPeriod$salvage$period$rate$basis=0{
  10011.         $cost            self::flattenSingleValue($cost);
  10012.         $purchased        self::flattenSingleValue($purchased);
  10013.         $firstPeriod    self::flattenSingleValue($firstPeriod);
  10014.         $salvage        self::flattenSingleValue($salvage);
  10015.         $period            self::flattenSingleValue($period);
  10016.         $rate            self::flattenSingleValue($rate);
  10017.         $basis            (is_null($basis))    :    (int) self::flattenSingleValue($basis);
  10018.  
  10019.         $fOneRate $cost $rate;
  10020.         $fCostDelta $cost $salvage;
  10021.         //    Note, quirky variation for leap years on the YEARFRAC for this function
  10022.         $purchasedYear self::YEAR($purchased);
  10023.         $yearFrac self::YEARFRAC($purchased$firstPeriod$basis);
  10024.         if (($basis == 1&& ($yearFrac 1&& (self::_isLeapYear($purchasedYear))) {
  10025.             $yearFrac *= 365 366;
  10026.         }
  10027.         $f0Rate $yearFrac $rate $cost;
  10028.         $nNumOfFullPeriods intval(($cost $salvage $f0Rate$fOneRate);
  10029.  
  10030.         if ($period == 0{
  10031.             return $f0Rate;
  10032.         elseif ($period <= $nNumOfFullPeriods{
  10033.             return $fOneRate;
  10034.         elseif ($period == ($nNumOfFullPeriods 1)) {
  10035.             return ($fCostDelta $fOneRate $nNumOfFullPeriods $f0Rate);
  10036.         else {
  10037.             return 0.0;
  10038.         }
  10039.     }    //    function AMORLINC()
  10040.  
  10041.  
  10042.     private static function _lastDayOfMonth($testDate{
  10043.         $date clone $testDate;
  10044.         $date->modify('+1 day');
  10045.         return ($date->format('d'== 1);
  10046.     }    //    function _lastDayOfMonth()
  10047.  
  10048.     private static function _firstDayOfMonth($testDate{
  10049.         $date clone $testDate;
  10050.         return ($date->format('d'== 1);
  10051.     }    //    function _lastDayOfMonth()
  10052.  
  10053.     private static function _coupFirstPeriodDate($settlement$maturity$frequency$next{
  10054.         $months 12 $frequency;
  10055.  
  10056.         $result PHPExcel_Shared_Date::ExcelToPHPObject($maturity);
  10057.         $eom self::_lastDayOfMonth($result);
  10058.  
  10059.         while ($settlement PHPExcel_Shared_Date::PHPToExcel($result)) {
  10060.             $result->modify('-'.$months.' months');
  10061.         }
  10062.         if ($next{
  10063.             $result->modify('+'.$months.' months');
  10064.         }
  10065.  
  10066.         if ($eom{
  10067.             $result->modify('-1 day');
  10068.         }
  10069.  
  10070.         return PHPExcel_Shared_Date::PHPToExcel($result);
  10071.     }    //    function _coupFirstPeriodDate()
  10072.  
  10073.  
  10074.     private static function _validFrequency($frequency{
  10075.         if (($frequency == 1|| ($frequency == 2|| ($frequency == 4)) {
  10076.             return true;
  10077.         }
  10078.         if ((self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC&&
  10079.             (($frequency == 6|| ($frequency == 12))) {
  10080.             return true;
  10081.         }
  10082.         return false;
  10083.     }    //    function _validFrequency()
  10084.  
  10085.     public static function COUPDAYS($settlement$maturity$frequency$basis=0{
  10086.         $settlement    self::flattenSingleValue($settlement);
  10087.         $maturity    self::flattenSingleValue($maturity);
  10088.         $frequency    = (int) self::flattenSingleValue($frequency);
  10089.         $basis        (is_null($basis))    :    (int) self::flattenSingleValue($basis);
  10090.  
  10091.         if (is_string($settlement self::_getDateValue($settlement))) {
  10092.             return self::$_errorCodes['value'];
  10093.         }
  10094.         if (is_string($maturity self::_getDateValue($maturity))) {
  10095.             return self::$_errorCodes['value'];
  10096.         }
  10097.  
  10098.         if (($settlement $maturity||
  10099.             (!self::_validFrequency($frequency)) ||
  10100.             (($basis 0|| ($basis 4))) {
  10101.             return self::$_errorCodes['num'];
  10102.         }
  10103.  
  10104.         switch ($basis{
  10105.             case 3// Actual/365
  10106.                     return 365 $frequency;
  10107.             case 1// Actual/actual
  10108.                     if ($frequency == 1{
  10109.                         $daysPerYear self::_daysPerYear(self::YEAR($maturity),$basis);
  10110.                         return ($daysPerYear $frequency);
  10111.                     else {
  10112.                         $prev self::_coupFirstPeriodDate($settlement$maturity$frequencyFalse);
  10113.                         $next self::_coupFirstPeriodDate($settlement$maturity$frequencyTrue);
  10114.                         return ($next $prev);
  10115.                     }
  10116.             default// US (NASD) 30/360, Actual/360 or European 30/360
  10117.                     return 360 $frequency;
  10118.         }
  10119.         return self::$_errorCodes['value'];
  10120.     }    //    function COUPDAYS()
  10121.  
  10122.  
  10123.     public static function COUPDAYBS($settlement$maturity$frequency$basis=0{
  10124.         $settlement    self::flattenSingleValue($settlement);
  10125.         $maturity    self::flattenSingleValue($maturity);
  10126.         $frequency    = (int) self::flattenSingleValue($frequency);
  10127.         $basis        (is_null($basis))    :    (int) self::flattenSingleValue($basis);
  10128.  
  10129.         if (is_string($settlement self::_getDateValue($settlement))) {
  10130.             return self::$_errorCodes['value'];
  10131.         }
  10132.         if (is_string($maturity self::_getDateValue($maturity))) {
  10133.             return self::$_errorCodes['value'];
  10134.         }
  10135.  
  10136.         if (($settlement $maturity||
  10137.             (!self::_validFrequency($frequency)) ||
  10138.             (($basis 0|| ($basis 4))) {
  10139.             return self::$_errorCodes['num'];
  10140.         }
  10141.  
  10142.         $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  10143.         $prev self::_coupFirstPeriodDate($settlement$maturity$frequencyFalse);
  10144.  
  10145.         return self::YEARFRAC($prev$settlement$basis$daysPerYear;
  10146.     }    //    function COUPDAYBS()
  10147.  
  10148.  
  10149.     public static function COUPDAYSNC($settlement$maturity$frequency$basis=0{
  10150.         $settlement    self::flattenSingleValue($settlement);
  10151.         $maturity    self::flattenSingleValue($maturity);
  10152.         $frequency    = (int) self::flattenSingleValue($frequency);
  10153.         $basis        (is_null($basis))    :    (int) self::flattenSingleValue($basis);
  10154.  
  10155.         if (is_string($settlement self::_getDateValue($settlement))) {
  10156.             return self::$_errorCodes['value'];
  10157.         }
  10158.         if (is_string($maturity self::_getDateValue($maturity))) {
  10159.             return self::$_errorCodes['value'];
  10160.         }
  10161.  
  10162.         if (($settlement $maturity||
  10163.             (!self::_validFrequency($frequency)) ||
  10164.             (($basis 0|| ($basis 4))) {
  10165.             return self::$_errorCodes['num'];
  10166.         }
  10167.  
  10168.         $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  10169.         $next self::_coupFirstPeriodDate($settlement$maturity$frequencyTrue);
  10170.  
  10171.         return self::YEARFRAC($settlement$next$basis$daysPerYear;
  10172.     }    //    function COUPDAYSNC()
  10173.  
  10174.  
  10175.     public static function COUPNCD($settlement$maturity$frequency$basis=0{
  10176.         $settlement    self::flattenSingleValue($settlement);
  10177.         $maturity    self::flattenSingleValue($maturity);
  10178.         $frequency    = (int) self::flattenSingleValue($frequency);
  10179.         $basis        (is_null($basis))    :    (int) self::flattenSingleValue($basis);
  10180.  
  10181.         if (is_string($settlement self::_getDateValue($settlement))) {
  10182.             return self::$_errorCodes['value'];
  10183.         }
  10184.         if (is_string($maturity self::_getDateValue($maturity))) {
  10185.             return self::$_errorCodes['value'];
  10186.         }
  10187.  
  10188.         if (($settlement $maturity||
  10189.             (!self::_validFrequency($frequency)) ||
  10190.             (($basis 0|| ($basis 4))) {
  10191.             return self::$_errorCodes['num'];
  10192.         }
  10193.  
  10194.         return self::_coupFirstPeriodDate($settlement$maturity$frequencyTrue);
  10195.     }    //    function COUPNCD()
  10196.  
  10197.  
  10198.     public static function COUPPCD($settlement$maturity$frequency$basis=0{
  10199.         $settlement    self::flattenSingleValue($settlement);
  10200.         $maturity    self::flattenSingleValue($maturity);
  10201.         $frequency    = (int) self::flattenSingleValue($frequency);
  10202.         $basis        (is_null($basis))    :    (int) self::flattenSingleValue($basis);
  10203.  
  10204.         if (is_string($settlement self::_getDateValue($settlement))) {
  10205.             return self::$_errorCodes['value'];
  10206.         }
  10207.         if (is_string($maturity self::_getDateValue($maturity))) {
  10208.             return self::$_errorCodes['value'];
  10209.         }
  10210.  
  10211.         if (($settlement $maturity||
  10212.             (!self::_validFrequency($frequency)) ||
  10213.             (($basis 0|| ($basis 4))) {
  10214.             return self::$_errorCodes['num'];
  10215.         }
  10216.  
  10217.         return self::_coupFirstPeriodDate($settlement$maturity$frequencyFalse);
  10218.     }    //    function COUPPCD()
  10219.  
  10220.  
  10221.     public static function COUPNUM($settlement$maturity$frequency$basis=0{
  10222.         $settlement    self::flattenSingleValue($settlement);
  10223.         $maturity    self::flattenSingleValue($maturity);
  10224.         $frequency    = (int) self::flattenSingleValue($frequency);
  10225.         $basis        (is_null($basis))    :    (int) self::flattenSingleValue($basis);
  10226.  
  10227.         if (is_string($settlement self::_getDateValue($settlement))) {
  10228.             return self::$_errorCodes['value'];
  10229.         }
  10230.         if (is_string($maturity self::_getDateValue($maturity))) {
  10231.             return self::$_errorCodes['value'];
  10232.         }
  10233.  
  10234.         if (($settlement $maturity||
  10235.             (!self::_validFrequency($frequency)) ||
  10236.             (($basis 0|| ($basis 4))) {
  10237.             return self::$_errorCodes['num'];
  10238.         }
  10239.  
  10240.         $settlement self::_coupFirstPeriodDate($settlement$maturity$frequencyTrue);
  10241.         $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis365;
  10242.  
  10243.         switch ($frequency{
  10244.             case 1// annual payments
  10245.                     return ceil($daysBetweenSettlementAndMaturity 360);
  10246.             case 2// half-yearly
  10247.                     return ceil($daysBetweenSettlementAndMaturity 180);
  10248.             case 4// quarterly
  10249.                     return ceil($daysBetweenSettlementAndMaturity 90);
  10250.             case 6// bimonthly
  10251.                     return ceil($daysBetweenSettlementAndMaturity 60);
  10252.             case 12// monthly
  10253.                     return ceil($daysBetweenSettlementAndMaturity 30);
  10254.         }
  10255.         return self::$_errorCodes['value'];
  10256.     }    //    function COUPNUM()
  10257.  
  10258.  
  10259.     public static function PRICE($settlement$maturity$rate$yield$redemption$frequency$basis=0{
  10260.         $settlement    self::flattenSingleValue($settlement);
  10261.         $maturity    self::flattenSingleValue($maturity);
  10262.         $rate        = (float) self::flattenSingleValue($rate);
  10263.         $yield        = (float) self::flattenSingleValue($yield);
  10264.         $redemption    = (float) self::flattenSingleValue($redemption);
  10265.         $frequency    = (int) self::flattenSingleValue($frequency);
  10266.         $basis        (is_null($basis))    :    (int) self::flattenSingleValue($basis);
  10267.  
  10268.         if (is_string($settlement self::_getDateValue($settlement))) {
  10269.             return self::$_errorCodes['value'];
  10270.         }
  10271.         if (is_string($maturity self::_getDateValue($maturity))) {
  10272.             return self::$_errorCodes['value'];
  10273.         }
  10274.  
  10275.         if (($settlement $maturity||
  10276.             (!self::_validFrequency($frequency)) ||
  10277.             (($basis 0|| ($basis 4))) {
  10278.             return self::$_errorCodes['num'];
  10279.         }
  10280.  
  10281.         $dsc self::COUPDAYSNC($settlement$maturity$frequency$basis);
  10282.         $e self::COUPDAYS($settlement$maturity$frequency$basis);
  10283.         $n self::COUPNUM($settlement$maturity$frequency$basis);
  10284.         $a self::COUPDAYBS($settlement$maturity$frequency$basis);
  10285.  
  10286.         $baseYF    1.0 ($yield $frequency);
  10287.         $rfp    100 ($rate $frequency);
  10288.         $de    $dsc $e;
  10289.  
  10290.         $result $redemption pow($baseYF(--$n $de));
  10291.         for($k 0$k <= $n++$k{
  10292.             $result += $rfp (pow($baseYF($k $de)));
  10293.         }
  10294.         $result -= $rfp ($a $e);
  10295.  
  10296.         return $result;
  10297.     }    //    function PRICE()
  10298.  
  10299.  
  10300.     /**
  10301.      *    DISC
  10302.      *
  10303.      *    Returns the discount rate for a security.
  10304.      *
  10305.      *    @param    mixed    settlement    The security's settlement date.
  10306.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  10307.      *    @param    mixed    maturity    The security's maturity date.
  10308.      *                                 The maturity date is the date when the security expires.
  10309.      *    @param    int        price        The security's price per $100 face value.
  10310.      *    @param    int        redemption    the security's redemption value per $100 face value.
  10311.      *    @param    int        basis        The type of day count to use.
  10312.      *                                         0 or omitted    US (NASD) 30/360
  10313.      *                                         1                Actual/actual
  10314.      *                                         2                Actual/360
  10315.      *                                         3                Actual/365
  10316.      *                                         4                European 30/360
  10317.      *    @return    float 
  10318.      */
  10319.     public static function DISC($settlement$maturity$price$redemption$basis=0{
  10320.         $settlement    self::flattenSingleValue($settlement);
  10321.         $maturity    self::flattenSingleValue($maturity);
  10322.         $price        = (float) self::flattenSingleValue($price);
  10323.         $redemption    = (float) self::flattenSingleValue($redemption);
  10324.         $basis        = (int) self::flattenSingleValue($basis);
  10325.  
  10326.         //    Validate
  10327.         if ((is_numeric($price)) && (is_numeric($redemption)) && (is_numeric($basis))) {
  10328.             if (($price <= 0|| ($redemption <= 0)) {
  10329.                 return self::$_errorCodes['num'];
  10330.             }
  10331.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  10332.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10333.                 return $daysBetweenSettlementAndMaturity;
  10334.             }
  10335.  
  10336.             return (($price $redemption$daysBetweenSettlementAndMaturity);
  10337.         }
  10338.         return self::$_errorCodes['value'];
  10339.     }    //    function DISC()
  10340.  
  10341.  
  10342.     /**
  10343.      *    PRICEDISC
  10344.      *
  10345.      *    Returns the price per $100 face value of a discounted security.
  10346.      *
  10347.      *    @param    mixed    settlement    The security's settlement date.
  10348.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  10349.      *    @param    mixed    maturity    The security's maturity date.
  10350.      *                                 The maturity date is the date when the security expires.
  10351.      *    @param    int        discount    The security's discount rate.
  10352.      *    @param    int        redemption    The security's redemption value per $100 face value.
  10353.      *    @param    int        basis        The type of day count to use.
  10354.      *                                         0 or omitted    US (NASD) 30/360
  10355.      *                                         1                Actual/actual
  10356.      *                                         2                Actual/360
  10357.      *                                         3                Actual/365
  10358.      *                                         4                European 30/360
  10359.      *    @return    float 
  10360.      */
  10361.     public static function PRICEDISC($settlement$maturity$discount$redemption$basis=0{
  10362.         $settlement    self::flattenSingleValue($settlement);
  10363.         $maturity    self::flattenSingleValue($maturity);
  10364.         $discount    = (float) self::flattenSingleValue($discount);
  10365.         $redemption    = (float) self::flattenSingleValue($redemption);
  10366.         $basis        = (int) self::flattenSingleValue($basis);
  10367.  
  10368.         //    Validate
  10369.         if ((is_numeric($discount)) && (is_numeric($redemption)) && (is_numeric($basis))) {
  10370.             if (($discount <= 0|| ($redemption <= 0)) {
  10371.                 return self::$_errorCodes['num'];
  10372.             }
  10373.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  10374.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10375.                 return $daysBetweenSettlementAndMaturity;
  10376.             }
  10377.  
  10378.             return $redemption ($discount $daysBetweenSettlementAndMaturity);
  10379.         }
  10380.         return self::$_errorCodes['value'];
  10381.     }    //    function PRICEDISC()
  10382.  
  10383.  
  10384.     /**
  10385.      *    PRICEMAT
  10386.      *
  10387.      *    Returns the price per $100 face value of a security that pays interest at maturity.
  10388.      *
  10389.      *    @param    mixed    settlement    The security's settlement date.
  10390.      *                                 The security's settlement date is the date after the issue date when the security is traded to the buyer.
  10391.      *    @param    mixed    maturity    The security's maturity date.
  10392.      *                                 The maturity date is the date when the security expires.
  10393.      *    @param    mixed    issue        The security's issue date.
  10394.      *    @param    int        rate        The security's interest rate at date of issue.
  10395.      *    @param    int        yield        The security's annual yield.
  10396.      *    @param    int        basis        The type of day count to use.
  10397.      *                                         0 or omitted    US (NASD) 30/360
  10398.      *                                         1                Actual/actual
  10399.      *                                         2                Actual/360
  10400.      *                                         3                Actual/365
  10401.      *                                         4                European 30/360
  10402.      *    @return    float 
  10403.      */
  10404.     public static function PRICEMAT($settlement$maturity$issue$rate$yield$basis=0{
  10405.         $settlement    self::flattenSingleValue($settlement);
  10406.         $maturity    self::flattenSingleValue($maturity);
  10407.         $issue        self::flattenSingleValue($issue);
  10408.         $rate        self::flattenSingleValue($rate);
  10409.         $yield        self::flattenSingleValue($yield);
  10410.         $basis        = (int) self::flattenSingleValue($basis);
  10411.  
  10412.         //    Validate
  10413.         if (is_numeric($rate&& is_numeric($yield)) {
  10414.             if (($rate <= 0|| ($yield <= 0)) {
  10415.                 return self::$_errorCodes['num'];
  10416.             }
  10417.             $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  10418.             if (!is_numeric($daysPerYear)) {
  10419.                 return $daysPerYear;
  10420.             }
  10421.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  10422.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  10423.                 return $daysBetweenIssueAndSettlement;
  10424.             }
  10425.             $daysBetweenIssueAndSettlement *= $daysPerYear;
  10426.             $daysBetweenIssueAndMaturity self::YEARFRAC($issue$maturity$basis);
  10427.             if (!is_numeric($daysBetweenIssueAndMaturity)) {
  10428.                 return $daysBetweenIssueAndMaturity;
  10429.             }
  10430.             $daysBetweenIssueAndMaturity *= $daysPerYear;
  10431.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  10432.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10433.                 return $daysBetweenSettlementAndMaturity;
  10434.             }
  10435.             $daysBetweenSettlementAndMaturity *= $daysPerYear;
  10436.  
  10437.             return ((100 (($daysBetweenIssueAndMaturity $daysPerYear$rate 100)) /
  10438.                    ((($daysBetweenSettlementAndMaturity $daysPerYear$yield)) -
  10439.                    (($daysBetweenIssueAndSettlement $daysPerYear$rate 100));
  10440.         }
  10441.         return self::$_errorCodes['value'];
  10442.     }    //    function PRICEMAT()
  10443.  
  10444.  
  10445.     /**
  10446.      *    RECEIVED
  10447.      *
  10448.      *    Returns the price per $100 face value of a discounted security.
  10449.      *
  10450.      *    @param    mixed    settlement    The security's settlement date.
  10451.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  10452.      *    @param    mixed    maturity    The security's maturity date.
  10453.      *                                 The maturity date is the date when the security expires.
  10454.      *    @param    int        investment    The amount invested in the security.
  10455.      *    @param    int        discount    The security's discount rate.
  10456.      *    @param    int        basis        The type of day count to use.
  10457.      *                                         0 or omitted    US (NASD) 30/360
  10458.      *                                         1                Actual/actual
  10459.      *                                         2                Actual/360
  10460.      *                                         3                Actual/365
  10461.      *                                         4                European 30/360
  10462.      *    @return    float 
  10463.      */
  10464.     public static function RECEIVED($settlement$maturity$investment$discount$basis=0{
  10465.         $settlement    self::flattenSingleValue($settlement);
  10466.         $maturity    self::flattenSingleValue($maturity);
  10467.         $investment    = (float) self::flattenSingleValue($investment);
  10468.         $discount    = (float) self::flattenSingleValue($discount);
  10469.         $basis        = (int) self::flattenSingleValue($basis);
  10470.  
  10471.         //    Validate
  10472.         if ((is_numeric($investment)) && (is_numeric($discount)) && (is_numeric($basis))) {
  10473.             if (($investment <= 0|| ($discount <= 0)) {
  10474.                 return self::$_errorCodes['num'];
  10475.             }
  10476.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  10477.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10478.                 return $daysBetweenSettlementAndMaturity;
  10479.             }
  10480.  
  10481.             return $investment ($discount $daysBetweenSettlementAndMaturity));
  10482.         }
  10483.         return self::$_errorCodes['value'];
  10484.     }    //    function RECEIVED()
  10485.  
  10486.  
  10487.     /**
  10488.      *    INTRATE
  10489.      *
  10490.      *    Returns the interest rate for a fully invested security.
  10491.      *
  10492.      *    @param    mixed    settlement    The security's settlement date.
  10493.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  10494.      *    @param    mixed    maturity    The security's maturity date.
  10495.      *                                 The maturity date is the date when the security expires.
  10496.      *    @param    int        investment    The amount invested in the security.
  10497.      *    @param    int        redemption    The amount to be received at maturity.
  10498.      *    @param    int        basis        The type of day count to use.
  10499.      *                                         0 or omitted    US (NASD) 30/360
  10500.      *                                         1                Actual/actual
  10501.      *                                         2                Actual/360
  10502.      *                                         3                Actual/365
  10503.      *                                         4                European 30/360
  10504.      *    @return    float 
  10505.      */
  10506.     public static function INTRATE($settlement$maturity$investment$redemption$basis=0{
  10507.         $settlement    self::flattenSingleValue($settlement);
  10508.         $maturity    self::flattenSingleValue($maturity);
  10509.         $investment    = (float) self::flattenSingleValue($investment);
  10510.         $redemption    = (float) self::flattenSingleValue($redemption);
  10511.         $basis        = (int) self::flattenSingleValue($basis);
  10512.  
  10513.         //    Validate
  10514.         if ((is_numeric($investment)) && (is_numeric($redemption)) && (is_numeric($basis))) {
  10515.             if (($investment <= 0|| ($redemption <= 0)) {
  10516.                 return self::$_errorCodes['num'];
  10517.             }
  10518.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  10519.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10520.                 return $daysBetweenSettlementAndMaturity;
  10521.             }
  10522.  
  10523.             return (($redemption $investment1($daysBetweenSettlementAndMaturity);
  10524.         }
  10525.         return self::$_errorCodes['value'];
  10526.     }    //    function INTRATE()
  10527.  
  10528.  
  10529.     /**
  10530.      *    TBILLEQ
  10531.      *
  10532.      *    Returns the bond-equivalent yield for a Treasury bill.
  10533.      *
  10534.      *    @param    mixed    settlement    The Treasury bill's settlement date.
  10535.      *                                 The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  10536.      *    @param    mixed    maturity    The Treasury bill's maturity date.
  10537.      *                                 The maturity date is the date when the Treasury bill expires.
  10538.      *    @param    int        discount    The Treasury bill's discount rate.
  10539.      *    @return    float 
  10540.      */
  10541.     public static function TBILLEQ($settlement$maturity$discount{
  10542.         $settlement    self::flattenSingleValue($settlement);
  10543.         $maturity    self::flattenSingleValue($maturity);
  10544.         $discount    self::flattenSingleValue($discount);
  10545.  
  10546.         //    Use TBILLPRICE for validation
  10547.         $testValue self::TBILLPRICE($settlement$maturity$discount);
  10548.         if (is_string($testValue)) {
  10549.             return $testValue;
  10550.         }
  10551.  
  10552.         if (is_string($maturity self::_getDateValue($maturity))) {
  10553.             return self::$_errorCodes['value'];
  10554.         }
  10555.  
  10556.         if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  10557.             ++$maturity;
  10558.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity360;
  10559.         else {
  10560.             $daysBetweenSettlementAndMaturity (self::_getDateValue($maturityself::_getDateValue($settlement));
  10561.         }
  10562.  
  10563.         return (365 $discount(360 $discount $daysBetweenSettlementAndMaturity);
  10564.     }    //    function TBILLEQ()
  10565.  
  10566.  
  10567.     /**
  10568.      *    TBILLPRICE
  10569.      *
  10570.      *    Returns the yield for a Treasury bill.
  10571.      *
  10572.      *    @param    mixed    settlement    The Treasury bill's settlement date.
  10573.      *                                 The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  10574.      *    @param    mixed    maturity    The Treasury bill's maturity date.
  10575.      *                                 The maturity date is the date when the Treasury bill expires.
  10576.      *    @param    int        discount    The Treasury bill's discount rate.
  10577.      *    @return    float 
  10578.      */
  10579.     public static function TBILLPRICE($settlement$maturity$discount{
  10580.         $settlement    self::flattenSingleValue($settlement);
  10581.         $maturity    self::flattenSingleValue($maturity);
  10582.         $discount    self::flattenSingleValue($discount);
  10583.  
  10584.         if (is_string($maturity self::_getDateValue($maturity))) {
  10585.             return self::$_errorCodes['value'];
  10586.         }
  10587.  
  10588.         //    Validate
  10589.         if (is_numeric($discount)) {
  10590.             if ($discount <= 0{
  10591.                 return self::$_errorCodes['num'];
  10592.             }
  10593.  
  10594.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  10595.                 ++$maturity;
  10596.                 $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity360;
  10597.                 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10598.                     return $daysBetweenSettlementAndMaturity;
  10599.                 }
  10600.             else {
  10601.                 $daysBetweenSettlementAndMaturity (self::_getDateValue($maturityself::_getDateValue($settlement));
  10602.             }
  10603.  
  10604.             if ($daysBetweenSettlementAndMaturity 360{
  10605.                 return self::$_errorCodes['num'];
  10606.             }
  10607.  
  10608.             $price 100 ((($discount $daysBetweenSettlementAndMaturity360));
  10609.             if ($price <= 0{
  10610.                 return self::$_errorCodes['num'];
  10611.             }
  10612.             return $price;
  10613.         }
  10614.         return self::$_errorCodes['value'];
  10615.     }    //    function TBILLPRICE()
  10616.  
  10617.  
  10618.     /**
  10619.      *    TBILLYIELD
  10620.      *
  10621.      *    Returns the yield for a Treasury bill.
  10622.      *
  10623.      *    @param    mixed    settlement    The Treasury bill's settlement date.
  10624.      *                                 The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  10625.      *    @param    mixed    maturity    The Treasury bill's maturity date.
  10626.      *                                 The maturity date is the date when the Treasury bill expires.
  10627.      *    @param    int        price        The Treasury bill's price per $100 face value.
  10628.      *    @return    float 
  10629.      */
  10630.     public static function TBILLYIELD($settlement$maturity$price{
  10631.         $settlement    self::flattenSingleValue($settlement);
  10632.         $maturity    self::flattenSingleValue($maturity);
  10633.         $price        self::flattenSingleValue($price);
  10634.  
  10635.         //    Validate
  10636.         if (is_numeric($price)) {
  10637.             if ($price <= 0{
  10638.                 return self::$_errorCodes['num'];
  10639.             }
  10640.  
  10641.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  10642.                 ++$maturity;
  10643.                 $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity360;
  10644.                 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10645.                     return $daysBetweenSettlementAndMaturity;
  10646.                 }
  10647.             else {
  10648.                 $daysBetweenSettlementAndMaturity (self::_getDateValue($maturityself::_getDateValue($settlement));
  10649.             }
  10650.  
  10651.             if ($daysBetweenSettlementAndMaturity 360{
  10652.                 return self::$_errorCodes['num'];
  10653.             }
  10654.  
  10655.             return ((100 $price$price(360 $daysBetweenSettlementAndMaturity);
  10656.         }
  10657.         return self::$_errorCodes['value'];
  10658.     }    //    function TBILLYIELD()
  10659.  
  10660.  
  10661.     /**
  10662.      * SLN
  10663.      *
  10664.      * Returns the straight-line depreciation of an asset for one period
  10665.      *
  10666.      * @param    cost        Initial cost of the asset
  10667.      * @param    salvage        Value at the end of the depreciation
  10668.      * @param    life        Number of periods over which the asset is depreciated
  10669.      * @return    float 
  10670.      */
  10671.     public static function SLN($cost$salvage$life{
  10672.         $cost        self::flattenSingleValue($cost);
  10673.         $salvage    self::flattenSingleValue($salvage);
  10674.         $life        self::flattenSingleValue($life);
  10675.  
  10676.         // Calculate
  10677.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life))) {
  10678.             if ($life 0{
  10679.                 return self::$_errorCodes['num'];
  10680.             }
  10681.             return ($cost $salvage$life;
  10682.         }
  10683.         return self::$_errorCodes['value'];
  10684.     }    //    function SLN()
  10685.  
  10686.  
  10687.     /**
  10688.      *    YIELDMAT
  10689.      *
  10690.      *    Returns the annual yield of a security that pays interest at maturity.
  10691.      *
  10692.      *    @param    mixed    settlement    The security's settlement date.
  10693.      *                                 The security's settlement date is the date after the issue date when the security is traded to the buyer.
  10694.      *    @param    mixed    maturity    The security's maturity date.
  10695.      *                                 The maturity date is the date when the security expires.
  10696.      *    @param    mixed    issue        The security's issue date.
  10697.      *    @param    int        rate        The security's interest rate at date of issue.
  10698.      *    @param    int        price        The security's price per $100 face value.
  10699.      *    @param    int        basis        The type of day count to use.
  10700.      *                                         0 or omitted    US (NASD) 30/360
  10701.      *                                         1                Actual/actual
  10702.      *                                         2                Actual/360
  10703.      *                                         3                Actual/365
  10704.      *                                         4                European 30/360
  10705.      *    @return    float 
  10706.      */
  10707.     public static function YIELDMAT($settlement$maturity$issue$rate$price$basis=0{
  10708.         $settlement    self::flattenSingleValue($settlement);
  10709.         $maturity    self::flattenSingleValue($maturity);
  10710.         $issue        self::flattenSingleValue($issue);
  10711.         $rate        self::flattenSingleValue($rate);
  10712.         $price        self::flattenSingleValue($price);
  10713.         $basis        = (int) self::flattenSingleValue($basis);
  10714.  
  10715.         //    Validate
  10716.         if (is_numeric($rate&& is_numeric($price)) {
  10717.             if (($rate <= 0|| ($price <= 0)) {
  10718.                 return self::$_errorCodes['num'];
  10719.             }
  10720.             $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  10721.             if (!is_numeric($daysPerYear)) {
  10722.                 return $daysPerYear;
  10723.             }
  10724.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  10725.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  10726.                 return $daysBetweenIssueAndSettlement;
  10727.             }
  10728.             $daysBetweenIssueAndSettlement *= $daysPerYear;
  10729.             $daysBetweenIssueAndMaturity self::YEARFRAC($issue$maturity$basis);
  10730.             if (!is_numeric($daysBetweenIssueAndMaturity)) {
  10731.                 return $daysBetweenIssueAndMaturity;
  10732.             }
  10733.             $daysBetweenIssueAndMaturity *= $daysPerYear;
  10734.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  10735.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10736.                 return $daysBetweenSettlementAndMaturity;
  10737.             }
  10738.             $daysBetweenSettlementAndMaturity *= $daysPerYear;
  10739.  
  10740.             return (((($daysBetweenIssueAndMaturity $daysPerYear$rate(($price 100(($daysBetweenIssueAndSettlement $daysPerYear$rate))) /
  10741.                    (($price 100(($daysBetweenIssueAndSettlement $daysPerYear$rate))) *
  10742.                    ($daysPerYear $daysBetweenSettlementAndMaturity);
  10743.         }
  10744.         return self::$_errorCodes['value'];
  10745.     }    //    function YIELDMAT()
  10746.  
  10747.  
  10748.     /**
  10749.      *    YIELDDISC
  10750.      *
  10751.      *    Returns the annual yield of a security that pays interest at maturity.
  10752.      *
  10753.      *    @param    mixed    settlement    The security's settlement date.
  10754.      *                                 The security's settlement date is the date after the issue date when the security is traded to the buyer.
  10755.      *    @param    mixed    maturity    The security's maturity date.
  10756.      *                                 The maturity date is the date when the security expires.
  10757.      *    @param    int        price        The security's price per $100 face value.
  10758.      *    @param    int        redemption    The security's redemption value per $100 face value.
  10759.      *    @param    int        basis        The type of day count to use.
  10760.      *                                         0 or omitted    US (NASD) 30/360
  10761.      *                                         1                Actual/actual
  10762.      *                                         2                Actual/360
  10763.      *                                         3                Actual/365
  10764.      *                                         4                European 30/360
  10765.      *    @return    float 
  10766.      */
  10767.     public static function YIELDDISC($settlement$maturity$price$redemption$basis=0{
  10768.         $settlement    self::flattenSingleValue($settlement);
  10769.         $maturity    self::flattenSingleValue($maturity);
  10770.         $price        self::flattenSingleValue($price);
  10771.         $redemption    self::flattenSingleValue($redemption);
  10772.         $basis        = (int) self::flattenSingleValue($basis);
  10773.  
  10774.         //    Validate
  10775.         if (is_numeric($price&& is_numeric($redemption)) {
  10776.             if (($price <= 0|| ($redemption <= 0)) {
  10777.                 return self::$_errorCodes['num'];
  10778.             }
  10779.             $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  10780.             if (!is_numeric($daysPerYear)) {
  10781.                 return $daysPerYear;
  10782.             }
  10783.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity,$basis);
  10784.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10785.                 return $daysBetweenSettlementAndMaturity;
  10786.             }
  10787.             $daysBetweenSettlementAndMaturity *= $daysPerYear;
  10788.  
  10789.             return (($redemption $price$price($daysPerYear $daysBetweenSettlementAndMaturity);
  10790.         }
  10791.         return self::$_errorCodes['value'];
  10792.     }    //    function YIELDDISC()
  10793.  
  10794.  
  10795.     /**
  10796.      *    CELL_ADDRESS
  10797.      *
  10798.      *    Creates a cell address as text, given specified row and column numbers.
  10799.      *
  10800.      *    @param    row                Row number to use in the cell reference
  10801.      *    @param    column            Column number to use in the cell reference
  10802.      *    @param    relativity        Flag indicating the type of reference to return
  10803.      *                                 1 or omitted    Absolute
  10804.      *                                 2                Absolute row; relative column
  10805.      *                                 3                Relative row; absolute column
  10806.      *                                 4                Relative
  10807.      *    @param    referenceStyle    A logical value that specifies the A1 or R1C1 reference style.
  10808.      *                                 TRUE or omitted        CELL_ADDRESS returns an A1-style reference
  10809.      *                                 FALSE                CELL_ADDRESS returns an R1C1-style reference
  10810.      *    @param    sheetText        Optional Name of worksheet to use
  10811.      *    @return    string 
  10812.      */
  10813.     public static function CELL_ADDRESS($row$column$relativity=1$referenceStyle=True$sheetText=''{
  10814.         $row        self::flattenSingleValue($row);
  10815.         $column        self::flattenSingleValue($column);
  10816.         $relativity    self::flattenSingleValue($relativity);
  10817.         $sheetText    self::flattenSingleValue($sheetText);
  10818.  
  10819.         if (($row 1|| ($column 1)) {
  10820.             return self::$_errorCodes['value'];
  10821.         }
  10822.  
  10823.         if ($sheetText ''{
  10824.             if (strpos($sheetText,' '!== False$sheetText "'".$sheetText."'"}
  10825.             $sheetText .='!';
  10826.         }
  10827.         if ((!is_bool($referenceStyle)) || $referenceStyle{
  10828.             $rowRelative $columnRelative '$';
  10829.             $column PHPExcel_Cell::stringFromColumnIndex($column-1);
  10830.             if (($relativity == 2|| ($relativity == 4)) $columnRelative ''}
  10831.             if (($relativity == 3|| ($relativity == 4)) $rowRelative ''}
  10832.             return $sheetText.$columnRelative.$column.$rowRelative.$row;
  10833.         else {
  10834.             if (($relativity == 2|| ($relativity == 4)) $column '['.$column.']'}
  10835.             if (($relativity == 3|| ($relativity == 4)) $row '['.$row.']'}
  10836.             return $sheetText.'R'.$row.'C'.$column;
  10837.         }
  10838.     }    //    function CELL_ADDRESS()
  10839.  
  10840.  
  10841.     /**
  10842.      *    COLUMN
  10843.      *
  10844.      *    Returns the column number of the given cell reference
  10845.      *    If the cell reference is a range of cells, COLUMN returns the column numbers of each column in the reference as a horizontal array.
  10846.      *    If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the
  10847.      *        reference of the cell in which the COLUMN function appears; otherwise this function returns 0.
  10848.      *
  10849.      *    @param    cellAddress        A reference to a range of cells for which you want the column numbers
  10850.      *    @return    integer or array of integer
  10851.      */
  10852.     public static function COLUMN($cellAddress=Null{
  10853.         if (is_null($cellAddress|| trim($cellAddress=== ''return 0}
  10854.  
  10855.         if (is_array($cellAddress)) {
  10856.             foreach($cellAddress as $columnKey => $value{
  10857.                 $columnKey preg_replace('/[^a-z]/i','',$columnKey);
  10858.                 return (integer) PHPExcel_Cell::columnIndexFromString($columnKey);
  10859.             }
  10860.         else {
  10861.             if (strpos($cellAddress,'!'!== false{
  10862.                 list($sheet,$cellAddressexplode('!',$cellAddress);
  10863.             }
  10864.             if (strpos($cellAddress,':'!== false{
  10865.                 list($startAddress,$endAddressexplode(':',$cellAddress);
  10866.                 $startAddress preg_replace('/[^a-z]/i','',$startAddress);
  10867.                 $endAddress preg_replace('/[^a-z]/i','',$endAddress);
  10868.                 $returnValue array();
  10869.                 do {
  10870.                     $returnValue[= (integer) PHPExcel_Cell::columnIndexFromString($startAddress);
  10871.                 while ($startAddress++ != $endAddress);
  10872.                 return $returnValue;
  10873.             else {
  10874.                 $cellAddress preg_replace('/[^a-z]/i','',$cellAddress);
  10875.                 return (integer) PHPExcel_Cell::columnIndexFromString($cellAddress);
  10876.             }
  10877.         }
  10878.     }    //    function COLUMN()
  10879.  
  10880.  
  10881.     /**
  10882.      *    COLUMNS
  10883.      *
  10884.      *    Returns the number of columns in an array or reference.
  10885.      *
  10886.      *    @param    cellAddress        An array or array formula, or a reference to a range of cells for which you want the number of columns
  10887.      *    @return    integer 
  10888.      */
  10889.     public static function COLUMNS($cellAddress=Null{
  10890.         if (is_null($cellAddress|| $cellAddress === ''{
  10891.             return 1;
  10892.         elseif (!is_array($cellAddress)) {
  10893.             return self::$_errorCodes['value'];
  10894.         }
  10895.  
  10896.         $x array_keys($cellAddress);
  10897.         $x array_shift($x);
  10898.         $isMatrix (is_numeric($x));
  10899.         list($columns,$rowsPHPExcel_Calculation::_getMatrixDimensions($cellAddress);
  10900.  
  10901.         if ($isMatrix{
  10902.             return $rows;
  10903.         else {
  10904.             return $columns;
  10905.         }
  10906.     }    //    function COLUMNS()
  10907.  
  10908.  
  10909.     /**
  10910.      *    ROW
  10911.      *
  10912.      *    Returns the row number of the given cell reference
  10913.      *    If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference as a vertical array.
  10914.      *    If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the
  10915.      *        reference of the cell in which the ROW function appears; otherwise this function returns 0.
  10916.      *
  10917.      *    @param    cellAddress        A reference to a range of cells for which you want the row numbers
  10918.      *    @return    integer or array of integer
  10919.      */
  10920.     public static function ROW($cellAddress=Null{
  10921.         if (is_null($cellAddress|| trim($cellAddress=== ''return 0}
  10922.  
  10923.         if (is_array($cellAddress)) {
  10924.             foreach($cellAddress as $columnKey => $rowValue{
  10925.                 foreach($rowValue as $rowKey => $cellValue{
  10926.                     return (integer) preg_replace('/[^0-9]/i','',$rowKey);
  10927.                 }
  10928.             }
  10929.         else {
  10930.             if (strpos($cellAddress,'!'!== false{
  10931.                 list($sheet,$cellAddressexplode('!',$cellAddress);
  10932.             }
  10933.             if (strpos($cellAddress,':'!== false{
  10934.                 list($startAddress,$endAddressexplode(':',$cellAddress);
  10935.                 $startAddress preg_replace('/[^0-9]/','',$startAddress);
  10936.                 $endAddress preg_replace('/[^0-9]/','',$endAddress);
  10937.                 $returnValue array();
  10938.                 do {
  10939.                     $returnValue[][= (integer) $startAddress;
  10940.                 while ($startAddress++ != $endAddress);
  10941.                 return $returnValue;
  10942.             else {
  10943.                 list($cellAddressexplode(':',$cellAddress);
  10944.                 return (integer) preg_replace('/[^0-9]/','',$cellAddress);
  10945.             }
  10946.         }
  10947.     }    //    function ROW()
  10948.  
  10949.  
  10950.     /**
  10951.      *    ROWS
  10952.      *
  10953.      *    Returns the number of rows in an array or reference.
  10954.      *
  10955.      *    @param    cellAddress        An array or array formula, or a reference to a range of cells for which you want the number of rows
  10956.      *    @return    integer 
  10957.      */
  10958.     public static function ROWS($cellAddress=Null{
  10959.         if (is_null($cellAddress|| $cellAddress === ''{
  10960.             return 1;
  10961.         elseif (!is_array($cellAddress)) {
  10962.             return self::$_errorCodes['value'];
  10963.         }
  10964.  
  10965.         $i array_keys($cellAddress);
  10966.         $isMatrix (is_numeric(array_shift($i)));
  10967.         list($columns,$rowsPHPExcel_Calculation::_getMatrixDimensions($cellAddress);
  10968.  
  10969.         if ($isMatrix{
  10970.             return $columns;
  10971.         else {
  10972.             return $rows;
  10973.         }
  10974.     }    //    function ROWS()
  10975.  
  10976.  
  10977.     /**
  10978.      *    INDIRECT
  10979.      *
  10980.      *    Returns the number of rows in an array or reference.
  10981.      *
  10982.      *    @param    cellAddress        An array or array formula, or a reference to a range of cells for which you want the number of rows
  10983.      *    @return    integer 
  10984.      */
  10985.     public static function INDIRECT($cellAddress=NullPHPExcel_Cell $pCell null{
  10986.         $cellAddress    self::flattenSingleValue($cellAddress);
  10987.         if (is_null($cellAddress|| $cellAddress === ''{
  10988.             return self::REF();
  10989.         }
  10990.  
  10991.         $cellAddress1 $cellAddress;
  10992.         $cellAddress2 NULL;
  10993.         if (strpos($cellAddress,':'!== false{
  10994.             list($cellAddress1,$cellAddress2explode(':',$cellAddress);
  10995.         }
  10996.  
  10997.         if ((!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i'$cellAddress1$matches)) ||
  10998.             ((!is_null($cellAddress2)) && (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i'$cellAddress2$matches)))) {
  10999.             return self::REF();
  11000.         }
  11001.  
  11002.         if (strpos($cellAddress,'!'!== false{
  11003.             list($sheetName,$cellAddressexplode('!',$cellAddress);
  11004.             $pSheet $pCell->getParent()->getParent()->getSheetByName($sheetName);
  11005.         else {
  11006.             $pSheet $pCell->getParent();
  11007.         }
  11008.  
  11009.         return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress$pSheetFalse);
  11010.     }    //    function INDIRECT()
  11011.  
  11012.  
  11013.     /**
  11014.      *    OFFSET
  11015.      *
  11016.      *    Returns a reference to a range that is a specified number of rows and columns from a cell or range of cells.
  11017.      *    The reference that is returned can be a single cell or a range of cells. You can specify the number of rows and
  11018.      *    the number of columns to be returned.
  11019.      *
  11020.      *    @param    cellAddress        The reference from which you want to base the offset. Reference must refer to a cell or
  11021.      *                                 range of adjacent cells; otherwise, OFFSET returns the #VALUE! error value.
  11022.      *    @param    rows            The number of rows, up or down, that you want the upper-left cell to refer to.
  11023.      *                                 Using 5 as the rows argument specifies that the upper-left cell in the reference is
  11024.      *                                 five rows below reference. Rows can be positive (which means below the starting reference)
  11025.      *                                 or negative (which means above the starting reference).
  11026.      *    @param    cols            The number of columns, to the left or right, that you want the upper-left cell of the result
  11027.      *                                 to refer to. Using 5 as the cols argument specifies that the upper-left cell in the
  11028.      *                                 reference is five columns to the right of reference. Cols can be positive (which means
  11029.      *                                 to the right of the starting reference) or negative (which means to the left of the
  11030.      *                                 starting reference).
  11031.      *    @param    height            The height, in number of rows, that you want the returned reference to be. Height must be a positive number.
  11032.      *    @param    width            The width, in number of columns, that you want the returned reference to be. Width must be a positive number.
  11033.      *    @return    string            A reference to a cell or range of cells
  11034.      */
  11035.     public static function OFFSET($cellAddress=Null,$rows=0,$columns=0,$height=null,$width=null{
  11036.         $rows        self::flattenSingleValue($rows);
  11037.         $columns    self::flattenSingleValue($columns);
  11038.         $height        self::flattenSingleValue($height);
  11039.         $width        self::flattenSingleValue($width);
  11040.         if ($cellAddress == Null{
  11041.             return 0;
  11042.         }
  11043.  
  11044.         $args func_get_args();
  11045.         $pCell array_pop($args);
  11046.         if (!is_object($pCell)) {
  11047.             return self::$_errorCodes['reference'];
  11048.         }
  11049.  
  11050.         $sheetName null;
  11051.         if (strpos($cellAddress,"!")) {
  11052.             list($sheetName,$cellAddressexplode("!",$cellAddress);
  11053.         }
  11054.         if (strpos($cellAddress,":")) {
  11055.             list($startCell,$endCellexplode(":",$cellAddress);
  11056.         else {
  11057.             $startCell $endCell $cellAddress;
  11058.         }
  11059.         list($startCellColumn,$startCellRowPHPExcel_Cell::coordinateFromString($startCell);
  11060.         list($endCellColumn,$endCellRowPHPExcel_Cell::coordinateFromString($endCell);
  11061.  
  11062.         $startCellRow += $rows;
  11063.         $startCellColumn PHPExcel_Cell::columnIndexFromString($startCellColumn1;
  11064.         $startCellColumn += $columns;
  11065.  
  11066.         if (($startCellRow <= 0|| ($startCellColumn 0)) {
  11067.             return self::$_errorCodes['reference'];
  11068.         }
  11069.         $endCellColumn PHPExcel_Cell::columnIndexFromString($endCellColumn1;
  11070.         if (($width != null&& (!is_object($width))) {
  11071.             $endCellColumn $startCellColumn $width 1;
  11072.         else {
  11073.             $endCellColumn += $columns;
  11074.         }
  11075.         $startCellColumn PHPExcel_Cell::stringFromColumnIndex($startCellColumn);
  11076.  
  11077.         if (($height != null&& (!is_object($height))) {
  11078.             $endCellRow $startCellRow $height 1;
  11079.         else {
  11080.             $endCellRow += $rows;
  11081.         }
  11082.  
  11083.         if (($endCellRow <= 0|| ($endCellColumn 0)) {
  11084.             return self::$_errorCodes['reference'];
  11085.         }
  11086.         $endCellColumn PHPExcel_Cell::stringFromColumnIndex($endCellColumn);
  11087.  
  11088.         $cellAddress $startCellColumn.$startCellRow;
  11089.         if (($startCellColumn != $endCellColumn|| ($startCellRow != $endCellRow)) {
  11090.             $cellAddress .= ':'.$endCellColumn.$endCellRow;
  11091.         }
  11092.  
  11093.         if ($sheetName !== null{
  11094.             $pSheet $pCell->getParent()->getParent()->getSheetByName($sheetName);
  11095.         else {
  11096.             $pSheet $pCell->getParent();
  11097.         }
  11098.  
  11099.         return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress$pSheetFalse);
  11100.     }    //    function OFFSET()
  11101.  
  11102.  
  11103.     public static function CHOOSE({
  11104.         $chooseArgs func_get_args();
  11105.         $chosenEntry self::flattenArray(array_shift($chooseArgs));
  11106.         $entryCount count($chooseArgs1;
  11107.  
  11108.         if(is_array($chosenEntry)) {
  11109.             $chosenEntry array_shift($chosenEntry);
  11110.         }
  11111.         if ((is_numeric($chosenEntry)) && (!is_bool($chosenEntry))) {
  11112.             --$chosenEntry;
  11113.         else {
  11114.             return self::$_errorCodes['value'];
  11115.         }
  11116.         $chosenEntry floor($chosenEntry);
  11117.         if (($chosenEntry <= 0|| ($chosenEntry $entryCount)) {
  11118.             return self::$_errorCodes['value'];
  11119.         }
  11120.  
  11121.         if (is_array($chooseArgs[$chosenEntry])) {
  11122.             return self::flattenArray($chooseArgs[$chosenEntry]);
  11123.         else {
  11124.             return $chooseArgs[$chosenEntry];
  11125.         }
  11126.     }    //    function CHOOSE()
  11127.  
  11128.  
  11129.     /**
  11130.      *    MATCH
  11131.      *
  11132.      *    The MATCH function searches for a specified item in a range of cells
  11133.      *
  11134.      *    @param    lookup_value    The value that you want to match in lookup_array
  11135.      *    @param    lookup_array    The range of cells being searched
  11136.      *    @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.
  11137.      *    @return    integer            The relative position of the found item
  11138.      */
  11139.     public static function MATCH($lookup_value$lookup_array$match_type=1{
  11140.         $lookup_array self::flattenArray($lookup_array);
  11141.         $lookup_value self::flattenSingleValue($lookup_value);
  11142.         $match_type    (is_null($match_type)) : (int) self::flattenSingleValue($match_type);
  11143.         //    MATCH is not case sensitive
  11144.         $lookup_value strtolower($lookup_value);
  11145.  
  11146.         //    lookup_value type has to be number, text, or logical values
  11147.         if ((!is_numeric($lookup_value)) && (!is_string($lookup_value)) && (!is_bool($lookup_value))) {
  11148.             return self::$_errorCodes['na'];
  11149.         }
  11150.  
  11151.         //    match_type is 0, 1 or -1
  11152.         if (($match_type !== 0&& ($match_type !== -1&& ($match_type !== 1)) {
  11153.             return self::$_errorCodes['na'];
  11154.         }
  11155.  
  11156.         //    lookup_array should not be empty
  11157.         $lookupArraySize count($lookup_array);
  11158.         if ($lookupArraySize <= 0{
  11159.             return self::$_errorCodes['na'];
  11160.         }
  11161.  
  11162.         //    lookup_array should contain only number, text, or logical values, or empty (null) cells
  11163.         foreach($lookup_array as $i => $lookupArrayValue{
  11164.             //    check the type of the value
  11165.             if ((!is_numeric($lookupArrayValue)) && (!is_string($lookupArrayValue)) &&
  11166.                 (!is_bool($lookupArrayValue)) && (!is_null($lookupArrayValue))) {
  11167.                 return self::$_errorCodes['na'];
  11168.             }
  11169.             //    convert strings to lowercase for case-insensitive testing
  11170.             if (is_string($lookupArrayValue)) {
  11171.                 $lookup_array[$istrtolower($lookupArrayValue);
  11172.             }
  11173.             if ((is_null($lookupArrayValue)) && (($match_type == 1|| ($match_type == -1))) {
  11174.                 $lookup_array array_slice($lookup_array,0,$i-1);
  11175.             }
  11176.         }
  11177.  
  11178.         // if match_type is 1 or -1, the list has to be ordered
  11179.         if ($match_type == 1{
  11180.             asort($lookup_array);
  11181.             $keySet array_keys($lookup_array);
  11182.         elseif($match_type == -1{
  11183.             arsort($lookup_array);
  11184.             $keySet array_keys($lookup_array);
  11185.         }
  11186.  
  11187.         // **
  11188.         // find the match
  11189.         // **
  11190.         // loop on the cells
  11191. //        var_dump($lookup_array);
  11192. //        echo '<br />';
  11193.         foreach($lookup_array as $i => $lookupArrayValue{
  11194.             if (($match_type == 0&& ($lookupArrayValue == $lookup_value)) {
  11195.                 //    exact match
  11196.                 return ++$i;
  11197.             elseif (($match_type == -1&& ($lookupArrayValue <= $lookup_value)) {
  11198. //                echo '$i = '.$i.' => ';
  11199. //                var_dump($lookupArrayValue);
  11200. //                echo '<br />';
  11201. //                echo 'Keyset = ';
  11202. //                var_dump($keySet);
  11203. //                echo '<br />';
  11204.                 $i array_search($i,$keySet);
  11205. //                echo '$i='.$i.'<br />';
  11206.                 // if match_type is -1 <=> find the smallest value that is greater than or equal to lookup_value
  11207.                 if ($i 1){
  11208.                     // 1st cell was allready smaller than the lookup_value
  11209.                     break;
  11210.                 else {
  11211.                     // the previous cell was the match
  11212.                     return $keySet[$i-1]+1;
  11213.                 }
  11214.             elseif (($match_type == 1&& ($lookupArrayValue >= $lookup_value)) {
  11215. //                echo '$i = '.$i.' => ';
  11216. //                var_dump($lookupArrayValue);
  11217. //                echo '<br />';
  11218. //                echo 'Keyset = ';
  11219. //                var_dump($keySet);
  11220. //                echo '<br />';
  11221.                 $i array_search($i,$keySet);
  11222. //                echo '$i='.$i.'<br />';
  11223.                 // if match_type is 1 <=> find the largest value that is less than or equal to lookup_value
  11224.                 if ($i 1){
  11225.                     // 1st cell was allready bigger than the lookup_value
  11226.                     break;
  11227.                 else {
  11228.                     // the previous cell was the match
  11229.                     return $keySet[$i-1]+1;
  11230.                 }
  11231.             }
  11232.         }
  11233.  
  11234.         //    unsuccessful in finding a match, return #N/A error value
  11235.         return self::$_errorCodes['na'];
  11236.     }    //    function MATCH()
  11237.  
  11238.  
  11239.     /**
  11240.      *    INDEX
  11241.      *
  11242.      * Uses an index to choose a value from a reference or array
  11243.      * implemented: Return the value of a specified cell or array of cells    Array form
  11244.      * not implemented: Return a reference to specified cells    Reference form
  11245.      *
  11246.      * @param    range_array    a range of cells or an array constant
  11247.      * @param    row_num        selects the row in array from which to return a value. If row_num is omitted, column_num is required.
  11248.      * @param    column_num    selects the column in array from which to return a value. If column_num is omitted, row_num is required.
  11249.      */
  11250.     public static function INDEX($arrayValues,$rowNum 0,$columnNum 0{
  11251.  
  11252.         if (($rowNum 0|| ($columnNum 0)) {
  11253.             return self::$_errorCodes['value'];
  11254.         }
  11255.  
  11256.         if (!is_array($arrayValues)) {
  11257.             return self::$_errorCodes['reference'];
  11258.         }
  11259.  
  11260.         $rowKeys array_keys($arrayValues);
  11261.         $columnKeys @array_keys($arrayValues[$rowKeys[0]]);
  11262.  
  11263.         if ($columnNum count($columnKeys)) {
  11264.             return self::$_errorCodes['value'];
  11265.         elseif ($columnNum == 0{
  11266.             if ($rowNum == 0{
  11267.                 return $arrayValues;
  11268.             }
  11269.             $rowNum $rowKeys[--$rowNum];
  11270.             $returnArray array();
  11271.             foreach($arrayValues as $arrayColumn{
  11272.                 if (is_array($arrayColumn)) {
  11273.                     if (isset($arrayColumn[$rowNum])) {
  11274.                         $returnArray[$arrayColumn[$rowNum];
  11275.                     else {
  11276.                         return $arrayValues[$rowNum];
  11277.                     }
  11278.                 else {
  11279.                     return $arrayValues[$rowNum];
  11280.                 }
  11281.             }
  11282.             return $returnArray;
  11283.         }
  11284.         $columnNum $columnKeys[--$columnNum];
  11285.         if ($rowNum count($rowKeys)) {
  11286.             return self::$_errorCodes['value'];
  11287.         elseif ($rowNum == 0{
  11288.             return $arrayValues[$columnNum];
  11289.         }
  11290.         $rowNum $rowKeys[--$rowNum];
  11291.  
  11292.         return $arrayValues[$rowNum][$columnNum];
  11293.     }    //    function INDEX()
  11294.  
  11295.  
  11296.     /**
  11297.      *    N
  11298.      *
  11299.      *    Returns a value converted to a number
  11300.      *
  11301.      *    @param    value        The value you want converted
  11302.      *    @return    number        N converts values listed in the following table
  11303.      *         If value is or refers to N returns
  11304.      *         A number            That number
  11305.      *         A date                The serial number of that date
  11306.      *         TRUE                1
  11307.      *         FALSE                0
  11308.      *         An error value        The error value
  11309.      *         Anything else        0
  11310.      */
  11311.     public static function N($value{
  11312.         while (is_array($value)) {
  11313.             $value array_shift($value);
  11314.         }
  11315.  
  11316.         switch (gettype($value)) {
  11317.             case 'double'    :
  11318.             case 'float'    :
  11319.             case 'integer'    :
  11320.                 return $value;
  11321.                 break;
  11322.             case 'boolean'    :
  11323.                 return (integer) $value;
  11324.                 break;
  11325.             case 'string'    :
  11326.                 //    Errors
  11327.                 if ((strlen($value0&& ($value{0== '#')) {
  11328.                     return $value;
  11329.                 }
  11330.                 break;
  11331.         }
  11332.         return 0;
  11333.     }    //    function N()
  11334.  
  11335.  
  11336.     /**
  11337.      *    TYPE
  11338.      *
  11339.      *    Returns a number that identifies the type of a value
  11340.      *
  11341.      *    @param    value        The value you want tested
  11342.      *    @return    number        N converts values listed in the following table
  11343.      *         If value is or refers to N returns
  11344.      *         A number            1
  11345.      *         Text                2
  11346.      *         Logical Value        4
  11347.      *         An error value        16
  11348.      *         Array or Matrix        64
  11349.      */
  11350.     public static function TYPE($value{
  11351.         $value    self::flattenArrayIndexed($value);
  11352.         if (is_array($value&& (count($value1)) {
  11353.             $a array_keys($value);
  11354.             $a array_pop($a);
  11355.             //    Range of cells is an error
  11356.             if (self::isCellValue($a)) {
  11357.                 return 16;
  11358.             //    Test for Matrix
  11359.             elseif (self::isMatrixValue($a)) {
  11360.                 return 64;
  11361.             }
  11362.         elseif(count($value== 0{
  11363.             //    Empty Cell
  11364.             return 1;
  11365.         }
  11366.         $value    self::flattenSingleValue($value);
  11367.  
  11368.         if ((is_float($value)) || (is_int($value))) {
  11369.                 return 1;
  11370.         elseif(is_bool($value)) {
  11371.                 return 4;
  11372.         elseif(is_array($value)) {
  11373.                 return 64;
  11374.                 break;
  11375.         elseif(is_string($value)) {
  11376.             //    Errors
  11377.             if ((strlen($value0&& ($value{0== '#')) {
  11378.                 return 16;
  11379.             }
  11380.             return 2;
  11381.         }
  11382.         return 0;
  11383.     }    //    function TYPE()
  11384.  
  11385.  
  11386.     /**
  11387.      * SYD
  11388.      *
  11389.      * Returns the sum-of-years' digits depreciation of an asset for a specified period.
  11390.      *
  11391.      * @param    cost        Initial cost of the asset
  11392.      * @param    salvage        Value at the end of the depreciation
  11393.      * @param    life        Number of periods over which the asset is depreciated
  11394.      * @param    period        Period
  11395.      * @return    float 
  11396.      */
  11397.     public static function SYD($cost$salvage$life$period{
  11398.         $cost        self::flattenSingleValue($cost);
  11399.         $salvage    self::flattenSingleValue($salvage);
  11400.         $life        self::flattenSingleValue($life);
  11401.         $period        self::flattenSingleValue($period);
  11402.  
  11403.         // Calculate
  11404.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period))) {
  11405.             if (($life 1|| ($period $life)) {
  11406.                 return self::$_errorCodes['num'];
  11407.             }
  11408.             return (($cost $salvage($life $period 12($life ($life 1));
  11409.         }
  11410.         return self::$_errorCodes['value'];
  11411.     }    //    function SYD()
  11412.  
  11413.  
  11414.     /**
  11415.      * TRANSPOSE
  11416.      *
  11417.      * @param    array    $matrixData    A matrix of values
  11418.      * @return    array 
  11419.      *
  11420.      *  Unlike the Excel TRANSPOSE function, which will only work on a single row or column, this function will transpose a full matrix.
  11421.      */
  11422.     public static function TRANSPOSE($matrixData{
  11423.         $returnMatrix array();
  11424.         if (!is_array($matrixData)) $matrixData array(array($matrixData))}
  11425.  
  11426.         $column 0;
  11427.         foreach($matrixData as $matrixRow{
  11428.             $row 0;
  11429.             foreach($matrixRow as $matrixCell{
  11430.                 $returnMatrix[$row][$column$matrixCell;
  11431.                 ++$row;
  11432.             }
  11433.             ++$column;
  11434.         }
  11435.         return $returnMatrix;
  11436.     }    //    function TRANSPOSE()
  11437.  
  11438.  
  11439.     /**
  11440.      * MMULT
  11441.      *
  11442.      * @param    array    $matrixData1    A matrix of values
  11443.      * @param    array    $matrixData2    A matrix of values
  11444.      * @return    array 
  11445.      */
  11446.     public static function MMULT($matrixData1,$matrixData2{
  11447.         $matrixAData $matrixBData array();
  11448.         if (!is_array($matrixData1)) $matrixData1 array(array($matrixData1))}
  11449.         if (!is_array($matrixData2)) $matrixData2 array(array($matrixData2))}
  11450.  
  11451.         $rowA 0;
  11452.         foreach($matrixData1 as $matrixRow{
  11453.             $columnA 0;
  11454.             foreach($matrixRow as $matrixCell{
  11455.                 if ((is_string($matrixCell)) || ($matrixCell === null)) {
  11456.                     return self::$_errorCodes['value'];
  11457.                 }
  11458.                 $matrixAData[$rowA][$columnA$matrixCell;
  11459.                 ++$columnA;
  11460.             }
  11461.             ++$rowA;
  11462.         }
  11463.         try {
  11464.             $matrixA new Matrix($matrixAData);
  11465.             $rowB 0;
  11466.             foreach($matrixData2 as $matrixRow{
  11467.                 $columnB 0;
  11468.                 foreach($matrixRow as $matrixCell{
  11469.                     if ((is_string($matrixCell)) || ($matrixCell === null)) {
  11470.                         return self::$_errorCodes['value'];
  11471.                     }
  11472.                     $matrixBData[$rowB][$columnB$matrixCell;
  11473.                     ++$columnB;
  11474.                 }
  11475.                 ++$rowB;
  11476.             }
  11477.             $matrixB new Matrix($matrixBData);
  11478.  
  11479.             if (($rowA != $columnB|| ($rowB != $columnA)) {
  11480.                 return self::$_errorCodes['value'];
  11481.             }
  11482.  
  11483.             return $matrixA->times($matrixB)->getArray();
  11484.         catch (Exception $ex{
  11485.             return self::$_errorCodes['value'];
  11486.         }
  11487.     }    //    function MMULT()
  11488.  
  11489.  
  11490.     /**
  11491.      * MINVERSE
  11492.      *
  11493.      * @param    array    $matrixValues    A matrix of values
  11494.      * @return    array 
  11495.      */
  11496.     public static function MINVERSE($matrixValues{
  11497.         $matrixData array();
  11498.         if (!is_array($matrixValues)) $matrixValues array(array($matrixValues))}
  11499.  
  11500.         $row $maxColumn 0;
  11501.         foreach($matrixValues as $matrixRow{
  11502.             $column 0;
  11503.             foreach($matrixRow as $matrixCell{
  11504.                 if ((is_string($matrixCell)) || ($matrixCell === null)) {
  11505.                     return self::$_errorCodes['value'];
  11506.                 }
  11507.                 $matrixData[$column][$row$matrixCell;
  11508.                 ++$column;
  11509.             }
  11510.             if ($column $maxColumn$maxColumn $column}
  11511.             ++$row;
  11512.         }
  11513.         if ($row != $maxColumnreturn self::$_errorCodes['value']}
  11514.  
  11515.         try {
  11516.             $matrix new Matrix($matrixData);
  11517.             return $matrix->inverse()->getArray();
  11518.         catch (Exception $ex{
  11519.             return self::$_errorCodes['value'];
  11520.         }
  11521.     }    //    function MINVERSE()
  11522.  
  11523.  
  11524.     /**
  11525.      * MDETERM
  11526.      *
  11527.      * @param    array    $matrixValues    A matrix of values
  11528.      * @return    float 
  11529.      */
  11530.     public static function MDETERM($matrixValues{
  11531.         $matrixData array();
  11532.         if (!is_array($matrixValues)) $matrixValues array(array($matrixValues))}
  11533.  
  11534.         $row $maxColumn 0;
  11535.         foreach($matrixValues as $matrixRow{
  11536.             $column 0;
  11537.             foreach($matrixRow as $matrixCell{
  11538.                 if ((is_string($matrixCell)) || ($matrixCell === null)) {
  11539.                     return self::$_errorCodes['value'];
  11540.                 }
  11541.                 $matrixData[$column][$row$matrixCell;
  11542.                 ++$column;
  11543.             }
  11544.             if ($column $maxColumn$maxColumn $column}
  11545.             ++$row;
  11546.         }
  11547.         if ($row != $maxColumnreturn self::$_errorCodes['value']}
  11548.  
  11549.         try {
  11550.             $matrix new Matrix($matrixData);
  11551.             return $matrix->det();
  11552.         catch (Exception $ex{
  11553.             return self::$_errorCodes['value'];
  11554.         }
  11555.     }    //    function MDETERM()
  11556.  
  11557.  
  11558.     /**
  11559.      * SUMPRODUCT
  11560.      *
  11561.      * @param    mixed    $value    Value to check
  11562.      * @return    float 
  11563.      */
  11564.     public static function SUMPRODUCT({
  11565.         $arrayList func_get_args();
  11566.  
  11567.         $wrkArray self::flattenArray(array_shift($arrayList));
  11568.         $wrkCellCount count($wrkArray);
  11569.  
  11570.         foreach($arrayList as $matrixData{
  11571.             $array2 self::flattenArray($matrixData);
  11572.             $count count($array2);
  11573.             if ($wrkCellCount != $count{
  11574.                 return self::$_errorCodes['value'];
  11575.             }
  11576.  
  11577.             foreach ($array2 as $i => $val{
  11578.                 if (((is_numeric($wrkArray[$i])) && (!is_string($wrkArray[$i]))) &&
  11579.                     ((is_numeric($val)) && (!is_string($val)))) {
  11580.                     $wrkArray[$i*= $val;
  11581.                 }
  11582.             }
  11583.         }
  11584.  
  11585.         return array_sum($wrkArray);
  11586.     }    //    function SUMPRODUCT()
  11587.  
  11588.  
  11589.     /**
  11590.      * SUMX2MY2
  11591.      *
  11592.      * @param    mixed    $value    Value to check
  11593.      * @return    float 
  11594.      */
  11595.     public static function SUMX2MY2($matrixData1,$matrixData2{
  11596.         $array1 self::flattenArray($matrixData1);
  11597.         $array2 self::flattenArray($matrixData2);
  11598.         $count1 count($array1);
  11599.         $count2 count($array2);
  11600.         if ($count1 $count2{
  11601.             $count $count1;
  11602.         else {
  11603.             $count $count2;
  11604.         }
  11605.  
  11606.         $result 0;
  11607.         for ($i 0$i $count++$i{
  11608.             if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
  11609.                 ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
  11610.                 $result += ($array1[$i$array1[$i]($array2[$i$array2[$i]);
  11611.             }
  11612.         }
  11613.  
  11614.         return $result;
  11615.     }    //    function SUMX2MY2()
  11616.  
  11617.  
  11618.     /**
  11619.      * SUMX2PY2
  11620.      *
  11621.      * @param    mixed    $value    Value to check
  11622.      * @return    float 
  11623.      */
  11624.     public static function SUMX2PY2($matrixData1,$matrixData2{
  11625.         $array1 self::flattenArray($matrixData1);
  11626.         $array2 self::flattenArray($matrixData2);
  11627.         $count1 count($array1);
  11628.         $count2 count($array2);
  11629.         if ($count1 $count2{
  11630.             $count $count1;
  11631.         else {
  11632.             $count $count2;
  11633.         }
  11634.  
  11635.         $result 0;
  11636.         for ($i 0$i $count++$i{
  11637.             if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
  11638.                 ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
  11639.                 $result += ($array1[$i$array1[$i]($array2[$i$array2[$i]);
  11640.             }
  11641.         }
  11642.  
  11643.         return $result;
  11644.     }    //    function SUMX2PY2()
  11645.  
  11646.  
  11647.     /**
  11648.      * SUMXMY2
  11649.      *
  11650.      * @param    mixed    $value    Value to check
  11651.      * @return    float 
  11652.      */
  11653.     public static function SUMXMY2($matrixData1,$matrixData2{
  11654.         $array1 self::flattenArray($matrixData1);
  11655.         $array2 self::flattenArray($matrixData2);
  11656.         $count1 count($array1);
  11657.         $count2 count($array2);
  11658.         if ($count1 $count2{
  11659.             $count $count1;
  11660.         else {
  11661.             $count $count2;
  11662.         }
  11663.  
  11664.         $result 0;
  11665.         for ($i 0$i $count++$i{
  11666.             if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
  11667.                 ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
  11668.                 $result += ($array1[$i$array2[$i]($array1[$i$array2[$i]);
  11669.             }
  11670.         }
  11671.  
  11672.         return $result;
  11673.     }    //    function SUMXMY2()
  11674.  
  11675.  
  11676.     private static function _vlookupSort($a,$b{
  11677.         $f array_keys($a);
  11678.         $firstColumn array_shift($f);
  11679.         if (strtolower($a[$firstColumn]== strtolower($b[$firstColumn])) {
  11680.             return 0;
  11681.         }
  11682.         return (strtolower($a[$firstColumn]strtolower($b[$firstColumn])) ? -1;
  11683.     }    //    function _vlookupSort()
  11684.  
  11685.  
  11686.     /**
  11687.     * VLOOKUP
  11688.     * 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.
  11689.     * @param    lookup_value    The value that you want to match in lookup_array
  11690.     * @param    lookup_array    The range of cells being searched
  11691.     * @param    index_number    The column number in table_array from which the matching value must be returned. The first column is 1.
  11692.     * @param    not_exact_match    Determines if you are looking for an exact match based on lookup_value.
  11693.     * @return    mixed            The value of the found cell
  11694.     */
  11695.     public static function VLOOKUP($lookup_value$lookup_array$index_number$not_exact_match=true{
  11696.         $lookup_value    self::flattenSingleValue($lookup_value);
  11697.         $index_number    self::flattenSingleValue($index_number);
  11698.         $not_exact_match    self::flattenSingleValue($not_exact_match);
  11699.  
  11700.         // index_number must be greater than or equal to 1
  11701.         if ($index_number 1{
  11702.             return self::$_errorCodes['value'];
  11703.         }
  11704.  
  11705.         // index_number must be less than or equal to the number of columns in lookup_array
  11706.         if ((!is_array($lookup_array)) || (count($lookup_array1)) {
  11707.             return self::$_errorCodes['reference'];
  11708.         else {
  11709.             $f array_keys($lookup_array);
  11710.             $firstRow array_pop($f);
  11711.             if ((!is_array($lookup_array[$firstRow])) || ($index_number count($lookup_array[$firstRow]))) {
  11712.                 return self::$_errorCodes['reference'];
  11713.             else {
  11714.                 $columnKeys array_keys($lookup_array[$firstRow]);
  11715.                 $returnColumn $columnKeys[--$index_number];
  11716.                 $firstColumn array_shift($columnKeys);
  11717.             }
  11718.         }
  11719.  
  11720.         if (!$not_exact_match{
  11721.             uasort($lookup_array,array('self','_vlookupSort'));
  11722.         }
  11723.  
  11724.         $rowNumber $rowValue False;
  11725.         foreach($lookup_array as $rowKey => $rowData{
  11726.             if (strtolower($rowData[$firstColumn]strtolower($lookup_value)) {
  11727.                 break;
  11728.             }
  11729.             $rowNumber $rowKey;
  11730.             $rowValue $rowData[$firstColumn];
  11731.         }
  11732.  
  11733.         if ($rowNumber !== false{
  11734.             if ((!$not_exact_match&& ($rowValue != $lookup_value)) {
  11735.                 //    if an exact match is required, we have what we need to return an appropriate response
  11736.                 return self::$_errorCodes['na'];
  11737.             else {
  11738.                 //    otherwise return the appropriate value
  11739.                 return $lookup_array[$rowNumber][$returnColumn];
  11740.             }
  11741.         }
  11742.  
  11743.         return self::$_errorCodes['na'];
  11744.     }    //    function VLOOKUP()
  11745.  
  11746.  
  11747.     /**
  11748.      * LOOKUP
  11749.      * The LOOKUP function searches for value either from a one-row or one-column range or from an array.
  11750.      * @param    lookup_value    The value that you want to match in lookup_array
  11751.      * @param    lookup_vector    The range of cells being searched
  11752.      * @param    result_vector    The column from which the matching value must be returned
  11753.      * @return    mixed            The value of the found cell
  11754.      */
  11755.     public static function LOOKUP($lookup_value$lookup_vector$result_vector=null{
  11756.         $lookup_value    self::flattenSingleValue($lookup_value);
  11757.  
  11758.         if (!is_array($lookup_vector)) {
  11759.             return self::$_errorCodes['na'];
  11760.         }
  11761.         $lookupRows count($lookup_vector);
  11762.         $l array_keys($lookup_vector);
  11763.         $l array_shift($l);
  11764.         $lookupColumns count($lookup_vector[$l]);
  11765.         if ((($lookupRows == 1&& ($lookupColumns 1)) || (($lookupRows == 2&& ($lookupColumns != 2))) {
  11766.             $lookup_vector self::TRANSPOSE($lookup_vector);
  11767.             $lookupRows count($lookup_vector);
  11768.             $l array_keys($lookup_vector);
  11769.             $lookupColumns count($lookup_vector[array_shift($l)]);
  11770.         }
  11771.  
  11772.         if (is_null($result_vector)) {
  11773.             $result_vector $lookup_vector;
  11774.         }
  11775.         $resultRows count($result_vector);
  11776.         $l array_keys($result_vector);
  11777.         $l array_shift($l);
  11778.         $resultColumns count($result_vector[$l]);
  11779.         if ((($resultRows == 1&& ($resultColumns 1)) || (($resultRows == 2&& ($resultColumns != 2))) {
  11780.             $result_vector self::TRANSPOSE($result_vector);
  11781.             $resultRows count($result_vector);
  11782.             $r array_keys($result_vector);
  11783.             $resultColumns count($result_vector[array_shift($r)]);
  11784.         }
  11785.  
  11786.         if ($lookupRows == 2{
  11787.             $result_vector array_pop($lookup_vector);
  11788.             $lookup_vector array_shift($lookup_vector);
  11789.         }
  11790.         if ($lookupColumns != 2{
  11791.             foreach($lookup_vector as &$value{
  11792.                 if (is_array($value)) {
  11793.                     $k array_keys($value);
  11794.                     $key1 $key2 array_shift($k);
  11795.                     $key2++;
  11796.                     $dataValue1 $value[$key1];
  11797.                 else {
  11798.                     $key1 0;
  11799.                     $key2 1;
  11800.                     $dataValue1 $value;
  11801.                 }
  11802.                 $dataValue2 array_shift($result_vector);
  11803.                 if (is_array($dataValue2)) {
  11804.                     $dataValue2 array_shift($dataValue2);
  11805.                 }
  11806.                 $value array($key1 => $dataValue1$key2 => $dataValue2);
  11807.             }
  11808.             unset($value);
  11809.         }
  11810.  
  11811.         return self::VLOOKUP($lookup_value,$lookup_vector,2);
  11812.      }    //    function LOOKUP()
  11813.  
  11814.  
  11815.     /**
  11816.      *    Convert a multi-dimensional array to a simple 1-dimensional array
  11817.      *
  11818.      *    @param    array    $array    Array to be flattened
  11819.      *    @return    array    Flattened array
  11820.      */
  11821.     public static function flattenArray($array{
  11822.         if (!is_array($array)) {
  11823.             return (array) $array;
  11824.         }
  11825.  
  11826.         $arrayValues array();
  11827.         foreach ($array as $value{
  11828.             if (is_array($value)) {
  11829.                 foreach ($value as $val{
  11830.                     if (is_array($val)) {
  11831.                         foreach ($val as $v{
  11832.                             $arrayValues[$v;
  11833.                         }
  11834.                     else {
  11835.                         $arrayValues[$val;
  11836.                     }
  11837.                 }
  11838.             else {
  11839.                 $arrayValues[$value;
  11840.             }
  11841.         }
  11842.  
  11843.         return $arrayValues;
  11844.     }    //    function flattenArray()
  11845.  
  11846.  
  11847.     /**
  11848.      *    Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing
  11849.      *
  11850.      *    @param    array    $array    Array to be flattened
  11851.      *    @return    array    Flattened array
  11852.      */
  11853.     public static function flattenArrayIndexed($array{
  11854.         if (!is_array($array)) {
  11855.             return (array) $array;
  11856.         }
  11857.  
  11858.         $arrayValues array();
  11859.         foreach ($array as $k1 => $value{
  11860.             if (is_array($value)) {
  11861.                 foreach ($value as $k2 => $val{
  11862.                     if (is_array($val)) {
  11863.                         foreach ($val as $k3 => $v{
  11864.                             $arrayValues[$k1.'.'.$k2.'.'.$k3$v;
  11865.                         }
  11866.                     else {
  11867.                         $arrayValues[$k1.'.'.$k2$val;
  11868.                     }
  11869.                 }
  11870.             else {
  11871.                 $arrayValues[$k1$value;
  11872.             }
  11873.         }
  11874.  
  11875.         return $arrayValues;
  11876.     }    //    function flattenArrayIndexed()
  11877.  
  11878.  
  11879.     /**
  11880.      *    Convert an array to a single scalar value by extracting the first element
  11881.      *
  11882.      *    @param    mixed        $value        Array or scalar value
  11883.      *    @return    mixed 
  11884.      */
  11885.     public static function flattenSingleValue($value ''{
  11886.         while (is_array($value)) {
  11887.             $value array_pop($value);
  11888.         }
  11889.  
  11890.         return $value;
  11891.     }    //    function flattenSingleValue()
  11892.  
  11893. }    //    class PHPExcel_Calculation_Functions
  11894.  
  11895.  
  11896. //
  11897. //    There are a few mathematical functions that aren't available on all versions of PHP for all platforms
  11898. //    These functions aren't available in Windows implementations of PHP prior to version 5.3.0
  11899. //    So we test if they do exist for this version of PHP/operating platform; and if not we create them
  11900. //
  11901. if (!function_exists('acosh')) {
  11902.     function acosh($x{
  11903.         return log(sqrt(($x 12sqrt(($x 12));
  11904.     }    //    function acosh()
  11905. }
  11906.  
  11907. if (!function_exists('asinh')) {
  11908.     function asinh($x{
  11909.         return log($x sqrt($x $x));
  11910.     }    //    function asinh()
  11911. }
  11912.  
  11913. if (!function_exists('atanh')) {
  11914.     function atanh($x{
  11915.         return (log($xlog($x)) 2;
  11916.     }    //    function atanh()
  11917. }
  11918.  
  11919. if (!function_exists('money_format')) {
  11920.     function money_format($format$number{
  11921.         $regex array'/%((?:[\^!\-]|\+|\(|\=.)*)([0-9]+)?(?:#([0-9]+))?',
  11922.                          '(?:\.([0-9]+))?([in%])/'
  11923.                       );
  11924.         $regex implode(''$regex);
  11925.         if (setlocale(LC_MONETARYnull== ''{
  11926.             setlocale(LC_MONETARY'');
  11927.         }
  11928.         $locale localeconv();
  11929.         $number floatval($number);
  11930.         if (!preg_match($regex$format$fmatch)) {
  11931.             trigger_error("No format specified or invalid format"E_USER_WARNING);
  11932.             return $number;
  11933.         }
  11934.         $flags array'fillchar'    => preg_match('/\=(.)/'$fmatch[1]$match$match[1' ',
  11935.                         'nogroup'    => preg_match('/\^/'$fmatch[1]0,
  11936.                         'usesignal'    => preg_match('/\+|\(/'$fmatch[1]$match$match[0'+',
  11937.                         'nosimbol'    => preg_match('/\!/'$fmatch[1]0,
  11938.                         'isleft'    => preg_match('/\-/'$fmatch[1]0
  11939.                       );
  11940.         $width    trim($fmatch[2]? (int)$fmatch[20;
  11941.         $left    trim($fmatch[3]? (int)$fmatch[30;
  11942.         $right    trim($fmatch[4]? (int)$fmatch[4$locale['int_frac_digits'];
  11943.         $conversion $fmatch[5];
  11944.         $positive true;
  11945.         if ($number 0{
  11946.             $positive false;
  11947.             $number *= -1;
  11948.         }
  11949.         $letter $positive 'p' 'n';
  11950.         $prefix $suffix $cprefix $csuffix $signal '';
  11951.         if (!$positive{
  11952.             $signal $locale['negative_sign'];
  11953.             switch (true{
  11954.                 case $locale['n_sign_posn'== || $flags['usesignal'== '(':
  11955.                     $prefix '(';
  11956.                     $suffix ')';
  11957.                     break;
  11958.                 case $locale['n_sign_posn'== 1:
  11959.                     $prefix $signal;
  11960.                     break;
  11961.                 case $locale['n_sign_posn'== 2:
  11962.                     $suffix $signal;
  11963.                     break;
  11964.                 case $locale['n_sign_posn'== 3:
  11965.                     $cprefix $signal;
  11966.                     break;
  11967.                 case $locale['n_sign_posn'== 4:
  11968.                     $csuffix $signal;
  11969.                     break;
  11970.             }
  11971.         }
  11972.         if (!$flags['nosimbol']{
  11973.             $currency $cprefix;
  11974.             $currency .= ($conversion == 'i' $locale['int_curr_symbol'$locale['currency_symbol']);
  11975.             $currency .= $csuffix;
  11976.             $currency iconv('ISO-8859-1','UTF-8',$currency);
  11977.         else {
  11978.             $currency '';
  11979.         }
  11980.         $space $locale["{$letter}_sep_by_space"' ' '';
  11981.  
  11982.         $number number_format($number$right$locale['mon_decimal_point']$flags['nogroup''' $locale['mon_thousands_sep');
  11983.         $number explode($locale['mon_decimal_point']$number);
  11984.  
  11985.         $n strlen($prefixstrlen($currency);
  11986.         if ($left && $left $n{
  11987.             if ($flags['isleft']{
  11988.                 $number[0.= str_repeat($flags['fillchar']$left $n);
  11989.             else {
  11990.                 $number[0str_repeat($flags['fillchar']$left $n$number[0];
  11991.             }
  11992.         }
  11993.         $number implode($locale['mon_decimal_point']$number);
  11994.         if ($locale["{$letter}_cs_precedes"]{
  11995.             $number $prefix $currency $space $number $suffix;
  11996.         else {
  11997.             $number $prefix $number $space $currency $suffix;
  11998.         }
  11999.         if ($width 0{
  12000.             $number str_pad($number$width$flags['fillchar']$flags['isleft'STR_PAD_RIGHT STR_PAD_LEFT);
  12001.         }
  12002.         $format str_replace($fmatch[0]$number$format);
  12003.         return $format;
  12004.     }    //    function money_format()
  12005. }
  12006.  
  12007.  
  12008. //
  12009. //    Strangely, PHP doesn't have a mb_str_replace multibyte function
  12010. //    As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set
  12011. //
  12012. if ((!function_exists('mb_str_replace')) &&
  12013.     (function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos'))) {
  12014.     function mb_str_replace($search$replace$subject{
  12015.         if(is_array($subject)) {
  12016.             $ret array();
  12017.             foreach($subject as $key => $val{
  12018.                 $ret[$keymb_str_replace($search$replace$val);
  12019.             }
  12020.             return $ret;
  12021.         }
  12022.  
  12023.         foreach((array) $search as $key => $s{
  12024.             if($s == ''{
  12025.                 continue;
  12026.             }
  12027.             $r !is_array($replace$replace (array_key_exists($key$replace$replace[$key'');
  12028.             $pos mb_strpos($subject$s0'UTF-8');
  12029.             while($pos !== false{
  12030.                 $subject mb_substr($subject0$pos'UTF-8'$r mb_substr($subject$pos mb_strlen($s'UTF-8')65535'UTF-8');
  12031.                 $pos mb_strpos($subject$s$pos mb_strlen($r'UTF-8')'UTF-8');
  12032.             }
  12033.         }
  12034.         return $subject;
  12035.     }
  12036. }

Documentation generated on Thu, 26 Aug 2010 17:43:09 +0200 by phpDocumentor 1.4.3