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.2, 2010-01-11
  26.  */
  27.  
  28.  
  29. /** EPS */
  30. define('EPS'2.22e-16);
  31.  
  32. /** MAX_VALUE */
  33. define('MAX_VALUE'1.2e308);
  34.  
  35. /** LOG_GAMMA_X_MAX_VALUE */
  36. define('LOG_GAMMA_X_MAX_VALUE'2.55e305);
  37.  
  38. /** SQRT2PI */
  39. define('SQRT2PI'2.5066282746310005024157652848110452530069867406099);
  40.  
  41. /** 2 / PI */
  42. define('M_2DIVPI'0.63661977236758134307553505349006);
  43.  
  44. /** XMININ */
  45. define('XMININ'2.23e-308);
  46.  
  47. /** MAX_ITERATIONS */
  48. define('MAX_ITERATIONS'256);
  49. /** FINANCIAL_MAX_ITERATIONS */
  50. define('FINANCIAL_MAX_ITERATIONS'128);
  51.  
  52. /** PRECISION */
  53. define('PRECISION'8.88E-016);
  54. /** FINANCIAL_PRECISION */
  55. define('FINANCIAL_PRECISION'1.0e-08);
  56.  
  57. /** EULER */
  58. define('EULER'2.71828182845904523536);
  59.  
  60. $savedPrecision ini_get('precision');
  61. if ($savedPrecision 16{
  62.     ini_set('precision',16);
  63. }
  64.  
  65.  
  66. /** PHPExcel root directory */
  67. if (!defined('PHPEXCEL_ROOT')) {
  68.     /**
  69.      * @ignore
  70.      */
  71.     define('PHPEXCEL_ROOT'dirname(__FILE__'/../../');
  72. }
  73.  
  74. /** PHPExcel_Cell */
  75. require_once PHPEXCEL_ROOT 'PHPExcel/Cell.php';
  76.  
  77. /** PHPExcel_Calculation */
  78. require_once PHPEXCEL_ROOT 'PHPExcel/Calculation.php';
  79.  
  80. /** PHPExcel_Cell_DataType */
  81. require_once PHPEXCEL_ROOT 'PHPExcel/Cell/DataType.php';
  82.  
  83. /** PHPExcel_Style_NumberFormat */
  84. require_once PHPEXCEL_ROOT 'PHPExcel/Style/NumberFormat.php';
  85.  
  86. /** PHPExcel_Shared_Date */
  87. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/Date.php';
  88.  
  89. /** Matrix */
  90. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/JAMA/Matrix.php';
  91. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/trend/trendClass.php';
  92.  
  93.  
  94. /**
  95.  * PHPExcel_Calculation_Functions
  96.  *
  97.  * @category    PHPExcel
  98.  * @package        PHPExcel_Calculation
  99.  * @copyright    Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel)
  100.  */
  101.  
  102.     /** constants */
  103.     const COMPATIBILITY_EXCEL        'Excel';
  104.     const COMPATIBILITY_GNUMERIC    'Gnumeric';
  105.     const COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc';
  106.  
  107.     const RETURNDATE_PHP_NUMERIC    'P';
  108.     const RETURNDATE_PHP_OBJECT        'O';
  109.     const RETURNDATE_EXCEL            'E';
  110.  
  111.  
  112.     /**
  113.      *    Compatibility mode to use for error checking and responses
  114.      *
  115.      *    @access    private
  116.      *    @var string 
  117.      */
  118.     private static $compatibilityMode    self::COMPATIBILITY_EXCEL;
  119.  
  120.     /**
  121.      *    Data Type to use when returning date values
  122.      *
  123.      *    @access    private
  124.      *    @var integer 
  125.      */
  126.     private static $ReturnDateType    self::RETURNDATE_EXCEL;
  127.  
  128.     /**
  129.      *    List of error codes
  130.      *
  131.      *    @access    private
  132.      *    @var array 
  133.      */
  134.     private static $_errorCodes    array'null'                => '#NULL!',
  135.                                          'divisionbyzero'    => '#DIV/0!',
  136.                                          'value'            => '#VALUE!',
  137.                                          'reference'        => '#REF!',
  138.                                          'name'                => '#NAME?',
  139.                                          'num'                => '#NUM!',
  140.                                          'na'                => '#N/A',
  141.                                          'gettingdata'        => '#GETTING_DATA'
  142.                                        );
  143.  
  144.  
  145.     /**
  146.      *    Set the Compatibility Mode
  147.      *
  148.      *    @access    public
  149.      *    @category Function Configuration
  150.      *    @param     string        $compatibilityMode        Compatibility Mode
  151.      *                                                 Permitted values are:
  152.      *                                                     PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL            'Excel'
  153.      *                                                     PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
  154.      *                                                     PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
  155.      *    @return     boolean    (Success or Failure)
  156.      */
  157.     public static function setCompatibilityMode($compatibilityMode{
  158.         if (($compatibilityMode == self::COMPATIBILITY_EXCEL||
  159.             ($compatibilityMode == self::COMPATIBILITY_GNUMERIC||
  160.             ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  161.             self::$compatibilityMode $compatibilityMode;
  162.             return True;
  163.         }
  164.         return False;
  165.     }    //    function setCompatibilityMode()
  166.  
  167.  
  168.     /**
  169.      *    Return the current Compatibility Mode
  170.      *
  171.      *    @access    public
  172.      *    @category Function Configuration
  173.      *    @return     string        Compatibility Mode
  174.      *                             Possible Return values are:
  175.      *                                 PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL            'Excel'
  176.      *                                 PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
  177.      *                                 PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
  178.      */
  179.     public static function getCompatibilityMode({
  180.         return self::$compatibilityMode;
  181.     }    //    function getCompatibilityMode()
  182.  
  183.  
  184.     /**
  185.      *    Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
  186.      *
  187.      *    @access    public
  188.      *    @category Function Configuration
  189.      *    @param     string    $returnDateType            Return Date Format
  190.      *                                                 Permitted values are:
  191.      *                                                     PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC        'P'
  192.      *                                                     PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT        'O'
  193.      *                                                     PHPExcel_Calculation_Functions::RETURNDATE_EXCEL            'E'
  194.      *    @return     boolean                            Success or failure
  195.      */
  196.     public static function setReturnDateType($returnDateType{
  197.         if (($returnDateType == self::RETURNDATE_PHP_NUMERIC||
  198.             ($returnDateType == self::RETURNDATE_PHP_OBJECT||
  199.             ($returnDateType == self::RETURNDATE_EXCEL)) {
  200.             self::$ReturnDateType $returnDateType;
  201.             return True;
  202.         }
  203.         return False;
  204.     }    //    function setReturnDateType()
  205.  
  206.  
  207.     /**
  208.      *    Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
  209.      *
  210.      *    @access    public
  211.      *    @category Function Configuration
  212.      *    @return     string        Return Date Format
  213.      *                             Possible Return values are:
  214.      *                                 PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC        'P'
  215.      *                                 PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT        'O'
  216.      *                                 PHPExcel_Calculation_Functions::RETURNDATE_EXCEL            'E'
  217.      */
  218.     public static function getReturnDateType({
  219.         return self::$ReturnDateType;
  220.     }    //    function getReturnDateType()
  221.  
  222.  
  223.     /**
  224.      *    DUMMY
  225.      *
  226.      *    @access    public
  227.      *    @category Error Returns
  228.      *    @return    string    #Not Yet Implemented
  229.      */
  230.     public static function DUMMY({
  231.         return '#Not Yet Implemented';
  232.     }    //    function DUMMY()
  233.  
  234.  
  235.     /**
  236.      *    NA
  237.      *
  238.      *    @access    public
  239.      *    @category Error Returns
  240.      *    @return    string    #N/A!
  241.      */
  242.     public static function NA({
  243.         return self::$_errorCodes['na'];
  244.     }    //    function NA()
  245.  
  246.  
  247.     /**
  248.      *    NAN
  249.      *
  250.      *    @access    public
  251.      *    @category Error Returns
  252.      *    @return    string    #NUM!
  253.      */
  254.     public static function NaN({
  255.         return self::$_errorCodes['num'];
  256.     }    //    function NAN()
  257.  
  258.  
  259.     /**
  260.      *    NAME
  261.      *
  262.      *    @access    public
  263.      *    @category Error Returns
  264.      *    @return    string    #NAME!
  265.      */
  266.     public static function NAME({
  267.         return self::$_errorCodes['name'];
  268.     }    //    function NAME()
  269.  
  270.  
  271.     /**
  272.      *    REF
  273.      *
  274.      *    @access    public
  275.      *    @category Error Returns
  276.      *    @return    string    #REF!
  277.      */
  278.     public static function REF({
  279.         return self::$_errorCodes['reference'];
  280.     }    //    function REF()
  281.  
  282.  
  283.     /**
  284.      *    VALUE
  285.      *
  286.      *    @access    public
  287.      *    @category Error Returns
  288.      *    @return    string    #VALUE!
  289.      */
  290.     public static function VALUE({
  291.         return self::$_errorCodes['value'];
  292.     }    //    function VALUE()
  293.  
  294.  
  295.     private static function isMatrixValue($idx{
  296.         return ((substr_count($idx,'.'<= 1|| (preg_match('/\.[A-Z]/',$idx0));
  297.     }
  298.  
  299.  
  300.     private static function isValue($idx{
  301.         return (substr_count($idx,'.'== 0);
  302.     }
  303.  
  304.  
  305.     private static function isCellValue($idx{
  306.         return (substr_count($idx,'.'1);
  307.     }
  308.  
  309.  
  310.     /**
  311.      *    LOGICAL_AND
  312.      *
  313.      *    Returns boolean TRUE if all its arguments are TRUE; returns FALSE if one or more argument is FALSE.
  314.      *
  315.      *    Excel Function:
  316.      *        =AND(logical1[,logical2[, ...]])
  317.      *
  318.      *        The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
  319.      *            or references that contain logical values.
  320.      *
  321.      *        Boolean arguments are treated as True or False as appropriate
  322.      *        Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  323.      *        If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
  324.      *            the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
  325.      *
  326.      *    @access    public
  327.      *    @category Logical Functions
  328.      *    @param    mixed        $arg,...        Data values
  329.      *    @return    boolean        The logical AND of the arguments.
  330.      */
  331.     public static function LOGICAL_AND({
  332.         // Return value
  333.         $returnValue True;
  334.  
  335.         // Loop through the arguments
  336.         $aArgs self::flattenArray(func_get_args());
  337.         $argCount 0;
  338.         foreach ($aArgs as $arg{
  339.             // Is it a boolean value?
  340.             if (is_bool($arg)) {
  341.                 $returnValue $returnValue && $arg;
  342.             elseif ((is_numeric($arg)) && (!is_string($arg))) {
  343.                 $returnValue $returnValue && ($arg != 0);
  344.             elseif (is_string($arg)) {
  345.                 $arg strtoupper($arg);
  346.                 if ($arg == 'TRUE'{
  347.                     $arg 1;
  348.                 elseif ($arg == 'FALSE'{
  349.                     $arg 0;
  350.                 else {
  351.                     return self::$_errorCodes['value'];
  352.                 }
  353.                 $returnValue $returnValue && ($arg != 0);
  354.             }
  355.             ++$argCount;
  356.         }
  357.  
  358.         // Return
  359.         if ($argCount == 0{
  360.             return self::$_errorCodes['value'];
  361.         }
  362.         return $returnValue;
  363.     }    //    function LOGICAL_AND()
  364.  
  365.  
  366.     /**
  367.      *    LOGICAL_OR
  368.      *
  369.      *    Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE.
  370.      *
  371.      *    Excel Function:
  372.      *        =OR(logical1[,logical2[, ...]])
  373.      *
  374.      *        The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
  375.      *            or references that contain logical values.
  376.      *
  377.      *        Boolean arguments are treated as True or False as appropriate
  378.      *        Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  379.      *        If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
  380.      *            the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
  381.      *
  382.      *    @access    public
  383.      *    @category Logical Functions
  384.      *    @param    mixed        $arg,...        Data values
  385.      *    @return    boolean        The logical OR of the arguments.
  386.      */
  387.     public static function LOGICAL_OR({
  388.         // Return value
  389.         $returnValue False;
  390.  
  391.         // Loop through the arguments
  392.         $aArgs self::flattenArray(func_get_args());
  393.         $argCount 0;
  394.         foreach ($aArgs as $arg{
  395.             // Is it a boolean value?
  396.             if (is_bool($arg)) {
  397.                 $returnValue $returnValue || $arg;
  398.             elseif ((is_numeric($arg)) && (!is_string($arg))) {
  399.                 $returnValue $returnValue || ($arg != 0);
  400.             elseif (is_string($arg)) {
  401.                 $arg strtoupper($arg);
  402.                 if ($arg == 'TRUE'{
  403.                     $arg 1;
  404.                 elseif ($arg == 'FALSE'{
  405.                     $arg 0;
  406.                 else {
  407.                     return self::$_errorCodes['value'];
  408.                 }
  409.                 $returnValue $returnValue || ($arg != 0);
  410.             }
  411.             ++$argCount;
  412.         }
  413.  
  414.         // Return
  415.         if ($argCount == 0{
  416.             return self::$_errorCodes['value'];
  417.         }
  418.         return $returnValue;
  419.     }    //    function LOGICAL_OR()
  420.  
  421.  
  422.     /**
  423.      *    LOGICAL_FALSE
  424.      *
  425.      *    Returns the boolean FALSE.
  426.      *
  427.      *    Excel Function:
  428.      *        =FALSE()
  429.      *
  430.      *    @access    public
  431.      *    @category Logical Functions
  432.      *    @return    boolean        False
  433.      */
  434.     public static function LOGICAL_FALSE({
  435.         return False;
  436.     }    //    function LOGICAL_FALSE()
  437.  
  438.  
  439.     /**
  440.      *    LOGICAL_TRUE
  441.      *
  442.      *    Returns the boolean TRUE.
  443.      *
  444.      *    Excel Function:
  445.      *        =TRUE()
  446.      *
  447.      *    @access    public
  448.      *    @category Logical Functions
  449.      *    @return    boolean        True
  450.      */
  451.     public static function LOGICAL_TRUE({
  452.         return True;
  453.     }    //    function LOGICAL_TRUE()
  454.  
  455.  
  456.     /**
  457.      *    LOGICAL_NOT
  458.      *
  459.      *    Returns the boolean inverse of the argument.
  460.      *
  461.      *    Excel Function:
  462.      *        =NOT(logical)
  463.      *
  464.      *        The argument must evaluate to a logical value such as TRUE or FALSE
  465.      *
  466.      *        Boolean arguments are treated as True or False as appropriate
  467.      *        Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  468.      *        If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
  469.      *            the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
  470.      *
  471.      *    @access    public
  472.      *    @category Logical Functions
  473.      *    @param    mixed        $logical    A value or expression that can be evaluated to TRUE or FALSE
  474.      *    @return    boolean        The boolean inverse of the argument.
  475.      */
  476.     public static function LOGICAL_NOT($logical{
  477.         $logical self::flattenSingleValue($logical);
  478.         if (is_string($logical)) {
  479.             $logical strtoupper($logical);
  480.             if ($logical == 'TRUE'{
  481.                 return False;
  482.             elseif ($logical == 'FALSE'{
  483.                 return True;
  484.             else {
  485.                 return self::$_errorCodes['value'];
  486.             }
  487.         }
  488.  
  489.         return !$logical;
  490.     }    //    function LOGICAL_NOT()
  491.  
  492.  
  493.     /**
  494.      *    STATEMENT_IF
  495.      *
  496.      *    Returns one value if a condition you specify evaluates to TRUE and another value if it evaluates to FALSE.
  497.      *
  498.      *    Excel Function:
  499.      *        =IF(condition[,returnIfTrue[,returnIfFalse]])
  500.      *
  501.      *        Condition is any value or expression that can be evaluated to TRUE or FALSE.
  502.      *            For example, A10=100 is a logical expression; if the value in cell A10 is equal to 100,
  503.      *            the expression evaluates to TRUE. Otherwise, the expression evaluates to FALSE.
  504.      *            This argument can use any comparison calculation operator.
  505.      *        ReturnIfTrue is the value that is returned if condition evaluates to TRUE.
  506.      *            For example, if this argument is the text string "Within budget" and the condition argument evaluates to TRUE,
  507.      *            then the IF function returns the text "Within budget"
  508.      *            If condition is TRUE and ReturnIfTrue is blank, this argument returns 0 (zero). To display the word TRUE, use
  509.      *            the logical value TRUE for this argument.
  510.      *            ReturnIfTrue can be another formula.
  511.      *        ReturnIfFalse is the value that is returned if condition evaluates to FALSE.
  512.      *            For example, if this argument is the text string "Over budget" and the condition argument evaluates to FALSE,
  513.      *            then the IF function returns the text "Over budget".
  514.      *            If condition is FALSE and ReturnIfFalse is omitted, then the logical value FALSE is returned.
  515.      *            If condition is FALSE and ReturnIfFalse is blank, then the value 0 (zero) is returned.
  516.      *            ReturnIfFalse can be another formula.
  517.      *
  518.      *    @access    public
  519.      *    @category Logical Functions
  520.      *    @param    mixed    $condition        Condition to evaluate
  521.      *    @param    mixed    $returnIfTrue    Value to return when condition is true
  522.      *    @param    mixed    $returnIfFalse    Optional value to return when condition is false
  523.      *    @return    mixed    The value of returnIfTrue or returnIfFalse determined by condition
  524.      */
  525.     public static function STATEMENT_IF($condition true$returnIfTrue 0$returnIfFalse False{
  526.         $condition        (is_null($condition))        True :    (boolean) self::flattenSingleValue($condition);
  527.         $returnIfTrue    (is_null($returnIfTrue))    :        self::flattenSingleValue($returnIfTrue);
  528.         $returnIfFalse    (is_null($returnIfFalse))    False :    self::flattenSingleValue($returnIfFalse);
  529.  
  530.         return ($condition $returnIfTrue $returnIfFalse);
  531.     }    //    function STATEMENT_IF()
  532.  
  533.  
  534.     /**
  535.      *    STATEMENT_IFERROR
  536.      *
  537.      *    Excel Function:
  538.      *        =IFERROR(testValue,errorpart)
  539.      *
  540.      *    @access    public
  541.      *    @category Logical Functions
  542.      *    @param    mixed    $testValue    Value to check, is also the value returned when no error
  543.      *    @param    mixed    $errorpart    Value to return when testValue is an error condition
  544.      *    @return    mixed    The value of errorpart or testValue determined by error condition
  545.      */
  546.     public static function STATEMENT_IFERROR($testValue ''$errorpart ''{
  547.         $testValue    (is_null($testValue))    '' :    self::flattenSingleValue($testValue);
  548.         $errorpart    (is_null($errorpart))    '' :    self::flattenSingleValue($errorpart);
  549.  
  550.         return self::STATEMENT_IF(self::IS_ERROR($testValue)$errorpart$testValue);
  551.     }    //    function STATEMENT_IFERROR()
  552.  
  553.  
  554.     /**
  555.      *    ATAN2
  556.      *
  557.      *    This function calculates the arc tangent of the two variables x and y. It is similar to
  558.      *        calculating the arc tangent of y ÷ x, except that the signs of both arguments are used
  559.      *        to determine the quadrant of the result.
  560.      *    The arctangent is the angle from the x-axis to a line containing the origin (0, 0) and a
  561.      *        point with coordinates (xCoordinate, yCoordinate). The angle is given in radians between
  562.      *        -pi and pi, excluding -pi.
  563.      *
  564.      *    Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard
  565.      *        PHP atan2() function, so we need to reverse them here before calling the PHP atan() function.
  566.      *
  567.      *    Excel Function:
  568.      *        ATAN2(xCoordinate,yCoordinate)
  569.      *
  570.      *    @access    public
  571.      *    @category Mathematical and Trigonometric Functions
  572.      *    @param    float    $xCoordinate        The x-coordinate of the point.
  573.      *    @param    float    $yCoordinate        The y-coordinate of the point.
  574.      *    @return    float    The inverse tangent of the specified x- and y-coordinates.
  575.      */
  576.     public static function REVERSE_ATAN2($xCoordinate$yCoordinate{
  577.         $xCoordinate    = (float) self::flattenSingleValue($xCoordinate);
  578.         $yCoordinate    = (float) self::flattenSingleValue($yCoordinate);
  579.  
  580.         if (($xCoordinate == 0&& ($yCoordinate == 0)) {
  581.             return self::$_errorCodes['divisionbyzero'];
  582.         }
  583.  
  584.         return atan2($yCoordinate$xCoordinate);
  585.     }    //    function REVERSE_ATAN2()
  586.  
  587.  
  588.     /**
  589.      *    LOG_BASE
  590.      *
  591.      *    Returns the logarithm of a number to a specified base. The default base is 10.
  592.      *
  593.      *    Excel Function:
  594.      *        LOG(number[,base])
  595.      *
  596.      *    @access    public
  597.      *    @category Mathematical and Trigonometric Functions
  598.      *    @param    float    $value        The positive real number for which you want the logarithm
  599.      *    @param    float    $base        The base of the logarithm. If base is omitted, it is assumed to be 10.
  600.      *    @return    float 
  601.      */
  602.     public static function LOG_BASE($number$base=10{
  603.         $number    self::flattenSingleValue($number);
  604.         $base    (is_null($base))    10 :    (float) self::flattenSingleValue($base);
  605.  
  606.         return log($number$base);
  607.     }    //    function LOG_BASE()
  608.  
  609.  
  610.     /**
  611.      *    SUM
  612.      *
  613.      *    SUM computes the sum of all the values and cells referenced in the argument list.
  614.      *
  615.      *    Excel Function:
  616.      *        SUM(value1[,value2[, ...]])
  617.      *
  618.      *    @access    public
  619.      *    @category Mathematical and Trigonometric Functions
  620.      *    @param    mixed        $arg,...        Data values
  621.      *    @return    float 
  622.      */
  623.     public static function SUM({
  624.         // Return value
  625.         $returnValue 0;
  626.  
  627.         // Loop through the arguments
  628.         $aArgs self::flattenArray(func_get_args());
  629.         foreach ($aArgs as $arg{
  630.             // Is it a numeric value?
  631.             if ((is_numeric($arg)) && (!is_string($arg))) {
  632.                 $returnValue += $arg;
  633.             }
  634.         }
  635.  
  636.         // Return
  637.         return $returnValue;
  638.     }    //    function SUM()
  639.  
  640.  
  641.     /**
  642.      *    SUMSQ
  643.      *
  644.      *    SUMSQ returns the sum of the squares of the arguments
  645.      *
  646.      *    Excel Function:
  647.      *        SUMSQ(value1[,value2[, ...]])
  648.      *
  649.      *    @access    public
  650.      *    @category Mathematical and Trigonometric Functions
  651.      *    @param    mixed        $arg,...        Data values
  652.      *    @return    float 
  653.      */
  654.     public static function SUMSQ({
  655.         // Return value
  656.         $returnValue 0;
  657.  
  658.         // Loop through arguments
  659.         $aArgs self::flattenArray(func_get_args());
  660.         foreach ($aArgs as $arg{
  661.             // Is it a numeric value?
  662.             if ((is_numeric($arg)) && (!is_string($arg))) {
  663.                 $returnValue += ($arg $arg);
  664.             }
  665.         }
  666.  
  667.         // Return
  668.         return $returnValue;
  669.     }    //    function SUMSQ()
  670.  
  671.  
  672.     /**
  673.      *    PRODUCT
  674.      *
  675.      *    PRODUCT returns the product of all the values and cells referenced in the argument list.
  676.      *
  677.      *    Excel Function:
  678.      *        PRODUCT(value1[,value2[, ...]])
  679.      *
  680.      *    @access    public
  681.      *    @category Mathematical and Trigonometric Functions
  682.      *    @param    mixed        $arg,...        Data values
  683.      *    @return    float 
  684.      */
  685.     public static function PRODUCT({
  686.         // Return value
  687.         $returnValue null;
  688.  
  689.         // Loop through arguments
  690.         $aArgs self::flattenArray(func_get_args());
  691.         foreach ($aArgs as $arg{
  692.             // Is it a numeric value?
  693.             if ((is_numeric($arg)) && (!is_string($arg))) {
  694.                 if (is_null($returnValue)) {
  695.                     $returnValue $arg;
  696.                 else {
  697.                     $returnValue *= $arg;
  698.                 }
  699.             }
  700.         }
  701.  
  702.         // Return
  703.         if (is_null($returnValue)) {
  704.             return 0;
  705.         }
  706.         return $returnValue;
  707.     }    //    function PRODUCT()
  708.  
  709.  
  710.     /**
  711.      *    QUOTIENT
  712.      *
  713.      *    QUOTIENT function returns the integer portion of a division. Numerator is the divided number
  714.      *        and denominator is the divisor.
  715.      *
  716.      *    Excel Function:
  717.      *        QUOTIENT(value1[,value2[, ...]])
  718.      *
  719.      *    @access    public
  720.      *    @category Mathematical and Trigonometric Functions
  721.      *    @param    mixed        $arg,...        Data values
  722.      *    @return    float 
  723.      */
  724.     public static function QUOTIENT({
  725.         // Return value
  726.         $returnValue null;
  727.  
  728.         // Loop through arguments
  729.         $aArgs self::flattenArray(func_get_args());
  730.         foreach ($aArgs as $arg{
  731.             // Is it a numeric value?
  732.             if ((is_numeric($arg)) && (!is_string($arg))) {
  733.                 if (is_null($returnValue)) {
  734.                     $returnValue ($arg == 0$arg;
  735.                 else {
  736.                     if (($returnValue == 0|| ($arg == 0)) {
  737.                         $returnValue 0;
  738.                     else {
  739.                         $returnValue /= $arg;
  740.                     }
  741.                 }
  742.             }
  743.         }
  744.  
  745.         // Return
  746.         return intval($returnValue);
  747.     }    //    function QUOTIENT()
  748.  
  749.  
  750.     /**
  751.      *    MIN
  752.      *
  753.      *    MIN returns the value of the element of the values passed that has the smallest value,
  754.      *        with negative numbers considered smaller than positive numbers.
  755.      *
  756.      *    Excel Function:
  757.      *        MIN(value1[,value2[, ...]])
  758.      *
  759.      *    @access    public
  760.      *    @category Statistical Functions
  761.      *    @param    mixed        $arg,...        Data values
  762.      *    @return    float 
  763.      */
  764.     public static function MIN({
  765.         // Return value
  766.         $returnValue null;
  767.  
  768.         // Loop through arguments
  769.         $aArgs self::flattenArray(func_get_args());
  770.         foreach ($aArgs as $arg{
  771.             // Is it a numeric value?
  772.             if ((is_numeric($arg)) && (!is_string($arg))) {
  773.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  774.                     $returnValue $arg;
  775.                 }
  776.             }
  777.         }
  778.  
  779.         // Return
  780.         if(is_null($returnValue)) {
  781.             return 0;
  782.         }
  783.         return $returnValue;
  784.     }    //    function MIN()
  785.  
  786.  
  787.     /**
  788.      *    MINA
  789.      *
  790.      *    Returns the smallest value in a list of arguments, including numbers, text, and logical values
  791.      *
  792.      *    Excel Function:
  793.      *        MINA(value1[,value2[, ...]])
  794.      *
  795.      *    @access    public
  796.      *    @category Statistical Functions
  797.      *    @param    mixed        $arg,...        Data values
  798.      *    @return    float 
  799.      */
  800.     public static function MINA({
  801.         // Return value
  802.         $returnValue null;
  803.  
  804.         // Loop through arguments
  805.         $aArgs self::flattenArray(func_get_args());
  806.         foreach ($aArgs as $arg{
  807.             // Is it a numeric value?
  808.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  809.                 if (is_bool($arg)) {
  810.                     $arg = (integer) $arg;
  811.                 elseif (is_string($arg)) {
  812.                     $arg 0;
  813.                 }
  814.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  815.                     $returnValue $arg;
  816.                 }
  817.             }
  818.         }
  819.  
  820.         // Return
  821.         if(is_null($returnValue)) {
  822.             return 0;
  823.         }
  824.         return $returnValue;
  825.     }    //    function MINA()
  826.  
  827.  
  828.     /**
  829.      *    SMALL
  830.      *
  831.      *    Returns the nth smallest value in a data set. You can use this function to
  832.      *        select a value based on its relative standing.
  833.      *
  834.      *    Excel Function:
  835.      *        SMALL(value1[,value2[, ...]],entry)
  836.      *
  837.      *    @access    public
  838.      *    @category Statistical Functions
  839.      *    @param    mixed        $arg,...        Data values
  840.      *    @param    int            $entry            Position (ordered from the smallest) in the array or range of data to return
  841.      *    @return    float 
  842.      */
  843.     public static function SMALL({
  844.         $aArgs self::flattenArray(func_get_args());
  845.  
  846.         // Calculate
  847.         $entry array_pop($aArgs);
  848.  
  849.         if ((is_numeric($entry)) && (!is_string($entry))) {
  850.             $mArgs array();
  851.             foreach ($aArgs as $arg{
  852.                 // Is it a numeric value?
  853.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  854.                     $mArgs[$arg;
  855.                 }
  856.             }
  857.             $count self::COUNT($mArgs);
  858.             $entry floor(--$entry);
  859.             if (($entry 0|| ($entry >= $count|| ($count == 0)) {
  860.                 return self::$_errorCodes['num'];
  861.             }
  862.             sort($mArgs);
  863.             return $mArgs[$entry];
  864.         }
  865.         return self::$_errorCodes['value'];
  866.     }    //    function SMALL()
  867.  
  868.  
  869.     /**
  870.      *    MAX
  871.      *
  872.      *    MAX returns the value of the element of the values passed that has the highest value,
  873.      *        with negative numbers considered smaller than positive numbers.
  874.      *
  875.      *    Excel Function:
  876.      *        MAX(value1[,value2[, ...]])
  877.      *
  878.      *    @access    public
  879.      *    @category Statistical Functions
  880.      *    @param    mixed        $arg,...        Data values
  881.      *    @return    float 
  882.      */
  883.     public static function MAX({
  884.         // Return value
  885.         $returnValue null;
  886.  
  887.         // Loop through arguments
  888.         $aArgs self::flattenArray(func_get_args());
  889.         foreach ($aArgs as $arg{
  890.             // Is it a numeric value?
  891.             if ((is_numeric($arg)) && (!is_string($arg))) {
  892.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  893.                     $returnValue $arg;
  894.                 }
  895.             }
  896.         }
  897.  
  898.         // Return
  899.         if(is_null($returnValue)) {
  900.             return 0;
  901.         }
  902.         return $returnValue;
  903.     }    //    function MAX()
  904.  
  905.  
  906.     /**
  907.      *    MAXA
  908.      *
  909.      *    Returns the greatest value in a list of arguments, including numbers, text, and logical values
  910.      *
  911.      *    Excel Function:
  912.      *        MAXA(value1[,value2[, ...]])
  913.      *
  914.      *    @access    public
  915.      *    @category Statistical Functions
  916.      *    @param    mixed        $arg,...        Data values
  917.      *    @return    float 
  918.      */
  919.     public static function MAXA({
  920.         // Return value
  921.         $returnValue null;
  922.  
  923.         // Loop through arguments
  924.         $aArgs self::flattenArray(func_get_args());
  925.         foreach ($aArgs as $arg{
  926.             // Is it a numeric value?
  927.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  928.                 if (is_bool($arg)) {
  929.                     $arg = (integer) $arg;
  930.                 elseif (is_string($arg)) {
  931.                     $arg 0;
  932.                 }
  933.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  934.                     $returnValue $arg;
  935.                 }
  936.             }
  937.         }
  938.  
  939.         // Return
  940.         if(is_null($returnValue)) {
  941.             return 0;
  942.         }
  943.         return $returnValue;
  944.     }    //    function MAXA()
  945.  
  946.  
  947.     /**
  948.      *    LARGE
  949.      *
  950.      *    Returns the nth largest value in a data set. You can use this function to
  951.      *        select a value based on its relative standing.
  952.      *
  953.      *    Excel Function:
  954.      *        LARGE(value1[,value2[, ...]],entry)
  955.      *
  956.      *    @access    public
  957.      *    @category Statistical Functions
  958.      *    @param    mixed        $arg,...        Data values
  959.      *    @param    int            $entry            Position (ordered from the largest) in the array or range of data to return
  960.      *    @return    float 
  961.      *
  962.      */
  963.     public static function LARGE({
  964.         $aArgs self::flattenArray(func_get_args());
  965.  
  966.         // Calculate
  967.         $entry floor(array_pop($aArgs));
  968.  
  969.         if ((is_numeric($entry)) && (!is_string($entry))) {
  970.             $mArgs array();
  971.             foreach ($aArgs as $arg{
  972.                 // Is it a numeric value?
  973.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  974.                     $mArgs[$arg;
  975.                 }
  976.             }
  977.             $count self::COUNT($mArgs);
  978.             $entry floor(--$entry);
  979.             if (($entry 0|| ($entry >= $count|| ($count == 0)) {
  980.                 return self::$_errorCodes['num'];
  981.             }
  982.             rsort($mArgs);
  983.             return $mArgs[$entry];
  984.         }
  985.         return self::$_errorCodes['value'];
  986.     }    //    function LARGE()
  987.  
  988.  
  989.     /**
  990.      *    PERCENTILE
  991.      *
  992.      *    Returns the nth percentile of values in a range..
  993.      *
  994.      *    Excel Function:
  995.      *        PERCENTILE(value1[,value2[, ...]],entry)
  996.      *
  997.      *    @access    public
  998.      *    @category Statistical Functions
  999.      *    @param    mixed        $arg,...        Data values
  1000.      *    @param    float        $entry            Percentile value in the range 0..1, inclusive.
  1001.      *    @return    float 
  1002.      */
  1003.     public static function PERCENTILE({
  1004.         $aArgs self::flattenArray(func_get_args());
  1005.  
  1006.         // Calculate
  1007.         $entry array_pop($aArgs);
  1008.  
  1009.         if ((is_numeric($entry)) && (!is_string($entry))) {
  1010.             if (($entry 0|| ($entry 1)) {
  1011.                 return self::$_errorCodes['num'];
  1012.             }
  1013.             $mArgs array();
  1014.             foreach ($aArgs as $arg{
  1015.                 // Is it a numeric value?
  1016.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1017.                     $mArgs[$arg;
  1018.                 }
  1019.             }
  1020.             $mValueCount count($mArgs);
  1021.             if ($mValueCount 0{
  1022.                 sort($mArgs);
  1023.                 $count self::COUNT($mArgs);
  1024.                 $index $entry ($count-1);
  1025.                 $iBase floor($index);
  1026.                 if ($index == $iBase{
  1027.                     return $mArgs[$index];
  1028.                 else {
  1029.                     $iNext $iBase 1;
  1030.                     $iProportion $index $iBase;
  1031.                     return $mArgs[$iBase(($mArgs[$iNext$mArgs[$iBase]$iProportion;
  1032.                 }
  1033.             }
  1034.         }
  1035.         return self::$_errorCodes['value'];
  1036.     }    //    function PERCENTILE()
  1037.  
  1038.  
  1039.     /**
  1040.      *    QUARTILE
  1041.      *
  1042.      *    Returns the quartile of a data set.
  1043.      *
  1044.      *    Excel Function:
  1045.      *        QUARTILE(value1[,value2[, ...]],entry)
  1046.      *
  1047.      *    @access    public
  1048.      *    @category Statistical Functions
  1049.      *    @param    mixed        $arg,...        Data values
  1050.      *    @param    int            $entry            Quartile value in the range 1..3, inclusive.
  1051.      *    @return    float 
  1052.      */
  1053.     public static function QUARTILE({
  1054.         $aArgs self::flattenArray(func_get_args());
  1055.  
  1056.         // Calculate
  1057.         $entry floor(array_pop($aArgs));
  1058.  
  1059.         if ((is_numeric($entry)) && (!is_string($entry))) {
  1060.             $entry /= 4;
  1061.             if (($entry 0|| ($entry 1)) {
  1062.                 return self::$_errorCodes['num'];
  1063.             }
  1064.             return self::PERCENTILE($aArgs,$entry);
  1065.         }
  1066.         return self::$_errorCodes['value'];
  1067.     }    //    function QUARTILE()
  1068.  
  1069.  
  1070.     /**
  1071.      *    COUNT
  1072.      *
  1073.      *    Counts the number of cells that contain numbers within the list of arguments
  1074.      *
  1075.      *    Excel Function:
  1076.      *        COUNT(value1[,value2[, ...]])
  1077.      *
  1078.      *    @access    public
  1079.      *    @category Statistical Functions
  1080.      *    @param    mixed        $arg,...        Data values
  1081.      *    @return    int 
  1082.      */
  1083.     public static function COUNT({
  1084.         // Return value
  1085.         $returnValue 0;
  1086.  
  1087.         // Loop through arguments
  1088.         $aArgs self::flattenArrayIndexed(func_get_args());
  1089.         foreach ($aArgs as $k => $arg{
  1090.             if ((is_bool($arg)) &&
  1091.                 ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1092.                 $arg = (integer) $arg;
  1093.             }
  1094.             // Is it a numeric value?
  1095.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1096.                 ++$returnValue;
  1097.             }
  1098.         }
  1099.  
  1100.         // Return
  1101.         return $returnValue;
  1102.     }    //    function COUNT()
  1103.  
  1104.  
  1105.     /**
  1106.      *    COUNTBLANK
  1107.      *
  1108.      *    Counts the number of empty cells within the list of arguments
  1109.      *
  1110.      *    Excel Function:
  1111.      *        COUNTBLANK(value1[,value2[, ...]])
  1112.      *
  1113.      *    @access    public
  1114.      *    @category Statistical Functions
  1115.      *    @param    mixed        $arg,...        Data values
  1116.      *    @return    int 
  1117.      */
  1118.     public static function COUNTBLANK({
  1119.         // Return value
  1120.         $returnValue 0;
  1121.  
  1122.         // Loop through arguments
  1123.         $aArgs self::flattenArray(func_get_args());
  1124.         foreach ($aArgs as $arg{
  1125.             // Is it a blank cell?
  1126.             if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) {
  1127.                 ++$returnValue;
  1128.             }
  1129.         }
  1130.  
  1131.         // Return
  1132.         return $returnValue;
  1133.     }    //    function COUNTBLANK()
  1134.  
  1135.  
  1136.     /**
  1137.      *    COUNTA
  1138.      *
  1139.      *    Counts the number of cells that are not empty within the list of arguments
  1140.      *
  1141.      *    Excel Function:
  1142.      *        COUNTA(value1[,value2[, ...]])
  1143.      *
  1144.      *    @access    public
  1145.      *    @category Statistical Functions
  1146.      *    @param    mixed        $arg,...        Data values
  1147.      *    @return    int 
  1148.      */
  1149.     public static function COUNTA({
  1150.         // Return value
  1151.         $returnValue 0;
  1152.  
  1153.         // Loop through arguments
  1154.         $aArgs self::flattenArray(func_get_args());
  1155.         foreach ($aArgs as $arg{
  1156.             // Is it a numeric, boolean or string value?
  1157.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  1158.                 ++$returnValue;
  1159.             }
  1160.         }
  1161.  
  1162.         // Return
  1163.         return $returnValue;
  1164.     }    //    function COUNTA()
  1165.  
  1166.  
  1167.     /**
  1168.      *    COUNTIF
  1169.      *
  1170.      *    Counts the number of cells that contain numbers within the list of arguments
  1171.      *
  1172.      *    Excel Function:
  1173.      *        COUNTIF(value1[,value2[, ...]],condition)
  1174.      *
  1175.      *    @access    public
  1176.      *    @category Statistical Functions
  1177.      *    @param    mixed        $arg,...        Data values
  1178.      *    @param    string        $condition        The criteria that defines which cells will be counted.
  1179.      *    @return    int 
  1180.      */
  1181.     public static function COUNTIF($aArgs,$condition{
  1182.         // Return value
  1183.         $returnValue 0;
  1184.  
  1185.         $aArgs self::flattenArray($aArgs);
  1186.         $condition    self::flattenSingleValue($condition);
  1187.         if (!in_array($condition{0},array('>''<''='))) {
  1188.             if (!is_numeric($condition)) $condition PHPExcel_Calculation::_wrapResult(strtoupper($condition))}
  1189.             $condition '='.$condition;
  1190.         else {
  1191.             preg_match('/([<>=]+)(.*)/',$condition,$matches);
  1192.             list(,$operator,$operand$matches;
  1193.             if (!is_numeric($operand)) $operand PHPExcel_Calculation::_wrapResult(strtoupper($operand))}
  1194.             $condition $operator.$operand;
  1195.         }
  1196.         // Loop through arguments
  1197.         foreach ($aArgs as $arg{
  1198.             if (!is_numeric($arg)) $arg PHPExcel_Calculation::_wrapResult(strtoupper($arg))}
  1199.             $testCondition '='.$arg.$condition;
  1200.             if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
  1201.                 // Is it a value within our criteria
  1202.                 ++$returnValue;
  1203.             }
  1204.         }
  1205.  
  1206.         // Return
  1207.         return $returnValue;
  1208.     }    //    function COUNTIF()
  1209.  
  1210.  
  1211.     /**
  1212.      *    SUMIF
  1213.      *
  1214.      *    Counts the number of cells that contain numbers within the list of arguments
  1215.      *
  1216.      *    Excel Function:
  1217.      *        SUMIF(value1[,value2[, ...]],condition)
  1218.      *
  1219.      *    @access    public
  1220.      *    @category Mathematical and Trigonometric Functions
  1221.      *    @param    mixed        $arg,...        Data values
  1222.      *    @param    string        $condition        The criteria that defines which cells will be summed.
  1223.      *    @return    float 
  1224.      */
  1225.     public static function SUMIF($aArgs,$condition,$sumArgs array()) {
  1226.         // Return value
  1227.         $returnValue 0;
  1228.  
  1229.         $aArgs self::flattenArray($aArgs);
  1230.         $sumArgs self::flattenArray($sumArgs);
  1231.         if (count($sumArgs== 0{
  1232.             $sumArgs $aArgs;
  1233.         }
  1234.         if (!in_array($condition{0},array('>''<''='))) {
  1235.             if (!is_numeric($condition)) $condition PHPExcel_Calculation::_wrapResult(strtoupper($condition))}
  1236.             $condition '='.$condition;
  1237.         else {
  1238.             preg_match('/([<>=]+)(.*)/',$condition,$matches);
  1239.             list(,$operator,$operand$matches;
  1240.             if (!is_numeric($operand)) $operand PHPExcel_Calculation::_wrapResult(strtoupper($operand))}
  1241.             $condition $operator.$operand;
  1242.         }
  1243.         // Loop through arguments
  1244.         foreach ($aArgs as $key => $arg{
  1245.             if (!is_numeric($arg)) $arg PHPExcel_Calculation::_wrapResult(strtoupper($arg))}
  1246.             $testCondition '='.$arg.$condition;
  1247.             if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
  1248.                 // Is it a value within our criteria
  1249.                 $returnValue += $sumArgs[$key];
  1250.             }
  1251.         }
  1252.  
  1253.         // Return
  1254.         return $returnValue;
  1255.     }    //    function SUMIF()
  1256.  
  1257.  
  1258.     /**
  1259.      *    AVERAGE
  1260.      *
  1261.      *    Returns the average (arithmetic mean) of the arguments
  1262.      *
  1263.      *    Excel Function:
  1264.      *        AVERAGE(value1[,value2[, ...]])
  1265.      *
  1266.      *    @access    public
  1267.      *    @category Statistical Functions
  1268.      *    @param    mixed        $arg,...        Data values
  1269.      *    @return    float 
  1270.      */
  1271.     public static function AVERAGE({
  1272.         $aArgs self::flattenArrayIndexed(func_get_args());
  1273.  
  1274.         $returnValue $aCount 0;
  1275.         // Loop through arguments
  1276.         foreach ($aArgs as $k => $arg{
  1277.             if ((is_bool($arg)) &&
  1278.                 ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1279.                 $arg = (integer) $arg;
  1280.             }
  1281.             // Is it a numeric value?
  1282.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1283.                 if (is_null($returnValue)) {
  1284.                     $returnValue $arg;
  1285.                 else {
  1286.                     $returnValue += $arg;
  1287.                 }
  1288.                 ++$aCount;
  1289.             }
  1290.         }
  1291.  
  1292.         // Return
  1293.         if ($aCount 0{
  1294.             return $returnValue $aCount;
  1295.         else {
  1296.             return self::$_errorCodes['divisionbyzero'];
  1297.         }
  1298.     }    //    function AVERAGE()
  1299.  
  1300.  
  1301.     /**
  1302.      *    AVERAGEA
  1303.      *
  1304.      *    Returns the average of its arguments, including numbers, text, and logical values
  1305.      *
  1306.      *    Excel Function:
  1307.      *        AVERAGEA(value1[,value2[, ...]])
  1308.      *
  1309.      *    @access    public
  1310.      *    @category Statistical Functions
  1311.      *    @param    mixed        $arg,...        Data values
  1312.      *    @return    float 
  1313.      */
  1314.     public static function AVERAGEA({
  1315.         // Return value
  1316.         $returnValue null;
  1317.  
  1318.         // Loop through arguments
  1319.         $aArgs self::flattenArrayIndexed(func_get_args());
  1320.         $aCount 0;
  1321.         foreach ($aArgs as $k => $arg{
  1322.             if ((is_bool($arg)) &&
  1323.                 (!self::isMatrixValue($k))) {
  1324.             else {
  1325.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  1326.                     if (is_bool($arg)) {
  1327.                         $arg = (integer) $arg;
  1328.                     elseif (is_string($arg)) {
  1329.                         $arg 0;
  1330.                     }
  1331.                     if (is_null($returnValue)) {
  1332.                         $returnValue $arg;
  1333.                     else {
  1334.                         $returnValue += $arg;
  1335.                     }
  1336.                     ++$aCount;
  1337.                 }
  1338.             }
  1339.         }
  1340.  
  1341.         // Return
  1342.         if ($aCount 0{
  1343.             return $returnValue $aCount;
  1344.         else {
  1345.             return self::$_errorCodes['divisionbyzero'];
  1346.         }
  1347.     }    //    function AVERAGEA()
  1348.  
  1349.  
  1350.     /**
  1351.      *    MEDIAN
  1352.      *
  1353.      *    Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
  1354.      *
  1355.      *    Excel Function:
  1356.      *        MEDIAN(value1[,value2[, ...]])
  1357.      *
  1358.      *    @access    public
  1359.      *    @category Statistical Functions
  1360.      *    @param    mixed        $arg,...        Data values
  1361.      *    @return    float 
  1362.      */
  1363.     public static function MEDIAN({
  1364.         // Return value
  1365.         $returnValue self::$_errorCodes['num'];
  1366.  
  1367.         $mArgs array();
  1368.         // Loop through arguments
  1369.         $aArgs self::flattenArray(func_get_args());
  1370.         foreach ($aArgs as $arg{
  1371.             // Is it a numeric value?
  1372.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1373.                 $mArgs[$arg;
  1374.             }
  1375.         }
  1376.  
  1377.         $mValueCount count($mArgs);
  1378.         if ($mValueCount 0{
  1379.             sort($mArgs,SORT_NUMERIC);
  1380.             $mValueCount $mValueCount 2;
  1381.             if ($mValueCount == floor($mValueCount)) {
  1382.                 $returnValue ($mArgs[$mValueCount--$mArgs[$mValueCount]2;
  1383.             else {
  1384.                 $mValueCount == floor($mValueCount);
  1385.                 $returnValue $mArgs[$mValueCount];
  1386.             }
  1387.         }
  1388.  
  1389.         // Return
  1390.         return $returnValue;
  1391.     }    //    function MEDIAN()
  1392.  
  1393.  
  1394.     //
  1395.     //    Special variant of array_count_values that isn't limited to strings and integers,
  1396.     //        but can work with floating point numbers as values
  1397.     //
  1398.     private static function _modeCalc($data{
  1399.         $frequencyArray array();
  1400.         foreach($data as $datum{
  1401.             $found False;
  1402.             foreach($frequencyArray as $key => $value{
  1403.                 if ((string) $value['value'== (string) $datum{
  1404.                     ++$frequencyArray[$key]['frequency'];
  1405.                     $found True;
  1406.                     break;
  1407.                 }
  1408.             }
  1409.             if (!$found{
  1410.                 $frequencyArray[array('value'        => $datum,
  1411.                                           'frequency'    =>    );
  1412.             }
  1413.         }
  1414.  
  1415.         foreach($frequencyArray as $key => $value{
  1416.             $frequencyList[$key$value['frequency'];
  1417.             $valueList[$key$value['value'];
  1418.         }
  1419.         array_multisort($frequencyListSORT_DESC$valueListSORT_ASCSORT_NUMERIC$frequencyArray);
  1420.  
  1421.         if ($frequencyArray[0]['frequency'== 1{
  1422.             return self::NA();
  1423.         }
  1424.         return $frequencyArray[0]['value'];
  1425.     }    //    function _modeCalc()
  1426.  
  1427.  
  1428.     /**
  1429.      *    MODE
  1430.      *
  1431.      *    Returns the most frequently occurring, or repetitive, value in an array or range of data
  1432.      *
  1433.      *    Excel Function:
  1434.      *        MODE(value1[,value2[, ...]])
  1435.      *
  1436.      *    @access    public
  1437.      *    @category Statistical Functions
  1438.      *    @param    mixed        $arg,...        Data values
  1439.      *    @return    float 
  1440.      */
  1441.     public static function MODE({
  1442.         // Return value
  1443.         $returnValue self::NA();
  1444.  
  1445.         // Loop through arguments
  1446.         $aArgs self::flattenArray(func_get_args());
  1447.  
  1448.         $mArgs array();
  1449.         foreach ($aArgs as $arg{
  1450.             // Is it a numeric value?
  1451.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1452.                 $mArgs[$arg;
  1453.             }
  1454.         }
  1455.  
  1456.         if (count($mArgs0{
  1457.             return self::_modeCalc($mArgs);
  1458.         }
  1459.  
  1460.         // Return
  1461.         return $returnValue;
  1462.     }    //    function MODE()
  1463.  
  1464.  
  1465.     /**
  1466.      *    DEVSQ
  1467.      *
  1468.      *    Returns the sum of squares of deviations of data points from their sample mean.
  1469.      *
  1470.      *    Excel Function:
  1471.      *        DEVSQ(value1[,value2[, ...]])
  1472.      *
  1473.      *    @access    public
  1474.      *    @category Statistical Functions
  1475.      *    @param    mixed        $arg,...        Data values
  1476.      *    @return    float 
  1477.      */
  1478.     public static function DEVSQ({
  1479.         $aArgs self::flattenArrayIndexed(func_get_args());
  1480.  
  1481.         // Return value
  1482.         $returnValue null;
  1483.  
  1484.         $aMean self::AVERAGE($aArgs);
  1485.         if ($aMean != self::$_errorCodes['divisionbyzero']{
  1486.             $aCount = -1;
  1487.             foreach ($aArgs as $k => $arg{
  1488.                 // Is it a numeric value?
  1489.                 if ((is_bool($arg)) &&
  1490.                     ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1491.                     $arg = (integer) $arg;
  1492.                 }
  1493.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1494.                     if (is_null($returnValue)) {
  1495.                         $returnValue pow(($arg $aMean),2);
  1496.                     else {
  1497.                         $returnValue += pow(($arg $aMean),2);
  1498.                     }
  1499.                     ++$aCount;
  1500.                 }
  1501.             }
  1502.  
  1503.             // Return
  1504.             if (is_null($returnValue)) {
  1505.                 return self::$_errorCodes['num'];
  1506.             else {
  1507.                 return $returnValue;
  1508.             }
  1509.         }
  1510.         return self::NA();
  1511.     }    //    function DEVSQ()
  1512.  
  1513.  
  1514.     /**
  1515.      *    AVEDEV
  1516.      *
  1517.      *    Returns the average of the absolute deviations of data points from their mean.
  1518.      *    AVEDEV is a measure of the variability in a data set.
  1519.      *
  1520.      *    Excel Function:
  1521.      *        AVEDEV(value1[,value2[, ...]])
  1522.      *
  1523.      *    @access    public
  1524.      *    @category Statistical Functions
  1525.      *    @param    mixed        $arg,...        Data values
  1526.      *    @return    float 
  1527.      */
  1528.     public static function AVEDEV({
  1529.         $aArgs self::flattenArrayIndexed(func_get_args());
  1530.  
  1531.         // Return value
  1532.         $returnValue null;
  1533.  
  1534.         $aMean self::AVERAGE($aArgs);
  1535.         if ($aMean != self::$_errorCodes['divisionbyzero']{
  1536.             $aCount 0;
  1537.             foreach ($aArgs as $k => $arg{
  1538.                 if ((is_bool($arg)) &&
  1539.                     ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1540.                     $arg = (integer) $arg;
  1541.                 }
  1542.                 // Is it a numeric value?
  1543.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1544.                     if (is_null($returnValue)) {
  1545.                         $returnValue abs($arg $aMean);
  1546.                     else {
  1547.                         $returnValue += abs($arg $aMean);
  1548.                     }
  1549.                     ++$aCount;
  1550.                 }
  1551.             }
  1552.  
  1553.             // Return
  1554.             if ($aCount == 0{
  1555.                 return self::$_errorCodes['divisionbyzero'];
  1556.             }
  1557.             return $returnValue $aCount;
  1558.         }
  1559.         return self::$_errorCodes['num'];
  1560.     }    //    function AVEDEV()
  1561.  
  1562.  
  1563.     /**
  1564.      *    GEOMEAN
  1565.      *
  1566.      *    Returns the geometric mean of an array or range of positive data. For example, you
  1567.      *        can use GEOMEAN to calculate average growth rate given compound interest with
  1568.      *        variable rates.
  1569.      *
  1570.      *    Excel Function:
  1571.      *        GEOMEAN(value1[,value2[, ...]])
  1572.      *
  1573.      *    @access    public
  1574.      *    @category Statistical Functions
  1575.      *    @param    mixed        $arg,...        Data values
  1576.      *    @return    float 
  1577.      */
  1578.     public static function GEOMEAN({
  1579.         $aArgs self::flattenArray(func_get_args());
  1580.  
  1581.         $aMean self::PRODUCT($aArgs);
  1582.         if (is_numeric($aMean&& ($aMean 0)) {
  1583.             $aCount self::COUNT($aArgs;
  1584.             if (self::MIN($aArgs0{
  1585.                 return pow($aMean($aCount));
  1586.             }
  1587.         }
  1588.         return self::$_errorCodes['num'];
  1589.     }    //    GEOMEAN()
  1590.  
  1591.  
  1592.     /**
  1593.      *    HARMEAN
  1594.      *
  1595.      *    Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the
  1596.      *        arithmetic mean of reciprocals.
  1597.      *
  1598.      *    Excel Function:
  1599.      *        HARMEAN(value1[,value2[, ...]])
  1600.      *
  1601.      *    @access    public
  1602.      *    @category Statistical Functions
  1603.      *    @param    mixed        $arg,...        Data values
  1604.      *    @return    float 
  1605.      */
  1606.     public static function HARMEAN({
  1607.         // Return value
  1608.         $returnValue self::NA();
  1609.  
  1610.         // Loop through arguments
  1611.         $aArgs self::flattenArray(func_get_args());
  1612.         if (self::MIN($aArgs0{
  1613.             return self::$_errorCodes['num'];
  1614.         }
  1615.         $aCount 0;
  1616.         foreach ($aArgs as $arg{
  1617.             // Is it a numeric value?
  1618.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1619.                 if ($arg <= 0{
  1620.                     return self::$_errorCodes['num'];
  1621.                 }
  1622.                 if (is_null($returnValue)) {
  1623.                     $returnValue ($arg);
  1624.                 else {
  1625.                     $returnValue += ($arg);
  1626.                 }
  1627.                 ++$aCount;
  1628.             }
  1629.         }
  1630.  
  1631.         // Return
  1632.         if ($aCount 0{
  1633.             return ($returnValue $aCount);
  1634.         else {
  1635.             return $returnValue;
  1636.         }
  1637.     }    //    function HARMEAN()
  1638.  
  1639.  
  1640.     /**
  1641.      *    TRIMMEAN
  1642.      *
  1643.      *    Returns the mean of the interior of a data set. TRIMMEAN calculates the mean
  1644.      *    taken by excluding a percentage of data points from the top and bottom tails
  1645.      *    of a data set.
  1646.      *
  1647.      *    Excel Function:
  1648.      *        TRIMEAN(value1[,value2[, ...]],$discard)
  1649.      *
  1650.      *    @access    public
  1651.      *    @category Statistical Functions
  1652.      *    @param    mixed        $arg,...        Data values
  1653.      *    @param    float        $discard        Percentage to discard
  1654.      *    @return    float 
  1655.      */
  1656.     public static function TRIMMEAN({
  1657.         $aArgs self::flattenArray(func_get_args());
  1658.  
  1659.         // Calculate
  1660.         $percent array_pop($aArgs);
  1661.  
  1662.         if ((is_numeric($percent)) && (!is_string($percent))) {
  1663.             if (($percent 0|| ($percent 1)) {
  1664.                 return self::$_errorCodes['num'];
  1665.             }
  1666.             $mArgs array();
  1667.             foreach ($aArgs as $arg{
  1668.                 // Is it a numeric value?
  1669.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1670.                     $mArgs[$arg;
  1671.                 }
  1672.             }
  1673.             $discard floor(self::COUNT($mArgs$percent 2);
  1674.             sort($mArgs);
  1675.             for ($i=0$i $discard++$i{
  1676.                 array_pop($mArgs);
  1677.                 array_shift($mArgs);
  1678.             }
  1679.             return self::AVERAGE($mArgs);
  1680.         }
  1681.         return self::$_errorCodes['value'];
  1682.     }    //    function TRIMMEAN()
  1683.  
  1684.  
  1685.     /**
  1686.      *    STDEV
  1687.      *
  1688.      *    Estimates standard deviation based on a sample. The standard deviation is a measure of how
  1689.      *    widely values are dispersed from the average value (the mean).
  1690.      *
  1691.      *    Excel Function:
  1692.      *        STDEV(value1[,value2[, ...]])
  1693.      *
  1694.      *    @access    public
  1695.      *    @category Statistical Functions
  1696.      *    @param    mixed        $arg,...        Data values
  1697.      *    @return    float 
  1698.      */
  1699.     public static function STDEV({
  1700.         $aArgs self::flattenArrayIndexed(func_get_args());
  1701.  
  1702.         // Return value
  1703.         $returnValue null;
  1704.  
  1705.         $aMean self::AVERAGE($aArgs);
  1706.         if (!is_null($aMean)) {
  1707.             $aCount = -1;
  1708.             foreach ($aArgs as $k => $arg{
  1709.                 if ((is_bool($arg)) &&
  1710.                     ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1711.                     $arg = (integer) $arg;
  1712.                 }
  1713.                 // Is it a numeric value?
  1714.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1715.                     if (is_null($returnValue)) {
  1716.                         $returnValue pow(($arg $aMean),2);
  1717.                     else {
  1718.                         $returnValue += pow(($arg $aMean),2);
  1719.                     }
  1720.                     ++$aCount;
  1721.                 }
  1722.             }
  1723.  
  1724.             // Return
  1725.             if (($aCount 0&& ($returnValue 0)) {
  1726.                 return sqrt($returnValue $aCount);
  1727.             }
  1728.         }
  1729.         return self::$_errorCodes['divisionbyzero'];
  1730.     }    //    function STDEV()
  1731.  
  1732.  
  1733.     /**
  1734.      *    STDEVA
  1735.      *
  1736.      *    Estimates standard deviation based on a sample, including numbers, text, and logical values
  1737.      *
  1738.      *    Excel Function:
  1739.      *        STDEVA(value1[,value2[, ...]])
  1740.      *
  1741.      *    @access    public
  1742.      *    @category Statistical Functions
  1743.      *    @param    mixed        $arg,...        Data values
  1744.      *    @return    float 
  1745.      */
  1746.     public static function STDEVA({
  1747.         $aArgs self::flattenArrayIndexed(func_get_args());
  1748.  
  1749.         // Return value
  1750.         $returnValue null;
  1751.  
  1752.         $aMean self::AVERAGEA($aArgs);
  1753.         if (!is_null($aMean)) {
  1754.             $aCount = -1;
  1755.             foreach ($aArgs as $k => $arg{
  1756.                 if ((is_bool($arg)) &&
  1757.                     (!self::isMatrixValue($k))) {
  1758.                 else {
  1759.                     // Is it a numeric value?
  1760.                     if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1761.                         if (is_bool($arg)) {
  1762.                             $arg = (integer) $arg;
  1763.                         elseif (is_string($arg)) {
  1764.                             $arg 0;
  1765.                         }
  1766.                         if (is_null($returnValue)) {
  1767.                             $returnValue pow(($arg $aMean),2);
  1768.                         else {
  1769.                             $returnValue += pow(($arg $aMean),2);
  1770.                         }
  1771.                         ++$aCount;
  1772.                     }
  1773.                 }
  1774.             }
  1775.  
  1776.             // Return
  1777.             if (($aCount 0&& ($returnValue 0)) {
  1778.                 return sqrt($returnValue $aCount);
  1779.             }
  1780.         }
  1781.         return self::$_errorCodes['divisionbyzero'];
  1782.     }    //    function STDEVA()
  1783.  
  1784.  
  1785.     /**
  1786.      *    STDEVP
  1787.      *
  1788.      *    Calculates standard deviation based on the entire population
  1789.      *
  1790.      *    Excel Function:
  1791.      *        STDEVP(value1[,value2[, ...]])
  1792.      *
  1793.      *    @access    public
  1794.      *    @category Statistical Functions
  1795.      *    @param    mixed        $arg,...        Data values
  1796.      *    @return    float 
  1797.      */
  1798.     public static function STDEVP({
  1799.         $aArgs self::flattenArrayIndexed(func_get_args());
  1800.  
  1801.         // Return value
  1802.         $returnValue null;
  1803.  
  1804.         $aMean self::AVERAGE($aArgs);
  1805.         if (!is_null($aMean)) {
  1806.             $aCount 0;
  1807.             foreach ($aArgs as $k => $arg{
  1808.                 if ((is_bool($arg)) &&
  1809.                     ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) {
  1810.                     $arg = (integer) $arg;
  1811.                 }
  1812.                 // Is it a numeric value?
  1813.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1814.                     if (is_null($returnValue)) {
  1815.                         $returnValue pow(($arg $aMean),2);
  1816.                     else {
  1817.                         $returnValue += pow(($arg $aMean),2);
  1818.                     }
  1819.                     ++$aCount;
  1820.                 }
  1821.             }
  1822.  
  1823.             // Return
  1824.             if (($aCount 0&& ($returnValue 0)) {
  1825.                 return sqrt($returnValue $aCount);
  1826.             }
  1827.         }
  1828.         return self::$_errorCodes['divisionbyzero'];
  1829.     }    //    function STDEVP()
  1830.  
  1831.  
  1832.     /**
  1833.      *    STDEVPA
  1834.      *
  1835.      *    Calculates standard deviation based on the entire population, including numbers, text, and logical values
  1836.      *
  1837.      *    Excel Function:
  1838.      *        STDEVPA(value1[,value2[, ...]])
  1839.      *
  1840.      *    @access    public
  1841.      *    @category Statistical Functions
  1842.      *    @param    mixed        $arg,...        Data values
  1843.      *    @return    float 
  1844.      */
  1845.     public static function STDEVPA({
  1846.         $aArgs self::flattenArrayIndexed(func_get_args());
  1847.  
  1848.         // Return value
  1849.         $returnValue null;
  1850.  
  1851.         $aMean self::AVERAGEA($aArgs);
  1852.         if (!is_null($aMean)) {
  1853.             $aCount 0;
  1854.             foreach ($aArgs as $k => $arg{
  1855.                 if ((is_bool($arg)) &&
  1856.                     (!self::isMatrixValue($k))) {
  1857.                 else {
  1858.                     // Is it a numeric value?
  1859.                     if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1860.                         if (is_bool($arg)) {
  1861.                             $arg = (integer) $arg;
  1862.                         elseif (is_string($arg)) {
  1863.                             $arg 0;
  1864.                         }
  1865.                         if (is_null($returnValue)) {
  1866.                             $returnValue pow(($arg $aMean),2);
  1867.                         else {
  1868.                             $returnValue += pow(($arg $aMean),2);
  1869.                         }
  1870.                         ++$aCount;
  1871.                     }
  1872.                 }
  1873.             }
  1874.  
  1875.             // Return
  1876.             if (($aCount 0&& ($returnValue 0)) {
  1877.                 return sqrt($returnValue $aCount);
  1878.             }
  1879.         }
  1880.         return self::$_errorCodes['divisionbyzero'];
  1881.     }    //    function STDEVPA()
  1882.  
  1883.  
  1884.     /**
  1885.      *    VARFunc
  1886.      *
  1887.      *    Estimates variance based on a sample.
  1888.      *
  1889.      *    Excel Function:
  1890.      *        VAR(value1[,value2[, ...]])
  1891.      *
  1892.      *    @access    public
  1893.      *    @category Statistical Functions
  1894.      *    @param    mixed        $arg,...        Data values
  1895.      *    @return    float 
  1896.      */
  1897.     public static function VARFunc({
  1898.         // Return value
  1899.         $returnValue self::$_errorCodes['divisionbyzero'];
  1900.  
  1901.         $summerA $summerB 0;
  1902.  
  1903.         // Loop through arguments
  1904.         $aArgs self::flattenArray(func_get_args());
  1905.         $aCount 0;
  1906.         foreach ($aArgs as $arg{
  1907.             if (is_bool($arg)) $arg = (integer) $arg}
  1908.             // Is it a numeric value?
  1909.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1910.                 $summerA += ($arg $arg);
  1911.                 $summerB += $arg;
  1912.                 ++$aCount;
  1913.             }
  1914.         }
  1915.  
  1916.         // Return
  1917.         if ($aCount 1{
  1918.             $summerA *= $aCount;
  1919.             $summerB *= $summerB;
  1920.             $returnValue ($summerA $summerB($aCount ($aCount 1));
  1921.         }
  1922.         return $returnValue;
  1923.     }    //    function VARFunc()
  1924.  
  1925.  
  1926.     /**
  1927.      *    VARA
  1928.      *
  1929.      *    Estimates variance based on a sample, including numbers, text, and logical values
  1930.      *
  1931.      *    Excel Function:
  1932.      *        VARA(value1[,value2[, ...]])
  1933.      *
  1934.      *    @access    public
  1935.      *    @category Statistical Functions
  1936.      *    @param    mixed        $arg,...        Data values
  1937.      *    @return    float 
  1938.      */
  1939.     public static function VARA({
  1940.         // Return value
  1941.         $returnValue self::$_errorCodes['divisionbyzero'];
  1942.  
  1943.         $summerA $summerB 0;
  1944.  
  1945.         // Loop through arguments
  1946.         $aArgs self::flattenArrayIndexed(func_get_args());
  1947.         $aCount 0;
  1948.         foreach ($aArgs as $k => $arg{
  1949.             if ((is_string($arg)) &&
  1950.                 (self::isValue($k))) {
  1951.                 return self::$_errorCodes['value'];
  1952.             elseif ((is_string($arg)) &&
  1953.                 (!self::isMatrixValue($k))) {
  1954.             else {
  1955.                 // Is it a numeric value?
  1956.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1957.                     if (is_bool($arg)) {
  1958.                         $arg = (integer) $arg;
  1959.                     elseif (is_string($arg)) {
  1960.                         $arg 0;
  1961.                     }
  1962.                     $summerA += ($arg $arg);
  1963.                     $summerB += $arg;
  1964.                     ++$aCount;
  1965.                 }
  1966.             }
  1967.         }
  1968.  
  1969.         // Return
  1970.         if ($aCount 1{
  1971.             $summerA *= $aCount;
  1972.             $summerB *= $summerB;
  1973.             $returnValue ($summerA $summerB($aCount ($aCount 1));
  1974.         }
  1975.         return $returnValue;
  1976.     }    //    function VARA()
  1977.  
  1978.  
  1979.     /**
  1980.      *    VARP
  1981.      *
  1982.      *    Calculates variance based on the entire population
  1983.      *
  1984.      *    Excel Function:
  1985.      *        VARP(value1[,value2[, ...]])
  1986.      *
  1987.      *    @access    public
  1988.      *    @category Statistical Functions
  1989.      *    @param    mixed        $arg,...        Data values
  1990.      *    @return    float 
  1991.      */
  1992.     public static function VARP({
  1993.         // Return value
  1994.         $returnValue self::$_errorCodes['divisionbyzero'];
  1995.  
  1996.         $summerA $summerB 0;
  1997.  
  1998.         // Loop through arguments
  1999.         $aArgs self::flattenArray(func_get_args());
  2000.         $aCount 0;
  2001.         foreach ($aArgs as $arg{
  2002.             if (is_bool($arg)) $arg = (integer) $arg}
  2003.             // Is it a numeric value?
  2004.             if ((is_numeric($arg)) && (!is_string($arg))) {
  2005.                 $summerA += ($arg $arg);
  2006.                 $summerB += $arg;
  2007.                 ++$aCount;
  2008.             }
  2009.         }
  2010.  
  2011.         // Return
  2012.         if ($aCount 0{
  2013.             $summerA *= $aCount;
  2014.             $summerB *= $summerB;
  2015.             $returnValue ($summerA $summerB($aCount $aCount);
  2016.         }
  2017.         return $returnValue;
  2018.     }    //    function VARP()
  2019.  
  2020.  
  2021.     /**
  2022.      *    VARPA
  2023.      *
  2024.      *    Calculates variance based on the entire population, including numbers, text, and logical values
  2025.      *
  2026.      *    Excel Function:
  2027.      *        VARPA(value1[,value2[, ...]])
  2028.      *
  2029.      *    @access    public
  2030.      *    @category Statistical Functions
  2031.      *    @param    mixed        $arg,...        Data values
  2032.      *    @return    float 
  2033.      */
  2034.     public static function VARPA({
  2035.         // Return value
  2036.         $returnValue self::$_errorCodes['divisionbyzero'];
  2037.  
  2038.         $summerA $summerB 0;
  2039.  
  2040.         // Loop through arguments
  2041.         $aArgs self::flattenArrayIndexed(func_get_args());
  2042.         $aCount 0;
  2043.         foreach ($aArgs as $k => $arg{
  2044.             if ((is_string($arg)) &&
  2045.                 (self::isValue($k))) {
  2046.                 return self::$_errorCodes['value'];
  2047.             elseif ((is_string($arg)) &&
  2048.                 (!self::isMatrixValue($k))) {
  2049.             else {
  2050.                 // Is it a numeric value?
  2051.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  2052.                     if (is_bool($arg)) {
  2053.                         $arg = (integer) $arg;
  2054.                     elseif (is_string($arg)) {
  2055.                         $arg 0;
  2056.                     }
  2057.                     $summerA += ($arg $arg);
  2058.                     $summerB += $arg;
  2059.                     ++$aCount;
  2060.                 }
  2061.             }
  2062.         }
  2063.  
  2064.         // Return
  2065.         if ($aCount 0{
  2066.             $summerA *= $aCount;
  2067.             $summerB *= $summerB;
  2068.             $returnValue ($summerA $summerB($aCount $aCount);
  2069.         }
  2070.         return $returnValue;
  2071.     }    //    function VARPA()
  2072.  
  2073.  
  2074.     /**
  2075.      *    RANK
  2076.      *
  2077.      *    Returns the rank of a number in a list of numbers.
  2078.      *
  2079.      *    @param    number                The number whose rank you want to find.
  2080.      *    @param    array of number        An array of, or a reference to, a list of numbers.
  2081.      *    @param    mixed                Order to sort the values in the value set
  2082.      *    @return    float 
  2083.      */
  2084.     public static function RANK($value,$valueSet,$order=0{
  2085.         $value self::flattenSingleValue($value);
  2086.         $valueSet self::flattenArray($valueSet);
  2087.         $order    (is_null($order))    :    (integer) self::flattenSingleValue($order);
  2088.  
  2089.         foreach($valueSet as $key => $valueEntry{
  2090.             if (!is_numeric($valueEntry)) {
  2091.                 unset($valueSet[$key]);
  2092.             }
  2093.         }
  2094.  
  2095.         if ($order == 0{
  2096.             rsort($valueSet,SORT_NUMERIC);
  2097.         else {
  2098.             sort($valueSet,SORT_NUMERIC);
  2099.         }
  2100.         $pos array_search($value,$valueSet);
  2101.         if ($pos === False{
  2102.             return self::$_errorCodes['na'];
  2103.         }
  2104.  
  2105.         return ++$pos;
  2106.     }    //    function RANK()
  2107.  
  2108.  
  2109.     /**
  2110.      *    PERCENTRANK
  2111.      *
  2112.      *    Returns the rank of a value in a data set as a percentage of the data set.
  2113.      *
  2114.      *    @param    array of number        An array of, or a reference to, a list of numbers.
  2115.      *    @param    number                The number whose rank you want to find.
  2116.      *    @param    number                The number of significant digits for the returned percentage value.
  2117.      *    @return    float 
  2118.      */
  2119.     public static function PERCENTRANK($valueSet,$value,$significance=3{
  2120.         $valueSet    self::flattenArray($valueSet);
  2121.         $value        self::flattenSingleValue($value);
  2122.         $significance    (is_null($significance))    :    (integer) self::flattenSingleValue($significance);
  2123.  
  2124.         foreach($valueSet as $key => $valueEntry{
  2125.             if (!is_numeric($valueEntry)) {
  2126.                 unset($valueSet[$key]);
  2127.             }
  2128.         }
  2129.         sort($valueSet,SORT_NUMERIC);
  2130.         $valueCount count($valueSet);
  2131.         if ($valueCount == 0{
  2132.             return self::$_errorCodes['num'];
  2133.         }
  2134.  
  2135.         $valueAdjustor $valueCount 1;
  2136.         if (($value $valueSet[0]|| ($value $valueSet[$valueAdjustor])) {
  2137.             return self::$_errorCodes['na'];
  2138.         }
  2139.  
  2140.         $pos array_search($value,$valueSet);
  2141.         if ($pos === False{
  2142.             $pos 0;
  2143.             $testValue $valueSet[0];
  2144.             while ($testValue $value{
  2145.                 $testValue $valueSet[++$pos];
  2146.             }
  2147.             --$pos;
  2148.             $pos += (($value $valueSet[$pos]($testValue $valueSet[$pos]));
  2149.         }
  2150.  
  2151.         return round($pos $valueAdjustor,$significance);
  2152.     }    //    function PERCENTRANK()
  2153.  
  2154.  
  2155.     private static function _checkTrendArrays(&$array1,&$array2{
  2156.         if (!is_array($array1)) $array1 array($array1)}
  2157.         if (!is_array($array2)) $array2 array($array2)}
  2158.  
  2159.         $array1 self::flattenArray($array1);
  2160.         $array2 self::flattenArray($array2);
  2161.         foreach($array1 as $key => $value{
  2162.             if ((is_bool($value)) || (is_string($value)) || (is_null($value))) {
  2163.                 unset($array1[$key]);
  2164.                 unset($array2[$key]);
  2165.             }
  2166.         }
  2167.         foreach($array2 as $key => $value{
  2168.             if ((is_bool($value)) || (is_string($value)) || (is_null($value))) {
  2169.                 unset($array1[$key]);
  2170.                 unset($array2[$key]);
  2171.             }
  2172.         }
  2173.         $array1 array_merge($array1);
  2174.         $array2 array_merge($array2);
  2175.  
  2176.         return True;
  2177.     }    //    function _checkTrendArrays()
  2178.  
  2179.  
  2180.     /**
  2181.      *    INTERCEPT
  2182.      *
  2183.      *    Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values.
  2184.      *
  2185.      *    @param    array of mixed        Data Series Y
  2186.      *    @param    array of mixed        Data Series X
  2187.      *    @return    float 
  2188.      */
  2189.     public static function INTERCEPT($yValues,$xValues{
  2190.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2191.             return self::$_errorCodes['value'];
  2192.         }
  2193.         $yValueCount count($yValues);
  2194.         $xValueCount count($xValues);
  2195.  
  2196.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2197.             return self::$_errorCodes['na'];
  2198.         elseif ($yValueCount == 1{
  2199.             return self::$_errorCodes['divisionbyzero'];
  2200.         }
  2201.  
  2202.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2203.         return $bestFitLinear->getIntersect();
  2204.     }    //    function INTERCEPT()
  2205.  
  2206.  
  2207.     /**
  2208.      *    RSQ
  2209.      *
  2210.      *    Returns the square of the Pearson product moment correlation coefficient through data points in known_y's and known_x's.
  2211.      *
  2212.      *    @param    array of mixed        Data Series Y
  2213.      *    @param    array of mixed        Data Series X
  2214.      *    @return    float 
  2215.      */
  2216.     public static function RSQ($yValues,$xValues{
  2217.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2218.             return self::$_errorCodes['value'];
  2219.         }
  2220.         $yValueCount count($yValues);
  2221.         $xValueCount count($xValues);
  2222.  
  2223.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2224.             return self::$_errorCodes['na'];
  2225.         elseif ($yValueCount == 1{
  2226.             return self::$_errorCodes['divisionbyzero'];
  2227.         }
  2228.  
  2229.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2230.         return $bestFitLinear->getGoodnessOfFit();
  2231.     }    //    function RSQ()
  2232.  
  2233.  
  2234.     /**
  2235.      *    SLOPE
  2236.      *
  2237.      *    Returns the slope of the linear regression line through data points in known_y's and known_x's.
  2238.      *
  2239.      *    @param    array of mixed        Data Series Y
  2240.      *    @param    array of mixed        Data Series X
  2241.      *    @return    float 
  2242.      */
  2243.     public static function SLOPE($yValues,$xValues{
  2244.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2245.             return self::$_errorCodes['value'];
  2246.         }
  2247.         $yValueCount count($yValues);
  2248.         $xValueCount count($xValues);
  2249.  
  2250.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2251.             return self::$_errorCodes['na'];
  2252.         elseif ($yValueCount == 1{
  2253.             return self::$_errorCodes['divisionbyzero'];
  2254.         }
  2255.  
  2256.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2257.         return $bestFitLinear->getSlope();
  2258.     }    //    function SLOPE()
  2259.  
  2260.  
  2261.     /**
  2262.      *    STEYX
  2263.      *
  2264.      *    Returns the standard error of the predicted y-value for each x in the regression.
  2265.      *
  2266.      *    @param    array of mixed        Data Series Y
  2267.      *    @param    array of mixed        Data Series X
  2268.      *    @return    float 
  2269.      */
  2270.     public static function STEYX($yValues,$xValues{
  2271.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2272.             return self::$_errorCodes['value'];
  2273.         }
  2274.         $yValueCount count($yValues);
  2275.         $xValueCount count($xValues);
  2276.  
  2277.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2278.             return self::$_errorCodes['na'];
  2279.         elseif ($yValueCount == 1{
  2280.             return self::$_errorCodes['divisionbyzero'];
  2281.         }
  2282.  
  2283.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2284.         return $bestFitLinear->getStdevOfResiduals();
  2285.     }    //    function STEYX()
  2286.  
  2287.  
  2288.     /**
  2289.      *    COVAR
  2290.      *
  2291.      *    Returns covariance, the average of the products of deviations for each data point pair.
  2292.      *
  2293.      *    @param    array of mixed        Data Series Y
  2294.      *    @param    array of mixed        Data Series X
  2295.      *    @return    float 
  2296.      */
  2297.     public static function COVAR($yValues,$xValues{
  2298.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2299.             return self::$_errorCodes['value'];
  2300.         }
  2301.         $yValueCount count($yValues);
  2302.         $xValueCount count($xValues);
  2303.  
  2304.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2305.             return self::$_errorCodes['na'];
  2306.         elseif ($yValueCount == 1{
  2307.             return self::$_errorCodes['divisionbyzero'];
  2308.         }
  2309.  
  2310.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2311.         return $bestFitLinear->getCovariance();
  2312.     }    //    function COVAR()
  2313.  
  2314.  
  2315.     /**
  2316.      *    CORREL
  2317.      *
  2318.      *    Returns covariance, the average of the products of deviations for each data point pair.
  2319.      *
  2320.      *    @param    array of mixed        Data Series Y
  2321.      *    @param    array of mixed        Data Series X
  2322.      *    @return    float 
  2323.      */
  2324.     public static function CORREL($yValues,$xValues=null{
  2325.         if ((is_null($xValues)) || (!is_array($yValues)) || (!is_array($xValues))) {
  2326.             return self::$_errorCodes['value'];
  2327.         }
  2328.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2329.             return self::$_errorCodes['value'];
  2330.         }
  2331.         $yValueCount count($yValues);
  2332.         $xValueCount count($xValues);
  2333.  
  2334.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2335.             return self::$_errorCodes['na'];
  2336.         elseif ($yValueCount == 1{
  2337.             return self::$_errorCodes['divisionbyzero'];
  2338.         }
  2339.  
  2340.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2341.         return $bestFitLinear->getCorrelation();
  2342.     }    //    function CORREL()
  2343.  
  2344.  
  2345.     /**
  2346.      *    LINEST
  2347.      *
  2348.      *    Calculates the statistics for a line by using the "least squares" method to calculate a straight line that best fits your data,
  2349.      *        and then returns an array that describes the line.
  2350.      *
  2351.      *    @param    array of mixed        Data Series Y
  2352.      *    @param    array of mixed        Data Series X
  2353.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2354.      *    @param    boolean                A logical value specifying whether to return additional regression statistics.
  2355.      *    @return    array 
  2356.      */
  2357.     public static function LINEST($yValues,$xValues=null,$const=True,$stats=False{
  2358.         $const    (is_null($const))    True :    (boolean) self::flattenSingleValue($const);
  2359.         $stats    (is_null($stats))    False :    (boolean) self::flattenSingleValue($stats);
  2360.         if (is_null($xValues)) $xValues range(1,count(self::flattenArray($yValues)));
  2361.  
  2362.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2363.             return self::$_errorCodes['value'];
  2364.         }
  2365.         $yValueCount count($yValues);
  2366.         $xValueCount count($xValues);
  2367.  
  2368.  
  2369.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2370.             return self::$_errorCodes['na'];
  2371.         elseif ($yValueCount == 1{
  2372.             return 0;
  2373.         }
  2374.  
  2375.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const);
  2376.         if ($stats{
  2377.             return arrayarray$bestFitLinear->getSlope(),
  2378.                                   $bestFitLinear->getSlopeSE(),
  2379.                                   $bestFitLinear->getGoodnessOfFit(),
  2380.                                   $bestFitLinear->getF(),
  2381.                                   $bestFitLinear->getSSRegression(),
  2382.                                ),
  2383.                           array$bestFitLinear->getIntersect(),
  2384.                                  $bestFitLinear->getIntersectSE(),
  2385.                                  $bestFitLinear->getStdevOfResiduals(),
  2386.                                  $bestFitLinear->getDFResiduals(),
  2387.                                  $bestFitLinear->getSSResiduals()
  2388.                                )
  2389.                         );
  2390.         else {
  2391.             return array$bestFitLinear->getSlope(),
  2392.                           $bestFitLinear->getIntersect()
  2393.                         );
  2394.         }
  2395.     }    //    function LINEST()
  2396.  
  2397.  
  2398.     /**
  2399.      *    LOGEST
  2400.      *
  2401.      *    Calculates an exponential curve that best fits the X and Y data series,
  2402.      *        and then returns an array that describes the line.
  2403.      *
  2404.      *    @param    array of mixed        Data Series Y
  2405.      *    @param    array of mixed        Data Series X
  2406.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2407.      *    @param    boolean                A logical value specifying whether to return additional regression statistics.
  2408.      *    @return    array 
  2409.      */
  2410.     public static function LOGEST($yValues,$xValues=null,$const=True,$stats=False{
  2411.         $const    (is_null($const))    True :    (boolean) self::flattenSingleValue($const);
  2412.         $stats    (is_null($stats))    False :    (boolean) self::flattenSingleValue($stats);
  2413.         if (is_null($xValues)) $xValues range(1,count(self::flattenArray($yValues)));
  2414.  
  2415.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2416.             return self::$_errorCodes['value'];
  2417.         }
  2418.         $yValueCount count($yValues);
  2419.         $xValueCount count($xValues);
  2420.  
  2421.         foreach($yValues as $value{
  2422.             if ($value <= 0.0{
  2423.                 return self::$_errorCodes['num'];
  2424.             }
  2425.         }
  2426.  
  2427.  
  2428.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2429.             return self::$_errorCodes['na'];
  2430.         elseif ($yValueCount == 1{
  2431.             return 1;
  2432.         }
  2433.  
  2434.         $bestFitExponential trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const);
  2435.         if ($stats{
  2436.             return arrayarray$bestFitExponential->getSlope(),
  2437.                                   $bestFitExponential->getSlopeSE(),
  2438.                                   $bestFitExponential->getGoodnessOfFit(),
  2439.                                   $bestFitExponential->getF(),
  2440.                                   $bestFitExponential->getSSRegression(),
  2441.                                ),
  2442.                           array$bestFitExponential->getIntersect(),
  2443.                                  $bestFitExponential->getIntersectSE(),
  2444.                                  $bestFitExponential->getStdevOfResiduals(),
  2445.                                  $bestFitExponential->getDFResiduals(),
  2446.                                  $bestFitExponential->getSSResiduals()
  2447.                                )
  2448.                         );
  2449.         else {
  2450.             return array$bestFitExponential->getSlope(),
  2451.                           $bestFitExponential->getIntersect()
  2452.                         );
  2453.         }
  2454.     }    //    function LOGEST()
  2455.  
  2456.  
  2457.     /**
  2458.      *    FORECAST
  2459.      *
  2460.      *    Calculates, or predicts, a future value by using existing values. The predicted value is a y-value for a given x-value.
  2461.      *
  2462.      *    @param    float                Value of X for which we want to find Y
  2463.      *    @param    array of mixed        Data Series Y
  2464.      *    @param    array of mixed        Data Series X
  2465.      *    @return    float 
  2466.      */
  2467.     public static function FORECAST($xValue,$yValues,$xValues{
  2468.         $xValue    self::flattenSingleValue($xValue);
  2469.         if (!is_numeric($xValue)) {
  2470.             return self::$_errorCodes['value'];
  2471.         }
  2472.  
  2473.         if (!self::_checkTrendArrays($yValues,$xValues)) {
  2474.             return self::$_errorCodes['value'];
  2475.         }
  2476.         $yValueCount count($yValues);
  2477.         $xValueCount count($xValues);
  2478.  
  2479.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2480.             return self::$_errorCodes['na'];
  2481.         elseif ($yValueCount == 1{
  2482.             return self::$_errorCodes['divisionbyzero'];
  2483.         }
  2484.  
  2485.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2486.         return $bestFitLinear->getValueOfYForX($xValue);
  2487.     }    //    function FORECAST()
  2488.  
  2489.  
  2490.     /**
  2491.      *    TREND
  2492.      *
  2493.      *    Returns values along a linear trend
  2494.      *
  2495.      *    @param    array of mixed        Data Series Y
  2496.      *    @param    array of mixed        Data Series X
  2497.      *    @param    array of mixed        Values of X for which we want to find Y
  2498.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2499.      *    @return    array of float
  2500.      */
  2501.     public static function TREND($yValues,$xValues=array(),$newValues=array(),$const=True{
  2502.         $yValues self::flattenArray($yValues);
  2503.         $xValues self::flattenArray($xValues);
  2504.         $newValues self::flattenArray($newValues);
  2505.         $const    (is_null($const))    True :    (boolean) self::flattenSingleValue($const);
  2506.  
  2507.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const);
  2508.         if (count($newValues== 0{
  2509.             $newValues $bestFitLinear->getXValues();
  2510.         }
  2511.  
  2512.         $returnArray array();
  2513.         foreach($newValues as $xValue{
  2514.             $returnArray[0][$bestFitLinear->getValueOfYForX($xValue);
  2515.         }
  2516.  
  2517.         return $returnArray;
  2518.     }    //    function TREND()
  2519.  
  2520.  
  2521.     /**
  2522.      *    GROWTH
  2523.      *
  2524.      *    Returns values along a predicted emponential trend
  2525.      *
  2526.      *    @param    array of mixed        Data Series Y
  2527.      *    @param    array of mixed        Data Series X
  2528.      *    @param    array of mixed        Values of X for which we want to find Y
  2529.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2530.      *    @return    array of float
  2531.      */
  2532.     public static function GROWTH($yValues,$xValues=array(),$newValues=array(),$const=True{
  2533.         $yValues self::flattenArray($yValues);
  2534.         $xValues self::flattenArray($xValues);
  2535.         $newValues self::flattenArray($newValues);
  2536.         $const    (is_null($const))    True :    (boolean) self::flattenSingleValue($const);
  2537.  
  2538.         $bestFitExponential trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const);
  2539.         if (count($newValues== 0{
  2540.             $newValues $bestFitExponential->getXValues();
  2541.         }
  2542.  
  2543.         $returnArray array();
  2544.         foreach($newValues as $xValue{
  2545.             $returnArray[0][$bestFitExponential->getValueOfYForX($xValue);
  2546.         }
  2547.  
  2548.         return $returnArray;
  2549.     }    //    function GROWTH()
  2550.  
  2551.  
  2552.     private static function _romanCut($num$n{
  2553.         return ($num ($num $n ) ) $n;
  2554.     }    //    function _romanCut()
  2555.  
  2556.  
  2557.     public static function ROMAN($aValue$style=0{
  2558.         $aValue    = (integer) self::flattenSingleValue($aValue);
  2559.         $style    (is_null($style))    :    (integer) self::flattenSingleValue($style);
  2560.         if ((!is_numeric($aValue)) || ($aValue 0|| ($aValue >= 4000)) {
  2561.             return self::$_errorCodes['value'];
  2562.         }
  2563.         if ($aValue == 0{
  2564.             return '';
  2565.         }
  2566.  
  2567.         $mill Array('''M''MM''MMM''MMMM''MMMMM');
  2568.         $cent Array('''C''CC''CCC''CD''D''DC''DCC''DCCC''CM');
  2569.         $tens Array('''X''XX''XXX''XL''L''LX''LXX''LXXX''XC');
  2570.         $ones Array('''I''II''III''IV''V''VI''VII''VIII''IX');
  2571.  
  2572.         $roman '';
  2573.         while ($aValue 5999{
  2574.             $roman .= 'M';
  2575.             $aValue -= 1000;
  2576.         }
  2577.         $m self::_romanCut($aValue1000);    $aValue %= 1000;
  2578.         $c self::_romanCut($aValue100);        $aValue %= 100;
  2579.         $t self::_romanCut($aValue10);        $aValue %= 10;
  2580.  
  2581.         return $roman.$mill[$m].$cent[$c].$tens[$t].$ones[$aValue];
  2582.     }    //    function ROMAN()
  2583.  
  2584.  
  2585.     /**
  2586.      *    SUBTOTAL
  2587.      *
  2588.      *    Returns a subtotal in a list or database.
  2589.      *
  2590.      *    @param    int        the number 1 to 11 that specifies which function to
  2591.      *                     use in calculating subtotals within a list.
  2592.      *    @param    array of mixed        Data Series
  2593.      *    @return    float 
  2594.      */
  2595.     public static function SUBTOTAL({
  2596.         $aArgs self::flattenArray(func_get_args());
  2597.  
  2598.         // Calculate
  2599.         $subtotal array_shift($aArgs);
  2600.  
  2601.         if ((is_numeric($subtotal)) && (!is_string($subtotal))) {
  2602.             switch($subtotal{
  2603.                 case 1    :
  2604.                     return self::AVERAGE($aArgs);
  2605.                     break;
  2606.                 case 2    :
  2607.                     return self::COUNT($aArgs);
  2608.                     break;
  2609.                 case 3    :
  2610.                     return self::COUNTA($aArgs);
  2611.                     break;
  2612.                 case 4    :
  2613.                     return self::MAX($aArgs);
  2614.                     break;
  2615.                 case 5    :
  2616.                     return self::MIN($aArgs);
  2617.                     break;
  2618.                 case 6    :
  2619.                     return self::PRODUCT($aArgs);
  2620.                     break;
  2621.                 case 7    :
  2622.                     return self::STDEV($aArgs);
  2623.                     break;
  2624.                 case 8    :
  2625.                     return self::STDEVP($aArgs);
  2626.                     break;
  2627.                 case 9    :
  2628.                     return self::SUM($aArgs);
  2629.                     break;
  2630.                 case 10    :
  2631.                     return self::VARFunc($aArgs);
  2632.                     break;
  2633.                 case 11    :
  2634.                     return self::VARP($aArgs);
  2635.                     break;
  2636.             }
  2637.         }
  2638.         return self::$_errorCodes['value'];
  2639.     }    //    function SUBTOTAL()
  2640.  
  2641.  
  2642.     /**
  2643.      *    SQRTPI
  2644.      *
  2645.      *    Returns the square root of (number * pi).
  2646.      *
  2647.      *    @param    float    $number        Number
  2648.      *    @return    float    Square Root of Number * Pi
  2649.      */
  2650.     public static function SQRTPI($number{
  2651.         $number    self::flattenSingleValue($number);
  2652.  
  2653.         if (is_numeric($number)) {
  2654.             if ($number 0{
  2655.                 return self::$_errorCodes['num'];
  2656.             }
  2657.             return sqrt($number M_PI;
  2658.         }
  2659.         return self::$_errorCodes['value'];
  2660.     }    //    function SQRTPI()
  2661.  
  2662.  
  2663.     /**
  2664.      *    FACT
  2665.      *
  2666.      *    Returns the factorial of a number.
  2667.      *
  2668.      *    @param    float    $factVal    Factorial Value
  2669.      *    @return    int        Factorial
  2670.      */
  2671.     public static function FACT($factVal{
  2672.         $factVal    self::flattenSingleValue($factVal);
  2673.  
  2674.         if (is_numeric($factVal)) {
  2675.             if ($factVal 0{
  2676.                 return self::$_errorCodes['num'];
  2677.             }
  2678.             $factLoop floor($factVal);
  2679.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  2680.                 if ($factVal $factLoop{
  2681.                     return self::$_errorCodes['num'];
  2682.                 }
  2683.             }
  2684.  
  2685.             $factorial 1;
  2686.             while ($factLoop 1{
  2687.                 $factorial *= $factLoop--;
  2688.             }
  2689.             return $factorial ;
  2690.         }
  2691.         return self::$_errorCodes['value'];
  2692.     }    //    function FACT()
  2693.  
  2694.  
  2695.     /**
  2696.      *    FACTDOUBLE
  2697.      *
  2698.      *    Returns the double factorial of a number.
  2699.      *
  2700.      *    @param    float    $factVal    Factorial Value
  2701.      *    @return    int        Double Factorial
  2702.      */
  2703.     public static function FACTDOUBLE($factVal{
  2704.         $factLoop    floor(self::flattenSingleValue($factVal));
  2705.  
  2706.         if (is_numeric($factLoop)) {
  2707.             if ($factVal 0{
  2708.                 return self::$_errorCodes['num'];
  2709.             }
  2710.             $factorial 1;
  2711.             while ($factLoop 1{
  2712.                 $factorial *= $factLoop--;
  2713.                 --$factLoop;
  2714.             }
  2715.             return $factorial ;
  2716.         }
  2717.         return self::$_errorCodes['value'];
  2718.     }    //    function FACTDOUBLE()
  2719.  
  2720.  
  2721.     /**
  2722.      *    MULTINOMIAL
  2723.      *
  2724.      *    Returns the ratio of the factorial of a sum of values to the product of factorials.
  2725.      *
  2726.      *    @param    array of mixed        Data Series
  2727.      *    @return    float 
  2728.      */
  2729.     public static function MULTINOMIAL({
  2730.         // Loop through arguments
  2731.         $aArgs self::flattenArray(func_get_args());
  2732.         $summer 0;
  2733.         $divisor 1;
  2734.         foreach ($aArgs as $arg{
  2735.             // Is it a numeric value?
  2736.             if (is_numeric($arg)) {
  2737.                 if ($arg 1{
  2738.                     return self::$_errorCodes['num'];
  2739.                 }
  2740.                 $summer += floor($arg);
  2741.                 $divisor *= self::FACT($arg);
  2742.             else {
  2743.                 return self::$_errorCodes['value'];
  2744.             }
  2745.         }
  2746.  
  2747.         // Return
  2748.         if ($summer 0{
  2749.             $summer self::FACT($summer);
  2750.             return $summer $divisor;
  2751.         }
  2752.         return 0;
  2753.     }    //    function MULTINOMIAL()
  2754.  
  2755.  
  2756.     /**
  2757.      *    CEILING
  2758.      *
  2759.      *    Returns number rounded up, away from zero, to the nearest multiple of significance.
  2760.      *
  2761.      *    @param    float    $number            Number to round
  2762.      *    @param    float    $significance    Significance
  2763.      *    @return    float    Rounded Number
  2764.      */
  2765.     public static function CEILING($number,$significance=null{
  2766.         $number            self::flattenSingleValue($number);
  2767.         $significance    self::flattenSingleValue($significance);
  2768.  
  2769.         if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  2770.             $significance $number/abs($number);
  2771.         }
  2772.  
  2773.         if ((is_numeric($number)) && (is_numeric($significance))) {
  2774.             if (self::SIGN($number== self::SIGN($significance)) {
  2775.                 if ($significance == 0.0{
  2776.                     return 0;
  2777.                 }
  2778.                 return ceil($number $significance$significance;
  2779.             else {
  2780.                 return self::$_errorCodes['num'];
  2781.             }
  2782.         }
  2783.         return self::$_errorCodes['value'];
  2784.     }    //    function CEILING()
  2785.  
  2786.  
  2787.     /**
  2788.      *    EVEN
  2789.      *
  2790.      *    Returns number rounded up to the nearest even integer.
  2791.      *
  2792.      *    @param    float    $number            Number to round
  2793.      *    @return    int        Rounded Number
  2794.      */
  2795.     public static function EVEN($number{
  2796.         $number    self::flattenSingleValue($number);
  2797.  
  2798.         if (is_numeric($number)) {
  2799.             $significance self::SIGN($number);
  2800.             return self::CEILING($number,$significance);
  2801.         }
  2802.         return self::$_errorCodes['value'];
  2803.     }    //    function EVEN()
  2804.  
  2805.  
  2806.     /**
  2807.      *    ODD
  2808.      *
  2809.      *    Returns number rounded up to the nearest odd integer.
  2810.      *
  2811.      *    @param    float    $number            Number to round
  2812.      *    @return    int        Rounded Number
  2813.      */
  2814.     public static function ODD($number{
  2815.         $number    self::flattenSingleValue($number);
  2816.  
  2817.         if (is_numeric($number)) {
  2818.             $significance self::SIGN($number);
  2819.             if ($significance == 0{
  2820.                 return 1;
  2821.             }
  2822.             $result self::CEILING($number,$significance);
  2823.             if (self::IS_EVEN($result)) {
  2824.                 $result += $significance;
  2825.             }
  2826.             return $result;
  2827.         }
  2828.         return self::$_errorCodes['value'];
  2829.     }    //    function ODD()
  2830.  
  2831.  
  2832.     /**
  2833.      *    INTVALUE
  2834.      *
  2835.      *    Casts a floating point value to an integer
  2836.      *
  2837.      *    @param    float    $number            Number to cast to an integer
  2838.      *    @return    integer    Integer value
  2839.      */
  2840.     public static function INTVALUE($number{
  2841.         $number    self::flattenSingleValue($number);
  2842.  
  2843.         if (is_numeric($number)) {
  2844.             return (int) floor($number);
  2845.         }
  2846.         return self::$_errorCodes['value'];
  2847.     }    //    function INTVALUE()
  2848.  
  2849.  
  2850.     /**
  2851.      *    ROUNDUP
  2852.      *
  2853.      *    Rounds a number up to a specified number of decimal places
  2854.      *
  2855.      *    @param    float    $number            Number to round
  2856.      *    @param    int        $digits            Number of digits to which you want to round $number
  2857.      *    @return    float    Rounded Number
  2858.      */
  2859.     public static function ROUNDUP($number,$digits{
  2860.         $number    self::flattenSingleValue($number);
  2861.         $digits    self::flattenSingleValue($digits);
  2862.  
  2863.         if ((is_numeric($number)) && (is_numeric($digits))) {
  2864.             $significance pow(10,$digits);
  2865.             if ($number 0.0{
  2866.                 return floor($number $significance$significance;
  2867.             else {
  2868.                 return ceil($number $significance$significance;
  2869.             }
  2870.         }
  2871.         return self::$_errorCodes['value'];
  2872.     }    //    function ROUNDUP()
  2873.  
  2874.  
  2875.     /**
  2876.      *    ROUNDDOWN
  2877.      *
  2878.      *    Rounds a number down to a specified number of decimal places
  2879.      *
  2880.      *    @param    float    $number            Number to round
  2881.      *    @param    int        $digits            Number of digits to which you want to round $number
  2882.      *    @return    float    Rounded Number
  2883.      */
  2884.     public static function ROUNDDOWN($number,$digits{
  2885.         $number    self::flattenSingleValue($number);
  2886.         $digits    self::flattenSingleValue($digits);
  2887.  
  2888.         if ((is_numeric($number)) && (is_numeric($digits))) {
  2889.             $significance pow(10,$digits);
  2890.             if ($number 0.0{
  2891.                 return ceil($number $significance$significance;
  2892.             else {
  2893.                 return floor($number $significance$significance;
  2894.             }
  2895.         }
  2896.         return self::$_errorCodes['value'];
  2897.     }    //    function ROUNDDOWN()
  2898.  
  2899.  
  2900.     /**
  2901.      *    MROUND
  2902.      *
  2903.      *    Rounds a number to the nearest multiple of a specified value
  2904.      *
  2905.      *    @param    float    $number            Number to round
  2906.      *    @param    int        $multiple        Multiple to which you want to round $number
  2907.      *    @return    float    Rounded Number
  2908.      */
  2909.     public static function MROUND($number,$multiple{
  2910.         $number        self::flattenSingleValue($number);
  2911.         $multiple    self::flattenSingleValue($multiple);
  2912.  
  2913.         if ((is_numeric($number)) && (is_numeric($multiple))) {
  2914.             if ($multiple == 0{
  2915.                 return 0;
  2916.             }
  2917.             if ((self::SIGN($number)) == (self::SIGN($multiple))) {
  2918.                 $multiplier $multiple;
  2919.                 return round($number $multiplier$multiplier;
  2920.             }
  2921.             return self::$_errorCodes['num'];
  2922.         }
  2923.         return self::$_errorCodes['value'];
  2924.     }    //    function MROUND()
  2925.  
  2926.  
  2927.     /**
  2928.      *    SIGN
  2929.      *
  2930.      *    Determines the sign of a number. Returns 1 if the number is positive, zero (0)
  2931.      *    if the number is 0, and -1 if the number is negative.
  2932.      *
  2933.      *    @param    float    $number            Number to round
  2934.      *    @return    int        sign value
  2935.      */
  2936.     public static function SIGN($number{
  2937.         $number    self::flattenSingleValue($number);
  2938.  
  2939.         if (is_numeric($number)) {
  2940.             if ($number == 0.0{
  2941.                 return 0;
  2942.             }
  2943.             return $number abs($number);
  2944.         }
  2945.         return self::$_errorCodes['value'];
  2946.     }    //    function SIGN()
  2947.  
  2948.  
  2949.     /**
  2950.      *    FLOOR
  2951.      *
  2952.      *    Rounds number down, toward zero, to the nearest multiple of significance.
  2953.      *
  2954.      *    @param    float    $number            Number to round
  2955.      *    @param    float    $significance    Significance
  2956.      *    @return    float    Rounded Number
  2957.      */
  2958.     public static function FLOOR($number,$significance=null{
  2959.         $number            self::flattenSingleValue($number);
  2960.         $significance    self::flattenSingleValue($significance);
  2961.  
  2962.         if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  2963.             $significance $number/abs($number);
  2964.         }
  2965.  
  2966.         if ((is_numeric($number)) && (is_numeric($significance))) {
  2967.             if ((float) $significance == 0.0{
  2968.                 return self::$_errorCodes['divisionbyzero'];
  2969.             }
  2970.             if (self::SIGN($number== self::SIGN($significance)) {
  2971.                 return floor($number $significance$significance;
  2972.             else {
  2973.                 return self::$_errorCodes['num'];
  2974.             }
  2975.         }
  2976.         return self::$_errorCodes['value'];
  2977.     }    //    function FLOOR()
  2978.  
  2979.  
  2980.     /**
  2981.      *    PERMUT
  2982.      *
  2983.      *    Returns the number of permutations for a given number of objects that can be
  2984.      *    selected from number objects. A permutation is any set or subset of objects or
  2985.      *    events where internal order is significant. Permutations are different from
  2986.      *    combinations, for which the internal order is not significant. Use this function
  2987.      *    for lottery-style probability calculations.
  2988.      *
  2989.      *    @param    int        $numObjs    Number of different objects
  2990.      *    @param    int        $numInSet    Number of objects in each permutation
  2991.      *    @return    int        Number of permutations
  2992.      */
  2993.     public static function PERMUT($numObjs,$numInSet{
  2994.         $numObjs    self::flattenSingleValue($numObjs);
  2995.         $numInSet    self::flattenSingleValue($numInSet);
  2996.  
  2997.         if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
  2998.             $numInSet floor($numInSet);
  2999.             if ($numObjs $numInSet{
  3000.                 return self::$_errorCodes['num'];
  3001.             }
  3002.             return round(self::FACT($numObjsself::FACT($numObjs $numInSet));
  3003.         }
  3004.         return self::$_errorCodes['value'];
  3005.     }    //    function PERMUT()
  3006.  
  3007.  
  3008.     /**
  3009.      *    COMBIN
  3010.      *
  3011.      *    Returns the number of combinations for a given number of items. Use COMBIN to
  3012.      *    determine the total possible number of groups for a given number of items.
  3013.      *
  3014.      *    @param    int        $numObjs    Number of different objects
  3015.      *    @param    int        $numInSet    Number of objects in each combination
  3016.      *    @return    int        Number of combinations
  3017.      */
  3018.     public static function COMBIN($numObjs,$numInSet{
  3019.         $numObjs    self::flattenSingleValue($numObjs);
  3020.         $numInSet    self::flattenSingleValue($numInSet);
  3021.  
  3022.         if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
  3023.             if ($numObjs $numInSet{
  3024.                 return self::$_errorCodes['num'];
  3025.             elseif ($numInSet 0{
  3026.                 return self::$_errorCodes['num'];
  3027.             }
  3028.             return round(self::FACT($numObjsself::FACT($numObjs $numInSet)) self::FACT($numInSet);
  3029.         }
  3030.         return self::$_errorCodes['value'];
  3031.     }    //    function COMBIN()
  3032.  
  3033.  
  3034.     /**
  3035.      *    SERIESSUM
  3036.      *
  3037.      *    Returns the sum of a power series
  3038.      *
  3039.      *    @param    float            $x    Input value to the power series
  3040.      *    @param    float            $n    Initial power to which you want to raise $x
  3041.      *    @param    float            $m    Step by which to increase $n for each term in the series
  3042.      *    @param    array of mixed        Data Series
  3043.      *    @return    float 
  3044.      */
  3045.     public static function SERIESSUM({
  3046.         // Return value
  3047.         $returnValue 0;
  3048.  
  3049.         // Loop through arguments
  3050.         $aArgs self::flattenArray(func_get_args());
  3051.  
  3052.         $x array_shift($aArgs);
  3053.         $n array_shift($aArgs);
  3054.         $m array_shift($aArgs);
  3055.  
  3056.         if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) {
  3057.             // Calculate
  3058.             $i 0;
  3059.             foreach($aArgs as $arg{
  3060.                 // Is it a numeric value?
  3061.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  3062.                     $returnValue += $arg pow($x,$n ($m $i++));
  3063.                 else {
  3064.                     return self::$_errorCodes['value'];
  3065.                 }
  3066.             }
  3067.             // Return
  3068.             return $returnValue;
  3069.         }
  3070.         return self::$_errorCodes['value'];
  3071.     }    //    function SERIESSUM()
  3072.  
  3073.  
  3074.     /**
  3075.      *    STANDARDIZE
  3076.      *
  3077.      *    Returns a normalized value from a distribution characterized by mean and standard_dev.
  3078.      *
  3079.      *    @param    float    $value        Value to normalize
  3080.      *    @param    float    $mean        Mean Value
  3081.      *    @param    float    $stdDev        Standard Deviation
  3082.      *    @return    float    Standardized value
  3083.      */
  3084.     public static function STANDARDIZE($value,$mean,$stdDev{
  3085.         $value    self::flattenSingleValue($value);
  3086.         $mean    self::flattenSingleValue($mean);
  3087.         $stdDev    self::flattenSingleValue($stdDev);
  3088.  
  3089.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  3090.             if ($stdDev <= 0{
  3091.                 return self::$_errorCodes['num'];
  3092.             }
  3093.             return ($value $mean$stdDev ;
  3094.         }
  3095.         return self::$_errorCodes['value'];
  3096.     }    //    function STANDARDIZE()
  3097.  
  3098.  
  3099.     //
  3100.     //    Private method to return an array of the factors of the input value
  3101.     //
  3102.     private static function _factors($value{
  3103.         $startVal floor(sqrt($value));
  3104.  
  3105.         $factorArray array();
  3106.         for ($i $startVal$i 1--$i{
  3107.             if (($value $i== 0{
  3108.                 $factorArray array_merge($factorArray,self::_factors($value $i));
  3109.                 $factorArray array_merge($factorArray,self::_factors($i));
  3110.                 if ($i <= sqrt($value)) {
  3111.                     break;
  3112.                 }
  3113.             }
  3114.         }
  3115.         if (count($factorArray0{
  3116.             rsort($factorArray);
  3117.             return $factorArray;
  3118.         else {
  3119.             return array((integer) $value);
  3120.         }
  3121.     }    //    function _factors()
  3122.  
  3123.  
  3124.     /**
  3125.      *    LCM
  3126.      *
  3127.      *    Returns the lowest common multiplier of a series of numbers
  3128.      *
  3129.      *    @param    $array    Values to calculate the Lowest Common Multiplier
  3130.      *    @return    int        Lowest Common Multiplier
  3131.      */
  3132.     public static function LCM({
  3133.         $aArgs self::flattenArray(func_get_args());
  3134.  
  3135.         $returnValue 1;
  3136.         $allPoweredFactors array();
  3137.         foreach($aArgs as $value{
  3138.             if (!is_numeric($value)) {
  3139.                 return self::$_errorCodes['value'];
  3140.             }
  3141.             if ($value == 0{
  3142.                 return 0;
  3143.             elseif ($value 0{
  3144.                 return self::$_errorCodes['num'];
  3145.             }
  3146.             $myFactors self::_factors(floor($value));
  3147.             $myCountedFactors array_count_values($myFactors);
  3148.             $myPoweredFactors array();
  3149.             foreach($myCountedFactors as $myCountedFactor => $myCountedPower{
  3150.                 $myPoweredFactors[$myCountedFactorpow($myCountedFactor,$myCountedPower);
  3151.             }
  3152.             foreach($myPoweredFactors as $myPoweredValue => $myPoweredFactor{
  3153.                 if (array_key_exists($myPoweredValue,$allPoweredFactors)) {
  3154.                     if ($allPoweredFactors[$myPoweredValue$myPoweredFactor{
  3155.                         $allPoweredFactors[$myPoweredValue$myPoweredFactor;
  3156.                     }
  3157.                 else {
  3158.                     $allPoweredFactors[$myPoweredValue$myPoweredFactor;
  3159.                 }
  3160.             }
  3161.         }
  3162.         foreach($allPoweredFactors as $allPoweredFactor{
  3163.             $returnValue *= (integer) $allPoweredFactor;
  3164.         }
  3165.         return $returnValue;
  3166.     }    //    function LCM()
  3167.  
  3168.  
  3169.     /**
  3170.      *    GCD
  3171.      *
  3172.      *    Returns the greatest common divisor of a series of numbers
  3173.      *
  3174.      *    @param    $array    Values to calculate the Greatest Common Divisor
  3175.      *    @return    int        Greatest Common Divisor
  3176.      */
  3177.     public static function GCD({
  3178.         $aArgs self::flattenArray(func_get_args());
  3179.  
  3180.         $returnValue 1;
  3181.         $allPoweredFactors array();
  3182.         foreach($aArgs as $value{
  3183.             if ($value == 0{
  3184.                 break;
  3185.             }
  3186.             $myFactors self::_factors($value);
  3187.             $myCountedFactors array_count_values($myFactors);
  3188.             $allValuesFactors[$myCountedFactors;
  3189.         }
  3190.         $allValuesCount count($allValuesFactors);
  3191.         $mergedArray $allValuesFactors[0];
  3192.         for ($i=1;$i $allValuesCount++$i{
  3193.             $mergedArray array_intersect_key($mergedArray,$allValuesFactors[$i]);
  3194.         }
  3195.         $mergedArrayValues count($mergedArray);
  3196.         if ($mergedArrayValues == 0{
  3197.             return $returnValue;
  3198.         elseif ($mergedArrayValues 1{
  3199.             foreach($mergedArray as $mergedKey => $mergedValue{
  3200.                 foreach($allValuesFactors as $highestPowerTest{
  3201.                     foreach($highestPowerTest as $testKey => $testValue{
  3202.                         if (($testKey == $mergedKey&& ($testValue $mergedValue)) {
  3203.                             $mergedArray[$mergedKey$testValue;
  3204.                             $mergedValue $testValue;
  3205.                         }
  3206.                     }
  3207.                 }
  3208.             }
  3209.  
  3210.             $returnValue 1;
  3211.             foreach($mergedArray as $key => $value{
  3212.                 $returnValue *= pow($key,$value);
  3213.             }
  3214.             return $returnValue;
  3215.         else {
  3216.             $keys array_keys($mergedArray);
  3217.             $key $keys[0];
  3218.             $value $mergedArray[$key];
  3219.             foreach($allValuesFactors as $testValue{
  3220.                 foreach($testValue as $mergedKey => $mergedValue{
  3221.                     if (($mergedKey == $key&& ($mergedValue $value)) {
  3222.                         $value $mergedValue;
  3223.                     }
  3224.                 }
  3225.             }
  3226.             return pow($key,$value);
  3227.         }
  3228.     }    //    function GCD()
  3229.  
  3230.  
  3231.     /**
  3232.      *    BINOMDIST
  3233.      *
  3234.      *    Returns the individual term binomial distribution probability. Use BINOMDIST in problems with
  3235.      *    a fixed number of tests or trials, when the outcomes of any trial are only success or failure,
  3236.      *    when trials are independent, and when the probability of success is constant throughout the
  3237.      *    experiment. For example, BINOMDIST can calculate the probability that two of the next three
  3238.      *    babies born are male.
  3239.      *
  3240.      *    @param    float        $value            Number of successes in trials
  3241.      *    @param    float        $trials            Number of trials
  3242.      *    @param    float        $probability    Probability of success on each trial
  3243.      *    @param    boolean        $cumulative 
  3244.      *    @return    float 
  3245.      *
  3246.      *    @todo    Cumulative distribution function
  3247.      *
  3248.      */
  3249.     public static function BINOMDIST($value$trials$probability$cumulative{
  3250.         $value            floor(self::flattenSingleValue($value));
  3251.         $trials            floor(self::flattenSingleValue($trials));
  3252.         $probability    self::flattenSingleValue($probability);
  3253.  
  3254.         if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) {
  3255.             if (($value 0|| ($value $trials)) {
  3256.                 return self::$_errorCodes['num'];
  3257.             }
  3258.             if (($probability 0|| ($probability 1)) {
  3259.                 return self::$_errorCodes['num'];
  3260.             }
  3261.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  3262.                 if ($cumulative{
  3263.                     $summer 0;
  3264.                     for ($i 0$i <= $value++$i{
  3265.                         $summer += self::COMBIN($trials,$ipow($probability,$ipow($probability,$trials $i);
  3266.                     }
  3267.                     return $summer;
  3268.                 else {
  3269.                     return self::COMBIN($trials,$valuepow($probability,$valuepow($probability,$trials $value;
  3270.                 }
  3271.             }
  3272.         }
  3273.         return self::$_errorCodes['value'];
  3274.     }    //    function BINOMDIST()
  3275.  
  3276.  
  3277.     /**
  3278.      *    NEGBINOMDIST
  3279.      *
  3280.      *    Returns the negative binomial distribution. NEGBINOMDIST returns the probability that
  3281.      *    there will be number_f failures before the number_s-th success, when the constant
  3282.      *    probability of a success is probability_s. This function is similar to the binomial
  3283.      *    distribution, except that the number of successes is fixed, and the number of trials is
  3284.      *    variable. Like the binomial, trials are assumed to be independent.
  3285.      *
  3286.      *    @param    float        $failures        Number of Failures
  3287.      *    @param    float        $successes        Threshold number of Successes
  3288.      *    @param    float        $probability    Probability of success on each trial
  3289.      *    @return    float 
  3290.      *
  3291.      */
  3292.     public static function NEGBINOMDIST($failures$successes$probability{
  3293.         $failures        floor(self::flattenSingleValue($failures));
  3294.         $successes        floor(self::flattenSingleValue($successes));
  3295.         $probability    self::flattenSingleValue($probability);
  3296.  
  3297.         if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) {
  3298.             if (($failures 0|| ($successes 1)) {
  3299.                 return self::$_errorCodes['num'];
  3300.             }
  3301.             if (($probability 0|| ($probability 1)) {
  3302.                 return self::$_errorCodes['num'];
  3303.             }
  3304.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  3305.                 if (($failures $successes 1<= 0{
  3306.                     return self::$_errorCodes['num'];
  3307.                 }
  3308.             }
  3309.             return (self::COMBIN($failures $successes 1,$successes 1)) (pow($probability,$successes)) (pow($probability,$failures)) ;
  3310.         }
  3311.         return self::$_errorCodes['value'];
  3312.     }    //    function NEGBINOMDIST()
  3313.  
  3314.  
  3315.     /**
  3316.      *    CRITBINOM
  3317.      *
  3318.      *    Returns the smallest value for which the cumulative binomial distribution is greater
  3319.      *    than or equal to a criterion value
  3320.      *
  3321.      *    See http://support.microsoft.com/kb/828117/ for details of the algorithm used
  3322.      *
  3323.      *    @param    float        $trials            number of Bernoulli trials
  3324.      *    @param    float        $probability    probability of a success on each trial
  3325.      *    @param    float        $alpha            criterion value
  3326.      *    @return    int 
  3327.      *
  3328.      *    @todo    Warning. This implementation differs from the algorithm detailed on the MS
  3329.      *             web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess
  3330.      *             This eliminates a potential endless loop error, but may have an adverse affect on the
  3331.      *             accuracy of the function (although all my tests have so far returned correct results).
  3332.      *
  3333.      */
  3334.     public static function CRITBINOM($trials$probability$alpha{
  3335.         $trials            floor(self::flattenSingleValue($trials));
  3336.         $probability    self::flattenSingleValue($probability);
  3337.         $alpha            self::flattenSingleValue($alpha);
  3338.  
  3339.         if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) {
  3340.             if ($trials 0{
  3341.                 return self::$_errorCodes['num'];
  3342.             }
  3343.             if (($probability 0|| ($probability 1)) {
  3344.                 return self::$_errorCodes['num'];
  3345.             }
  3346.             if (($alpha 0|| ($alpha 1)) {
  3347.                 return self::$_errorCodes['num'];
  3348.             }
  3349.             if ($alpha <= 0.5{
  3350.                 $t sqrt(log(($alpha $alpha)));
  3351.                 $trialsApprox ($t (2.515517 0.802853 $t 0.010328 $t $t(1.432788 $t 0.189269 $t $t 0.001308 $t $t $t));
  3352.             else {
  3353.                 $t sqrt(log(pow($alpha,2)));
  3354.                 $trialsApprox $t (2.515517 0.802853 $t 0.010328 $t $t(1.432788 $t 0.189269 $t $t 0.001308 $t $t $t);
  3355.             }
  3356.             $Guess floor($trials $probability $trialsApprox sqrt($trials $probability ($probability)));
  3357.             if ($Guess 0{
  3358.                 $Guess 0;
  3359.             elseif ($Guess $trials{
  3360.                 $Guess $trials;
  3361.             }
  3362.  
  3363.             $TotalUnscaledProbability $UnscaledPGuess $UnscaledCumPGuess 0.0;
  3364.             $EssentiallyZero 10e-12;
  3365.  
  3366.             $m floor($trials $probability);
  3367.             ++$TotalUnscaledProbability;
  3368.             if ($m == $Guess++$UnscaledPGuess}
  3369.             if ($m <= $Guess++$UnscaledCumPGuess}
  3370.  
  3371.             $PreviousValue 1;
  3372.             $Done False;
  3373.             $k $m 1;
  3374.             while ((!$Done&& ($k <= $trials)) {
  3375.                 $CurrentValue $PreviousValue ($trials $k 1$probability ($k ($probability));
  3376.                 $TotalUnscaledProbability += $CurrentValue;
  3377.                 if ($k == $Guess$UnscaledPGuess += $CurrentValue}
  3378.                 if ($k <= $Guess$UnscaledCumPGuess += $CurrentValue}
  3379.                 if ($CurrentValue <= $EssentiallyZero$Done True}
  3380.                 $PreviousValue $CurrentValue;
  3381.                 ++$k;
  3382.             }
  3383.  
  3384.             $PreviousValue 1;
  3385.             $Done False;
  3386.             $k $m 1;
  3387.             while ((!$Done&& ($k >= 0)) {
  3388.                 $CurrentValue $PreviousValue $k ($probability(($trials $k$probability);
  3389.                 $TotalUnscaledProbability += $CurrentValue;
  3390.                 if ($k == $Guess$UnscaledPGuess += $CurrentValue}
  3391.                 if ($k <= $Guess$UnscaledCumPGuess += $CurrentValue}
  3392.                 if ($CurrentValue <= $EssentiallyZero$Done True}
  3393.                 $PreviousValue $CurrentValue;
  3394.                 --$k;
  3395.             }
  3396.  
  3397.             $PGuess $UnscaledPGuess $TotalUnscaledProbability;
  3398.             $CumPGuess $UnscaledCumPGuess $TotalUnscaledProbability;
  3399.  
  3400. //            $CumPGuessMinus1 = $CumPGuess - $PGuess;
  3401.             $CumPGuessMinus1 $CumPGuess 1;
  3402.  
  3403.             while (True{
  3404.                 if (($CumPGuessMinus1 $alpha&& ($CumPGuess >= $alpha)) {
  3405.                     return $Guess;
  3406.                 elseif (($CumPGuessMinus1 $alpha&& ($CumPGuess $alpha)) {
  3407.                     $PGuessPlus1 $PGuess ($trials $Guess$probability $Guess ($probability);
  3408.                     $CumPGuessMinus1 $CumPGuess;
  3409.                     $CumPGuess $CumPGuess $PGuessPlus1;
  3410.                     $PGuess $PGuessPlus1;
  3411.                     ++$Guess;
  3412.                 elseif (($CumPGuessMinus1 >= $alpha&& ($CumPGuess >= $alpha)) {
  3413.                     $PGuessMinus1 $PGuess $Guess ($probability($trials $Guess 1$probability;
  3414.                     $CumPGuess $CumPGuessMinus1;
  3415.                     $CumPGuessMinus1 $CumPGuessMinus1 $PGuess;
  3416.                     $PGuess $PGuessMinus1;
  3417.                     --$Guess;
  3418.                 }
  3419.             }
  3420.         }
  3421.         return self::$_errorCodes['value'];
  3422.     }    //    function CRITBINOM()
  3423.  
  3424.  
  3425.     /**
  3426.      *    CHIDIST
  3427.      *
  3428.      *    Returns the one-tailed probability of the chi-squared distribution.
  3429.      *
  3430.      *    @param    float        $value            Value for the function
  3431.      *    @param    float        $degrees        degrees of freedom
  3432.      *    @return    float 
  3433.      */
  3434.     public static function CHIDIST($value$degrees{
  3435.         $value        self::flattenSingleValue($value);
  3436.         $degrees    floor(self::flattenSingleValue($degrees));
  3437.  
  3438.         if ((is_numeric($value)) && (is_numeric($degrees))) {
  3439.             if ($degrees 1{
  3440.                 return self::$_errorCodes['num'];
  3441.             }
  3442.             if ($value 0{
  3443.                 if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  3444.                     return 1;
  3445.                 }
  3446.                 return self::$_errorCodes['num'];
  3447.             }
  3448.             return (self::_incompleteGamma($degrees/2,$value/2self::_gamma($degrees/2));
  3449.         }
  3450.         return self::$_errorCodes['value'];
  3451.     }    //    function CHIDIST()
  3452.  
  3453.  
  3454.     /**
  3455.      *    CHIINV
  3456.      *
  3457.      *    Returns the one-tailed probability of the chi-squared distribution.
  3458.      *
  3459.      *    @param    float        $probability    Probability for the function
  3460.      *    @param    float        $degrees        degrees of freedom
  3461.      *    @return    float 
  3462.      */
  3463.     public static function CHIINV($probability$degrees{
  3464.         $probability    self::flattenSingleValue($probability);
  3465.         $degrees        floor(self::flattenSingleValue($degrees));
  3466.  
  3467.         if ((is_numeric($probability)) && (is_numeric($degrees))) {
  3468.  
  3469.             $xLo 100;
  3470.             $xHi 0;
  3471.  
  3472.             $x $xNew 1;
  3473.             $dx    1;
  3474.             $i 0;
  3475.  
  3476.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  3477.                 // Apply Newton-Raphson step
  3478.                 $result self::CHIDIST($x$degrees);
  3479.                 $error $result $probability;
  3480.                 if ($error == 0.0{
  3481.                     $dx 0;
  3482.                 elseif ($error 0.0{
  3483.                     $xLo $x;
  3484.                 else {
  3485.                     $xHi $x;
  3486.                 }
  3487.                 // Avoid division by zero
  3488.                 if ($result != 0.0{
  3489.                     $dx $error $result;
  3490.                     $xNew $x $dx;
  3491.                 }
  3492.                 // If the NR fails to converge (which for example may be the
  3493.                 // case if the initial guess is too rough) we apply a bisection
  3494.                 // step to determine a more narrow interval around the root.
  3495.                 if (($xNew $xLo|| ($xNew $xHi|| ($result == 0.0)) {
  3496.                     $xNew ($xLo $xHi2;
  3497.                     $dx $xNew $x;
  3498.                 }
  3499.                 $x $xNew;
  3500.             }
  3501.             if ($i == MAX_ITERATIONS{
  3502.                 return self::$_errorCodes['na'];
  3503.             }
  3504.             return round($x,12);
  3505.         }
  3506.         return self::$_errorCodes['value'];
  3507.     }    //    function CHIINV()
  3508.  
  3509.  
  3510.     /**
  3511.      *    EXPONDIST
  3512.      *
  3513.      *    Returns the exponential distribution. Use EXPONDIST to model the time between events,
  3514.      *    such as how long an automated bank teller takes to deliver cash. For example, you can
  3515.      *    use EXPONDIST to determine the probability that the process takes at most 1 minute.
  3516.      *
  3517.      *    @param    float        $value            Value of the function
  3518.      *    @param    float        $lambda            The parameter value
  3519.      *    @param    boolean        $cumulative 
  3520.      *    @return    float 
  3521.      */
  3522.     public static function EXPONDIST($value$lambda$cumulative{
  3523.         $value    self::flattenSingleValue($value);
  3524.         $lambda    self::flattenSingleValue($lambda);
  3525.         $cumulative    self::flattenSingleValue($cumulative);
  3526.  
  3527.         if ((is_numeric($value)) && (is_numeric($lambda))) {
  3528.             if (($value 0|| ($lambda 0)) {
  3529.                 return self::$_errorCodes['num'];
  3530.             }
  3531.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  3532.                 if ($cumulative{
  3533.                     return exp(0-$value*$lambda);
  3534.                 else {
  3535.                     return $lambda exp(0-$value*$lambda);
  3536.                 }
  3537.             }
  3538.         }
  3539.         return self::$_errorCodes['value'];
  3540.     }    //    function EXPONDIST()
  3541.  
  3542.  
  3543.     /**
  3544.      *    FISHER
  3545.      *
  3546.      *    Returns the Fisher transformation at x. This transformation produces a function that
  3547.      *    is normally distributed rather than skewed. Use this function to perform hypothesis
  3548.      *    testing on the correlation coefficient.
  3549.      *
  3550.      *    @param    float        $value 
  3551.      *    @return    float 
  3552.      */
  3553.     public static function FISHER($value{
  3554.         $value    self::flattenSingleValue($value);
  3555.  
  3556.         if (is_numeric($value)) {
  3557.             if (($value <= -1|| ($value >= 1)) {
  3558.                 return self::$_errorCodes['num'];
  3559.             }
  3560.             return 0.5 log((1+$value)/(1-$value));
  3561.         }
  3562.         return self::$_errorCodes['value'];
  3563.     }    //    function FISHER()
  3564.  
  3565.  
  3566.     /**
  3567.      *    FISHERINV
  3568.      *
  3569.      *    Returns the inverse of the Fisher transformation. Use this transformation when
  3570.      *    analyzing correlations between ranges or arrays of data. If y = FISHER(x), then
  3571.      *    FISHERINV(y) = x.
  3572.      *
  3573.      *    @param    float        $value 
  3574.      *    @return    float 
  3575.      */
  3576.     public static function FISHERINV($value{
  3577.         $value    self::flattenSingleValue($value);
  3578.  
  3579.         if (is_numeric($value)) {
  3580.             return (exp($value1(exp($value1);
  3581.         }
  3582.         return self::$_errorCodes['value'];
  3583.     }    //    function FISHERINV()
  3584.  
  3585.  
  3586.     // Function cache for _logBeta function
  3587.     private static $_logBetaCache_p            0.0;
  3588.     private static $_logBetaCache_q            0.0;
  3589.     private static $_logBetaCache_result    0.0;
  3590.  
  3591.     /**
  3592.      *    The natural logarithm of the beta function.
  3593.      *    @param require p>0
  3594.      *    @param require q>0
  3595.      *    @return if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
  3596.      *    @author Jaco van Kooten
  3597.      */
  3598.     private static function _logBeta($p$q{
  3599.         if ($p != self::$_logBetaCache_p || $q != self::$_logBetaCache_q{
  3600.             self::$_logBetaCache_p $p;
  3601.             self::$_logBetaCache_q $q;
  3602.             if (($p <= 0.0|| ($q <= 0.0|| (($p $qLOG_GAMMA_X_MAX_VALUE)) {
  3603.                 self::$_logBetaCache_result 0.0;
  3604.             else {
  3605.                 self::$_logBetaCache_result self::_logGamma($pself::_logGamma($qself::_logGamma($p $q);
  3606.             }
  3607.         }
  3608.         return self::$_logBetaCache_result;
  3609.     }    //    function _logBeta()
  3610.  
  3611.  
  3612.     /**
  3613.      *    Evaluates of continued fraction part of incomplete beta function.
  3614.      *    Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
  3615.      *    @author Jaco van Kooten
  3616.      */
  3617.     private static function _betaFraction($x$p$q{
  3618.         $c 1.0;
  3619.         $sum_pq $p $q;
  3620.         $p_plus $p 1.0;
  3621.         $p_minus $p 1.0;
  3622.         $h 1.0 $sum_pq $x $p_plus;
  3623.         if (abs($hXMININ{
  3624.             $h XMININ;
  3625.         }
  3626.         $h 1.0 $h;
  3627.         $frac $h;
  3628.         $m     1;
  3629.         $delta 0.0;
  3630.         while ($m <= MAX_ITERATIONS && abs($delta-1.0PRECISION {
  3631.             $m2 $m;
  3632.             // even index for d
  3633.             $d $m ($q $m$x ( ($p_minus $m2($p $m2));
  3634.             $h 1.0 $d $h;
  3635.             if (abs($hXMININ{
  3636.                 $h XMININ;
  3637.             }
  3638.             $h 1.0 $h;
  3639.             $c 1.0 $d $c;
  3640.             if (abs($cXMININ{
  3641.                 $c XMININ;
  3642.             }
  3643.             $frac *= $h $c;
  3644.             // odd index for d
  3645.             $d = -($p $m($sum_pq $m$x (($p $m2($p_plus $m2));
  3646.             $h 1.0 $d $h;
  3647.             if (abs($hXMININ{
  3648.                 $h XMININ;
  3649.             }
  3650.             $h 1.0 $h;
  3651.             $c 1.0 $d $c;
  3652.             if (abs($cXMININ{
  3653.                 $c XMININ;
  3654.             }
  3655.             $delta $h $c;
  3656.             $frac *= $delta;
  3657.             ++$m;
  3658.         }
  3659.         return $frac;
  3660.     }    //    function _betaFraction()
  3661.  
  3662.  
  3663.     /**
  3664.      * logGamma function
  3665.      *
  3666.      * @version 1.1
  3667.      * @author Jaco van Kooten
  3668.      *
  3669.      *  Original author was Jaco van Kooten. Ported to PHP by Paul Meagher.
  3670.      *
  3671.      *  The natural logarithm of the gamma function. <br />
  3672.      *  Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz <br />
  3673.      *  Applied Mathematics Division <br />
  3674.      *  Argonne National Laboratory <br />
  3675.      *  Argonne, IL 60439 <br />
  3676.      *  <p>
  3677.      *  References:
  3678.      *  <ol>
  3679.      *  <li>W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural
  3680.      *      Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.</li>
  3681.      *  <li>K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.</li>
  3682.      *  <li>Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.</li>
  3683.      *  </ol>
  3684.      *  </p>
  3685.      *  <p>
  3686.      *  From the original documentation:
  3687.      *  </p>
  3688.      *  <p>
  3689.      *  This routine calculates the LOG(GAMMA) function for a positive real argument X.
  3690.      *  Computation is based on an algorithm outlined in references 1 and 2.
  3691.      *  The program uses rational functions that theoretically approximate LOG(GAMMA)
  3692.      *  to at least 18 significant decimal digits. The approximation for X > 12 is from
  3693.      *  reference 3, while approximations for X < 12.0 are similar to those in reference
  3694.      *  1, but are unpublished. The accuracy achieved depends on the arithmetic system,
  3695.      *  the compiler, the intrinsic functions, and proper selection of the
  3696.      *  machine-dependent constants.
  3697.      *  </p>
  3698.      *  <p>
  3699.      *  Error returns: <br />
  3700.      *  The program returns the value XINF for X .LE. 0.0 or when overflow would occur.
  3701.      *  The computation is believed to be free of underflow and overflow.
  3702.      *  </p>
  3703.      * @return MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305
  3704.      */
  3705.  
  3706.     // Function cache for logGamma
  3707.     private static $_logGammaCache_result    0.0;
  3708.     private static $_logGammaCache_x        0.0;
  3709.  
  3710.     private static function _logGamma($x{
  3711.         // Log Gamma related constants
  3712.         static $lg_d1 = -0.5772156649015328605195174;
  3713.         static $lg_d2 0.4227843350984671393993777;
  3714.         static $lg_d4 1.791759469228055000094023;
  3715.  
  3716.         static $lg_p1 array(    4.945235359296727046734888,
  3717.                                 201.8112620856775083915565,
  3718.                                 2290.838373831346393026739,
  3719.                                 11319.67205903380828685045,
  3720.                                 28557.24635671635335736389,
  3721.                                 38484.96228443793359990269,
  3722.                                 26377.48787624195437963534,
  3723.                                 7225.813979700288197698961 );
  3724.         static $lg_p2 array(    4.974607845568932035012064,
  3725.                                 542.4138599891070494101986,
  3726.                                 15506.93864978364947665077,
  3727.                                 184793.2904445632425417223,
  3728.                                 1088204.76946882876749847,
  3729.                                 3338152.967987029735917223,
  3730.                                 5106661.678927352456275255,
  3731.                                 3074109.054850539556250927 );
  3732.         static $lg_p4 array(    14745.02166059939948905062,
  3733.                                 2426813.369486704502836312,
  3734.                                 121475557.4045093227939592,
  3735.                                 2663432449.630976949898078,
  3736.                                 29403789566.34553899906876,
  3737.                                 170266573776.5398868392998,
  3738.                                 492612579337.743088758812,
  3739.                                 560625185622.3951465078242 );
  3740.  
  3741.         static $lg_q1 array(    67.48212550303777196073036,
  3742.                                 1113.332393857199323513008,
  3743.                                 7738.757056935398733233834,
  3744.                                 27639.87074403340708898585,
  3745.                                 54993.10206226157329794414,
  3746.                                 61611.22180066002127833352,
  3747.                                 36351.27591501940507276287,
  3748.                                 8785.536302431013170870835 );
  3749.         static $lg_q2 array(    183.0328399370592604055942,
  3750.                                 7765.049321445005871323047,
  3751.                                 133190.3827966074194402448,
  3752.                                 1136705.821321969608938755,
  3753.                                 5267964.117437946917577538,
  3754.                                 13467014.54311101692290052,
  3755.                                 17827365.30353274213975932,
  3756.                                 9533095.591844353613395747 );
  3757.         static $lg_q4 array(    2690.530175870899333379843,
  3758.                                 639388.5654300092398984238,
  3759.                                 41355999.30241388052042842,
  3760.                                 1120872109.61614794137657,
  3761.                                 14886137286.78813811542398,
  3762.                                 101680358627.2438228077304,
  3763.                                 341747634550.7377132798597,
  3764.                                 446315818741.9713286462081 );
  3765.  
  3766.         static $lg_c  array(    -0.001910444077728,
  3767.                                 8.4171387781295e-4,
  3768.                                 -5.952379913043012e-4,
  3769.                                 7.93650793500350248e-4,
  3770.                                 -0.002777777777777681622553,
  3771.                                 0.08333333333333333331554247,
  3772.                                 0.0057083835261 );
  3773.  
  3774.     // Rough estimate of the fourth root of logGamma_xBig
  3775.     static $lg_frtbig 2.25e76;
  3776.     static $pnt68     0.6796875;
  3777.  
  3778.  
  3779.     if ($x == self::$_logGammaCache_x{
  3780.         return self::$_logGammaCache_result;
  3781.     }
  3782.     $y $x;
  3783.     if ($y 0.0 && $y <= LOG_GAMMA_X_MAX_VALUE{
  3784.         if ($y <= EPS{
  3785.             $res = -log(y);
  3786.         elseif ($y <= 1.5{
  3787.             // ---------------------
  3788.             //    EPS .LT. X .LE. 1.5
  3789.             // ---------------------
  3790.             if ($y $pnt68{
  3791.                 $corr = -log($y);
  3792.                 $xm1 $y;
  3793.             else {
  3794.                 $corr 0.0;
  3795.                 $xm1 $y 1.0;
  3796.             }
  3797.             if ($y <= 0.5 || $y >= $pnt68{
  3798.                 $xden 1.0;
  3799.                 $xnum 0.0;
  3800.                 for ($i 0$i 8++$i{
  3801.                     $xnum $xnum $xm1 $lg_p1[$i];
  3802.                     $xden $xden $xm1 $lg_q1[$i];
  3803.                 }
  3804.                 $res $corr $xm1 ($lg_d1 $xm1 ($xnum $xden));
  3805.             else {
  3806.                 $xm2 $y 1.0;
  3807.                 $xden 1.0;
  3808.                 $xnum 0.0;
  3809.                 for ($i 0$i 8++$i{
  3810.                     $xnum $xnum $xm2 $lg_p2[$i];
  3811.                     $xden $xden $xm2 $lg_q2[$i];
  3812.                 }
  3813.                 $res $corr $xm2 ($lg_d2 $xm2 ($xnum $xden));
  3814.             }
  3815.         elseif ($y <= 4.0{
  3816.             // ---------------------
  3817.             //    1.5 .LT. X .LE. 4.0
  3818.             // ---------------------
  3819.             $xm2 $y 2.0;
  3820.             $xden 1.0;
  3821.             $xnum 0.0;
  3822.             for ($i 0$i 8++$i{
  3823.                 $xnum $xnum $xm2 $lg_p2[$i];
  3824.                 $xden $xden $xm2 $lg_q2[$i];
  3825.             }
  3826.             $res $xm2 ($lg_d2 $xm2 ($xnum $xden));
  3827.         elseif ($y <= 12.0{
  3828.             // ----------------------
  3829.             //    4.0 .LT. X .LE. 12.0
  3830.             // ----------------------
  3831.             $xm4 $y 4.0;
  3832.             $xden = -1.0;
  3833.             $xnum 0.0;
  3834.             for ($i 0$i 8++$i{
  3835.                 $xnum $xnum $xm4 $lg_p4[$i];
  3836.                 $xden $xden $xm4 $lg_q4[$i];
  3837.             }
  3838.             $res $lg_d4 $xm4 ($xnum $xden);
  3839.         else {
  3840.             // ---------------------------------
  3841.             //    Evaluate for argument .GE. 12.0
  3842.             // ---------------------------------
  3843.             $res 0.0;
  3844.             if ($y <= $lg_frtbig{
  3845.                 $res $lg_c[6];
  3846.                 $ysq $y $y;
  3847.                 for ($i 0$i 6++$i)
  3848.                     $res $res $ysq $lg_c[$i];
  3849.                 }
  3850.                 $res /= $y;
  3851.                 $corr log($y);
  3852.                 $res $res log(SQRT2PI0.5 $corr;
  3853.                 $res += $y ($corr 1.0);
  3854.             }
  3855.         else {
  3856.             // --------------------------
  3857.             //    Return for bad arguments
  3858.             // --------------------------
  3859.             $res MAX_VALUE;
  3860.         }
  3861.         // ------------------------------
  3862.         //    Final adjustments and return
  3863.         // ------------------------------
  3864.         self::$_logGammaCache_x $x;
  3865.         self::$_logGammaCache_result $res;
  3866.         return $res;
  3867.     }    //    function _logGamma()
  3868.  
  3869.  
  3870.     /**
  3871.      * Beta function.
  3872.      *
  3873.      * @author Jaco van Kooten
  3874.      *
  3875.      * @param require p>0
  3876.      * @param require q>0
  3877.      * @return if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
  3878.      */
  3879.     private static function _beta($p$q{
  3880.         if ($p <= 0.0 || $q <= 0.0 || ($p $qLOG_GAMMA_X_MAX_VALUE{
  3881.             return 0.0;
  3882.         else {
  3883.             return exp(self::_logBeta($p$q));
  3884.         }
  3885.     }    //    function _beta()
  3886.  
  3887.  
  3888.     /**
  3889.      * Incomplete beta function
  3890.      *
  3891.      * @author Jaco van Kooten
  3892.      * @author Paul Meagher
  3893.      *
  3894.      *  The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992).
  3895.      * @param require 0<=x<=1
  3896.      * @param require p>0
  3897.      * @param require q>0
  3898.      * @return if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow
  3899.      */
  3900.     private static function _incompleteBeta($x$p$q{
  3901.         if ($x <= 0.0{
  3902.             return 0.0;
  3903.         elseif ($x >= 1.0{
  3904.             return 1.0;
  3905.         elseif (($p <= 0.0|| ($q <= 0.0|| (($p $qLOG_GAMMA_X_MAX_VALUE)) {
  3906.             return 0.0;
  3907.         }
  3908.         $beta_gam exp((self::_logBeta($p$q)) $p log($x$q log(1.0 $x));
  3909.         if ($x ($p 1.0($p $q 2.0)) {
  3910.             return $beta_gam self::_betaFraction($x$p$q$p;
  3911.         else {
  3912.             return 1.0 ($beta_gam self::_betaFraction($x$q$p$q);
  3913.         }
  3914.     }    //    function _incompleteBeta()
  3915.  
  3916.  
  3917.     /**
  3918.      * BETADIST
  3919.      *
  3920.      * Returns the beta distribution.
  3921.      *
  3922.      * @param    float        $value            Value at which you want to evaluate the distribution
  3923.      * @param    float        $alpha            Parameter to the distribution
  3924.      * @param    float        $beta            Parameter to the distribution
  3925.      * @param    boolean        $cumulative 
  3926.      * @return    float 
  3927.      *
  3928.      */
  3929.     public static function BETADIST($value,$alpha,$beta,$rMin=0,$rMax=1{
  3930.         $value    self::flattenSingleValue($value);
  3931.         $alpha    self::flattenSingleValue($alpha);
  3932.         $beta    self::flattenSingleValue($beta);
  3933.         $rMin    self::flattenSingleValue($rMin);
  3934.         $rMax    self::flattenSingleValue($rMax);
  3935.  
  3936.         if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
  3937.             if (($value $rMin|| ($value $rMax|| ($alpha <= 0|| ($beta <= 0|| ($rMin == $rMax)) {
  3938.                 return self::$_errorCodes['num'];
  3939.             }
  3940.             if ($rMin $rMax{
  3941.                 $tmp $rMin;
  3942.                 $rMin $rMax;
  3943.                 $rMax $tmp;
  3944.             }
  3945.             $value -= $rMin;
  3946.             $value /= ($rMax $rMin);
  3947.             return self::_incompleteBeta($value,$alpha,$beta);
  3948.         }
  3949.         return self::$_errorCodes['value'];
  3950.     }    //    function BETADIST()
  3951.  
  3952.  
  3953.     /**
  3954.      * BETAINV
  3955.      *
  3956.      * Returns the inverse of the beta distribution.
  3957.      *
  3958.      * @param    float        $probability    Probability at which you want to evaluate the distribution
  3959.      * @param    float        $alpha            Parameter to the distribution
  3960.      * @param    float        $beta            Parameter to the distribution
  3961.      * @param    boolean        $cumulative 
  3962.      * @return    float 
  3963.      *
  3964.      */
  3965.     public static function BETAINV($probability,$alpha,$beta,$rMin=0,$rMax=1{
  3966.         $probability    self::flattenSingleValue($probability);
  3967.         $alpha            self::flattenSingleValue($alpha);
  3968.         $beta            self::flattenSingleValue($beta);
  3969.         $rMin            self::flattenSingleValue($rMin);
  3970.         $rMax            self::flattenSingleValue($rMax);
  3971.  
  3972.         if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
  3973.             if (($alpha <= 0|| ($beta <= 0|| ($rMin == $rMax|| ($probability <= 0|| ($probability 1)) {
  3974.                 return self::$_errorCodes['num'];
  3975.             }
  3976.             if ($rMin $rMax{
  3977.                 $tmp $rMin;
  3978.                 $rMin $rMax;
  3979.                 $rMax $tmp;
  3980.             }
  3981.             $a 0;
  3982.             $b 2;
  3983.  
  3984.             $i 0;
  3985.             while ((($b $aPRECISION&& ($i++ < MAX_ITERATIONS)) {
  3986.                 $guess ($a $b2;
  3987.                 $result self::BETADIST($guess$alpha$beta);
  3988.                 if (($result == $probability|| ($result == 0)) {
  3989.                     $b $a;
  3990.                 elseif ($result $probability{
  3991.                     $b $guess;
  3992.                 else {
  3993.                     $a $guess;
  3994.                 }
  3995.             }
  3996.             if ($i == MAX_ITERATIONS{
  3997.                 return self::$_errorCodes['na'];
  3998.             }
  3999.             return round($rMin $guess ($rMax $rMin),12);
  4000.         }
  4001.         return self::$_errorCodes['value'];
  4002.     }    //    function BETAINV()
  4003.  
  4004.  
  4005.     //
  4006.     //    Private implementation of the incomplete Gamma function
  4007.     //
  4008.     private static function _incompleteGamma($a,$x{
  4009.         static $max 32;
  4010.         $summer 0;
  4011.         for ($n=0$n<=$max++$n{
  4012.             $divisor $a;
  4013.             for ($i=1$i<=$n++$i{
  4014.                 $divisor *= ($a $i);
  4015.             }
  4016.             $summer += (pow($x,$n$divisor);
  4017.         }
  4018.         return pow($x,$aexp(0-$x$summer;
  4019.     }    //    function _incompleteGamma()
  4020.  
  4021.  
  4022.     //
  4023.     //    Private implementation of the Gamma function
  4024.     //
  4025.     private static function _gamma($data{
  4026.         if ($data == 0.0return 0;
  4027.  
  4028.         static $p0 1.000000000190015;
  4029.         static $p array => 76.18009172947146,
  4030.                             => -86.50532032941677,
  4031.                             => 24.01409824083091,
  4032.                             => -1.231739572450155,
  4033.                             => 1.208650973866179e-3,
  4034.                             => -5.395239384953e-6
  4035.                           );
  4036.  
  4037.         $y $x $data;
  4038.         $tmp $x 5.5;
  4039.         $tmp -= ($x 0.5log($tmp);
  4040.  
  4041.         $summer $p0;
  4042.         for ($j=1;$j<=6;++$j{
  4043.             $summer += ($p[$j/ ++$y);
  4044.         }
  4045.         return exp($tmp log(SQRT2PI $summer $x));
  4046.     }    //    function _gamma()
  4047.  
  4048.  
  4049.     /**
  4050.      * GAMMADIST
  4051.      *
  4052.      * Returns the gamma distribution.
  4053.      *
  4054.      * @param    float        $value            Value at which you want to evaluate the distribution
  4055.      * @param    float        $a                Parameter to the distribution
  4056.      * @param    float        $b                Parameter to the distribution
  4057.      * @param    boolean        $cumulative 
  4058.      * @return    float 
  4059.      *
  4060.      */
  4061.     public static function GAMMADIST($value,$a,$b,$cumulative{
  4062.         $value    self::flattenSingleValue($value);
  4063.         $a        self::flattenSingleValue($a);
  4064.         $b        self::flattenSingleValue($b);
  4065.  
  4066.         if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) {
  4067.             if (($value 0|| ($a <= 0|| ($b <= 0)) {
  4068.                 return self::$_errorCodes['num'];
  4069.             }
  4070.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4071.                 if ($cumulative{
  4072.                     return self::_incompleteGamma($a,$value $bself::_gamma($a);
  4073.                 else {
  4074.                     return ((pow($b,$aself::_gamma($a))) pow($value,$a-1exp(0-($value $b));
  4075.                 }
  4076.             }
  4077.         }
  4078.         return self::$_errorCodes['value'];
  4079.     }    //    function GAMMADIST()
  4080.  
  4081.  
  4082.     /**
  4083.      * GAMMAINV
  4084.      *
  4085.      * Returns the inverse of the beta distribution.
  4086.      *
  4087.      * @param    float        $probability    Probability at which you want to evaluate the distribution
  4088.      * @param    float        $alpha            Parameter to the distribution
  4089.      * @param    float        $beta            Parameter to the distribution
  4090.      * @return    float 
  4091.      *
  4092.      */
  4093.     public static function GAMMAINV($probability,$alpha,$beta{
  4094.         $probability    self::flattenSingleValue($probability);
  4095.         $alpha            self::flattenSingleValue($alpha);
  4096.         $beta            self::flattenSingleValue($beta);
  4097.  
  4098.         if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) {
  4099.             if (($alpha <= 0|| ($beta <= 0|| ($probability 0|| ($probability 1)) {
  4100.                 return self::$_errorCodes['num'];
  4101.             }
  4102.  
  4103.             $xLo 0;
  4104.             $xHi $alpha $beta 5;
  4105.  
  4106.             $x $xNew 1;
  4107.             $error $pdf 0;
  4108.             $dx    1024;
  4109.             $i 0;
  4110.  
  4111.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  4112.                 // Apply Newton-Raphson step
  4113.                 $error self::GAMMADIST($x$alpha$betaTrue$probability;
  4114.                 if ($error 0.0{
  4115.                     $xLo $x;
  4116.                 else {
  4117.                     $xHi $x;
  4118.                 }
  4119.                 $pdf self::GAMMADIST($x$alpha$betaFalse);
  4120.                 // Avoid division by zero
  4121.                 if ($pdf != 0.0{
  4122.                     $dx $error $pdf;
  4123.                     $xNew $x $dx;
  4124.                 }
  4125.                 // If the NR fails to converge (which for example may be the
  4126.                 // case if the initial guess is too rough) we apply a bisection
  4127.                 // step to determine a more narrow interval around the root.
  4128.                 if (($xNew $xLo|| ($xNew $xHi|| ($pdf == 0.0)) {
  4129.                     $xNew ($xLo $xHi2;
  4130.                     $dx $xNew $x;
  4131.                 }
  4132.                 $x $xNew;
  4133.             }
  4134.             if ($i == MAX_ITERATIONS{
  4135.                 return self::$_errorCodes['na'];
  4136.             }
  4137.             return $x;
  4138.         }
  4139.         return self::$_errorCodes['value'];
  4140.     }    //    function GAMMAINV()
  4141.  
  4142.  
  4143.     /**
  4144.      * GAMMALN
  4145.      *
  4146.      * Returns the natural logarithm of the gamma function.
  4147.      *
  4148.      * @param    float        $value 
  4149.      * @return    float 
  4150.      */
  4151.     public static function GAMMALN($value{
  4152.         $value    self::flattenSingleValue($value);
  4153.  
  4154.         if (is_numeric($value)) {
  4155.             if ($value <= 0{
  4156.                 return self::$_errorCodes['num'];
  4157.             }
  4158.             return log(self::_gamma($value));
  4159.         }
  4160.         return self::$_errorCodes['value'];
  4161.     }    //    function GAMMALN()
  4162.  
  4163.  
  4164.     /**
  4165.      * NORMDIST
  4166.      *
  4167.      * Returns the normal distribution for the specified mean and standard deviation. This
  4168.      * function has a very wide range of applications in statistics, including hypothesis
  4169.      * testing.
  4170.      *
  4171.      * @param    float        $value 
  4172.      * @param    float        $mean        Mean Value
  4173.      * @param    float        $stdDev        Standard Deviation
  4174.      * @param    boolean        $cumulative 
  4175.      * @return    float 
  4176.      *
  4177.      */
  4178.     public static function NORMDIST($value$mean$stdDev$cumulative{
  4179.         $value    self::flattenSingleValue($value);
  4180.         $mean    self::flattenSingleValue($mean);
  4181.         $stdDev    self::flattenSingleValue($stdDev);
  4182.  
  4183.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4184.             if ($stdDev 0{
  4185.                 return self::$_errorCodes['num'];
  4186.             }
  4187.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4188.                 if ($cumulative{
  4189.                     return 0.5 (self::_erfVal(($value $mean($stdDev sqrt(2))));
  4190.                 else {
  4191.                     return ((SQRT2PI $stdDev)) exp((pow($value $mean,2(($stdDev $stdDev))));
  4192.                 }
  4193.             }
  4194.         }
  4195.         return self::$_errorCodes['value'];
  4196.     }    //    function NORMDIST()
  4197.  
  4198.  
  4199.     /**
  4200.      * NORMSDIST
  4201.      *
  4202.      * Returns the standard normal cumulative distribution function. The distribution has
  4203.      * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a
  4204.      * table of standard normal curve areas.
  4205.      *
  4206.      * @param    float        $value 
  4207.      * @return    float 
  4208.      */
  4209.     public static function NORMSDIST($value{
  4210.         $value    self::flattenSingleValue($value);
  4211.  
  4212.         return self::NORMDIST($value01True);
  4213.     }    //    function NORMSDIST()
  4214.  
  4215.  
  4216.     /**
  4217.      * LOGNORMDIST
  4218.      *
  4219.      * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed
  4220.      * with parameters mean and standard_dev.
  4221.      *
  4222.      * @param    float        $value 
  4223.      * @return    float 
  4224.      */
  4225.     public static function LOGNORMDIST($value$mean$stdDev{
  4226.         $value    self::flattenSingleValue($value);
  4227.         $mean    self::flattenSingleValue($mean);
  4228.         $stdDev    self::flattenSingleValue($stdDev);
  4229.  
  4230.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4231.             if (($value <= 0|| ($stdDev <= 0)) {
  4232.                 return self::$_errorCodes['num'];
  4233.             }
  4234.             return self::NORMSDIST((log($value$mean$stdDev);
  4235.         }
  4236.         return self::$_errorCodes['value'];
  4237.     }    //    function LOGNORMDIST()
  4238.  
  4239.  
  4240.     /***************************************************************************
  4241.      *                                inverse_ncdf.php
  4242.      *                            -------------------
  4243.      *    begin                : Friday, January 16, 2004
  4244.      *    copyright            : (C) 2004 Michael Nickerson
  4245.      *    email                : nickersonm@yahoo.com
  4246.      *
  4247.      ***************************************************************************/
  4248.     private static function _inverse_ncdf($p{
  4249.         //    Inverse ncdf approximation by Peter J. Acklam, implementation adapted to
  4250.         //    PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
  4251.         //    a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html
  4252.         //    I have not checked the accuracy of this implementation. Be aware that PHP
  4253.         //    will truncate the coeficcients to 14 digits.
  4254.  
  4255.         //    You have permission to use and distribute this function freely for
  4256.         //    whatever purpose you want, but please show common courtesy and give credit
  4257.         //    where credit is due.
  4258.  
  4259.         //    Input paramater is $p - probability - where 0 < p < 1.
  4260.  
  4261.         //    Coefficients in rational approximations
  4262.         static $a array(    => -3.969683028665376e+01,
  4263.                             => 2.209460984245205e+02,
  4264.                             => -2.759285104469687e+02,
  4265.                             => 1.383577518672690e+02,
  4266.                             => -3.066479806614716e+01,
  4267.                             => 2.506628277459239e+00
  4268.                          );
  4269.  
  4270.         static $b array(    => -5.447609879822406e+01,
  4271.                             => 1.615858368580409e+02,
  4272.                             => -1.556989798598866e+02,
  4273.                             => 6.680131188771972e+01,
  4274.                             => -1.328068155288572e+01
  4275.                          );
  4276.  
  4277.         static $c array(    => -7.784894002430293e-03,
  4278.                             => -3.223964580411365e-01,
  4279.                             => -2.400758277161838e+00,
  4280.                             => -2.549732539343734e+00,
  4281.                             => 4.374664141464968e+00,
  4282.                             => 2.938163982698783e+00
  4283.                          );
  4284.  
  4285.         static $d array(    => 7.784695709041462e-03,
  4286.                             => 3.224671290700398e-01,
  4287.                             => 2.445134137142996e+00,
  4288.                             => 3.754408661907416e+00
  4289.                          );
  4290.  
  4291.         //    Define lower and upper region break-points.
  4292.         $p_low 0.02425;            //Use lower region approx. below this
  4293.         $p_high $p_low;        //Use upper region approx. above this
  4294.  
  4295.         if ($p && $p $p_low{
  4296.             //    Rational approximation for lower region.
  4297.             $q sqrt(-log($p));
  4298.             return ((((($c[1$q $c[2]$q $c[3]$q $c[4]$q $c[5]$q $c[6]/
  4299.                     (((($d[1$q $d[2]$q $d[3]$q $d[4]$q 1);
  4300.         elseif ($p_low <= $p && $p <= $p_high{
  4301.             //    Rational approximation for central region.
  4302.             $q $p 0.5;
  4303.             $r $q $q;
  4304.             return ((((($a[1$r $a[2]$r $a[3]$r $a[4]$r $a[5]$r $a[6]$q /
  4305.                    ((((($b[1$r $b[2]$r $b[3]$r $b[4]$r $b[5]$r 1);
  4306.         elseif ($p_high $p && $p 1{
  4307.             //    Rational approximation for upper region.
  4308.             $q sqrt(-log($p));
  4309.             return -((((($c[1$q $c[2]$q $c[3]$q $c[4]$q $c[5]$q $c[6]/
  4310.                      (((($d[1$q $d[2]$q $d[3]$q $d[4]$q 1);
  4311.         }
  4312.         //    If 0 < p < 1, return a null value
  4313.         return self::$_errorCodes['null'];
  4314.     }    //    function _inverse_ncdf()
  4315.  
  4316.  
  4317.     private static function _inverse_ncdf2($prob{
  4318.         //    Approximation of inverse standard normal CDF developed by
  4319.         //    B. Moro, "The Full Monte," Risk 8(2), Feb 1995, 57-58.
  4320.  
  4321.         $a1 2.50662823884;
  4322.         $a2 = -18.61500062529;
  4323.         $a3 41.39119773534;
  4324.         $a4 = -25.44106049637;
  4325.  
  4326.         $b1 = -8.4735109309;
  4327.         $b2 23.08336743743;
  4328.         $b3 = -21.06224101826;
  4329.         $b4 3.13082909833;
  4330.  
  4331.         $c1 0.337475482272615;
  4332.         $c2 0.976169019091719;
  4333.         $c3 0.160797971491821;
  4334.         $c4 2.76438810333863E-02;
  4335.         $c5 3.8405729373609E-03;
  4336.         $c6 3.951896511919E-04;
  4337.         $c7 3.21767881768E-05;
  4338.         $c8 2.888167364E-07;
  4339.         $c9 3.960315187E-07;
  4340.  
  4341.         $y $prob 0.5;
  4342.         if (abs($y0.42{
  4343.             $z ($y $y);
  4344.             $z $y ((($a4 $z $a3$z $a2$z $a1(((($b4 $z $b3$z $b2$z $b1$z 1);
  4345.         else {
  4346.             if ($y 0{
  4347.                 $z log(-log($prob));
  4348.             else {
  4349.                 $z log(-log($prob));
  4350.             }
  4351.             $z $c1 $z ($c2 $z ($c3 $z ($c4 $z ($c5 $z ($c6 $z ($c7 $z ($c8 $z $c9)))))));
  4352.             if ($y 0{
  4353.                 $z = -$z;
  4354.             }
  4355.         }
  4356.         return $z;
  4357.     }    //    function _inverse_ncdf2()
  4358.  
  4359.  
  4360.     private static function _inverse_ncdf3($p{
  4361.         //    ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3.
  4362.         //    Produces the normal deviate Z corresponding to a given lower
  4363.         //    tail area of P; Z is accurate to about 1 part in 10**16.
  4364.         //
  4365.         //    This is a PHP version of the original FORTRAN code that can
  4366.         //    be found at http://lib.stat.cmu.edu/apstat/
  4367.         $split1 0.425;
  4368.         $split2 5;
  4369.         $const1 0.180625;
  4370.         $const2 1.6;
  4371.  
  4372.         //    coefficients for p close to 0.5
  4373.         $a0 3.3871328727963666080;
  4374.         $a1 1.3314166789178437745E+2;
  4375.         $a2 1.9715909503065514427E+3;
  4376.         $a3 1.3731693765509461125E+4;
  4377.         $a4 4.5921953931549871457E+4;
  4378.         $a5 6.7265770927008700853E+4;
  4379.         $a6 3.3430575583588128105E+4;
  4380.         $a7 2.5090809287301226727E+3;
  4381.  
  4382.         $b1 4.2313330701600911252E+1;
  4383.         $b2 6.8718700749205790830E+2;
  4384.         $b3 5.3941960214247511077E+3;
  4385.         $b4 2.1213794301586595867E+4;
  4386.         $b5 3.9307895800092710610E+4;
  4387.         $b6 2.8729085735721942674E+4;
  4388.         $b7 5.2264952788528545610E+3;
  4389.  
  4390.         //    coefficients for p not close to 0, 0.5 or 1.
  4391.         $c0 1.42343711074968357734;
  4392.         $c1 4.63033784615654529590;
  4393.         $c2 5.76949722146069140550;
  4394.         $c3 3.64784832476320460504;
  4395.         $c4 1.27045825245236838258;
  4396.         $c5 2.41780725177450611770E-1;
  4397.         $c6 2.27238449892691845833E-2;
  4398.         $c7 7.74545014278341407640E-4;
  4399.  
  4400.         $d1 2.05319162663775882187;
  4401.         $d2 1.67638483018380384940;
  4402.         $d3 6.89767334985100004550E-1;
  4403.         $d4 1.48103976427480074590E-1;
  4404.         $d5 1.51986665636164571966E-2;
  4405.         $d6 5.47593808499534494600E-4;
  4406.         $d7 1.05075007164441684324E-9;
  4407.  
  4408.         //    coefficients for p near 0 or 1.
  4409.         $e0 6.65790464350110377720;
  4410.         $e1 5.46378491116411436990;
  4411.         $e2 1.78482653991729133580;
  4412.         $e3 2.96560571828504891230E-1;
  4413.         $e4 2.65321895265761230930E-2;
  4414.         $e5 1.24266094738807843860E-3;
  4415.         $e6 2.71155556874348757815E-5;
  4416.         $e7 2.01033439929228813265E-7;
  4417.  
  4418.         $f1 5.99832206555887937690E-1;
  4419.         $f2 1.36929880922735805310E-1;
  4420.         $f3 1.48753612908506148525E-2;
  4421.         $f4 7.86869131145613259100E-4;
  4422.         $f5 1.84631831751005468180E-5;
  4423.         $f6 1.42151175831644588870E-7;
  4424.         $f7 2.04426310338993978564E-15;
  4425.  
  4426.         $q $p 0.5;
  4427.  
  4428.         //    computation for p close to 0.5
  4429.         if (abs($q<= split1{
  4430.             $R $const1 $q $q;
  4431.             $z $q ((((((($a7 $R $a6$R $a5$R $a4$R $a3$R $a2$R $a1$R $a0/
  4432.                       ((((((($b7 $R $b6$R $b5$R $b4$R $b3$R $b2$R $b1$R 1);
  4433.         else {
  4434.             if ($q 0{
  4435.                 $R $p;
  4436.             else {
  4437.                 $R $p;
  4438.             }
  4439.             $R pow(-log($R),2);
  4440.  
  4441.             //    computation for p not close to 0, 0.5 or 1.
  4442.             If ($R <= $split2{
  4443.                 $R $R $const2;
  4444.                 $z ((((((($c7 $R $c6$R $c5$R $c4$R $c3$R $c2$R $c1$R $c0/
  4445.                      ((((((($d7 $R $d6$R $d5$R $d4$R $d3$R $d2$R $d1$R 1);
  4446.             else {
  4447.             //    computation for p near 0 or 1.
  4448.                 $R $R $split2;
  4449.                 $z ((((((($e7 $R $e6$R $e5$R $e4$R $e3$R $e2$R $e1$R $e0/
  4450.                      ((((((($f7 $R $f6$R $f5$R $f4$R $f3$R $f2$R $f1$R 1);
  4451.             }
  4452.             if ($q 0{
  4453.                 $z = -$z;
  4454.             }
  4455.         }
  4456.         return $z;
  4457.     }    //    function _inverse_ncdf3()
  4458.  
  4459.  
  4460.     /**
  4461.      * NORMINV
  4462.      *
  4463.      * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation.
  4464.      *
  4465.      * @param    float        $value 
  4466.      * @param    float        $mean        Mean Value
  4467.      * @param    float        $stdDev        Standard Deviation
  4468.      * @return    float 
  4469.      *
  4470.      */
  4471.     public static function NORMINV($probability,$mean,$stdDev{
  4472.         $probability    self::flattenSingleValue($probability);
  4473.         $mean            self::flattenSingleValue($mean);
  4474.         $stdDev            self::flattenSingleValue($stdDev);
  4475.  
  4476.         if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4477.             if (($probability 0|| ($probability 1)) {
  4478.                 return self::$_errorCodes['num'];
  4479.             }
  4480.             if ($stdDev 0{
  4481.                 return self::$_errorCodes['num'];
  4482.             }
  4483.             return (self::_inverse_ncdf($probability$stdDev$mean;
  4484.         }
  4485.         return self::$_errorCodes['value'];
  4486.     }    //    function NORMINV()
  4487.  
  4488.  
  4489.     /**
  4490.      * NORMSINV
  4491.      *
  4492.      * Returns the inverse of the standard normal cumulative distribution
  4493.      *
  4494.      * @param    float        $value 
  4495.      * @return    float 
  4496.      */
  4497.     public static function NORMSINV($value{
  4498.         return self::NORMINV($value01);
  4499.     }    //    function NORMSINV()
  4500.  
  4501.  
  4502.     /**
  4503.      * LOGINV
  4504.      *
  4505.      * Returns the inverse of the normal cumulative distribution
  4506.      *
  4507.      * @param    float        $value 
  4508.      * @return    float 
  4509.      *
  4510.      * @todo    Try implementing P J Acklam's refinement algorithm for greater
  4511.      *             accuracy if I can get my head round the mathematics
  4512.      *             (as described at) http://home.online.no/~pjacklam/notes/invnorm/
  4513.      */
  4514.     public static function LOGINV($probability$mean$stdDev{
  4515.         $probability    self::flattenSingleValue($probability);
  4516.         $mean            self::flattenSingleValue($mean);
  4517.         $stdDev            self::flattenSingleValue($stdDev);
  4518.  
  4519.         if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4520.             if (($probability 0|| ($probability 1|| ($stdDev <= 0)) {
  4521.                 return self::$_errorCodes['num'];
  4522.             }
  4523.             return exp($mean $stdDev self::NORMSINV($probability));
  4524.         }
  4525.         return self::$_errorCodes['value'];
  4526.     }    //    function LOGINV()
  4527.  
  4528.  
  4529.     /**
  4530.      * HYPGEOMDIST
  4531.      *
  4532.      * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of
  4533.      * sample successes, given the sample size, population successes, and population size.
  4534.      *
  4535.      * @param    float        $sampleSuccesses        Number of successes in the sample
  4536.      * @param    float        $sampleNumber            Size of the sample
  4537.      * @param    float        $populationSuccesses    Number of successes in the population
  4538.      * @param    float        $populationNumber        Population size
  4539.      * @return    float 
  4540.      *
  4541.      */
  4542.     public static function HYPGEOMDIST($sampleSuccesses$sampleNumber$populationSuccesses$populationNumber{
  4543.         $sampleSuccesses        floor(self::flattenSingleValue($sampleSuccesses));
  4544.         $sampleNumber            floor(self::flattenSingleValue($sampleNumber));
  4545.         $populationSuccesses    floor(self::flattenSingleValue($populationSuccesses));
  4546.         $populationNumber        floor(self::flattenSingleValue($populationNumber));
  4547.  
  4548.         if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) {
  4549.             if (($sampleSuccesses 0|| ($sampleSuccesses $sampleNumber|| ($sampleSuccesses $populationSuccesses)) {
  4550.                 return self::$_errorCodes['num'];
  4551.             }
  4552.             if (($sampleNumber <= 0|| ($sampleNumber $populationNumber)) {
  4553.                 return self::$_errorCodes['num'];
  4554.             }
  4555.             if (($populationSuccesses <= 0|| ($populationSuccesses $populationNumber)) {
  4556.                 return self::$_errorCodes['num'];
  4557.             }
  4558.             return self::COMBIN($populationSuccesses,$sampleSuccesses*
  4559.                    self::COMBIN($populationNumber $populationSuccesses,$sampleNumber $sampleSuccesses/
  4560.                    self::COMBIN($populationNumber,$sampleNumber);
  4561.         }
  4562.         return self::$_errorCodes['value'];
  4563.     }    //    function HYPGEOMDIST()
  4564.  
  4565.  
  4566.     /**
  4567.      * TDIST
  4568.      *
  4569.      * Returns the probability of Student's T distribution.
  4570.      *
  4571.      * @param    float        $value            Value for the function
  4572.      * @param    float        $degrees        degrees of freedom
  4573.      * @param    float        $tails            number of tails (1 or 2)
  4574.      * @return    float 
  4575.      */
  4576.     public static function TDIST($value$degrees$tails{
  4577.         $value        self::flattenSingleValue($value);
  4578.         $degrees    floor(self::flattenSingleValue($degrees));
  4579.         $tails        floor(self::flattenSingleValue($tails));
  4580.  
  4581.         if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) {
  4582.             if (($value 0|| ($degrees 1|| ($tails 1|| ($tails 2)) {
  4583.                 return self::$_errorCodes['num'];
  4584.             }
  4585.             //    tdist, which finds the probability that corresponds to a given value
  4586.             //    of t with k degrees of freedom. This algorithm is translated from a
  4587.             //    pascal function on p81 of "Statistical Computing in Pascal" by D
  4588.             //    Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd:
  4589.             //    London). The above Pascal algorithm is itself a translation of the
  4590.             //    fortran algoritm "AS 3" by B E Cooper of the Atlas Computer
  4591.             //    Laboratory as reported in (among other places) "Applied Statistics
  4592.             //    Algorithms", editied by P Griffiths and I D Hill (1985; Ellis
  4593.             //    Horwood Ltd.; W. Sussex, England).
  4594.             $tterm $degrees;
  4595.             $ttheta atan2($value,sqrt($tterm));
  4596.             $tc cos($ttheta);
  4597.             $ts sin($ttheta);
  4598.             $tsum 0;
  4599.  
  4600.             if (($degrees 2== 1{
  4601.                 $ti 3;
  4602.                 $tterm $tc;
  4603.             else {
  4604.                 $ti 2;
  4605.                 $tterm 1;
  4606.             }
  4607.  
  4608.             $tsum $tterm;
  4609.             while ($ti $degrees{
  4610.                 $tterm *= $tc $tc ($ti 1$ti;
  4611.                 $tsum += $tterm;
  4612.                 $ti += 2;
  4613.             }
  4614.             $tsum *= $ts;
  4615.             if (($degrees 2== 1$tsum M_2DIVPI ($tsum $ttheta)}
  4616.             $tValue 0.5 ($tsum);
  4617.             if ($tails == 1{
  4618.                 return abs($tValue);
  4619.             else {
  4620.                 return abs(($tValue$tValue);
  4621.             }
  4622.         }
  4623.         return self::$_errorCodes['value'];
  4624.     }    //    function TDIST()
  4625.  
  4626.  
  4627.     /**
  4628.      * TINV
  4629.      *
  4630.      * Returns the one-tailed probability of the chi-squared distribution.
  4631.      *
  4632.      * @param    float        $probability    Probability for the function
  4633.      * @param    float        $degrees        degrees of freedom
  4634.      * @return    float 
  4635.      */
  4636.     public static function TINV($probability$degrees{
  4637.         $probability    self::flattenSingleValue($probability);
  4638.         $degrees        floor(self::flattenSingleValue($degrees));
  4639.  
  4640.         if ((is_numeric($probability)) && (is_numeric($degrees))) {
  4641.             $xLo 100;
  4642.             $xHi 0;
  4643.  
  4644.             $x $xNew 1;
  4645.             $dx    1;
  4646.             $i 0;
  4647.  
  4648.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  4649.                 // Apply Newton-Raphson step
  4650.                 $result self::TDIST($x$degrees2);
  4651.                 $error $result $probability;
  4652.                 if ($error == 0.0{
  4653.                     $dx 0;
  4654.                 elseif ($error 0.0{
  4655.                     $xLo $x;
  4656.                 else {
  4657.                     $xHi $x;
  4658.                 }
  4659.                 // Avoid division by zero
  4660.                 if ($result != 0.0{
  4661.                     $dx $error $result;
  4662.                     $xNew $x $dx;
  4663.                 }
  4664.                 // If the NR fails to converge (which for example may be the
  4665.                 // case if the initial guess is too rough) we apply a bisection
  4666.                 // step to determine a more narrow interval around the root.
  4667.                 if (($xNew $xLo|| ($xNew $xHi|| ($result == 0.0)) {
  4668.                     $xNew ($xLo $xHi2;
  4669.                     $dx $xNew $x;
  4670.                 }
  4671.                 $x $xNew;
  4672.             }
  4673.             if ($i == MAX_ITERATIONS{
  4674.                 return self::$_errorCodes['na'];
  4675.             }
  4676.             return round($x,12);
  4677.         }
  4678.         return self::$_errorCodes['value'];
  4679.     }    //    function TINV()
  4680.  
  4681.  
  4682.     /**
  4683.      * CONFIDENCE
  4684.      *
  4685.      * Returns the confidence interval for a population mean
  4686.      *
  4687.      * @param    float        $alpha 
  4688.      * @param    float        $stdDev        Standard Deviation
  4689.      * @param    float        $size 
  4690.      * @return    float 
  4691.      *
  4692.      */
  4693.     public static function CONFIDENCE($alpha,$stdDev,$size{
  4694.         $alpha    self::flattenSingleValue($alpha);
  4695.         $stdDev    self::flattenSingleValue($stdDev);
  4696.         $size    floor(self::flattenSingleValue($size));
  4697.  
  4698.         if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) {
  4699.             if (($alpha <= 0|| ($alpha >= 1)) {
  4700.                 return self::$_errorCodes['num'];
  4701.             }
  4702.             if (($stdDev <= 0|| ($size 1)) {
  4703.                 return self::$_errorCodes['num'];
  4704.             }
  4705.             return self::NORMSINV($alpha 2$stdDev sqrt($size);
  4706.         }
  4707.         return self::$_errorCodes['value'];
  4708.     }    //    function CONFIDENCE()
  4709.  
  4710.  
  4711.     /**
  4712.      * POISSON
  4713.      *
  4714.      * Returns the Poisson distribution. A common application of the Poisson distribution
  4715.      * is predicting the number of events over a specific time, such as the number of
  4716.      * cars arriving at a toll plaza in 1 minute.
  4717.      *
  4718.      * @param    float        $value 
  4719.      * @param    float        $mean        Mean Value
  4720.      * @param    boolean        $cumulative 
  4721.      * @return    float 
  4722.      *
  4723.      */
  4724.     public static function POISSON($value$mean$cumulative{
  4725.         $value    self::flattenSingleValue($value);
  4726.         $mean    self::flattenSingleValue($mean);
  4727.  
  4728.         if ((is_numeric($value)) && (is_numeric($mean))) {
  4729.             if (($value <= 0|| ($mean <= 0)) {
  4730.                 return self::$_errorCodes['num'];
  4731.             }
  4732.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4733.                 if ($cumulative{
  4734.                     $summer 0;
  4735.                     for ($i 0$i <= floor($value)++$i{
  4736.                         $summer += pow($mean,$iself::FACT($i);
  4737.                     }
  4738.                     return exp(0-$mean$summer;
  4739.                 else {
  4740.                     return (exp(0-$meanpow($mean,$value)) self::FACT($value);
  4741.                 }
  4742.             }
  4743.         }
  4744.         return self::$_errorCodes['value'];
  4745.     }    //    function POISSON()
  4746.  
  4747.  
  4748.     /**
  4749.      * WEIBULL
  4750.      *
  4751.      * Returns the Weibull distribution. Use this distribution in reliability
  4752.      * analysis, such as calculating a device's mean time to failure.
  4753.      *
  4754.      * @param    float        $value 
  4755.      * @param    float        $alpha        Alpha Parameter
  4756.      * @param    float        $beta        Beta Parameter
  4757.      * @param    boolean        $cumulative 
  4758.      * @return    float 
  4759.      *
  4760.      */
  4761.     public static function WEIBULL($value$alpha$beta$cumulative{
  4762.         $value    self::flattenSingleValue($value);
  4763.         $alpha    self::flattenSingleValue($alpha);
  4764.         $beta    self::flattenSingleValue($beta);
  4765.  
  4766.         if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) {
  4767.             if (($value 0|| ($alpha <= 0|| ($beta <= 0)) {
  4768.                 return self::$_errorCodes['num'];
  4769.             }
  4770.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4771.                 if ($cumulative{
  4772.                     return exp(pow($value $beta,$alpha));
  4773.                 else {
  4774.                     return ($alpha pow($beta,$alpha)) pow($value,$alpha 1exp(pow($value $beta,$alpha));
  4775.                 }
  4776.             }
  4777.         }
  4778.         return self::$_errorCodes['value'];
  4779.     }    //    function WEIBULL()
  4780.  
  4781.  
  4782.     /**
  4783.      * ZTEST
  4784.      *
  4785.      * Returns the Weibull distribution. Use this distribution in reliability
  4786.      * analysis, such as calculating a device's mean time to failure.
  4787.      *
  4788.      * @param    float        $value 
  4789.      * @param    float        $alpha        Alpha Parameter
  4790.      * @param    float        $beta        Beta Parameter
  4791.      * @param    boolean        $cumulative 
  4792.      * @return    float 
  4793.      *
  4794.      */
  4795.     public static function ZTEST($dataSet$m0$sigma=null{
  4796.         $dataSet    self::flattenArrayIndexed($dataSet);
  4797.         $m0            self::flattenSingleValue($m0);
  4798.         $sigma        self::flattenSingleValue($sigma);
  4799.  
  4800.         if (is_null($sigma)) {
  4801.             $sigma self::STDEV($dataSet);
  4802.         }
  4803.         $n count($dataSet);
  4804.  
  4805.         return self::NORMSDIST((self::AVERAGE($dataSet$m0)/($sigma/SQRT($n)));
  4806.     }    //    function ZTEST()
  4807.  
  4808.  
  4809.     /**
  4810.      * SKEW
  4811.      *
  4812.      * Returns the skewness of a distribution. Skewness characterizes the degree of asymmetry
  4813.      * of a distribution around its mean. Positive skewness indicates a distribution with an
  4814.      * asymmetric tail extending toward more positive values. Negative skewness indicates a
  4815.      * distribution with an asymmetric tail extending toward more negative values.
  4816.      *
  4817.      * @param    array    Data Series
  4818.      * @return    float 
  4819.      */
  4820.     public static function SKEW({
  4821.         $aArgs self::flattenArrayIndexed(func_get_args());
  4822.         $mean self::AVERAGE($aArgs);
  4823.         $stdDev self::STDEV($aArgs);
  4824.  
  4825.         $count $summer 0;
  4826.         // Loop through arguments
  4827.         foreach ($aArgs as $k => $arg{
  4828.             if ((is_bool($arg)) &&
  4829.                 (!self::isMatrixValue($k))) {
  4830.             else {
  4831.                 // Is it a numeric value?
  4832.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  4833.                     $summer += pow((($arg $mean$stdDev),3;
  4834.                     ++$count;
  4835.                 }
  4836.             }
  4837.         }
  4838.  
  4839.         // Return
  4840.         if ($count 2{
  4841.             return $summer ($count (($count-1($count-2)));
  4842.         }
  4843.         return self::$_errorCodes['divisionbyzero'];
  4844.     }    //    function SKEW()
  4845.  
  4846.  
  4847.     /**
  4848.      * KURT
  4849.      *
  4850.      * Returns the kurtosis of a data set. Kurtosis characterizes the relative peakedness
  4851.      * or flatness of a distribution compared with the normal distribution. Positive
  4852.      * kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a
  4853.      * relatively flat distribution.
  4854.      *
  4855.      * @param    array    Data Series
  4856.      * @return    float 
  4857.      */
  4858.     public static function KURT({
  4859.         $aArgs self::flattenArrayIndexed(func_get_args());
  4860.         $mean self::AVERAGE($aArgs);
  4861.         $stdDev self::STDEV($aArgs);
  4862.  
  4863.         if ($stdDev 0{
  4864.             $count $summer 0;
  4865.             // Loop through arguments
  4866.             foreach ($aArgs as $k => $arg{
  4867.                 if ((is_bool($arg)) &&
  4868.                     (!self::isMatrixValue($k))) {
  4869.                 else {
  4870.                     // Is it a numeric value?
  4871.                     if ((is_numeric($arg)) && (!is_string($arg))) {
  4872.                         $summer += pow((($arg $mean$stdDev),4;
  4873.                         ++$count;
  4874.                     }
  4875.                 }
  4876.             }
  4877.  
  4878.             // Return
  4879.             if ($count 3{
  4880.                 return $summer ($count ($count+1(($count-1($count-2($count-3))) (pow($count-1,2(($count-2($count-3)));
  4881.             }
  4882.         }
  4883.         return self::$_errorCodes['divisionbyzero'];
  4884.     }    //    function KURT()
  4885.  
  4886.  
  4887.     /**
  4888.      * RAND
  4889.      *
  4890.      * @param    int        $min    Minimal value
  4891.      * @param    int        $max    Maximal value
  4892.      * @return    int        Random number
  4893.      */
  4894.     public static function RAND($min 0$max 0{
  4895.         $min        self::flattenSingleValue($min);
  4896.         $max        self::flattenSingleValue($max);
  4897.  
  4898.         if ($min == && $max == 0{
  4899.             return (rand(0,10000000)) 10000000;
  4900.         else {
  4901.             return rand($min$max);
  4902.         }
  4903.     }    //    function RAND()
  4904.  
  4905.  
  4906.     /**
  4907.      * MOD
  4908.      *
  4909.      * @param    int        $a        Dividend
  4910.      * @param    int        $b        Divisor
  4911.      * @return    int        Remainder
  4912.      */
  4913.     public static function MOD($a 1$b 1{
  4914.         $a        self::flattenSingleValue($a);
  4915.         $b        self::flattenSingleValue($b);
  4916.  
  4917.         if ($b == 0.0{
  4918.             return self::$_errorCodes['divisionbyzero'];
  4919.         elseif (($a 0.0&& ($b 0.0)) {
  4920.             return $b fmod(abs($a),$b);
  4921.         elseif (($a 0.0&& ($b 0.0)) {
  4922.             return $b fmod($a,abs($b));
  4923.         }
  4924.  
  4925.         return fmod($a,$b);
  4926.     }    //    function MOD()
  4927.  
  4928.  
  4929.     /**
  4930.      * CHARACTER
  4931.      *
  4932.      * @param    string    $character    Value
  4933.      * @return    int 
  4934.      */
  4935.     public static function CHARACTER($character{
  4936.         $character    self::flattenSingleValue($character);
  4937.  
  4938.         if ((!is_numeric($character)) || ($character 0)) {
  4939.             return self::$_errorCodes['value'];
  4940.         }
  4941.  
  4942.         if (function_exists('mb_convert_encoding')) {
  4943.             return mb_convert_encoding('&#'.intval($character).';''UTF-8''HTML-ENTITIES');
  4944.         else {
  4945.             return chr(intval($character));
  4946.         }
  4947.     }
  4948.  
  4949.  
  4950.     private static function _uniord($c{
  4951.         if (ord($c{0}>=&& ord($c{0}<= 127)
  4952.             return ord($c{0});
  4953.         if (ord($c{0}>= 192 && ord($c{0}<= 223)
  4954.             return (ord($c{0})-192)*64 (ord($c{1})-128);
  4955.         if (ord($c{0}>= 224 && ord($c{0}<= 239)
  4956.             return (ord($c{0})-224)*4096 (ord($c{1})-128)*64 (ord($c{2})-128);
  4957.         if (ord($c{0}>= 240 && ord($c{0}<= 247)
  4958.             return (ord($c{0})-240)*262144 (ord($c{1})-128)*4096 (ord($c{2})-128)*64 (ord($c{3})-128);
  4959.         if (ord($c{0}>= 248 && ord($c{0}<= 251)
  4960.             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);
  4961.         if (ord($c{0}>= 252 && ord($c{0}<= 253)
  4962.             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);
  4963.         if (ord($c{0}>= 254 && ord($c{0}<= 255//error
  4964.             return self::$_errorCodes['value'];
  4965.         return 0;
  4966.     }    //    function _uniord()
  4967.  
  4968.     /**
  4969.      * ASCIICODE
  4970.      *
  4971.      * @param    string    $character    Value
  4972.      * @return    int 
  4973.      */
  4974.     public static function ASCIICODE($characters{
  4975.         $characters    self::flattenSingleValue($characters);
  4976.         if (is_bool($characters)) {
  4977.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  4978.                 $characters = (int) $characters;
  4979.             else {
  4980.                 if ($characters{
  4981.                     $characters 'True';
  4982.                 else {
  4983.                     $characters 'False';
  4984.                 }
  4985.             }
  4986.         }
  4987.  
  4988.         $character $characters;
  4989.         if ((function_exists('mb_strlen')) && (function_exists('mb_substr'))) {
  4990.             if (mb_strlen($characters'UTF-8'1$character mb_substr($characters01'UTF-8')}
  4991.             return self::_uniord($character);
  4992.         else {
  4993.             if (strlen($characters0$character substr($characters01)}
  4994.             return ord($character);
  4995.         }
  4996.     }    //    function ASCIICODE()
  4997.  
  4998.  
  4999.     /**
  5000.      * CONCATENATE
  5001.      *
  5002.      * @return    string 
  5003.      */
  5004.     public static function CONCATENATE({
  5005.         // Return value
  5006.         $returnValue '';
  5007.  
  5008.         // Loop through arguments
  5009.         $aArgs self::flattenArray(func_get_args());
  5010.         foreach ($aArgs as $arg{
  5011.             if (is_bool($arg)) {
  5012.                 if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5013.                     $arg = (int) $arg;
  5014.                 else {
  5015.                     if ($arg{
  5016.                         $arg 'TRUE';
  5017.                     else {
  5018.                         $arg 'FALSE';
  5019.                     }
  5020.                 }
  5021.             }
  5022.             $returnValue .= $arg;
  5023.         }
  5024.  
  5025.         // Return
  5026.         return $returnValue;
  5027.     }    //    function CONCATENATE()
  5028.  
  5029.  
  5030.     /**
  5031.      * STRINGLENGTH
  5032.      *
  5033.      * @param    string    $value    Value
  5034.      * @param    int        $chars    Number of characters
  5035.      * @return    string 
  5036.      */
  5037.     public static function STRINGLENGTH($value ''{
  5038.         $value        self::flattenSingleValue($value);
  5039.  
  5040.         if (is_bool($value)) {
  5041.             $value ($value'TRUE' 'FALSE';
  5042.         }
  5043.  
  5044.         if (function_exists('mb_strlen')) {
  5045.             return mb_strlen($value'UTF-8');
  5046.         else {
  5047.             return strlen($value);
  5048.         }
  5049.     }    //    function STRINGLENGTH()
  5050.  
  5051.  
  5052.     /**
  5053.      * SEARCHSENSITIVE
  5054.      *
  5055.      * @param    string    $needle        The string to look for
  5056.      * @param    string    $haystack    The string in which to look
  5057.      * @param    int        $offset        Offset within $haystack
  5058.      * @return    string 
  5059.      */
  5060.     public static function SEARCHSENSITIVE($needle,$haystack,$offset=1{
  5061.         $needle        self::flattenSingleValue($needle);
  5062.         $haystack    self::flattenSingleValue($haystack);
  5063.         $offset        self::flattenSingleValue($offset);
  5064.  
  5065.         if (!is_bool($needle)) {
  5066.             if (is_bool($haystack)) {
  5067.                 $haystack ($haystack'TRUE' 'FALSE';
  5068.             }
  5069.  
  5070.             if (($offset 0&& (strlen($haystack$offset)) {
  5071.                 if (function_exists('mb_strpos')) {
  5072.                     $pos mb_strpos($haystack$needle--$offset,'UTF-8');
  5073.                 else {
  5074.                     $pos strpos($haystack$needle--$offset);
  5075.                 }
  5076.                 if ($pos !== false{
  5077.                     return ++$pos;
  5078.                 }
  5079.             }
  5080.         }
  5081.         return self::$_errorCodes['value'];
  5082.     }    //    function SEARCHSENSITIVE()
  5083.  
  5084.  
  5085.     /**
  5086.      * SEARCHINSENSITIVE
  5087.      *
  5088.      * @param    string    $needle        The string to look for
  5089.      * @param    string    $haystack    The string in which to look
  5090.      * @param    int        $offset        Offset within $haystack
  5091.      * @return    string 
  5092.      */
  5093.     public static function SEARCHINSENSITIVE($needle,$haystack,$offset=1{
  5094.         $needle        self::flattenSingleValue($needle);
  5095.         $haystack    self::flattenSingleValue($haystack);
  5096.         $offset        self::flattenSingleValue($offset);
  5097.  
  5098.         if (!is_bool($needle)) {
  5099.             if (is_bool($haystack)) {
  5100.                 $haystack ($haystack'TRUE' 'FALSE';
  5101.             }
  5102.  
  5103.             if (($offset 0&& (strlen($haystack$offset)) {
  5104.                 if (function_exists('mb_stripos')) {
  5105.                     $pos mb_stripos($haystack$needle--$offset,'UTF-8');
  5106.                 else {
  5107.                     $pos stripos($haystack$needle--$offset);
  5108.                 }
  5109.                 if ($pos !== false{
  5110.                     return ++$pos;
  5111.                 }
  5112.             }
  5113.         }
  5114.         return self::$_errorCodes['value'];
  5115.     }    //    function SEARCHINSENSITIVE()
  5116.  
  5117.  
  5118.     /**
  5119.      * LEFT
  5120.      *
  5121.      * @param    string    $value    Value
  5122.      * @param    int        $chars    Number of characters
  5123.      * @return    string 
  5124.      */
  5125.     public static function LEFT($value ''$chars 1{
  5126.         $value        self::flattenSingleValue($value);
  5127.         $chars        self::flattenSingleValue($chars);
  5128.  
  5129.         if ($chars 0{
  5130.             return self::$_errorCodes['value'];
  5131.         }
  5132.  
  5133.         if (is_bool($value)) {
  5134.             $value ($value'TRUE' 'FALSE';
  5135.         }
  5136.  
  5137.         if (function_exists('mb_substr')) {
  5138.             return mb_substr($value0$chars'UTF-8');
  5139.         else {
  5140.             return substr($value0$chars);
  5141.         }
  5142.     }    //    function LEFT()
  5143.  
  5144.  
  5145.     /**
  5146.      *    RIGHT
  5147.      *
  5148.      *    @param    string    $value    Value
  5149.      *    @param    int        $chars    Number of characters
  5150.      *    @return    string 
  5151.      */
  5152.     public static function RIGHT($value ''$chars 1{
  5153.         $value        self::flattenSingleValue($value);
  5154.         $chars        self::flattenSingleValue($chars);
  5155.  
  5156.         if ($chars 0{
  5157.             return self::$_errorCodes['value'];
  5158.         }
  5159.  
  5160.         if (is_bool($value)) {
  5161.             $value ($value'TRUE' 'FALSE';
  5162.         }
  5163.  
  5164.         if ((function_exists('mb_substr')) && (function_exists('mb_strlen'))) {
  5165.             return mb_substr($valuemb_strlen($value'UTF-8'$chars$chars'UTF-8');
  5166.         else {
  5167.             return substr($valuestrlen($value$chars);
  5168.         }
  5169.     }    //    function RIGHT()
  5170.  
  5171.  
  5172.     /**
  5173.      *    MID
  5174.      *
  5175.      *    @param    string    $value    Value
  5176.      *    @param    int        $start    Start character
  5177.      *    @param    int        $chars    Number of characters
  5178.      *    @return    string 
  5179.      */
  5180.     public static function MID($value ''$start 1$chars null{
  5181.         $value        self::flattenSingleValue($value);
  5182.         $start        self::flattenSingleValue($start);
  5183.         $chars        self::flattenSingleValue($chars);
  5184.  
  5185.         if (($start 1|| ($chars 0)) {
  5186.             return self::$_errorCodes['value'];
  5187.         }
  5188.  
  5189.         if (is_bool($value)) {
  5190.             $value ($value'TRUE' 'FALSE';
  5191.         }
  5192.  
  5193.         if (function_exists('mb_substr')) {
  5194.             return mb_substr($value--$start$chars'UTF-8');
  5195.         else {
  5196.             return substr($value--$start$chars);
  5197.         }
  5198.     }    //    function MID()
  5199.  
  5200.  
  5201.     /**
  5202.      *    REPLACE
  5203.      *
  5204.      *    @param    string    $value    Value
  5205.      *    @param    int        $start    Start character
  5206.      *    @param    int        $chars    Number of characters
  5207.      *    @return    string 
  5208.      */
  5209.     public static function REPLACE($oldText ''$start 1$chars null$newText{
  5210.         $oldText    self::flattenSingleValue($oldText);
  5211.         $start        self::flattenSingleValue($start);
  5212.         $chars        self::flattenSingleValue($chars);
  5213.         $newText    self::flattenSingleValue($newText);
  5214.  
  5215.         $left self::LEFT($oldText,$start-1);
  5216.         $right self::RIGHT($oldText,self::STRINGLENGTH($oldText)-($start+$chars)+1);
  5217.  
  5218.         return $left.$newText.$right;
  5219.     }    //    function REPLACE()
  5220.  
  5221.  
  5222.     /**
  5223.      *    SUBSTITUTE
  5224.      *
  5225.      *    @param    string    $text        Value
  5226.      *    @param    string    $fromText    From Value
  5227.      *    @param    string    $toText        To Value
  5228.      *    @param    integer    $instance    Instance Number
  5229.      *    @return    string 
  5230.      */
  5231.     public static function SUBSTITUTE($text ''$fromText ''$toText ''$instance 0{
  5232.         $text        self::flattenSingleValue($text);
  5233.         $fromText    self::flattenSingleValue($fromText);
  5234.         $toText        self::flattenSingleValue($toText);
  5235.         $instance    floor(self::flattenSingleValue($instance));
  5236.  
  5237.         if ($instance == 0{
  5238.             if(function_exists('mb_str_replace')) {
  5239.                 return mb_str_replace($fromText,$toText,$text);
  5240.             else {
  5241.                 return str_replace($fromText,$toText,$text);
  5242.             }
  5243.         else {
  5244.             $pos = -1;
  5245.             while($instance 0{
  5246.                 if (function_exists('mb_strpos')) {
  5247.                     $pos mb_strpos($text$fromText$pos+1'UTF-8');
  5248.                 else {
  5249.                     $pos strpos($text$fromText$pos+1);
  5250.                 }
  5251.                 if ($pos === false{
  5252.                     break;
  5253.                 }
  5254.                 --$instance;
  5255.             }
  5256.             if ($pos !== false{
  5257.                 if (function_exists('mb_strlen')) {
  5258.                     return self::REPLACE($text,++$pos,mb_strlen($fromText'UTF-8'),$toText);
  5259.                 else {
  5260.                     return self::REPLACE($text,++$pos,strlen($fromText),$toText);
  5261.                 }
  5262.             }
  5263.         }
  5264.  
  5265.         return $left.$newText.$right;
  5266.     }    //    function SUBSTITUTE()
  5267.  
  5268.  
  5269.     /**
  5270.      *    RETURNSTRING
  5271.      *
  5272.      *    @param    mixed    $value    Value to check
  5273.      *    @return    boolean 
  5274.      */
  5275.     public static function RETURNSTRING($testValue ''{
  5276.         $testValue    self::flattenSingleValue($testValue);
  5277.  
  5278.         if (is_string($testValue)) {
  5279.             return $testValue;
  5280.         }
  5281.         return Null;
  5282.     }    //    function RETURNSTRING()
  5283.  
  5284.  
  5285.     /**
  5286.      *    FIXEDFORMAT
  5287.      *
  5288.      *    @param    mixed    $value    Value to check
  5289.      *    @return    boolean 
  5290.      */
  5291.     public static function FIXEDFORMAT($value,$decimals=2,$no_commas=false{
  5292.         $value        self::flattenSingleValue($value);
  5293.         $decimals    self::flattenSingleValue($decimals);
  5294.         $no_commas        self::flattenSingleValue($no_commas);
  5295.  
  5296.         $valueResult round($value,$decimals);
  5297.         if ($decimals 0$decimals 0}
  5298.         if (!$no_commas{
  5299.             $valueResult number_format($valueResult,$decimals);
  5300.         }
  5301.  
  5302.         return (string) $valueResult;
  5303.     }    //    function FIXEDFORMAT()
  5304.  
  5305.  
  5306.     /**
  5307.      *    TEXTFORMAT
  5308.      *
  5309.      *    @param    mixed    $value    Value to check
  5310.      *    @return    boolean 
  5311.      */
  5312.     public static function TEXTFORMAT($value,$format{
  5313.         $value    self::flattenSingleValue($value);
  5314.         $format    self::flattenSingleValue($format);
  5315.  
  5316.         if ((is_string($value)) && (!is_numeric($value)) && PHPExcel_Shared_Date::isDateTimeFormatCode($format)) {
  5317.             $value self::DATEVALUE($value);
  5318.         }
  5319.  
  5320.         return (string) PHPExcel_Style_NumberFormat::toFormattedString($value,$format);
  5321.     }    //    function TEXTFORMAT()
  5322.  
  5323.  
  5324.     /**
  5325.      *    TRIMSPACES
  5326.      *
  5327.      *    @param    mixed    $value    Value to check
  5328.      *    @return    string 
  5329.      */
  5330.     public static function TRIMSPACES($stringValue ''{
  5331.         $stringValue    self::flattenSingleValue($stringValue);
  5332.  
  5333.         if (is_string($stringValue|| is_numeric($stringValue)) {
  5334.             return trim(preg_replace('/  +/',' ',$stringValue));
  5335.         }
  5336.         return Null;
  5337.     }    //    function TRIMSPACES()
  5338.  
  5339.  
  5340.     private static $_invalidChars Null;
  5341.  
  5342.     /**
  5343.      *    TRIMNONPRINTABLE
  5344.      *
  5345.      *    @param    mixed    $value    Value to check
  5346.      *    @return    string 
  5347.      */
  5348.     public static function TRIMNONPRINTABLE($stringValue ''{
  5349.         $stringValue    self::flattenSingleValue($stringValue);
  5350.  
  5351.         if (is_bool($stringValue)) {
  5352.             $stringValue ($stringValue'TRUE' 'FALSE';
  5353.         }
  5354.  
  5355.         if (self::$_invalidChars == Null{
  5356.             self::$_invalidChars range(chr(0),chr(31));
  5357.         }
  5358.  
  5359.         if (is_string($stringValue|| is_numeric($stringValue)) {
  5360.             return str_replace(self::$_invalidChars,'',trim($stringValue,"\x00..\x1F"));
  5361.         }
  5362.         return Null;
  5363.     }    //    function TRIMNONPRINTABLE()
  5364.  
  5365.  
  5366.     /**
  5367.      *    ERROR_TYPE
  5368.      *
  5369.      *    @param    mixed    $value    Value to check
  5370.      *    @return    boolean 
  5371.      */
  5372.     public static function ERROR_TYPE($value ''{
  5373.         $value    self::flattenSingleValue($value);
  5374.  
  5375.         $i 1;
  5376.         foreach(self::$_errorCodes as $errorCode{
  5377.             if ($value == $errorCode{
  5378.                 return $i;
  5379.             }
  5380.             ++$i;
  5381.         }
  5382.         return self::$_errorCodes['na'];
  5383.     }    //    function ERROR_TYPE()
  5384.  
  5385.  
  5386.     /**
  5387.      *    IS_BLANK
  5388.      *
  5389.      *    @param    mixed    $value    Value to check
  5390.      *    @return    boolean 
  5391.      */
  5392.     public static function IS_BLANK($value=null{
  5393.         if (!is_null($value)) {
  5394.             $value    self::flattenSingleValue($value);
  5395.         }
  5396.  
  5397.         return is_null($value);
  5398.     }    //    function IS_BLANK()
  5399.  
  5400.  
  5401.     /**
  5402.      *    IS_ERR
  5403.      *
  5404.      *    @param    mixed    $value    Value to check
  5405.      *    @return    boolean 
  5406.      */
  5407.     public static function IS_ERR($value ''{
  5408.         $value        self::flattenSingleValue($value);
  5409.  
  5410.         return self::IS_ERROR($value&& (!self::IS_NA($value));
  5411.     }    //    function IS_ERR()
  5412.  
  5413.  
  5414.     /**
  5415.      *    IS_ERROR
  5416.      *
  5417.      *    @param    mixed    $value    Value to check
  5418.      *    @return    boolean 
  5419.      */
  5420.     public static function IS_ERROR($value ''{
  5421.         $value        self::flattenSingleValue($value);
  5422.  
  5423.         return in_array($valuearray_values(self::$_errorCodes));
  5424.     }    //    function IS_ERROR()
  5425.  
  5426.  
  5427.     /**
  5428.      *    IS_NA
  5429.      *
  5430.      *    @param    mixed    $value    Value to check
  5431.      *    @return    boolean 
  5432.      */
  5433.     public static function IS_NA($value ''{
  5434.         $value        self::flattenSingleValue($value);
  5435.  
  5436.         return ($value === self::$_errorCodes['na']);
  5437.     }    //    function IS_NA()
  5438.  
  5439.  
  5440.     /**
  5441.      *    IS_EVEN
  5442.      *
  5443.      *    @param    mixed    $value    Value to check
  5444.      *    @return    boolean 
  5445.      */
  5446.     public static function IS_EVEN($value 0{
  5447.         $value        self::flattenSingleValue($value);
  5448.  
  5449.         if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
  5450.             return self::$_errorCodes['value'];
  5451.         }
  5452.         return ($value == 0);
  5453.     }    //    function IS_EVEN()
  5454.  
  5455.  
  5456.     /**
  5457.      *    IS_ODD
  5458.      *
  5459.      *    @param    mixed    $value    Value to check
  5460.      *    @return    boolean 
  5461.      */
  5462.     public static function IS_ODD($value null{
  5463.         $value        self::flattenSingleValue($value);
  5464.  
  5465.         if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
  5466.             return self::$_errorCodes['value'];
  5467.         }
  5468.         return (abs($value== 1);
  5469.     }    //    function IS_ODD()
  5470.  
  5471.  
  5472.     /**
  5473.      *    IS_NUMBER
  5474.      *
  5475.      *    @param    mixed    $value        Value to check
  5476.      *    @return    boolean 
  5477.      */
  5478.     public static function IS_NUMBER($value 0{
  5479.         $value        self::flattenSingleValue($value);
  5480.  
  5481.         if (is_string($value)) {
  5482.             return False;
  5483.         }
  5484.         return is_numeric($value);
  5485.     }    //    function IS_NUMBER()
  5486.  
  5487.  
  5488.     /**
  5489.      *    IS_LOGICAL
  5490.      *
  5491.      *    @param    mixed    $value        Value to check
  5492.      *    @return    boolean 
  5493.      */
  5494.     public static function IS_LOGICAL($value true{
  5495.         $value        self::flattenSingleValue($value);
  5496.  
  5497.         return is_bool($value);
  5498.     }    //    function IS_LOGICAL()
  5499.  
  5500.  
  5501.     /**
  5502.      *    IS_TEXT
  5503.      *
  5504.      *    @param    mixed    $value        Value to check
  5505.      *    @return    boolean 
  5506.      */
  5507.     public static function IS_TEXT($value ''{
  5508.         $value        self::flattenSingleValue($value);
  5509.  
  5510.         return is_string($value);
  5511.     }    //    function IS_TEXT()
  5512.  
  5513.  
  5514.     /**
  5515.      *    IS_NONTEXT
  5516.      *
  5517.      *    @param    mixed    $value        Value to check
  5518.      *    @return    boolean 
  5519.      */
  5520.     public static function IS_NONTEXT($value ''{
  5521.         return !self::IS_TEXT($value);
  5522.     }    //    function IS_NONTEXT()
  5523.  
  5524.  
  5525.     /**
  5526.      *    VERSION
  5527.      *
  5528.      *    @return    string    Version information
  5529.      */
  5530.     public static function VERSION({
  5531.         return 'PHPExcel 1.7.2, 2010-01-11';
  5532.     }    //    function VERSION()
  5533.  
  5534.  
  5535.     /**
  5536.      * DATE
  5537.      *
  5538.      * @param    long    $year 
  5539.      * @param    long    $month 
  5540.      * @param    long    $day 
  5541.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5542.      *                         depending on the value of the ReturnDateType flag
  5543.      */
  5544.     public static function DATE($year 0$month 1$day 1{
  5545.         $year    = (integer) self::flattenSingleValue($year);
  5546.         $month    = (integer) self::flattenSingleValue($month);
  5547.         $day    = (integer) self::flattenSingleValue($day);
  5548.  
  5549.         $baseYear PHPExcel_Shared_Date::getExcelCalendar();
  5550.         // Validate parameters
  5551.         if ($year ($baseYear-1900)) {
  5552.             return self::$_errorCodes['num'];
  5553.         }
  5554.         if ((($baseYear-1900!= 0&& ($year $baseYear&& ($year >= 1900)) {
  5555.             return self::$_errorCodes['num'];
  5556.         }
  5557.  
  5558.         if (($year $baseYear&& ($year >= ($baseYear-1900))) {
  5559.             $year += 1900;
  5560.         }
  5561.  
  5562.         if ($month 1{
  5563.             //    Handle year/month adjustment if month < 1
  5564.             --$month;
  5565.             $year += ceil($month 121;
  5566.             $month 13 abs($month 12);
  5567.         elseif ($month 12{
  5568.             //    Handle year/month adjustment if month > 12
  5569.             $year += floor($month 12);
  5570.             $month ($month 12);
  5571.         }
  5572.  
  5573.         // Re-validate the year parameter after adjustments
  5574.         if (($year $baseYear|| ($year >= 10000)) {
  5575.             return self::$_errorCodes['num'];
  5576.         }
  5577.  
  5578.         // Execute function
  5579.         $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel($year$month$day);
  5580.         switch (self::getReturnDateType()) {
  5581.             case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  5582.                                                   break;
  5583.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
  5584.                                                   break;
  5585.             case self::RETURNDATE_PHP_OBJECT    return PHPExcel_Shared_Date::ExcelToPHPObject($excelDateValue);
  5586.                                                   break;
  5587.         }
  5588.     }    //    function DATE()
  5589.  
  5590.  
  5591.     /**
  5592.      * TIME
  5593.      *
  5594.      * @param    long    $hour 
  5595.      * @param    long    $minute 
  5596.      * @param    long    $second 
  5597.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5598.      *                         depending on the value of the ReturnDateType flag
  5599.      */
  5600.     public static function TIME($hour 0$minute 0$second 0{
  5601.         $hour    self::flattenSingleValue($hour);
  5602.         $minute    self::flattenSingleValue($minute);
  5603.         $second    self::flattenSingleValue($second);
  5604.  
  5605.         if ($hour == ''$hour 0}
  5606.         if ($minute == ''$minute 0}
  5607.         if ($second == ''$second 0}
  5608.  
  5609.         if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) {
  5610.             return self::$_errorCodes['value'];
  5611.         }
  5612.         $hour    = (integer) $hour;
  5613.         $minute    = (integer) $minute;
  5614.         $second    = (integer) $second;
  5615.  
  5616.         if ($second 0{
  5617.             $minute += floor($second 60);
  5618.             $second 60 abs($second 60);
  5619.             if ($second == 60$second 0}
  5620.         elseif ($second >= 60{
  5621.             $minute += floor($second 60);
  5622.             $second $second 60;
  5623.         }
  5624.         if ($minute 0{
  5625.             $hour += floor($minute 60);
  5626.             $minute 60 abs($minute 60);
  5627.             if ($minute == 60$minute 0}
  5628.         elseif ($minute >= 60{
  5629.             $hour += floor($minute 60);
  5630.             $minute $minute 60;
  5631.         }
  5632.  
  5633.         if ($hour 23{
  5634.             $hour $hour 24;
  5635.         elseif ($hour 0{
  5636.             return self::$_errorCodes['num'];
  5637.         }
  5638.  
  5639.         // Execute function
  5640.         switch (self::getReturnDateType()) {
  5641.             case self::RETURNDATE_EXCEL            $date 0;
  5642.                                                   $calendar PHPExcel_Shared_Date::getExcelCalendar();
  5643.                                                   if ($calendar != PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900{
  5644.                                                      $date 1;
  5645.                                                   }
  5646.                                                   return (float) PHPExcel_Shared_Date::FormattedPHPToExcel($calendar1$date$hour$minute$second);
  5647.                                                   break;
  5648.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(197011$hour-1$minute$second));    // -2147468400; //    -2147472000 + 3600
  5649.                                                   break;
  5650.             case self::RETURNDATE_PHP_OBJECT    $dayAdjust 0;
  5651.                                                   if ($hour 0{
  5652.                                                      $dayAdjust floor($hour 24);
  5653.                                                      $hour 24 abs($hour 24);
  5654.                                                      if ($hour == 24$hour 0}
  5655.                                                   elseif ($hour >= 24{
  5656.                                                      $dayAdjust floor($hour 24);
  5657.                                                      $hour $hour 24;
  5658.                                                   }
  5659.                                                   $phpDateObject new DateTime('1900-01-01 '.$hour.':'.$minute.':'.$second);
  5660.                                                   if ($dayAdjust != 0{
  5661.                                                      $phpDateObject->modify($dayAdjust.' days');
  5662.                                                   }
  5663.                                                   return $phpDateObject;
  5664.                                                   break;
  5665.         }
  5666.     }    //    function TIME()
  5667.  
  5668.  
  5669.     /**
  5670.      * DATEVALUE
  5671.      *
  5672.      * @param    string    $dateValue 
  5673.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5674.      *                         depending on the value of the ReturnDateType flag
  5675.      */
  5676.     public static function DATEVALUE($dateValue 1{
  5677.         $dateValue    str_replace(array('/','.',' '),array('-','-','-'),trim(self::flattenSingleValue($dateValue),'"'));
  5678.  
  5679.         $yearFound false;
  5680.         $t1 explode('-',$dateValue);
  5681.         foreach($t1 as &$t{
  5682.             if ((is_numeric($t)) && (($t 31&& ($t 100))) {
  5683.                 if ($yearFound{
  5684.                     return self::$_errorCodes['value'];
  5685.                 else {
  5686.                     $t += 1900;
  5687.                     $yearFound true;
  5688.                 }
  5689.             }
  5690.         }
  5691.         unset($t);
  5692.         $dateValue implode('-',$t1);
  5693.  
  5694.         $PHPDateArray date_parse($dateValue);
  5695.         if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  5696.             $testVal1 strtok($dateValue,'- ');
  5697.             if ($testVal1 !== False{
  5698.                 $testVal2 strtok('- ');
  5699.                 if ($testVal2 !== False{
  5700.                     $testVal3 strtok('- ');
  5701.                     if ($testVal3 === False{
  5702.                         $testVal3 strftime('%Y');
  5703.                     }
  5704.                 else {
  5705.                     return self::$_errorCodes['value'];
  5706.                 }
  5707.             else {
  5708.                 return self::$_errorCodes['value'];
  5709.             }
  5710.             $PHPDateArray date_parse($testVal1.'-'.$testVal2.'-'.$testVal3);
  5711.             if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  5712.                 $PHPDateArray date_parse($testVal2.'-'.$testVal1.'-'.$testVal3);
  5713.                 if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  5714.                     return self::$_errorCodes['value'];
  5715.                 }
  5716.             }
  5717.         }
  5718.  
  5719.         if (($PHPDateArray !== False&& ($PHPDateArray['error_count'== 0)) {
  5720.             // Execute function
  5721.             if ($PHPDateArray['year'== '')    $PHPDateArray['year'strftime('%Y')}
  5722.             if ($PHPDateArray['month'== '')    $PHPDateArray['month'strftime('%m')}
  5723.             if ($PHPDateArray['day'== '')        $PHPDateArray['day'strftime('%d')}
  5724.             $excelDateValue floor(PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']));
  5725.  
  5726.             switch (self::getReturnDateType()) {
  5727.                 case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  5728.                                                       break;
  5729.                 case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
  5730.                                                       break;
  5731.                 case self::RETURNDATE_PHP_OBJECT    return new DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00');
  5732.                                                       break;
  5733.             }
  5734.         }
  5735.         return self::$_errorCodes['value'];
  5736.     }    //    function DATEVALUE()
  5737.  
  5738.  
  5739.     /**
  5740.      * _getDateValue
  5741.      *
  5742.      * @param    string    $dateValue 
  5743.      * @return    mixed    Excel date/time serial value, or string if error
  5744.      */
  5745.     private static function _getDateValue($dateValue{
  5746.         if (!is_numeric($dateValue)) {
  5747.             if ((is_string($dateValue)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  5748.                 return self::$_errorCodes['value'];
  5749.             }
  5750.             if ((is_object($dateValue)) && ($dateValue instanceof PHPExcel_Shared_Date::$dateTimeObjectType)) {
  5751.                 $dateValue PHPExcel_Shared_Date::PHPToExcel($dateValue);
  5752.             else {
  5753.                 $saveReturnDateType self::getReturnDateType();
  5754.                 self::setReturnDateType(self::RETURNDATE_EXCEL);
  5755.                 $dateValue self::DATEVALUE($dateValue);
  5756.                 self::setReturnDateType($saveReturnDateType);
  5757.             }
  5758.         }
  5759.         return $dateValue;
  5760.     }    //    function _getDateValue()
  5761.  
  5762.  
  5763.     /**
  5764.      * TIMEVALUE
  5765.      *
  5766.      * @param    string    $timeValue 
  5767.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5768.      *                         depending on the value of the ReturnDateType flag
  5769.      */
  5770.     public static function TIMEVALUE($timeValue{
  5771.         $timeValue    self::flattenSingleValue($timeValue);
  5772.  
  5773.         if ((($PHPDateArray date_parse($timeValue)) !== False&& ($PHPDateArray['error_count'== 0)) {
  5774.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5775.                 $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']);
  5776.             else {
  5777.                 $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel(1900,1,1,$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']1;
  5778.             }
  5779.  
  5780.             switch (self::getReturnDateType()) {
  5781.                 case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  5782.                                                       break;
  5783.                 case self::RETURNDATE_PHP_NUMERIC    return (integer) $phpDateValue PHPExcel_Shared_Date::ExcelToPHP($excelDateValue+255693600;;
  5784.                                                       break;
  5785.                 case self::RETURNDATE_PHP_OBJECT    return new DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']);
  5786.                                                       break;
  5787.             }
  5788.         }
  5789.         return self::$_errorCodes['value'];
  5790.     }    //    function TIMEVALUE()
  5791.  
  5792.  
  5793.     /**
  5794.      * _getTimeValue
  5795.      *
  5796.      * @param    string    $timeValue 
  5797.      * @return    mixed    Excel date/time serial value, or string if error
  5798.      */
  5799.     private static function _getTimeValue($timeValue{
  5800.         $saveReturnDateType self::getReturnDateType();
  5801.         self::setReturnDateType(self::RETURNDATE_EXCEL);
  5802.         $timeValue self::TIMEVALUE($timeValue);
  5803.         self::setReturnDateType($saveReturnDateType);
  5804.         return $timeValue;
  5805.     }    //    function _getTimeValue()
  5806.  
  5807.  
  5808.     /**
  5809.      * DATETIMENOW
  5810.      *
  5811.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5812.      *                         depending on the value of the ReturnDateType flag
  5813.      */
  5814.     public static function DATETIMENOW({
  5815.         $saveTimeZone date_default_timezone_get();
  5816.         date_default_timezone_set('UTC');
  5817.         $retValue False;
  5818.         switch (self::getReturnDateType()) {
  5819.             case self::RETURNDATE_EXCEL            $retValue = (float) PHPExcel_Shared_Date::PHPToExcel(time());
  5820.                                                   break;
  5821.             case self::RETURNDATE_PHP_NUMERIC    $retValue = (integer) time();
  5822.                                                   break;
  5823.             case self::RETURNDATE_PHP_OBJECT    $retValue new DateTime();
  5824.                                                   break;
  5825.         }
  5826.         date_default_timezone_set($saveTimeZone);
  5827.  
  5828.         return $retValue;
  5829.     }    //    function DATETIMENOW()
  5830.  
  5831.  
  5832.     /**
  5833.      * DATENOW
  5834.      *
  5835.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5836.      *                         depending on the value of the ReturnDateType flag
  5837.      */
  5838.     public static function DATENOW({
  5839.         $saveTimeZone date_default_timezone_get();
  5840.         date_default_timezone_set('UTC');
  5841.         $retValue False;
  5842.         $excelDateTime floor(PHPExcel_Shared_Date::PHPToExcel(time()));
  5843.         switch (self::getReturnDateType()) {
  5844.             case self::RETURNDATE_EXCEL            $retValue = (float) $excelDateTime;
  5845.                                                   break;
  5846.             case self::RETURNDATE_PHP_NUMERIC    $retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime3600;
  5847.                                                   break;
  5848.             case self::RETURNDATE_PHP_OBJECT    $retValue PHPExcel_Shared_Date::ExcelToPHPObject($excelDateTime);
  5849.                                                   break;
  5850.         }
  5851.         date_default_timezone_set($saveTimeZone);
  5852.  
  5853.         return $retValue;
  5854.     }    //    function DATENOW()
  5855.  
  5856.  
  5857.     private static function _isLeapYear($year{
  5858.         return ((($year 4== 0&& (($year 100!= 0|| (($year 400== 0));
  5859.     }    //    function _isLeapYear()
  5860.  
  5861.  
  5862.     private static function _dateDiff360($startDay$startMonth$startYear$endDay$endMonth$endYear$methodUS{
  5863.         if ($startDay == 31{
  5864.             --$startDay;
  5865.         elseif ($methodUS && ($startMonth == && ($startDay == 29 || ($startDay == 28 && !self::_isLeapYear($startYear))))) {
  5866.             $startDay 30;
  5867.         }
  5868.         if ($endDay == 31{
  5869.             if ($methodUS && $startDay != 30{
  5870.                 $endDay 1;
  5871.                 if ($endMonth == 12{
  5872.                     ++$endYear;
  5873.                     $endMonth 1;
  5874.                 else {
  5875.                     ++$endMonth;
  5876.                 }
  5877.             else {
  5878.                 $endDay 30;
  5879.             }
  5880.         }
  5881.  
  5882.         return $endDay $endMonth 30 $endYear 360 $startDay $startMonth 30 $startYear 360;
  5883.     }    //    function _dateDiff360()
  5884.  
  5885.  
  5886.     /**
  5887.      * DAYS360
  5888.      *
  5889.      * @param    long    $startDate        Excel date serial value or a standard date string
  5890.      * @param    long    $endDate        Excel date serial value or a standard date string
  5891.      * @param    boolean    $method            US or European Method
  5892.      * @return    long    PHP date/time serial
  5893.      */
  5894.     public static function DAYS360($startDate 0$endDate 0$method false{
  5895.         $startDate    self::flattenSingleValue($startDate);
  5896.         $endDate    self::flattenSingleValue($endDate);
  5897.  
  5898.         if (is_string($startDate self::_getDateValue($startDate))) {
  5899.             return self::$_errorCodes['value'];
  5900.         }
  5901.         if (is_string($endDate self::_getDateValue($endDate))) {
  5902.             return self::$_errorCodes['value'];
  5903.         }
  5904.  
  5905.         // Execute function
  5906.         $PHPStartDateObject PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
  5907.         $startDay $PHPStartDateObject->format('j');
  5908.         $startMonth $PHPStartDateObject->format('n');
  5909.         $startYear $PHPStartDateObject->format('Y');
  5910.  
  5911.         $PHPEndDateObject PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  5912.         $endDay $PHPEndDateObject->format('j');
  5913.         $endMonth $PHPEndDateObject->format('n');
  5914.         $endYear $PHPEndDateObject->format('Y');
  5915.  
  5916.         return self::_dateDiff360($startDay$startMonth$startYear$endDay$endMonth$endYear!$method);
  5917.     }    //    function DAYS360()
  5918.  
  5919.  
  5920.     /**
  5921.      * DATEDIF
  5922.      *
  5923.      * @param    long    $startDate        Excel date serial value or a standard date string
  5924.      * @param    long    $endDate        Excel date serial value or a standard date string
  5925.      * @param    string    $unit 
  5926.      * @return    long    Interval between the dates
  5927.      */
  5928.     public static function DATEDIF($startDate 0$endDate 0$unit 'D'{
  5929.         $startDate    self::flattenSingleValue($startDate);
  5930.         $endDate    self::flattenSingleValue($endDate);
  5931.         $unit        strtoupper(self::flattenSingleValue($unit));
  5932.  
  5933.         if (is_string($startDate self::_getDateValue($startDate))) {
  5934.             return self::$_errorCodes['value'];
  5935.         }
  5936.         if (is_string($endDate self::_getDateValue($endDate))) {
  5937.             return self::$_errorCodes['value'];
  5938.         }
  5939.  
  5940.         // Validate parameters
  5941.         if ($startDate >= $endDate{
  5942.             return self::$_errorCodes['num'];
  5943.         }
  5944.  
  5945.         // Execute function
  5946.         $difference $endDate $startDate;
  5947.  
  5948.         $PHPStartDateObject PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
  5949.         $startDays $PHPStartDateObject->format('j');
  5950.         $startMonths $PHPStartDateObject->format('n');
  5951.         $startYears $PHPStartDateObject->format('Y');
  5952.  
  5953.         $PHPEndDateObject PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  5954.         $endDays $PHPEndDateObject->format('j');
  5955.         $endMonths $PHPEndDateObject->format('n');
  5956.         $endYears $PHPEndDateObject->format('Y');
  5957.  
  5958.         $retVal self::$_errorCodes['num'];
  5959.         switch ($unit{
  5960.             case 'D':
  5961.                 $retVal intval($difference);
  5962.                 break;
  5963.             case 'M':
  5964.                 $retVal intval($endMonths $startMonths(intval($endYears $startYears12);
  5965.                 //    We're only interested in full months
  5966.                 if ($endDays $startDays{
  5967.                     --$retVal;
  5968.                 }
  5969.                 break;
  5970.             case 'Y':
  5971.                 $retVal intval($endYears $startYears);
  5972.                 //    We're only interested in full months
  5973.                 if ($endMonths $startMonths{
  5974.                     --$retVal;
  5975.                 elseif (($endMonths == $startMonths&& ($endDays $startDays)) {
  5976.                     --$retVal;
  5977.                 }
  5978.                 break;
  5979.             case 'MD':
  5980.                 if ($endDays $startDays{
  5981.                     $retVal $endDays;
  5982.                     $PHPEndDateObject->modify('-'.$endDays.' days');
  5983.                     $adjustDays $PHPEndDateObject->format('j');
  5984.                     if ($adjustDays $startDays{
  5985.                         $retVal += ($adjustDays $startDays);
  5986.                     }
  5987.                 else {
  5988.                     $retVal $endDays $startDays;
  5989.                 }
  5990.                 break;
  5991.             case 'YM':
  5992.                 $retVal intval($endMonths $startMonths);
  5993.                 if ($retVal 0$retVal 12 $retVal;
  5994.                 //    We're only interested in full months
  5995.                 if ($endDays $startDays{
  5996.                     --$retVal;
  5997.                 }
  5998.                 break;
  5999.             case 'YD':
  6000.                 $retVal intval($difference);
  6001.                 if ($endYears $startYears{
  6002.                     while ($endYears $startYears{
  6003.                         $PHPEndDateObject->modify('-1 year');
  6004.                         $endYears $PHPEndDateObject->format('Y');
  6005.                     }
  6006.                     $retVal $PHPEndDateObject->format('z'$PHPStartDateObject->format('z');
  6007.                     if ($retVal 0$retVal += 365}
  6008.                 }
  6009.                 break;
  6010.         }
  6011.         return $retVal;
  6012.     }    //    function DATEDIF()
  6013.  
  6014.  
  6015.     /**
  6016.      *    YEARFRAC
  6017.      *
  6018.      *    Calculates the fraction of the year represented by the number of whole days between two dates (the start_date and the
  6019.      *    end_date). Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or obligations
  6020.      *    to assign to a specific term.
  6021.      *
  6022.      *    @param    mixed    $startDate        Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string
  6023.      *    @param    mixed    $endDate        Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string
  6024.      *    @param    integer    $method            Method used for the calculation
  6025.      *                                         0 or omitted    US (NASD) 30/360
  6026.      *                                         1                Actual/actual
  6027.      *                                         2                Actual/360
  6028.      *                                         3                Actual/365
  6029.      *                                         4                European 30/360
  6030.      *    @return    float    fraction of the year
  6031.      */
  6032.     public static function YEARFRAC($startDate 0$endDate 0$method 0{
  6033.         $startDate    self::flattenSingleValue($startDate);
  6034.         $endDate    self::flattenSingleValue($endDate);
  6035.         $method        self::flattenSingleValue($method);
  6036.  
  6037.         if (is_string($startDate self::_getDateValue($startDate))) {
  6038.             return self::$_errorCodes['value'];
  6039.         }
  6040.         if (is_string($endDate self::_getDateValue($endDate))) {
  6041.             return self::$_errorCodes['value'];
  6042.         }
  6043.  
  6044.         if ((is_numeric($method)) && (!is_string($method))) {
  6045.             switch($method{
  6046.                 case 0    :
  6047.                     return self::DAYS360($startDate,$endDate360;
  6048.                     break;
  6049.                 case 1    :
  6050.                     $startYear self::YEAR($startDate);
  6051.                     $endYear self::YEAR($endDate);
  6052.                     $leapDay 0;
  6053.                     if (self::_isLeapYear($startYear|| self::_isLeapYear($endYear)) {
  6054.                         $leapDay 1;
  6055.                     }
  6056.                     return self::DATEDIF($startDate,$endDate(365 $leapDay);
  6057.                     break;
  6058.                 case 2    :
  6059.                     return self::DATEDIF($startDate,$endDate360;
  6060.                     break;
  6061.                 case 3    :
  6062.                     return self::DATEDIF($startDate,$endDate365;
  6063.                     break;
  6064.                 case 4    :
  6065.                     return self::DAYS360($startDate,$endDate,True360;
  6066.                     break;
  6067.             }
  6068.         }
  6069.         return self::$_errorCodes['value'];
  6070.     }    //    function YEARFRAC()
  6071.  
  6072.  
  6073.     /**
  6074.      * NETWORKDAYS
  6075.      *
  6076.      * @param    mixed                Start date
  6077.      * @param    mixed                End date
  6078.      * @param    array of mixed        Optional Date Series
  6079.      * @return    long    Interval between the dates
  6080.      */
  6081.     public static function NETWORKDAYS($startDate,$endDate{
  6082.         //    Flush the mandatory start and end date that are referenced in the function definition
  6083.         $dateArgs self::flattenArray(func_get_args());
  6084.         array_shift($dateArgs);
  6085.         array_shift($dateArgs);
  6086.  
  6087.         //    Validate the start and end dates
  6088.         if (is_string($startDate $sDate self::_getDateValue($startDate))) {
  6089.             return self::$_errorCodes['value'];
  6090.         }
  6091.         if (is_string($endDate $eDate self::_getDateValue($endDate))) {
  6092.             return self::$_errorCodes['value'];
  6093.         }
  6094.  
  6095.         if ($sDate $eDate{
  6096.             $startDate $eDate;
  6097.             $endDate $sDate;
  6098.         }
  6099.  
  6100.         // Execute function
  6101.         $startDoW self::DAYOFWEEK($startDate,2);
  6102.         if ($startDoW 0$startDoW 0}
  6103.         $endDoW self::DAYOFWEEK($endDate,2);
  6104.         if ($endDoW >= 6$endDoW 0}
  6105.  
  6106.         $wholeWeekDays floor(($endDate $startDate75;
  6107.         $partWeekDays $endDoW $startDoW;
  6108.         if ($partWeekDays 5{
  6109.             $partWeekDays -= 5;
  6110.         }
  6111.  
  6112.         //    Test any extra holiday parameters
  6113.         $holidayCountedArray array();
  6114.         foreach ($dateArgs as $holidayDate{
  6115.             if (is_string($holidayDate self::_getDateValue($holidayDate))) {
  6116.                 return self::$_errorCodes['value'];
  6117.             }
  6118.             if (($holidayDate >= $startDate&& ($holidayDate <= $endDate)) {
  6119.                 if ((self::DAYOFWEEK($holidayDate,26&& (!in_array($holidayDate,$holidayCountedArray))) {
  6120.                     --$partWeekDays;
  6121.                     $holidayCountedArray[$holidayDate;
  6122.                 }
  6123.             }
  6124.         }
  6125.  
  6126.         if ($sDate $eDate{
  6127.             return ($wholeWeekDays $partWeekDays);
  6128.         }
  6129.         return $wholeWeekDays $partWeekDays;
  6130.     }    //    function NETWORKDAYS()
  6131.  
  6132.  
  6133.     /**
  6134.      * WORKDAY
  6135.      *
  6136.      * @param    mixed                Start date
  6137.      * @param    mixed                number of days for adjustment
  6138.      * @param    array of mixed        Optional Date Series
  6139.      * @return    long    Interval between the dates
  6140.      */
  6141.     public static function WORKDAY($startDate,$endDays{
  6142.         $dateArgs self::flattenArray(func_get_args());
  6143.  
  6144.         array_shift($dateArgs);
  6145.         array_shift($dateArgs);
  6146.  
  6147.         if (is_string($startDate self::_getDateValue($startDate))) {
  6148.             return self::$_errorCodes['value'];
  6149.         }
  6150.         if (!is_numeric($endDays)) {
  6151.             return self::$_errorCodes['value'];
  6152.         }
  6153.         $endDate = (float) $startDate (floor($endDays 57($endDays 5);
  6154.         if ($endDays 0{
  6155.             $endDate += 7;
  6156.         }
  6157.  
  6158.         $endDoW self::DAYOFWEEK($endDate,3);
  6159.         if ($endDoW >= 5{
  6160.             if ($endDays >= 0{
  6161.                 $endDate += ($endDoW);
  6162.             else {
  6163.                 $endDate -= ($endDoW 5);
  6164.             }
  6165.         }
  6166.  
  6167.         //    Test any extra holiday parameters
  6168.         if (count($dateArgs0{
  6169.             $holidayCountedArray $holidayDates array();
  6170.             foreach ($dateArgs as $holidayDate{
  6171.                 if (is_string($holidayDate self::_getDateValue($holidayDate))) {
  6172.                     return self::$_errorCodes['value'];
  6173.                 }
  6174.                 $holidayDates[$holidayDate;
  6175.             }
  6176.             if ($endDays >= 0{
  6177.                 sort($holidayDatesSORT_NUMERIC);
  6178.             else {
  6179.                 rsort($holidayDatesSORT_NUMERIC);
  6180.             }
  6181.             foreach ($holidayDates as $holidayDate{
  6182.                 if ($endDays >= 0{
  6183.                     if (($holidayDate >= $startDate&& ($holidayDate <= $endDate)) {
  6184.                         if ((self::DAYOFWEEK($holidayDate,26&& (!in_array($holidayDate,$holidayCountedArray))) {
  6185.                             ++$endDate;
  6186.                             $holidayCountedArray[$holidayDate;
  6187.                         }
  6188.                     }
  6189.                 else {
  6190.                     if (($holidayDate <= $startDate&& ($holidayDate >= $endDate)) {
  6191.                         if ((self::DAYOFWEEK($holidayDate,26&& (!in_array($holidayDate,$holidayCountedArray))) {
  6192.                             --$endDate;
  6193.                             $holidayCountedArray[$holidayDate;
  6194.                         }
  6195.                     }
  6196.                 }
  6197.                 $endDoW self::DAYOFWEEK($endDate,3);
  6198.                 if ($endDoW >= 5{
  6199.                     if ($endDays >= 0{
  6200.                         $endDate += ($endDoW);
  6201.                     else {
  6202.                         $endDate -= ($endDoW 5);
  6203.                     }
  6204.                 }
  6205.             }
  6206.         }
  6207.  
  6208.         switch (self::getReturnDateType()) {
  6209.             case self::RETURNDATE_EXCEL            return (float) $endDate;
  6210.                                                   break;
  6211.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($endDate);
  6212.                                                   break;
  6213.             case self::RETURNDATE_PHP_OBJECT    return PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  6214.                                                   break;
  6215.         }
  6216.     }    //    function WORKDAY()
  6217.  
  6218.  
  6219.     /**
  6220.      * DAYOFMONTH
  6221.      *
  6222.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6223.      * @return    int        Day
  6224.      */
  6225.     public static function DAYOFMONTH($dateValue 1{
  6226.         $dateValue    self::flattenSingleValue($dateValue);
  6227.  
  6228.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6229.             return self::$_errorCodes['value'];
  6230.         elseif ($dateValue == 0.0{
  6231.             return 0;
  6232.         elseif ($dateValue 0.0{
  6233.             return self::$_errorCodes['num'];
  6234.         }
  6235.  
  6236.         // Execute function
  6237.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6238.  
  6239.         return (int) $PHPDateObject->format('j');
  6240.     }    //    function DAYOFMONTH()
  6241.  
  6242.  
  6243.     /**
  6244.      * DAYOFWEEK
  6245.      *
  6246.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6247.      * @return    int        Day
  6248.      */
  6249.     public static function DAYOFWEEK($dateValue 1$style 1{
  6250.         $dateValue    self::flattenSingleValue($dateValue);
  6251.         $style        floor(self::flattenSingleValue($style));
  6252.  
  6253.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6254.             return self::$_errorCodes['value'];
  6255.         elseif ($dateValue 0.0{
  6256.             return self::$_errorCodes['num'];
  6257.         }
  6258.  
  6259.         // Execute function
  6260.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6261.         $DoW $PHPDateObject->format('w');
  6262.  
  6263.         $firstDay 1;
  6264.         switch ($style{
  6265.             case 1: ++$DoW;
  6266.                     break;
  6267.             case 2if ($DoW == 0$DoW 7}
  6268.                     break;
  6269.             case 3if ($DoW == 0$DoW 7}
  6270.                     $firstDay 0;
  6271.                     --$DoW;
  6272.                     break;
  6273.             default:
  6274.         }
  6275.         if (self::$compatibilityMode == self::COMPATIBILITY_EXCEL{
  6276.             //    Test for Excel's 1900 leap year, and introduce the error as required
  6277.             if (($PHPDateObject->format('Y'== 1900&& ($PHPDateObject->format('n'<= 2)) {
  6278.                 --$DoW;
  6279.                 if ($DoW $firstDay{
  6280.                     $DoW += 7;
  6281.                 }
  6282.             }
  6283.         }
  6284.  
  6285.         return (int) $DoW;
  6286.     }    //    function DAYOFWEEK()
  6287.  
  6288.  
  6289.     /**
  6290.      * WEEKOFYEAR
  6291.      *
  6292.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6293.      * @param    boolean    $method            Week begins on Sunday or Monday
  6294.      * @return    int        Week Number
  6295.      */
  6296.     public static function WEEKOFYEAR($dateValue 1$method 1{
  6297.         $dateValue    self::flattenSingleValue($dateValue);
  6298.         $method        floor(self::flattenSingleValue($method));
  6299.  
  6300.         if (!is_numeric($method)) {
  6301.             return self::$_errorCodes['value'];
  6302.         elseif (($method 1|| ($method 2)) {
  6303.             return self::$_errorCodes['num'];
  6304.         }
  6305.  
  6306.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6307.             return self::$_errorCodes['value'];
  6308.         elseif ($dateValue 0.0{
  6309.             return self::$_errorCodes['num'];
  6310.         }
  6311.  
  6312.         // Execute function
  6313.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6314.         $dayOfYear $PHPDateObject->format('z');
  6315.         $dow $PHPDateObject->format('w');
  6316.         $PHPDateObject->modify('-'.$dayOfYear.' days');
  6317.         $dow $PHPDateObject->format('w');
  6318.         $daysInFirstWeek (($dow ($method)) 7);
  6319.         $dayOfYear -= $daysInFirstWeek;
  6320.         $weekOfYear ceil($dayOfYear 71;
  6321.  
  6322.         return (int) $weekOfYear;
  6323.     }    //    function WEEKOFYEAR()
  6324.  
  6325.  
  6326.     /**
  6327.      * MONTHOFYEAR
  6328.      *
  6329.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6330.      * @return    int        Month
  6331.      */
  6332.     public static function MONTHOFYEAR($dateValue 1{
  6333.         $dateValue    self::flattenSingleValue($dateValue);
  6334.  
  6335.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6336.             return self::$_errorCodes['value'];
  6337.         elseif ($dateValue 0.0{
  6338.             return self::$_errorCodes['num'];
  6339.         }
  6340.  
  6341.         // Execute function
  6342.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6343.  
  6344.         return (int) $PHPDateObject->format('n');
  6345.     }    //    function MONTHOFYEAR()
  6346.  
  6347.  
  6348.     /**
  6349.      * YEAR
  6350.      *
  6351.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6352.      * @return    int        Year
  6353.      */
  6354.     public static function YEAR($dateValue 1{
  6355.         $dateValue    self::flattenSingleValue($dateValue);
  6356.  
  6357.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6358.             return self::$_errorCodes['value'];
  6359.         elseif ($dateValue 0.0{
  6360.             return self::$_errorCodes['num'];
  6361.         }
  6362.  
  6363.         // Execute function
  6364.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6365.  
  6366.         return (int) $PHPDateObject->format('Y');
  6367.     }    //    function YEAR()
  6368.  
  6369.  
  6370.     /**
  6371.      * HOUROFDAY
  6372.      *
  6373.      * @param    mixed    $timeValue        Excel time serial value or a standard time string
  6374.      * @return    int        Hour
  6375.      */
  6376.     public static function HOUROFDAY($timeValue 0{
  6377.         $timeValue    self::flattenSingleValue($timeValue);
  6378.  
  6379.         if (!is_numeric($timeValue)) {
  6380.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6381.                 $testVal strtok($timeValue,'/-: ');
  6382.                 if (strlen($testValstrlen($timeValue)) {
  6383.                     return self::$_errorCodes['value'];
  6384.                 }
  6385.             }
  6386.             $timeValue self::_getTimeValue($timeValue);
  6387.             if (is_string($timeValue)) {
  6388.                 return self::$_errorCodes['value'];
  6389.             }
  6390.         }
  6391.         // Execute function
  6392.         if ($timeValue >= 1{
  6393.             $timeValue fmod($timeValue,1);
  6394.         elseif ($timeValue 0.0{
  6395.             return self::$_errorCodes['num'];
  6396.         }
  6397.         $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  6398.  
  6399.         return (int) gmdate('G',$timeValue);
  6400.     }    //    function HOUROFDAY()
  6401.  
  6402.  
  6403.     /**
  6404.      * MINUTEOFHOUR
  6405.      *
  6406.      * @param    long    $timeValue        Excel time serial value or a standard time string
  6407.      * @return    int        Minute
  6408.      */
  6409.     public static function MINUTEOFHOUR($timeValue 0{
  6410.         $timeValue $timeTester    self::flattenSingleValue($timeValue);
  6411.  
  6412.         if (!is_numeric($timeValue)) {
  6413.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6414.                 $testVal strtok($timeValue,'/-: ');
  6415.                 if (strlen($testValstrlen($timeValue)) {
  6416.                     return self::$_errorCodes['value'];
  6417.                 }
  6418.             }
  6419.             $timeValue self::_getTimeValue($timeValue);
  6420.             if (is_string($timeValue)) {
  6421.                 return self::$_errorCodes['value'];
  6422.             }
  6423.         }
  6424.         // Execute function
  6425.         if ($timeValue >= 1{
  6426.             $timeValue fmod($timeValue,1);
  6427.         elseif ($timeValue 0.0{
  6428.             return self::$_errorCodes['num'];
  6429.         }
  6430.         $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  6431.  
  6432.         return (int) gmdate('i',$timeValue);
  6433.     }    //    function MINUTEOFHOUR()
  6434.  
  6435.  
  6436.     /**
  6437.      * SECONDOFMINUTE
  6438.      *
  6439.      * @param    long    $timeValue        Excel time serial value or a standard time string
  6440.      * @return    int        Second
  6441.      */
  6442.     public static function SECONDOFMINUTE($timeValue 0{
  6443.         $timeValue    self::flattenSingleValue($timeValue);
  6444.  
  6445.         if (!is_numeric($timeValue)) {
  6446.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6447.                 $testVal strtok($timeValue,'/-: ');
  6448.                 if (strlen($testValstrlen($timeValue)) {
  6449.                     return self::$_errorCodes['value'];
  6450.                 }
  6451.             }
  6452.             $timeValue self::_getTimeValue($timeValue);
  6453.             if (is_string($timeValue)) {
  6454.                 return self::$_errorCodes['value'];
  6455.             }
  6456.         }
  6457.         // Execute function
  6458.         if ($timeValue >= 1{
  6459.             $timeValue fmod($timeValue,1);
  6460.         elseif ($timeValue 0.0{
  6461.             return self::$_errorCodes['num'];
  6462.         }
  6463.         $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  6464.  
  6465.         return (int) gmdate('s',$timeValue);
  6466.     }    //    function SECONDOFMINUTE()
  6467.  
  6468.  
  6469.     private static function _adjustDateByMonths($dateValue 0$adjustmentMonths 0{
  6470.         // Execute function
  6471.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6472.         $oMonth = (int) $PHPDateObject->format('m');
  6473.         $oYear = (int) $PHPDateObject->format('Y');
  6474.  
  6475.         $adjustmentMonthsString = (string) $adjustmentMonths;
  6476.         if ($adjustmentMonths 0{
  6477.             $adjustmentMonthsString '+'.$adjustmentMonths;
  6478.         }
  6479.         if ($adjustmentMonths != 0{
  6480.             $PHPDateObject->modify($adjustmentMonthsString.' months');
  6481.         }
  6482.         $nMonth = (int) $PHPDateObject->format('m');
  6483.         $nYear = (int) $PHPDateObject->format('Y');
  6484.  
  6485.         $monthDiff ($nMonth $oMonth(($nYear $oYear12);
  6486.         if ($monthDiff != $adjustmentMonths{
  6487.             $adjustDays = (int) $PHPDateObject->format('d');
  6488.             $adjustDaysString '-'.$adjustDays.' days';
  6489.             $PHPDateObject->modify($adjustDaysString);
  6490.         }
  6491.         return $PHPDateObject;
  6492.     }    //    function _adjustDateByMonths()
  6493.  
  6494.  
  6495.     /**
  6496.      * EDATE
  6497.      *
  6498.      * Returns the serial number that represents the date that is the indicated number of months before or after a specified date
  6499.      * (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.
  6500.      *
  6501.      * @param    long    $dateValue                Excel date serial value or a standard date string
  6502.      * @param    int        $adjustmentMonths        Number of months to adjust by
  6503.      * @return    long    Excel date serial value
  6504.      */
  6505.     public static function EDATE($dateValue 1$adjustmentMonths 0{
  6506.         $dateValue            self::flattenSingleValue($dateValue);
  6507.         $adjustmentMonths    floor(self::flattenSingleValue($adjustmentMonths));
  6508.  
  6509.         if (!is_numeric($adjustmentMonths)) {
  6510.             return self::$_errorCodes['value'];
  6511.         }
  6512.  
  6513.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6514.             return self::$_errorCodes['value'];
  6515.         }
  6516.  
  6517.         // Execute function
  6518.         $PHPDateObject self::_adjustDateByMonths($dateValue,$adjustmentMonths);
  6519.  
  6520.         switch (self::getReturnDateType()) {
  6521.             case self::RETURNDATE_EXCEL            return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
  6522.                                                   break;
  6523.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
  6524.                                                   break;
  6525.             case self::RETURNDATE_PHP_OBJECT    return $PHPDateObject;
  6526.                                                   break;
  6527.         }
  6528.     }    //    function EDATE()
  6529.  
  6530.  
  6531.     /**
  6532.      * EOMONTH
  6533.      *
  6534.      * Returns the serial number for the last day of the month that is the indicated number of months before or after start_date.
  6535.      * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
  6536.      *
  6537.      * @param    long    $dateValue            Excel date serial value or a standard date string
  6538.      * @param    int        $adjustmentMonths    Number of months to adjust by
  6539.      * @return    long    Excel date serial value
  6540.      */
  6541.     public static function EOMONTH($dateValue 1$adjustmentMonths 0{
  6542.         $dateValue            self::flattenSingleValue($dateValue);
  6543.         $adjustmentMonths    floor(self::flattenSingleValue($adjustmentMonths));
  6544.  
  6545.         if (!is_numeric($adjustmentMonths)) {
  6546.             return self::$_errorCodes['value'];
  6547.         }
  6548.  
  6549.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6550.             return self::$_errorCodes['value'];
  6551.         }
  6552.  
  6553.         // Execute function
  6554.         $PHPDateObject self::_adjustDateByMonths($dateValue,$adjustmentMonths+1);
  6555.         $adjustDays = (int) $PHPDateObject->format('d');
  6556.         $adjustDaysString '-'.$adjustDays.' days';
  6557.         $PHPDateObject->modify($adjustDaysString);
  6558.  
  6559.         switch (self::getReturnDateType()) {
  6560.             case self::RETURNDATE_EXCEL            return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
  6561.                                                   break;
  6562.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
  6563.                                                   break;
  6564.             case self::RETURNDATE_PHP_OBJECT    return $PHPDateObject;
  6565.                                                   break;
  6566.         }
  6567.     }    //    function EOMONTH()
  6568.  
  6569.  
  6570.     /**
  6571.      *    TRUNC
  6572.      *
  6573.      *    Truncates value to the number of fractional digits by number_digits.
  6574.      *
  6575.      *    @param    float        $value 
  6576.      *    @param    int            $number_digits 
  6577.      *    @return    float        Truncated value
  6578.      */
  6579.     public static function TRUNC($value 0$number_digits 0{
  6580.         $value            self::flattenSingleValue($value);
  6581.         $number_digits    self::flattenSingleValue($number_digits);
  6582.  
  6583.         // Validate parameters
  6584.         if ($number_digits 0{
  6585.             return self::$_errorCodes['value'];
  6586.         }
  6587.  
  6588.         // Truncate
  6589.         if ($number_digits 0{
  6590.             $value $value pow(10$number_digits);
  6591.         }
  6592.         $value intval($value);
  6593.         if ($number_digits 0{
  6594.             $value $value pow(10$number_digits);
  6595.         }
  6596.  
  6597.         // Return
  6598.         return $value;
  6599.     }    //    function TRUNC()
  6600.  
  6601.     /**
  6602.      *    POWER
  6603.      *
  6604.      *    Computes x raised to the power y.
  6605.      *
  6606.      *    @param    float        $x 
  6607.      *    @param    float        $y 
  6608.      *    @return    float 
  6609.      */
  6610.     public static function POWER($x 0$y 2{
  6611.         $x    self::flattenSingleValue($x);
  6612.         $y    self::flattenSingleValue($y);
  6613.  
  6614.         // Validate parameters
  6615.         if ($x == && $y <= 0{
  6616.             return self::$_errorCodes['divisionbyzero'];
  6617.         }
  6618.  
  6619.         // Return
  6620.         return pow($x$y);
  6621.     }    //    function POWER()
  6622.  
  6623.  
  6624.     private static function _nbrConversionFormat($xVal,$places{
  6625.         if (!is_null($places)) {
  6626.             if (strlen($xVal<= $places{
  6627.                 return substr(str_pad($xVal,$places,'0',STR_PAD_LEFT),-10);
  6628.             else {
  6629.                 return self::$_errorCodes['num'];
  6630.             }
  6631.         }
  6632.  
  6633.         return substr($xVal,-10);
  6634.     }    //    function _nbrConversionFormat()
  6635.  
  6636.  
  6637.     /**
  6638.      * BINTODEC
  6639.      *
  6640.      * Return a binary value as Decimal.
  6641.      *
  6642.      * @param    string        $x 
  6643.      * @return    string 
  6644.      */
  6645.     public static function BINTODEC($x{
  6646.         $x    self::flattenSingleValue($x);
  6647.  
  6648.         if (is_bool($x)) {
  6649.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6650.                 $x = (int) $x;
  6651.             else {
  6652.                 return self::$_errorCodes['value'];
  6653.             }
  6654.         }
  6655.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6656.             $x floor($x);
  6657.         }
  6658.         $x = (string) $x;
  6659.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  6660.             return self::$_errorCodes['num'];
  6661.         }
  6662.         if (strlen($x10{
  6663.             return self::$_errorCodes['num'];
  6664.         elseif (strlen($x== 10{
  6665.             //    Two's Complement
  6666.             $x substr($x,-9);
  6667.             return '-'.(512-bindec($x));
  6668.         }
  6669.         return bindec($x);
  6670.     }    //    function BINTODEC()
  6671.  
  6672.  
  6673.     /**
  6674.      * BINTOHEX
  6675.      *
  6676.      * Return a binary value as Hex.
  6677.      *
  6678.      * @param    string        $x 
  6679.      * @return    string 
  6680.      */
  6681.     public static function BINTOHEX($x$places=null{
  6682.         $x    floor(self::flattenSingleValue($x));
  6683.         $places    self::flattenSingleValue($places);
  6684.  
  6685.         if (is_bool($x)) {
  6686.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6687.                 $x = (int) $x;
  6688.             else {
  6689.                 return self::$_errorCodes['value'];
  6690.             }
  6691.         }
  6692.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6693.             $x floor($x);
  6694.         }
  6695.         $x = (string) $x;
  6696.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  6697.             return self::$_errorCodes['num'];
  6698.         }
  6699.         if (strlen($x10{
  6700.             return self::$_errorCodes['num'];
  6701.         elseif (strlen($x== 10{
  6702.             //    Two's Complement
  6703.             return str_repeat('F',8).substr(strtoupper(dechex(bindec(substr($x,-9)))),-2);
  6704.         }
  6705.         $hexVal = (string) strtoupper(dechex(bindec($x)));
  6706.  
  6707.         return self::_nbrConversionFormat($hexVal,$places);
  6708.     }    //    function BINTOHEX()
  6709.  
  6710.  
  6711.     /**
  6712.      * BINTOOCT
  6713.      *
  6714.      * Return a binary value as Octal.
  6715.      *
  6716.      * @param    string        $x 
  6717.      * @return    string 
  6718.      */
  6719.     public static function BINTOOCT($x$places=null{
  6720.         $x    floor(self::flattenSingleValue($x));
  6721.         $places    self::flattenSingleValue($places);
  6722.  
  6723.         if (is_bool($x)) {
  6724.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6725.                 $x = (int) $x;
  6726.             else {
  6727.                 return self::$_errorCodes['value'];
  6728.             }
  6729.         }
  6730.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6731.             $x floor($x);
  6732.         }
  6733.         $x = (string) $x;
  6734.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  6735.             return self::$_errorCodes['num'];
  6736.         }
  6737.         if (strlen($x10{
  6738.             return self::$_errorCodes['num'];
  6739.         elseif (strlen($x== 10{
  6740.             //    Two's Complement
  6741.             return str_repeat('7',7).substr(strtoupper(decoct(bindec(substr($x,-9)))),-3);
  6742.         }
  6743.         $octVal = (string) decoct(bindec($x));
  6744.  
  6745.         return self::_nbrConversionFormat($octVal,$places);
  6746.     }    //    function BINTOOCT()
  6747.  
  6748.  
  6749.     /**
  6750.      * DECTOBIN
  6751.      *
  6752.      * Return an octal value as binary.
  6753.      *
  6754.      * @param    string        $x 
  6755.      * @return    string 
  6756.      */
  6757.     public static function DECTOBIN($x$places=null{
  6758.         $x    self::flattenSingleValue($x);
  6759.         $places    self::flattenSingleValue($places);
  6760.  
  6761.         if (is_bool($x)) {
  6762.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6763.                 $x = (int) $x;
  6764.             else {
  6765.                 return self::$_errorCodes['value'];
  6766.             }
  6767.         }
  6768.         $x = (string) $x;
  6769.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  6770.             return self::$_errorCodes['value'];
  6771.         }
  6772.         $x = (string) floor($x);
  6773.         $r decbin($x);
  6774.         if (strlen($r== 32{
  6775.             //    Two's Complement
  6776.             $r substr($r,-10);
  6777.         elseif (strlen($r11{
  6778.             return self::$_errorCodes['num'];
  6779.         }
  6780.  
  6781.         return self::_nbrConversionFormat($r,$places);
  6782.     }    //    function DECTOBIN()
  6783.  
  6784.  
  6785.     /**
  6786.      * DECTOOCT
  6787.      *
  6788.      * Return an octal value as binary.
  6789.      *
  6790.      * @param    string        $x 
  6791.      * @return    string 
  6792.      */
  6793.     public static function DECTOOCT($x$places=null{
  6794.         $x    self::flattenSingleValue($x);
  6795.         $places    self::flattenSingleValue($places);
  6796.  
  6797.         if (is_bool($x)) {
  6798.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6799.                 $x = (int) $x;
  6800.             else {
  6801.                 return self::$_errorCodes['value'];
  6802.             }
  6803.         }
  6804.         $x = (string) $x;
  6805.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  6806.             return self::$_errorCodes['value'];
  6807.         }
  6808.         $x = (string) floor($x);
  6809.         $r decoct($x);
  6810.         if (strlen($r== 11{
  6811.             //    Two's Complement
  6812.             $r substr($r,-10);
  6813.         }
  6814.  
  6815.         return self::_nbrConversionFormat($r,$places);
  6816.     }    //    function DECTOOCT()
  6817.  
  6818.  
  6819.     /**
  6820.      * DECTOHEX
  6821.      *
  6822.      * Return an octal value as binary.
  6823.      *
  6824.      * @param    string        $x 
  6825.      * @return    string 
  6826.      */
  6827.     public static function DECTOHEX($x$places=null{
  6828.         $x    self::flattenSingleValue($x);
  6829.         $places    self::flattenSingleValue($places);
  6830.  
  6831.         if (is_bool($x)) {
  6832.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6833.                 $x = (int) $x;
  6834.             else {
  6835.                 return self::$_errorCodes['value'];
  6836.             }
  6837.         }
  6838.         $x = (string) $x;
  6839.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  6840.             return self::$_errorCodes['value'];
  6841.         }
  6842.         $x = (string) floor($x);
  6843.         $r strtoupper(dechex($x));
  6844.         if (strlen($r== 8{
  6845.             //    Two's Complement
  6846.             $r 'FF'.$r;
  6847.         }
  6848.  
  6849.         return self::_nbrConversionFormat($r,$places);
  6850.     }    //    function DECTOHEX()
  6851.  
  6852.  
  6853.     /**
  6854.      * HEXTOBIN
  6855.      *
  6856.      * Return a hex value as binary.
  6857.      *
  6858.      * @param    string        $x 
  6859.      * @return    string 
  6860.      */
  6861.     public static function HEXTOBIN($x$places=null{
  6862.         $x    self::flattenSingleValue($x);
  6863.         $places    self::flattenSingleValue($places);
  6864.  
  6865.         if (is_bool($x)) {
  6866.             return self::$_errorCodes['value'];
  6867.         }
  6868.         $x = (string) $x;
  6869.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  6870.             return self::$_errorCodes['num'];
  6871.         }
  6872.         $binVal decbin(hexdec($x));
  6873.  
  6874.         return substr(self::_nbrConversionFormat($binVal,$places),-10);
  6875.     }    //    function HEXTOBIN()
  6876.  
  6877.  
  6878.     /**
  6879.      * HEXTOOCT
  6880.      *
  6881.      * Return a hex value as octal.
  6882.      *
  6883.      * @param    string        $x 
  6884.      * @return    string 
  6885.      */
  6886.     public static function HEXTOOCT($x$places=null{
  6887.         $x    self::flattenSingleValue($x);
  6888.         $places    self::flattenSingleValue($places);
  6889.  
  6890.         if (is_bool($x)) {
  6891.             return self::$_errorCodes['value'];
  6892.         }
  6893.         $x = (string) $x;
  6894.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  6895.             return self::$_errorCodes['num'];
  6896.         }
  6897.         $octVal decoct(hexdec($x));
  6898.  
  6899.         return self::_nbrConversionFormat($octVal,$places);
  6900.     }    //    function HEXTOOCT()
  6901.  
  6902.  
  6903.     /**
  6904.      * HEXTODEC
  6905.      *
  6906.      * Return a hex value as octal.
  6907.      *
  6908.      * @param    string        $x 
  6909.      * @return    string 
  6910.      */
  6911.     public static function HEXTODEC($x{
  6912.         $x    self::flattenSingleValue($x);
  6913.  
  6914.         if (is_bool($x)) {
  6915.             return self::$_errorCodes['value'];
  6916.         }
  6917.         $x = (string) $x;
  6918.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  6919.             return self::$_errorCodes['num'];
  6920.         }
  6921.         return hexdec($x);
  6922.     }    //    function HEXTODEC()
  6923.  
  6924.  
  6925.     /**
  6926.      * OCTTOBIN
  6927.      *
  6928.      * Return an octal value as binary.
  6929.      *
  6930.      * @param    string        $x 
  6931.      * @return    string 
  6932.      */
  6933.     public static function OCTTOBIN($x$places=null{
  6934.         $x    self::flattenSingleValue($x);
  6935.         $places    self::flattenSingleValue($places);
  6936.  
  6937.         if (is_bool($x)) {
  6938.             return self::$_errorCodes['value'];
  6939.         }
  6940.         $x = (string) $x;
  6941.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  6942.             return self::$_errorCodes['num'];
  6943.         }
  6944.         $r decbin(octdec($x));
  6945.  
  6946.         return self::_nbrConversionFormat($r,$places);
  6947.     }    //    function OCTTOBIN()
  6948.  
  6949.  
  6950.     /**
  6951.      * OCTTODEC
  6952.      *
  6953.      * Return an octal value as binary.
  6954.      *
  6955.      * @param    string        $x 
  6956.      * @return    string 
  6957.      */
  6958.     public static function OCTTODEC($x{
  6959.         $x    self::flattenSingleValue($x);
  6960.  
  6961.         if (is_bool($x)) {
  6962.             return self::$_errorCodes['value'];
  6963.         }
  6964.         $x = (string) $x;
  6965.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  6966.             return self::$_errorCodes['num'];
  6967.         }
  6968.         return octdec($x);
  6969.     }    //    function OCTTODEC()
  6970.  
  6971.  
  6972.     /**
  6973.      * OCTTOHEX
  6974.      *
  6975.      * Return an octal value as hex.
  6976.      *
  6977.      * @param    string        $x 
  6978.      * @return    string 
  6979.      */
  6980.     public static function OCTTOHEX($x$places=null{
  6981.         $x    self::flattenSingleValue($x);
  6982.         $places    self::flattenSingleValue($places);
  6983.  
  6984.         if (is_bool($x)) {
  6985.             return self::$_errorCodes['value'];
  6986.         }
  6987.         $x = (string) $x;
  6988.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  6989.             return self::$_errorCodes['num'];
  6990.         }
  6991.         $hexVal strtoupper(dechex(octdec($x)));
  6992.  
  6993.         return self::_nbrConversionFormat($hexVal,$places);
  6994.     }    //    function OCTTOHEX()
  6995.  
  6996.  
  6997.     public static function _parseComplex($complexNumber{
  6998.         $workString = (string) $complexNumber;
  6999.  
  7000.         $realNumber $imaginary 0;
  7001.         //    Extract the suffix, if there is one
  7002.         $suffix substr($workString,-1);
  7003.         if (!is_numeric($suffix)) {
  7004.             $workString substr($workString,0,-1);
  7005.         else {
  7006.             $suffix '';
  7007.         }
  7008.  
  7009.         //    Split the input into its Real and Imaginary components
  7010.         $leadingSign 0;
  7011.         if (strlen($workString0{
  7012.             $leadingSign (($workString{0== '+'|| ($workString{0== '-')) 0;
  7013.         }
  7014.         $power '';
  7015.         $realNumber strtok($workString'+-');
  7016.         if (strtoupper(substr($realNumber,-1)) == 'E'{
  7017.             $power strtok('+-');
  7018.             ++$leadingSign;
  7019.         }
  7020.  
  7021.         $realNumber substr($workString,0,strlen($realNumber)+strlen($power)+$leadingSign);
  7022.  
  7023.         if ($suffix != ''{
  7024.             $imaginary substr($workString,strlen($realNumber));
  7025.  
  7026.             if (($imaginary == ''&& (($realNumber == ''|| ($realNumber == '+'|| ($realNumber == '-'))) {
  7027.                 $imaginary $realNumber.'1';
  7028.                 $realNumber '0';
  7029.             else if ($imaginary == ''{
  7030.                 $imaginary $realNumber;
  7031.                 $realNumber '0';
  7032.             elseif (($imaginary == '+'|| ($imaginary == '-')) {
  7033.                 $imaginary .= '1';
  7034.             }
  7035.         }
  7036.  
  7037.         $complexArray array'real'        => $realNumber,
  7038.                                'imaginary'    => $imaginary,
  7039.                                'suffix'        => $suffix
  7040.                              );
  7041.  
  7042.         return $complexArray;
  7043.     }    //    function _parseComplex()
  7044.  
  7045.  
  7046.     private static function _cleanComplex($complexNumber{
  7047.         if ($complexNumber{0== '+'$complexNumber substr($complexNumber,1);
  7048.         if ($complexNumber{0== '0'$complexNumber substr($complexNumber,1);
  7049.         if ($complexNumber{0== '.'$complexNumber '0'.$complexNumber;
  7050.         if ($complexNumber{0== '+'$complexNumber substr($complexNumber,1);
  7051.         return $complexNumber;
  7052.     }
  7053.  
  7054.  
  7055.     /**
  7056.      * COMPLEX
  7057.      *
  7058.      * returns a complex number of the form x + yi or x + yj.
  7059.      *
  7060.      * @param    float        $realNumber 
  7061.      * @param    float        $imaginary 
  7062.      * @param    string        $suffix 
  7063.      * @return    string 
  7064.      */
  7065.     public static function COMPLEX($realNumber=0.0$imaginary=0.0$suffix='i'{
  7066.         $realNumber    self::flattenSingleValue($realNumber);
  7067.         $imaginary    self::flattenSingleValue($imaginary);
  7068.         $suffix        self::flattenSingleValue($suffix);
  7069.  
  7070.         if (((is_numeric($realNumber)) && (is_numeric($imaginary))) &&
  7071.             (($suffix == 'i'|| ($suffix == 'j'|| ($suffix == ''))) {
  7072.             if ($realNumber == 0.0{
  7073.                 if ($imaginary == 0.0{
  7074.                     return (string) '0';
  7075.                 elseif ($imaginary == 1.0{
  7076.                     return (string) $suffix;
  7077.                 elseif ($imaginary == -1.0{
  7078.                     return (string) '-'.$suffix;
  7079.                 }
  7080.                 return (string) $imaginary.$suffix;
  7081.             elseif ($imaginary == 0.0{
  7082.                 return (string) $realNumber;
  7083.             elseif ($imaginary == 1.0{
  7084.                 return (string) $realNumber.'+'.$suffix;
  7085.             elseif ($imaginary == -1.0{
  7086.                 return (string) $realNumber.'-'.$suffix;
  7087.             }
  7088.             if ($imaginary 0$imaginary = (string) '+'.$imaginary}
  7089.             return (string) $realNumber.$imaginary.$suffix;
  7090.         }
  7091.         return self::$_errorCodes['value'];
  7092.     }    //    function COMPLEX()
  7093.  
  7094.  
  7095.     /**
  7096.      * IMAGINARY
  7097.      *
  7098.      * Returns the imaginary coefficient of a complex number in x + yi or x + yj text format.
  7099.      *
  7100.      * @param    string        $complexNumber 
  7101.      * @return    real 
  7102.      */
  7103.     public static function IMAGINARY($complexNumber{
  7104.         $complexNumber    self::flattenSingleValue($complexNumber);
  7105.  
  7106.         $parsedComplex self::_parseComplex($complexNumber);
  7107.         if (!is_array($parsedComplex)) {
  7108.             return $parsedComplex;
  7109.         }
  7110.         return $parsedComplex['imaginary'];
  7111.     }    //    function IMAGINARY()
  7112.  
  7113.  
  7114.     /**
  7115.      * IMREAL
  7116.      *
  7117.      * Returns the real coefficient of a complex number in x + yi or x + yj text format.
  7118.      *
  7119.      * @param    string        $complexNumber 
  7120.      * @return    real 
  7121.      */
  7122.     public static function IMREAL($complexNumber{
  7123.         $complexNumber    self::flattenSingleValue($complexNumber);
  7124.  
  7125.         $parsedComplex self::_parseComplex($complexNumber);
  7126.         if (!is_array($parsedComplex)) {
  7127.             return $parsedComplex;
  7128.         }
  7129.         return $parsedComplex['real'];
  7130.     }    //    function IMREAL()
  7131.  
  7132.  
  7133.     /**
  7134.      * IMABS
  7135.      *
  7136.      * Returns the absolute value (modulus) of a complex number in x + yi or x + yj text format.
  7137.      *
  7138.      * @param    string        $complexNumber 
  7139.      * @return    real 
  7140.      */
  7141.     public static function IMABS($complexNumber{
  7142.         $complexNumber    self::flattenSingleValue($complexNumber);
  7143.  
  7144.         $parsedComplex self::_parseComplex($complexNumber);
  7145.         if (!is_array($parsedComplex)) {
  7146.             return $parsedComplex;
  7147.         }
  7148.         return sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary']));
  7149.     }    //    function IMABS()
  7150.  
  7151.  
  7152.     /**
  7153.      * IMARGUMENT
  7154.      *
  7155.      * 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.
  7156.      *
  7157.      * @param    string        $complexNumber 
  7158.      * @return    string 
  7159.      */
  7160.     public static function IMARGUMENT($complexNumber{
  7161.         $complexNumber    self::flattenSingleValue($complexNumber);
  7162.  
  7163.         $parsedComplex self::_parseComplex($complexNumber);
  7164.         if (!is_array($parsedComplex)) {
  7165.             return $parsedComplex;
  7166.         }
  7167.  
  7168.         if ($parsedComplex['real'== 0.0{
  7169.             if ($parsedComplex['imaginary'== 0.0{
  7170.                 return 0.0;
  7171.             elseif($parsedComplex['imaginary'0.0{
  7172.                 return M_PI / -2;
  7173.             else {
  7174.                 return M_PI 2;
  7175.             }
  7176.         elseif ($parsedComplex['real'0.0{
  7177.             return atan($parsedComplex['imaginary'$parsedComplex['real']);
  7178.         elseif ($parsedComplex['imaginary'0.0{
  7179.             return (M_PI atan(abs($parsedComplex['imaginary']abs($parsedComplex['real'])));
  7180.         else {
  7181.             return M_PI atan($parsedComplex['imaginary'abs($parsedComplex['real']));
  7182.         }
  7183.     }    //    function IMARGUMENT()
  7184.  
  7185.  
  7186.     /**
  7187.      * IMCONJUGATE
  7188.      *
  7189.      * Returns the complex conjugate of a complex number in x + yi or x + yj text format.
  7190.      *
  7191.      * @param    string        $complexNumber 
  7192.      * @return    string 
  7193.      */
  7194.     public static function IMCONJUGATE($complexNumber{
  7195.         $complexNumber    self::flattenSingleValue($complexNumber);
  7196.  
  7197.         $parsedComplex self::_parseComplex($complexNumber);
  7198.  
  7199.         if (!is_array($parsedComplex)) {
  7200.             return $parsedComplex;
  7201.         }
  7202.  
  7203.         if ($parsedComplex['imaginary'== 0.0{
  7204.             return $parsedComplex['real'];
  7205.         else {
  7206.             return self::_cleanComplex(self::COMPLEX($parsedComplex['real']$parsedComplex['imaginary']$parsedComplex['suffix']));
  7207.         }
  7208.     }    //    function IMCONJUGATE()
  7209.  
  7210.  
  7211.     /**
  7212.      * IMCOS
  7213.      *
  7214.      * Returns the cosine of a complex number in x + yi or x + yj text format.
  7215.      *
  7216.      * @param    string        $complexNumber 
  7217.      * @return    string 
  7218.      */
  7219.     public static function IMCOS($complexNumber{
  7220.         $complexNumber    self::flattenSingleValue($complexNumber);
  7221.  
  7222.         $parsedComplex self::_parseComplex($complexNumber);
  7223.         if (!is_array($parsedComplex)) {
  7224.             return $parsedComplex;
  7225.         }
  7226.  
  7227.         if ($parsedComplex['imaginary'== 0.0{
  7228.             return cos($parsedComplex['real']);
  7229.         else {
  7230.             return self::IMCONJUGATE(self::COMPLEX(cos($parsedComplex['real']cosh($parsedComplex['imaginary']),sin($parsedComplex['real']sinh($parsedComplex['imaginary']),$parsedComplex['suffix']));
  7231.         }
  7232.     }    //    function IMCOS()
  7233.  
  7234.  
  7235.     /**
  7236.      * IMSIN
  7237.      *
  7238.      * Returns the sine of a complex number in x + yi or x + yj text format.
  7239.      *
  7240.      * @param    string        $complexNumber 
  7241.      * @return    string 
  7242.      */
  7243.     public static function IMSIN($complexNumber{
  7244.         $complexNumber    self::flattenSingleValue($complexNumber);
  7245.  
  7246.         $parsedComplex self::_parseComplex($complexNumber);
  7247.         if (!is_array($parsedComplex)) {
  7248.             return $parsedComplex;
  7249.         }
  7250.  
  7251.         if ($parsedComplex['imaginary'== 0.0{
  7252.             return sin($parsedComplex['real']);
  7253.         else {
  7254.             return self::COMPLEX(sin($parsedComplex['real']cosh($parsedComplex['imaginary']),cos($parsedComplex['real']sinh($parsedComplex['imaginary']),$parsedComplex['suffix']);
  7255.         }
  7256.     }    //    function IMSIN()
  7257.  
  7258.  
  7259.     /**
  7260.      * IMSQRT
  7261.      *
  7262.      * Returns the square root of a complex number in x + yi or x + yj text format.
  7263.      *
  7264.      * @param    string        $complexNumber 
  7265.      * @return    string 
  7266.      */
  7267.     public static function IMSQRT($complexNumber{
  7268.         $complexNumber    self::flattenSingleValue($complexNumber);
  7269.  
  7270.         $parsedComplex self::_parseComplex($complexNumber);
  7271.         if (!is_array($parsedComplex)) {
  7272.             return $parsedComplex;
  7273.         }
  7274.  
  7275.         $theta self::IMARGUMENT($complexNumber);
  7276.         $d1 cos($theta 2);
  7277.         $d2 sin($theta 2);
  7278.         $r sqrt(sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary'])));
  7279.  
  7280.         if ($parsedComplex['suffix'== ''{
  7281.             return self::COMPLEX($d1 $r,$d2 $r);
  7282.         else {
  7283.             return self::COMPLEX($d1 $r,$d2 $r,$parsedComplex['suffix']);
  7284.         }
  7285.     }    //    function IMSQRT()
  7286.  
  7287.  
  7288.     /**
  7289.      * IMLN
  7290.      *
  7291.      * Returns the natural logarithm of a complex number in x + yi or x + yj text format.
  7292.      *
  7293.      * @param    string        $complexNumber 
  7294.      * @return    string 
  7295.      */
  7296.     public static function IMLN($complexNumber{
  7297.         $complexNumber    self::flattenSingleValue($complexNumber);
  7298.  
  7299.         $parsedComplex self::_parseComplex($complexNumber);
  7300.         if (!is_array($parsedComplex)) {
  7301.             return $parsedComplex;
  7302.         }
  7303.  
  7304.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7305.             return self::$_errorCodes['num'];
  7306.         }
  7307.  
  7308.         $logR log(sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary'])));
  7309.         $t self::IMARGUMENT($complexNumber);
  7310.  
  7311.         if ($parsedComplex['suffix'== ''{
  7312.             return self::COMPLEX($logR,$t);
  7313.         else {
  7314.             return self::COMPLEX($logR,$t,$parsedComplex['suffix']);
  7315.         }
  7316.     }    //    function IMLN()
  7317.  
  7318.  
  7319.     /**
  7320.      * IMLOG10
  7321.      *
  7322.      * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
  7323.      *
  7324.      * @param    string        $complexNumber 
  7325.      * @return    string 
  7326.      */
  7327.     public static function IMLOG10($complexNumber{
  7328.         $complexNumber    self::flattenSingleValue($complexNumber);
  7329.  
  7330.         $parsedComplex self::_parseComplex($complexNumber);
  7331.         if (!is_array($parsedComplex)) {
  7332.             return $parsedComplex;
  7333.         }
  7334.  
  7335.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7336.             return self::$_errorCodes['num'];
  7337.         elseif (($parsedComplex['real'0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7338.             return log10($parsedComplex['real']);
  7339.         }
  7340.  
  7341.         return self::IMPRODUCT(log10(EULER),self::IMLN($complexNumber));
  7342.     }    //    function IMLOG10()
  7343.  
  7344.  
  7345.     /**
  7346.      * IMLOG2
  7347.      *
  7348.      * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
  7349.      *
  7350.      * @param    string        $complexNumber 
  7351.      * @return    string 
  7352.      */
  7353.     public static function IMLOG2($complexNumber{
  7354.         $complexNumber    self::flattenSingleValue($complexNumber);
  7355.  
  7356.         $parsedComplex self::_parseComplex($complexNumber);
  7357.         if (!is_array($parsedComplex)) {
  7358.             return $parsedComplex;
  7359.         }
  7360.  
  7361.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7362.             return self::$_errorCodes['num'];
  7363.         elseif (($parsedComplex['real'0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7364.             return log($parsedComplex['real'],2);
  7365.         }
  7366.  
  7367.         return self::IMPRODUCT(log(EULER,2),self::IMLN($complexNumber));
  7368.     }    //    function IMLOG2()
  7369.  
  7370.  
  7371.     /**
  7372.      * IMEXP
  7373.      *
  7374.      * Returns the exponential of a complex number in x + yi or x + yj text format.
  7375.      *
  7376.      * @param    string        $complexNumber 
  7377.      * @return    string 
  7378.      */
  7379.     public static function IMEXP($complexNumber{
  7380.         $complexNumber    self::flattenSingleValue($complexNumber);
  7381.  
  7382.         $parsedComplex self::_parseComplex($complexNumber);
  7383.         if (!is_array($parsedComplex)) {
  7384.             return $parsedComplex;
  7385.         }
  7386.  
  7387.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7388.             return '1';
  7389.         }
  7390.  
  7391.         $e exp($parsedComplex['real']);
  7392.         $eX $e cos($parsedComplex['imaginary']);
  7393.         $eY $e sin($parsedComplex['imaginary']);
  7394.  
  7395.         if ($parsedComplex['suffix'== ''{
  7396.             return self::COMPLEX($eX,$eY);
  7397.         else {
  7398.             return self::COMPLEX($eX,$eY,$parsedComplex['suffix']);
  7399.         }
  7400.     }    //    function IMEXP()
  7401.  
  7402.  
  7403.     /**
  7404.      * IMPOWER
  7405.      *
  7406.      * Returns a complex number in x + yi or x + yj text format raised to a power.
  7407.      *
  7408.      * @param    string        $complexNumber 
  7409.      * @return    string 
  7410.      */
  7411.     public static function IMPOWER($complexNumber,$realNumber{
  7412.         $complexNumber    self::flattenSingleValue($complexNumber);
  7413.         $realNumber        self::flattenSingleValue($realNumber);
  7414.  
  7415.         if (!is_numeric($realNumber)) {
  7416.             return self::$_errorCodes['value'];
  7417.         }
  7418.  
  7419.         $parsedComplex self::_parseComplex($complexNumber);
  7420.         if (!is_array($parsedComplex)) {
  7421.             return $parsedComplex;
  7422.         }
  7423.  
  7424.         $r sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary']));
  7425.         $rPower pow($r,$realNumber);
  7426.         $theta self::IMARGUMENT($complexNumber$realNumber;
  7427.         if ($theta == 0{
  7428.             return 1;
  7429.         elseif ($parsedComplex['imaginary'== 0.0{
  7430.             return self::COMPLEX($rPower cos($theta),$rPower sin($theta),$parsedComplex['suffix']);
  7431.         else {
  7432.             return self::COMPLEX($rPower cos($theta),$rPower sin($theta),$parsedComplex['suffix']);
  7433.         }
  7434.     }    //    function IMPOWER()
  7435.  
  7436.  
  7437.     /**
  7438.      * IMDIV
  7439.      *
  7440.      * Returns the quotient of two complex numbers in x + yi or x + yj text format.
  7441.      *
  7442.      * @param    string        $complexDividend 
  7443.      * @param    string        $complexDivisor 
  7444.      * @return    real 
  7445.      */
  7446.     public static function IMDIV($complexDividend,$complexDivisor{
  7447.         $complexDividend    self::flattenSingleValue($complexDividend);
  7448.         $complexDivisor    self::flattenSingleValue($complexDivisor);
  7449.  
  7450.         $parsedComplexDividend self::_parseComplex($complexDividend);
  7451.         if (!is_array($parsedComplexDividend)) {
  7452.             return $parsedComplexDividend;
  7453.         }
  7454.  
  7455.         $parsedComplexDivisor self::_parseComplex($complexDivisor);
  7456.         if (!is_array($parsedComplexDivisor)) {
  7457.             return $parsedComplexDividend;
  7458.         }
  7459.  
  7460.         if (($parsedComplexDividend['suffix'!= ''&& ($parsedComplexDivisor['suffix'!= ''&&
  7461.             ($parsedComplexDividend['suffix'!= $parsedComplexDivisor['suffix'])) {
  7462.             return self::$_errorCodes['num'];
  7463.         }
  7464.         if (($parsedComplexDividend['suffix'!= ''&& ($parsedComplexDivisor['suffix'== '')) {
  7465.             $parsedComplexDivisor['suffix'$parsedComplexDividend['suffix'];
  7466.         }
  7467.  
  7468.         $d1 ($parsedComplexDividend['real'$parsedComplexDivisor['real']($parsedComplexDividend['imaginary'$parsedComplexDivisor['imaginary']);
  7469.         $d2 ($parsedComplexDividend['imaginary'$parsedComplexDivisor['real']($parsedComplexDividend['real'$parsedComplexDivisor['imaginary']);
  7470.         $d3 ($parsedComplexDivisor['real'$parsedComplexDivisor['real']($parsedComplexDivisor['imaginary'$parsedComplexDivisor['imaginary']);
  7471.  
  7472.         $r $d1/$d3;
  7473.         $i $d2/$d3;
  7474.  
  7475.         if ($i 0.0{
  7476.             return self::_cleanComplex($r.'+'.$i.$parsedComplexDivisor['suffix']);
  7477.         elseif ($i 0.0{
  7478.             return self::_cleanComplex($r.$i.$parsedComplexDivisor['suffix']);
  7479.         else {
  7480.             return $r;
  7481.         }
  7482.     }    //    function IMDIV()
  7483.  
  7484.  
  7485.     /**
  7486.      * IMSUB
  7487.      *
  7488.      * Returns the difference of two complex numbers in x + yi or x + yj text format.
  7489.      *
  7490.      * @param    string        $complexNumber1 
  7491.      * @param    string        $complexNumber2 
  7492.      * @return    real 
  7493.      */
  7494.     public static function IMSUB($complexNumber1,$complexNumber2{
  7495.         $complexNumber1    self::flattenSingleValue($complexNumber1);
  7496.         $complexNumber2    self::flattenSingleValue($complexNumber2);
  7497.  
  7498.         $parsedComplex1 self::_parseComplex($complexNumber1);
  7499.         if (!is_array($parsedComplex1)) {
  7500.             return $parsedComplex1;
  7501.         }
  7502.  
  7503.         $parsedComplex2 self::_parseComplex($complexNumber2);
  7504.         if (!is_array($parsedComplex2)) {
  7505.             return $parsedComplex2;
  7506.         }
  7507.  
  7508.         if ((($parsedComplex1['suffix'!= ''&& ($parsedComplex2['suffix'!= '')) &&
  7509.             ($parsedComplex1['suffix'!= $parsedComplex2['suffix'])) {
  7510.             return self::$_errorCodes['num'];
  7511.         elseif (($parsedComplex1['suffix'== ''&& ($parsedComplex2['suffix'!= '')) {
  7512.             $parsedComplex1['suffix'$parsedComplex2['suffix'];
  7513.         }
  7514.  
  7515.         $d1 $parsedComplex1['real'$parsedComplex2['real'];
  7516.         $d2 $parsedComplex1['imaginary'$parsedComplex2['imaginary'];
  7517.  
  7518.         return self::COMPLEX($d1,$d2,$parsedComplex1['suffix']);
  7519.     }    //    function IMSUB()
  7520.  
  7521.  
  7522.     /**
  7523.      * IMSUM
  7524.      *
  7525.      * Returns the sum of two or more complex numbers in x + yi or x + yj text format.
  7526.      *
  7527.      * @param    array of mixed        Data Series
  7528.      * @return    real 
  7529.      */
  7530.     public static function IMSUM({
  7531.         // Return value
  7532.         $returnValue self::_parseComplex('0');
  7533.         $activeSuffix '';
  7534.  
  7535.         // Loop through the arguments
  7536.         $aArgs self::flattenArray(func_get_args());
  7537.         foreach ($aArgs as $arg{
  7538.             $parsedComplex self::_parseComplex($arg);
  7539.             if (!is_array($parsedComplex)) {
  7540.                 return $parsedComplex;
  7541.             }
  7542.  
  7543.             if ($activeSuffix == ''{
  7544.                 $activeSuffix $parsedComplex['suffix'];
  7545.             elseif (($parsedComplex['suffix'!= ''&& ($activeSuffix != $parsedComplex['suffix'])) {
  7546.                 return self::$_errorCodes['value'];
  7547.             }
  7548.  
  7549.             $returnValue['real'+= $parsedComplex['real'];
  7550.             $returnValue['imaginary'+= $parsedComplex['imaginary'];
  7551.         }
  7552.  
  7553.         if ($returnValue['imaginary'== 0.0$activeSuffix ''}
  7554.         return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix);
  7555.     }    //    function IMSUM()
  7556.  
  7557.  
  7558.     /**
  7559.      * IMPRODUCT
  7560.      *
  7561.      * Returns the product of two or more complex numbers in x + yi or x + yj text format.
  7562.      *
  7563.      * @param    array of mixed        Data Series
  7564.      * @return    real 
  7565.      */
  7566.     public static function IMPRODUCT({
  7567.         // Return value
  7568.         $returnValue self::_parseComplex('1');
  7569.         $activeSuffix '';
  7570.  
  7571.         // Loop through the arguments
  7572.         $aArgs self::flattenArray(func_get_args());
  7573.         foreach ($aArgs as $arg{
  7574.             $parsedComplex self::_parseComplex($arg);
  7575.             if (!is_array($parsedComplex)) {
  7576.                 return $parsedComplex;
  7577.             }
  7578.             $workValue $returnValue;
  7579.             if (($parsedComplex['suffix'!= ''&& ($activeSuffix == '')) {
  7580.                 $activeSuffix $parsedComplex['suffix'];
  7581.             elseif (($parsedComplex['suffix'!= ''&& ($activeSuffix != $parsedComplex['suffix'])) {
  7582.                 return self::$_errorCodes['num'];
  7583.             }
  7584.             $returnValue['real'($workValue['real'$parsedComplex['real']($workValue['imaginary'$parsedComplex['imaginary']);
  7585.             $returnValue['imaginary'($workValue['real'$parsedComplex['imaginary']($workValue['imaginary'$parsedComplex['real']);
  7586.         }
  7587.  
  7588.         if ($returnValue['imaginary'== 0.0$activeSuffix ''}
  7589.         return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix);
  7590.     }    //    function IMPRODUCT()
  7591.  
  7592.  
  7593.     private static $_conversionUnits array'g'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Gram',                        'AllowPrefix'    => True        ),
  7594.                                               'sg'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Slug',                        'AllowPrefix'    => False    ),
  7595.                                               'lbm'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Pound mass (avoirdupois)',    'AllowPrefix'    => False    ),
  7596.                                               'u'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'U (atomic mass unit)',        'AllowPrefix'    => True        ),
  7597.                                               'ozm'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Ounce mass (avoirdupois)',    'AllowPrefix'    => False    ),
  7598.                                               'm'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Meter',                        'AllowPrefix'    => True        ),
  7599.                                               'mi'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Statute mile',                'AllowPrefix'    => False    ),
  7600.                                               'Nmi'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Nautical mile',                'AllowPrefix'    => False    ),
  7601.                                               'in'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Inch',                        'AllowPrefix'    => False    ),
  7602.                                               'ft'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Foot',                        'AllowPrefix'    => False    ),
  7603.                                               'yd'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Yard',                        'AllowPrefix'    => False    ),
  7604.                                               'ang'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Angstrom',                    'AllowPrefix'    => True        ),
  7605.                                               'Pica'    => array(    'Group'    => 'Distance',        'Unit Name'    => 'Pica (1/72 in)',            'AllowPrefix'    => False    ),
  7606.                                               'yr'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Year',                        'AllowPrefix'    => False    ),
  7607.                                               'day'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Day',                        'AllowPrefix'    => False    ),
  7608.                                               'hr'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Hour',                        'AllowPrefix'    => False    ),
  7609.                                               'mn'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Minute',                    'AllowPrefix'    => False    ),
  7610.                                               'sec'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Second',                    'AllowPrefix'    => True        ),
  7611.                                               'Pa'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Pascal',                    'AllowPrefix'    => True        ),
  7612.                                               'p'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Pascal',                    'AllowPrefix'    => True        ),
  7613.                                               'atm'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Atmosphere',                'AllowPrefix'    => True        ),
  7614.                                               'at'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Atmosphere',                'AllowPrefix'    => True        ),
  7615.                                               'mmHg'    => array(    'Group'    => 'Pressure',        'Unit Name'    => 'mm of Mercury',                'AllowPrefix'    => True        ),
  7616.                                               'N'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Newton',                    'AllowPrefix'    => True        ),
  7617.                                               'dyn'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Dyne',                        'AllowPrefix'    => True        ),
  7618.                                               'dy'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Dyne',                        'AllowPrefix'    => True        ),
  7619.                                               'lbf'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Pound force',                'AllowPrefix'    => False    ),
  7620.                                               'J'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Joule',                        'AllowPrefix'    => True        ),
  7621.                                               'e'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Erg',                        'AllowPrefix'    => True        ),
  7622.                                               'c'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Thermodynamic calorie',        'AllowPrefix'    => True        ),
  7623.                                               'cal'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'IT calorie',                'AllowPrefix'    => True        ),
  7624.                                               'eV'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Electron volt',                'AllowPrefix'    => True        ),
  7625.                                               'ev'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Electron volt',                'AllowPrefix'    => True        ),
  7626.                                               'HPh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Horsepower-hour',            'AllowPrefix'    => False    ),
  7627.                                               'hh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Horsepower-hour',            'AllowPrefix'    => False    ),
  7628.                                               'Wh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Watt-hour',                    'AllowPrefix'    => True        ),
  7629.                                               'wh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Watt-hour',                    'AllowPrefix'    => True        ),
  7630.                                               'flb'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Foot-pound',                'AllowPrefix'    => False    ),
  7631.                                               'BTU'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'BTU',                        'AllowPrefix'    => False    ),
  7632.                                               'btu'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'BTU',                        'AllowPrefix'    => False    ),
  7633.                                               'HP'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Horsepower',                'AllowPrefix'    => False    ),
  7634.                                               'h'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Horsepower',                'AllowPrefix'    => False    ),
  7635.                                               'W'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Watt',                        'AllowPrefix'    => True        ),
  7636.                                               'w'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Watt',                        'AllowPrefix'    => True        ),
  7637.                                               'T'        => array(    'Group'    => 'Magnetism',        'Unit Name'    => 'Tesla',                        'AllowPrefix'    => True        ),
  7638.                                               'ga'        => array(    'Group'    => 'Magnetism',        'Unit Name'    => 'Gauss',                        'AllowPrefix'    => True        ),
  7639.                                               'C'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Celsius',                    'AllowPrefix'    => False    ),
  7640.                                               'cel'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Celsius',                    'AllowPrefix'    => False    ),
  7641.                                               'F'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Fahrenheit',                'AllowPrefix'    => False    ),
  7642.                                               'fah'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Fahrenheit',                'AllowPrefix'    => False    ),
  7643.                                               'K'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Kelvin',                    'AllowPrefix'    => False    ),
  7644.                                               'kel'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Kelvin',                    'AllowPrefix'    => False    ),
  7645.                                               'tsp'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Teaspoon',                    'AllowPrefix'    => False    ),
  7646.                                               'tbs'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Tablespoon',                'AllowPrefix'    => False    ),
  7647.                                               'oz'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Fluid Ounce',                'AllowPrefix'    => False    ),
  7648.                                               'cup'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Cup',                        'AllowPrefix'    => False    ),
  7649.                                               'pt'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'U.S. Pint',                    'AllowPrefix'    => False    ),
  7650.                                               'us_pt'    => array(    'Group'    => 'Liquid',        'Unit Name'    => 'U.S. Pint',                    'AllowPrefix'    => False    ),
  7651.                                               'uk_pt'    => array(    'Group'    => 'Liquid',        'Unit Name'    => 'U.K. Pint',                    'AllowPrefix'    => False    ),
  7652.                                               'qt'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Quart',                        'AllowPrefix'    => False    ),
  7653.                                               'gal'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Gallon',                    'AllowPrefix'    => False    ),
  7654.                                               'l'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Litre',                        'AllowPrefix'    => True        ),
  7655.                                               'lt'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Litre',                        'AllowPrefix'    => True        )
  7656.                                             );
  7657.  
  7658.     private static $_conversionMultipliers array(    'Y'    => array(    'multiplier'    => 1E24,    'name'    => 'yotta'    ),
  7659.                                                     'Z'    => array(    'multiplier'    => 1E21,    'name'    => 'zetta'    ),
  7660.                                                     'E'    => array(    'multiplier'    => 1E18,    'name'    => 'exa'    ),
  7661.                                                     'P'    => array(    'multiplier'    => 1E15,    'name'    => 'peta'    ),
  7662.                                                     'T'    => array(    'multiplier'    => 1E12,    'name'    => 'tera'    ),
  7663.                                                     'G'    => array(    'multiplier'    => 1E9,        'name'    => 'giga'    ),
  7664.                                                     'M'    => array(    'multiplier'    => 1E6,        'name'    => 'mega'    ),
  7665.                                                     'k'    => array(    'multiplier'    => 1E3,        'name'    => 'kilo'    ),
  7666.                                                     'h'    => array(    'multiplier'    => 1E2,        'name'    => 'hecto'    ),
  7667.                                                     'e'    => array(    'multiplier'    => 1E1,        'name'    => 'deka'    ),
  7668.                                                     'd'    => array(    'multiplier'    => 1E-1,    'name'    => 'deci'    ),
  7669.                                                     'c'    => array(    'multiplier'    => 1E-2,    'name'    => 'centi'    ),
  7670.                                                     'm'    => array(    'multiplier'    => 1E-3,    'name'    => 'milli'    ),
  7671.                                                     'u'    => array(    'multiplier'    => 1E-6,    'name'    => 'micro'    ),
  7672.                                                     'n'    => array(    'multiplier'    => 1E-9,    'name'    => 'nano'    ),
  7673.                                                     'p'    => array(    'multiplier'    => 1E-12,    'name'    => 'pico'    ),
  7674.                                                     'f'    => array(    'multiplier'    => 1E-15,    'name'    => 'femto'    ),
  7675.                                                     'a'    => array(    'multiplier'    => 1E-18,    'name'    => 'atto'    ),
  7676.                                                     'z'    => array(    'multiplier'    => 1E-21,    'name'    => 'zepto'    ),
  7677.                                                     'y'    => array(    'multiplier'    => 1E-24,    'name'    => 'yocto'    )
  7678.                                                  );
  7679.  
  7680.     private static $_unitConversions array(    'Mass'        => array(    'g'        => array(    'g'        => 1.0,
  7681.                                                                                             'sg'    => 6.85220500053478E-05,
  7682.                                                                                             'lbm'    => 2.20462291469134E-03,
  7683.                                                                                             'u'        => 6.02217000000000E+23,
  7684.                                                                                             'ozm'    => 3.52739718003627E-02
  7685.                                                                                         ),
  7686.                                                                         'sg'    => array(    'g'        => 1.45938424189287E+04,
  7687.                                                                                             'sg'    => 1.0,
  7688.                                                                                             'lbm'    => 3.21739194101647E+01,
  7689.                                                                                             'u'        => 8.78866000000000E+27,
  7690.                                                                                             'ozm'    => 5.14782785944229E+02
  7691.                                                                                         ),
  7692.                                                                         'lbm'    => array(    'g'        => 4.5359230974881148E+02,
  7693.                                                                                             'sg'    => 3.10810749306493E-02,
  7694.                                                                                             'lbm'    => 1.0,
  7695.                                                                                             'u'        => 2.73161000000000E+26,
  7696.                                                                                             'ozm'    => 1.60000023429410E+01
  7697.                                                                                         ),
  7698.                                                                         'u'        => array(    'g'        => 1.66053100460465E-24,
  7699.                                                                                             'sg'    => 1.13782988532950E-28,
  7700.                                                                                             'lbm'    => 3.66084470330684E-27,
  7701.                                                                                             'u'        => 1.0,
  7702.                                                                                             'ozm'    => 5.85735238300524E-26
  7703.                                                                                         ),
  7704.                                                                         'ozm'    => array(    'g'        => 2.83495152079732E+01,
  7705.                                                                                             'sg'    => 1.94256689870811E-03,
  7706.                                                                                             'lbm'    => 6.24999908478882E-02,
  7707.                                                                                             'u'        => 1.70725600000000E+25,
  7708.                                                                                             'ozm'    => 1.0
  7709.                                                                                         )
  7710.                                                                     ),
  7711.                                                 'Distance'    => array(    'm'        => array(    'm'        => 1.0,
  7712.                                                                                             'mi'    => 6.21371192237334E-04,
  7713.                                                                                             'Nmi'    => 5.39956803455724E-04,
  7714.                                                                                             'in'    => 3.93700787401575E+01,
  7715.                                                                                             'ft'    => 3.28083989501312E+00,
  7716.                                                                                             'yd'    => 1.09361329797891E+00,
  7717.                                                                                             'ang'    => 1.00000000000000E+10,
  7718.                                                                                             'Pica'    => 2.83464566929116E+03
  7719.                                                                                         ),
  7720.                                                                         'mi'    => array(    'm'        => 1.60934400000000E+03,
  7721.                                                                                             'mi'    => 1.0,
  7722.                                                                                             'Nmi'    => 8.68976241900648E-01,
  7723.                                                                                             'in'    => 6.33600000000000E+04,
  7724.                                                                                             'ft'    => 5.28000000000000E+03,
  7725.                                                                                             'yd'    => 1.76000000000000E+03,
  7726.                                                                                             'ang'    => 1.60934400000000E+13,
  7727.                                                                                             'Pica'    => 4.56191999999971E+06
  7728.                                                                                         ),
  7729.                                                                         'Nmi'    => array(    'm'        => 1.85200000000000E+03,
  7730.                                                                                             'mi'    => 1.15077944802354E+00,
  7731.                                                                                             'Nmi'    => 1.0,
  7732.                                                                                             'in'    => 7.29133858267717E+04,
  7733.                                                                                             'ft'    => 6.07611548556430E+03,
  7734.                                                                                             'yd'    => 2.02537182785694E+03,
  7735.                                                                                             'ang'    => 1.85200000000000E+13,
  7736.                                                                                             'Pica'    => 5.24976377952723E+06
  7737.                                                                                         ),
  7738.                                                                         'in'    => array(    'm'        => 2.54000000000000E-02,
  7739.                                                                                             'mi'    => 1.57828282828283E-05,
  7740.                                                                                             'Nmi'    => 1.37149028077754E-05,
  7741.                                                                                             'in'    => 1.0,
  7742.                                                                                             'ft'    => 8.33333333333333E-02,
  7743.                                                                                             'yd'    => 2.77777777686643E-02,
  7744.                                                                                             'ang'    => 2.54000000000000E+08,
  7745.                                                                                             'Pica'    => 7.19999999999955E+01
  7746.                                                                                         ),
  7747.                                                                         'ft'    => array(    'm'        => 3.04800000000000E-01,
  7748.                                                                                             'mi'    => 1.89393939393939E-04,
  7749.                                                                                             'Nmi'    => 1.64578833693305E-04,
  7750.                                                                                             'in'    => 1.20000000000000E+01,
  7751.                                                                                             'ft'    => 1.0,
  7752.                                                                                             'yd'    => 3.33333333223972E-01,
  7753.                                                                                             'ang'    => 3.04800000000000E+09,
  7754.                                                                                             'Pica'    => 8.63999999999946E+02
  7755.                                                                                         ),
  7756.                                                                         'yd'    => array(    'm'        => 9.14400000300000E-01,
  7757.                                                                                             'mi'    => 5.68181818368230E-04,
  7758.                                                                                             'Nmi'    => 4.93736501241901E-04,
  7759.                                                                                             'in'    => 3.60000000118110E+01,
  7760.                                                                                             'ft'    => 3.00000000000000E+00,
  7761.                                                                                             'yd'    => 1.0,
  7762.                                                                                             'ang'    => 9.14400000300000E+09,
  7763.                                                                                             'Pica'    => 2.59200000085023E+03
  7764.                                                                                         ),
  7765.                                                                         'ang'    => array(    'm'        => 1.00000000000000E-10,
  7766.                                                                                             'mi'    => 6.21371192237334E-14,
  7767.                                                                                             'Nmi'    => 5.39956803455724E-14,
  7768.                                                                                             'in'    => 3.93700787401575E-09,
  7769.                                                                                             'ft'    => 3.28083989501312E-10,
  7770.                                                                                             'yd'    => 1.09361329797891E-10,
  7771.                                                                                             'ang'    => 1.0,
  7772.                                                                                             'Pica'    => 2.83464566929116E-07
  7773.                                                                                         ),
  7774.                                                                         'Pica'    => array(    'm'        => 3.52777777777800E-04,
  7775.                                                                                             'mi'    => 2.19205948372629E-07,
  7776.                                                                                             'Nmi'    => 1.90484761219114E-07,
  7777.                                                                                             'in'    => 1.38888888888898E-02,
  7778.                                                                                             'ft'    => 1.15740740740748E-03,
  7779.                                                                                             'yd'    => 3.85802469009251E-04,
  7780.                                                                                             'ang'    => 3.52777777777800E+06,
  7781.                                                                                             'Pica'    => 1.0
  7782.                                                                                         )
  7783.                                                                     ),
  7784.                                                 'Time'        => array(    'yr'    => array(    'yr'        => 1.0,
  7785.                                                                                             'day'        => 365.25,
  7786.                                                                                             'hr'        => 8766.0,
  7787.                                                                                             'mn'        => 525960.0,
  7788.                                                                                             'sec'        => 31557600.0
  7789.                                                                                         ),
  7790.                                                                         'day'    => array(    'yr'        => 2.73785078713210E-03,
  7791.                                                                                             'day'        => 1.0,
  7792.                                                                                             'hr'        => 24.0,
  7793.                                                                                             'mn'        => 1440.0,
  7794.                                                                                             'sec'        => 86400.0
  7795.                                                                                         ),
  7796.                                                                         'hr'    => array(    'yr'        => 1.14077116130504E-04,
  7797.                                                                                             'day'        => 4.16666666666667E-02,
  7798.                                                                                             'hr'        => 1.0,
  7799.                                                                                             'mn'        => 60.0,
  7800.                                                                                             'sec'        => 3600.0
  7801.                                                                                         ),
  7802.                                                                         'mn'    => array(    'yr'        => 1.90128526884174E-06,
  7803.                                                                                             'day'        => 6.94444444444444E-04,
  7804.                                                                                             'hr'        => 1.66666666666667E-02,
  7805.                                                                                             'mn'        => 1.0,
  7806.                                                                                             'sec'        => 60.0
  7807.                                                                                         ),
  7808.                                                                         'sec'    => array(    'yr'        => 3.16880878140289E-08,
  7809.                                                                                             'day'        => 1.15740740740741E-05,
  7810.                                                                                             'hr'        => 2.77777777777778E-04,
  7811.                                                                                             'mn'        => 1.66666666666667E-02,
  7812.                                                                                             'sec'        => 1.0
  7813.                                                                                         )
  7814.                                                                     ),
  7815.                                                 'Pressure'    => array(    'Pa'    => array(    'Pa'        => 1.0,
  7816.                                                                                             'p'            => 1.0,
  7817.                                                                                             'atm'        => 9.86923299998193E-06,
  7818.                                                                                             'at'        => 9.86923299998193E-06,
  7819.                                                                                             'mmHg'        => 7.50061707998627E-03
  7820.                                                                                         ),
  7821.                                                                         'p'        => array(    'Pa'        => 1.0,
  7822.                                                                                             'p'            => 1.0,
  7823.                                                                                             'atm'        => 9.86923299998193E-06,
  7824.                                                                                             'at'        => 9.86923299998193E-06,
  7825.                                                                                             'mmHg'        => 7.50061707998627E-03
  7826.                                                                                         ),
  7827.                                                                         'atm'    => array(    'Pa'        => 1.01324996583000E+05,
  7828.                                                                                             'p'            => 1.01324996583000E+05,
  7829.                                                                                             'atm'        => 1.0,
  7830.                                                                                             'at'        => 1.0,
  7831.                                                                                             'mmHg'        => 760.0
  7832.                                                                                         ),
  7833.                                                                         'at'    => array(    'Pa'        => 1.01324996583000E+05,
  7834.                                                                                             'p'            => 1.01324996583000E+05,
  7835.                                                                                             'atm'        => 1.0,
  7836.                                                                                             'at'        => 1.0,
  7837.                                                                                             'mmHg'        => 760.0
  7838.                                                                                         ),
  7839.                                                                         'mmHg'    => array(    'Pa'        => 1.33322363925000E+02,
  7840.                                                                                             'p'            => 1.33322363925000E+02,
  7841.                                                                                             'atm'        => 1.31578947368421E-03,
  7842.                                                                                             'at'        => 1.31578947368421E-03,
  7843.                                                                                             'mmHg'        => 1.0
  7844.                                                                                         )
  7845.                                                                     ),
  7846.                                                 'Force'        => array(    'N'        => array(    'N'            => 1.0,
  7847.                                                                                             'dyn'        => 1.0E+5,
  7848.                                                                                             'dy'        => 1.0E+5,
  7849.                                                                                             'lbf'        => 2.24808923655339E-01
  7850.                                                                                         ),
  7851.                                                                         'dyn'    => array(    'N'            => 1.0E-5,
  7852.                                                                                             'dyn'        => 1.0,
  7853.                                                                                             'dy'        => 1.0,
  7854.                                                                                             'lbf'        => 2.24808923655339E-06
  7855.                                                                                         ),
  7856.                                                                         'dy'    => array(    'N'            => 1.0E-5,
  7857.                                                                                             'dyn'        => 1.0,
  7858.                                                                                             'dy'        => 1.0,
  7859.                                                                                             'lbf'        => 2.24808923655339E-06
  7860.                                                                                         ),
  7861.                                                                         'lbf'    => array(    'N'            => 4.448222,
  7862.                                                                                             'dyn'        => 4.448222E+5,
  7863.                                                                                             'dy'        => 4.448222E+5,
  7864.                                                                                             'lbf'        => 1.0
  7865.                                                                                         )
  7866.                                                                     ),
  7867.                                                 'Energy'    => array(    'J'        => array(    'J'            => 1.0,
  7868.                                                                                             'e'            => 9.99999519343231E+06,
  7869.                                                                                             'c'            => 2.39006249473467E-01,
  7870.                                                                                             'cal'        => 2.38846190642017E-01,
  7871.                                                                                             'eV'        => 6.24145700000000E+18,
  7872.                                                                                             'ev'        => 6.24145700000000E+18,
  7873.                                                                                             'HPh'        => 3.72506430801000E-07,
  7874.                                                                                             'hh'        => 3.72506430801000E-07,
  7875.                                                                                             'Wh'        => 2.77777916238711E-04,
  7876.                                                                                             'wh'        => 2.77777916238711E-04,
  7877.                                                                                             'flb'        => 2.37304222192651E+01,
  7878.                                                                                             'BTU'        => 9.47815067349015E-04,
  7879.                                                                                             'btu'        => 9.47815067349015E-04
  7880.                                                                                         ),
  7881.                                                                         'e'        => array(    'J'            => 1.00000048065700E-07,
  7882.                                                                                             'e'            => 1.0,
  7883.                                                                                             'c'            => 2.39006364353494E-08,
  7884.                                                                                             'cal'        => 2.38846305445111E-08,
  7885.                                                                                             'eV'        => 6.24146000000000E+11,
  7886.                                                                                             'ev'        => 6.24146000000000E+11,
  7887.                                                                                             'HPh'        => 3.72506609848824E-14,
  7888.                                                                                             'hh'        => 3.72506609848824E-14,
  7889.                                                                                             'Wh'        => 2.77778049754611E-11,
  7890.                                                                                             'wh'        => 2.77778049754611E-11,
  7891.                                                                                             'flb'        => 2.37304336254586E-06,
  7892.                                                                                             'BTU'        => 9.47815522922962E-11,
  7893.                                                                                             'btu'        => 9.47815522922962E-11
  7894.                                                                                         ),
  7895.                                                                         'c'        => array(    'J'            => 4.18399101363672E+00,
  7896.                                                                                             'e'            => 4.18398900257312E+07,
  7897.                                                                                             'c'            => 1.0,
  7898.                                                                                             'cal'        => 9.99330315287563E-01,
  7899.                                                                                             'eV'        => 2.61142000000000E+19,
  7900.                                                                                             'ev'        => 2.61142000000000E+19,
  7901.                                                                                             'HPh'        => 1.55856355899327E-06,
  7902.                                                                                             'hh'        => 1.55856355899327E-06,
  7903.                                                                                             'Wh'        => 1.16222030532950E-03,
  7904.                                                                                             'wh'        => 1.16222030532950E-03,
  7905.                                                                                             'flb'        => 9.92878733152102E+01,
  7906.                                                                                             'BTU'        => 3.96564972437776E-03,
  7907.                                                                                             'btu'        => 3.96564972437776E-03
  7908.                                                                                         ),
  7909.                                                                         'cal'    => array(    'J'            => 4.18679484613929E+00,
  7910.                                                                                             'e'            => 4.18679283372801E+07,
  7911.                                                                                             'c'            => 1.00067013349059E+00,
  7912.                                                                                             'cal'        => 1.0,
  7913.                                                                                             'eV'        => 2.61317000000000E+19,
  7914.                                                                                             'ev'        => 2.61317000000000E+19,
  7915.                                                                                             'HPh'        => 1.55960800463137E-06,
  7916.                                                                                             'hh'        => 1.55960800463137E-06,
  7917.                                                                                             'Wh'        => 1.16299914807955E-03,
  7918.                                                                                             'wh'        => 1.16299914807955E-03,
  7919.                                                                                             'flb'        => 9.93544094443283E+01,
  7920.                                                                                             'BTU'        => 3.96830723907002E-03,
  7921.                                                                                             'btu'        => 3.96830723907002E-03
  7922.                                                                                         ),
  7923.                                                                         'eV'    => array(    'J'            => 1.60219000146921E-19,
  7924.                                                                                             'e'            => 1.60218923136574E-12,
  7925.                                                                                             'c'            => 3.82933423195043E-20,
  7926.                                                                                             'cal'        => 3.82676978535648E-20,
  7927.                                                                                             'eV'        => 1.0,
  7928.                                                                                             'ev'        => 1.0,
  7929.                                                                                             'HPh'        => 5.96826078912344E-26,
  7930.                                                                                             'hh'        => 5.96826078912344E-26,
  7931.                                                                                             'Wh'        => 4.45053000026614E-23,
  7932.                                                                                             'wh'        => 4.45053000026614E-23,
  7933.                                                                                             'flb'        => 3.80206452103492E-18,
  7934.                                                                                             'BTU'        => 1.51857982414846E-22,
  7935.                                                                                             'btu'        => 1.51857982414846E-22
  7936.                                                                                         ),
  7937.                                                                         'ev'    => array(    'J'            => 1.60219000146921E-19,
  7938.                                                                                             'e'            => 1.60218923136574E-12,
  7939.                                                                                             'c'            => 3.82933423195043E-20,
  7940.                                                                                             'cal'        => 3.82676978535648E-20,
  7941.                                                                                             'eV'        => 1.0,
  7942.                                                                                             'ev'        => 1.0,
  7943.                                                                                             'HPh'        => 5.96826078912344E-26,
  7944.                                                                                             'hh'        => 5.96826078912344E-26,
  7945.                                                                                             'Wh'        => 4.45053000026614E-23,
  7946.                                                                                             'wh'        => 4.45053000026614E-23,
  7947.                                                                                             'flb'        => 3.80206452103492E-18,
  7948.                                                                                             'BTU'        => 1.51857982414846E-22,
  7949.                                                                                             'btu'        => 1.51857982414846E-22
  7950.                                                                                         ),
  7951.                                                                         'HPh'    => array(    'J'            => 2.68451741316170E+06,
  7952.                                                                                             'e'            => 2.68451612283024E+13,
  7953.                                                                                             'c'            => 6.41616438565991E+05,
  7954.                                                                                             'cal'        => 6.41186757845835E+05,
  7955.                                                                                             'eV'        => 1.67553000000000E+25,
  7956.                                                                                             'ev'        => 1.67553000000000E+25,
  7957.                                                                                             'HPh'        => 1.0,
  7958.                                                                                             'hh'        => 1.0,
  7959.                                                                                             'Wh'        => 7.45699653134593E+02,
  7960.                                                                                             'wh'        => 7.45699653134593E+02,
  7961.                                                                                             'flb'        => 6.37047316692964E+07,
  7962.                                                                                             'BTU'        => 2.54442605275546E+03,
  7963.                                                                                             'btu'        => 2.54442605275546E+03
  7964.                                                                                         ),
  7965.                                                                         'hh'    => array(    'J'            => 2.68451741316170E+06,
  7966.                                                                                             'e'            => 2.68451612283024E+13,
  7967.                                                                                             'c'            => 6.41616438565991E+05,
  7968.                                                                                             'cal'        => 6.41186757845835E+05,
  7969.                                                                                             'eV'        => 1.67553000000000E+25,
  7970.                                                                                             'ev'        => 1.67553000000000E+25,
  7971.                                                                                             'HPh'        => 1.0,
  7972.                                                                                             'hh'        => 1.0,
  7973.                                                                                             'Wh'        => 7.45699653134593E+02,
  7974.                                                                                             'wh'        => 7.45699653134593E+02,
  7975.                                                                                             'flb'        => 6.37047316692964E+07,
  7976.                                                                                             'BTU'        => 2.54442605275546E+03,
  7977.                                                                                             'btu'        => 2.54442605275546E+03
  7978.                                                                                         ),
  7979.                                                                         'Wh'    => array(    'J'            => 3.59999820554720E+03,
  7980.                                                                                             'e'            => 3.59999647518369E+10,
  7981.                                                                                             'c'            => 8.60422069219046E+02,
  7982.                                                                                             'cal'        => 8.59845857713046E+02,
  7983.                                                                                             'eV'        => 2.24692340000000E+22,
  7984.                                                                                             'ev'        => 2.24692340000000E+22,
  7985.                                                                                             'HPh'        => 1.34102248243839E-03,
  7986.                                                                                             'hh'        => 1.34102248243839E-03,
  7987.                                                                                             'Wh'        => 1.0,
  7988.                                                                                             'wh'        => 1.0,
  7989.                                                                                             'flb'        => 8.54294774062316E+04,
  7990.                                                                                             'BTU'        => 3.41213254164705E+00,
  7991.                                                                                             'btu'        => 3.41213254164705E+00
  7992.                                                                                         ),
  7993.                                                                         'wh'    => array(    'J'            => 3.59999820554720E+03,
  7994.                                                                                             'e'            => 3.59999647518369E+10,
  7995.                                                                                             'c'            => 8.60422069219046E+02,
  7996.                                                                                             'cal'        => 8.59845857713046E+02,
  7997.                                                                                             'eV'        => 2.24692340000000E+22,
  7998.                                                                                             'ev'        => 2.24692340000000E+22,
  7999.                                                                                             'HPh'        => 1.34102248243839E-03,
  8000.                                                                                             'hh'        => 1.34102248243839E-03,
  8001.                                                                                             'Wh'        => 1.0,
  8002.                                                                                             'wh'        => 1.0,
  8003.                                                                                             'flb'        => 8.54294774062316E+04,
  8004.                                                                                             'BTU'        => 3.41213254164705E+00,
  8005.                                                                                             'btu'        => 3.41213254164705E+00
  8006.                                                                                         ),
  8007.                                                                         'flb'    => array(    'J'            => 4.21400003236424E-02,
  8008.                                                                                             'e'            => 4.21399800687660E+05,
  8009.                                                                                             'c'            => 1.00717234301644E-02,
  8010.                                                                                             'cal'        => 1.00649785509554E-02,
  8011.                                                                                             'eV'        => 2.63015000000000E+17,
  8012.                                                                                             'ev'        => 2.63015000000000E+17,
  8013.                                                                                             'HPh'        => 1.56974211145130E-08,
  8014.                                                                                             'hh'        => 1.56974211145130E-08,
  8015.                                                                                             'Wh'        => 1.17055614802000E-05,
  8016.                                                                                             'wh'        => 1.17055614802000E-05,
  8017.                                                                                             'flb'        => 1.0,
  8018.                                                                                             'BTU'        => 3.99409272448406E-05,
  8019.                                                                                             'btu'        => 3.99409272448406E-05
  8020.                                                                                         ),
  8021.                                                                         'BTU'    => array(    'J'            => 1.05505813786749E+03,
  8022.                                                                                             'e'            => 1.05505763074665E+10,
  8023.                                                                                             'c'            => 2.52165488508168E+02,
  8024.                                                                                             'cal'        => 2.51996617135510E+02,
  8025.                                                                                             'eV'        => 6.58510000000000E+21,
  8026.                                                                                             'ev'        => 6.58510000000000E+21,
  8027.                                                                                             'HPh'        => 3.93015941224568E-04,
  8028.                                                                                             'hh'        => 3.93015941224568E-04,
  8029.                                                                                             'Wh'        => 2.93071851047526E-01,
  8030.                                                                                             'wh'        => 2.93071851047526E-01,
  8031.                                                                                             'flb'        => 2.50369750774671E+04,
  8032.                                                                                             'BTU'        => 1.0,
  8033.                                                                                             'btu'        => 1.0,
  8034.                                                                                         ),
  8035.                                                                         'btu'    => array(    'J'            => 1.05505813786749E+03,
  8036.                                                                                             'e'            => 1.05505763074665E+10,
  8037.                                                                                             'c'            => 2.52165488508168E+02,
  8038.                                                                                             'cal'        => 2.51996617135510E+02,
  8039.                                                                                             'eV'        => 6.58510000000000E+21,
  8040.                                                                                             'ev'        => 6.58510000000000E+21,
  8041.                                                                                             'HPh'        => 3.93015941224568E-04,
  8042.                                                                                             'hh'        => 3.93015941224568E-04,
  8043.                                                                                             'Wh'        => 2.93071851047526E-01,
  8044.                                                                                             'wh'        => 2.93071851047526E-01,
  8045.                                                                                             'flb'        => 2.50369750774671E+04,
  8046.                                                                                             'BTU'        => 1.0,
  8047.                                                                                             'btu'        => 1.0,
  8048.                                                                                         )
  8049.                                                                     ),
  8050.                                                 'Power'        => array(    'HP'    => array(    'HP'        => 1.0,
  8051.                                                                                             'h'            => 1.0,
  8052.                                                                                             'W'            => 7.45701000000000E+02,
  8053.                                                                                             'w'            => 7.45701000000000E+02
  8054.                                                                                         ),
  8055.                                                                         'h'        => array(    'HP'        => 1.0,
  8056.                                                                                             'h'            => 1.0,
  8057.                                                                                             'W'            => 7.45701000000000E+02,
  8058.                                                                                             'w'            => 7.45701000000000E+02
  8059.                                                                                         ),
  8060.                                                                         'W'        => array(    'HP'        => 1.34102006031908E-03,
  8061.                                                                                             'h'            => 1.34102006031908E-03,
  8062.                                                                                             'W'            => 1.0,
  8063.                                                                                             'w'            => 1.0
  8064.                                                                                         ),
  8065.                                                                         'w'        => array(    'HP'        => 1.34102006031908E-03,
  8066.                                                                                             'h'            => 1.34102006031908E-03,
  8067.                                                                                             'W'            => 1.0,
  8068.                                                                                             'w'            => 1.0
  8069.                                                                                         )
  8070.                                                                     ),
  8071.                                                 'Magnetism'    => array(    'T'        => array(    'T'            => 1.0,
  8072.                                                                                             'ga'        => 10000.0
  8073.                                                                                         ),
  8074.                                                                         'ga'    => array(    'T'            => 0.0001,
  8075.                                                                                             'ga'        => 1.0
  8076.                                                                                         )
  8077.                                                                     ),
  8078.                                                 'Liquid'    => array(    'tsp'    => array(    'tsp'        => 1.0,
  8079.                                                                                             'tbs'        => 3.33333333333333E-01,
  8080.                                                                                             'oz'        => 1.66666666666667E-01,
  8081.                                                                                             'cup'        => 2.08333333333333E-02,
  8082.                                                                                             'pt'        => 1.04166666666667E-02,
  8083.                                                                                             'us_pt'        => 1.04166666666667E-02,
  8084.                                                                                             'uk_pt'        => 8.67558516821960E-03,
  8085.                                                                                             'qt'        => 5.20833333333333E-03,
  8086.                                                                                             'gal'        => 1.30208333333333E-03,
  8087.                                                                                             'l'            => 4.92999408400710E-03,
  8088.                                                                                             'lt'        => 4.92999408400710E-03
  8089.                                                                                         ),
  8090.                                                                         'tbs'    => array(    'tsp'        => 3.00000000000000E+00,
  8091.                                                                                             'tbs'        => 1.0,
  8092.                                                                                             'oz'        => 5.00000000000000E-01,
  8093.                                                                                             'cup'        => 6.25000000000000E-02,
  8094.                                                                                             'pt'        => 3.12500000000000E-02,
  8095.                                                                                             'us_pt'        => 3.12500000000000E-02,
  8096.                                                                                             'uk_pt'        => 2.60267555046588E-02,
  8097.                                                                                             'qt'        => 1.56250000000000E-02,
  8098.                                                                                             'gal'        => 3.90625000000000E-03,
  8099.                                                                                             'l'            => 1.47899822520213E-02,
  8100.                                                                                             'lt'        => 1.47899822520213E-02
  8101.                                                                                         ),
  8102.                                                                         'oz'    => array(    'tsp'        => 6.00000000000000E+00,
  8103.                                                                                             'tbs'        => 2.00000000000000E+00,
  8104.                                                                                             'oz'        => 1.0,
  8105.                                                                                             'cup'        => 1.25000000000000E-01,
  8106.                                                                                             'pt'        => 6.25000000000000E-02,
  8107.                                                                                             'us_pt'        => 6.25000000000000E-02,
  8108.                                                                                             'uk_pt'        => 5.20535110093176E-02,
  8109.                                                                                             'qt'        => 3.12500000000000E-02,
  8110.                                                                                             'gal'        => 7.81250000000000E-03,
  8111.                                                                                             'l'            => 2.95799645040426E-02,
  8112.                                                                                             'lt'        => 2.95799645040426E-02
  8113.                                                                                         ),
  8114.                                                                         'cup'    => array(    'tsp'        => 4.80000000000000E+01,
  8115.                                                                                             'tbs'        => 1.60000000000000E+01,
  8116.                                                                                             'oz'        => 8.00000000000000E+00,
  8117.                                                                                             'cup'        => 1.0,
  8118.                                                                                             'pt'        => 5.00000000000000E-01,
  8119.                                                                                             'us_pt'        => 5.00000000000000E-01,
  8120.                                                                                             'uk_pt'        => 4.16428088074541E-01,
  8121.                                                                                             'qt'        => 2.50000000000000E-01,
  8122.                                                                                             'gal'        => 6.25000000000000E-02,
  8123.                                                                                             'l'            => 2.36639716032341E-01,
  8124.                                                                                             'lt'        => 2.36639716032341E-01
  8125.                                                                                         ),
  8126.                                                                         'pt'    => array(    'tsp'        => 9.60000000000000E+01,
  8127.                                                                                             'tbs'        => 3.20000000000000E+01,
  8128.                                                                                             'oz'        => 1.60000000000000E+01,
  8129.                                                                                             'cup'        => 2.00000000000000E+00,
  8130.                                                                                             'pt'        => 1.0,
  8131.                                                                                             'us_pt'        => 1.0,
  8132.                                                                                             'uk_pt'        => 8.32856176149081E-01,
  8133.                                                                                             'qt'        => 5.00000000000000E-01,
  8134.                                                                                             'gal'        => 1.25000000000000E-01,
  8135.                                                                                             'l'            => 4.73279432064682E-01,
  8136.                                                                                             'lt'        => 4.73279432064682E-01
  8137.                                                                                         ),
  8138.                                                                         'us_pt'    => array(    'tsp'        => 9.60000000000000E+01,
  8139.                                                                                             'tbs'        => 3.20000000000000E+01,
  8140.                                                                                             'oz'        => 1.60000000000000E+01,
  8141.                                                                                             'cup'        => 2.00000000000000E+00,
  8142.                                                                                             'pt'        => 1.0,
  8143.                                                                                             'us_pt'        => 1.0,
  8144.                                                                                             'uk_pt'        => 8.32856176149081E-01,
  8145.                                                                                             'qt'        => 5.00000000000000E-01,
  8146.                                                                                             'gal'        => 1.25000000000000E-01,
  8147.                                                                                             'l'            => 4.73279432064682E-01,
  8148.                                                                                             'lt'        => 4.73279432064682E-01
  8149.                                                                                         ),
  8150.                                                                         'uk_pt'    => array(    'tsp'        => 1.15266000000000E+02,
  8151.                                                                                             'tbs'        => 3.84220000000000E+01,
  8152.                                                                                             'oz'        => 1.92110000000000E+01,
  8153.                                                                                             'cup'        => 2.40137500000000E+00,
  8154.                                                                                             'pt'        => 1.20068750000000E+00,
  8155.                                                                                             'us_pt'        => 1.20068750000000E+00,
  8156.                                                                                             'uk_pt'        => 1.0,
  8157.                                                                                             'qt'        => 6.00343750000000E-01,
  8158.                                                                                             'gal'        => 1.50085937500000E-01,
  8159.                                                                                             'l'            => 5.68260698087162E-01,
  8160.                                                                                             'lt'        => 5.68260698087162E-01
  8161.                                                                                         ),
  8162.                                                                         'qt'    => array(    'tsp'        => 1.92000000000000E+02,
  8163.                                                                                             'tbs'        => 6.40000000000000E+01,
  8164.                                                                                             'oz'        => 3.20000000000000E+01,
  8165.                                                                                             'cup'        => 4.00000000000000E+00,
  8166.                                                                                             'pt'        => 2.00000000000000E+00,
  8167.                                                                                             'us_pt'        => 2.00000000000000E+00,
  8168.                                                                                             'uk_pt'        => 1.66571235229816E+00,
  8169.                                                                                             'qt'        => 1.0,
  8170.                                                                                             'gal'        => 2.50000000000000E-01,
  8171.                                                                                             'l'            => 9.46558864129363E-01,
  8172.                                                                                             'lt'        => 9.46558864129363E-01
  8173.                                                                                         ),
  8174.                                                                         'gal'    => array(    'tsp'        => 7.68000000000000E+02,
  8175.                                                                                             'tbs'        => 2.56000000000000E+02,
  8176.                                                                                             'oz'        => 1.28000000000000E+02,
  8177.                                                                                             'cup'        => 1.60000000000000E+01,
  8178.                                                                                             'pt'        => 8.00000000000000E+00,
  8179.                                                                                             'us_pt'        => 8.00000000000000E+00,
  8180.                                                                                             'uk_pt'        => 6.66284940919265E+00,
  8181.                                                                                             'qt'        => 4.00000000000000E+00,
  8182.                                                                                             'gal'        => 1.0,
  8183.                                                                                             'l'            => 3.78623545651745E+00,
  8184.                                                                                             'lt'        => 3.78623545651745E+00
  8185.                                                                                         ),
  8186.                                                                         'l'        => array(    'tsp'        => 2.02840000000000E+02,
  8187.                                                                                             'tbs'        => 6.76133333333333E+01,
  8188.                                                                                             'oz'        => 3.38066666666667E+01,
  8189.                                                                                             'cup'        => 4.22583333333333E+00,
  8190.                                                                                             'pt'        => 2.11291666666667E+00,
  8191.                                                                                             'us_pt'        => 2.11291666666667E+00,
  8192.                                                                                             'uk_pt'        => 1.75975569552166E+00,
  8193.                                                                                             'qt'        => 1.05645833333333E+00,
  8194.                                                                                             'gal'        => 2.64114583333333E-01,
  8195.                                                                                             'l'            => 1.0,
  8196.                                                                                             'lt'        => 1.0
  8197.                                                                                         ),
  8198.                                                                         'lt'    => array(    'tsp'        => 2.02840000000000E+02,
  8199.                                                                                             'tbs'        => 6.76133333333333E+01,
  8200.                                                                                             'oz'        => 3.38066666666667E+01,
  8201.                                                                                             'cup'        => 4.22583333333333E+00,
  8202.                                                                                             'pt'        => 2.11291666666667E+00,
  8203.                                                                                             'us_pt'        => 2.11291666666667E+00,
  8204.                                                                                             'uk_pt'        => 1.75975569552166E+00,
  8205.                                                                                             'qt'        => 1.05645833333333E+00,
  8206.                                                                                             'gal'        => 2.64114583333333E-01,
  8207.                                                                                             'l'            => 1.0,
  8208.                                                                                             'lt'        => 1.0
  8209.                                                                                         )
  8210.                                                                     )
  8211.                                             );
  8212.  
  8213.  
  8214.     /**
  8215.      * getConversionGroups
  8216.      *
  8217.      * @return    array 
  8218.      */
  8219.     public static function getConversionGroups({
  8220.         $conversionGroups array();
  8221.         foreach(self::$_conversionUnits as $conversionUnit{
  8222.             $conversionGroups[$conversionUnit['Group'];
  8223.         }
  8224.         return array_merge(array_unique($conversionGroups));
  8225.     }    //    function getConversionGroups()
  8226.  
  8227.  
  8228.     /**
  8229.      * getConversionGroupUnits
  8230.      *
  8231.      * @return    array 
  8232.      */
  8233.     public static function getConversionGroupUnits($group NULL{
  8234.         $conversionGroups array();
  8235.         foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup{
  8236.             if ((is_null($group)) || ($conversionGroup['Group'== $group)) {
  8237.                 $conversionGroups[$conversionGroup['Group']][$conversionUnit;
  8238.             }
  8239.         }
  8240.         return $conversionGroups;
  8241.     }    //    function getConversionGroupUnits()
  8242.  
  8243.  
  8244.     /**
  8245.      * getConversionGroupUnitDetails
  8246.      *
  8247.      * @return    array 
  8248.      */
  8249.     public static function getConversionGroupUnitDetails($group NULL{
  8250.         $conversionGroups array();
  8251.         foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup{
  8252.             if ((is_null($group)) || ($conversionGroup['Group'== $group)) {
  8253.                 $conversionGroups[$conversionGroup['Group']][array(    'unit'            => $conversionUnit,
  8254.                                                                         'description'    => $conversionGroup['Unit Name']
  8255.                                                                       );
  8256.             }
  8257.         }
  8258.         return $conversionGroups;
  8259.     }    //    function getConversionGroupUnitDetails()
  8260.  
  8261.  
  8262.     /**
  8263.      * getConversionGroups
  8264.      *
  8265.      * @return    array 
  8266.      */
  8267.     public static function getConversionMultipliers({
  8268.         return self::$_conversionMultipliers;
  8269.     }    //    function getConversionGroups()
  8270.  
  8271.  
  8272.     /**
  8273.      * CONVERTUOM
  8274.      *
  8275.      * @param    float        $value 
  8276.      * @param    string        $fromUOM 
  8277.      * @param    string        $toUOM 
  8278.      * @return    float 
  8279.      */
  8280.     public static function CONVERTUOM($value$fromUOM$toUOM{
  8281.         $value        self::flattenSingleValue($value);
  8282.         $fromUOM    self::flattenSingleValue($fromUOM);
  8283.         $toUOM        self::flattenSingleValue($toUOM);
  8284.  
  8285.         if (!is_numeric($value)) {
  8286.             return self::$_errorCodes['value'];
  8287.         }
  8288.         $fromMultiplier 1;
  8289.         if (isset(self::$_conversionUnits[$fromUOM])) {
  8290.             $unitGroup1 self::$_conversionUnits[$fromUOM]['Group'];
  8291.         else {
  8292.             $fromMultiplier substr($fromUOM,0,1);
  8293.             $fromUOM substr($fromUOM,1);
  8294.             if (isset(self::$_conversionMultipliers[$fromMultiplier])) {
  8295.                 $fromMultiplier self::$_conversionMultipliers[$fromMultiplier]['multiplier'];
  8296.             else {
  8297.                 return self::$_errorCodes['na'];
  8298.             }
  8299.             if ((isset(self::$_conversionUnits[$fromUOM])) && (self::$_conversionUnits[$fromUOM]['AllowPrefix'])) {
  8300.                 $unitGroup1 self::$_conversionUnits[$fromUOM]['Group'];
  8301.             else {
  8302.                 return self::$_errorCodes['na'];
  8303.             }
  8304.         }
  8305.         $value *= $fromMultiplier;
  8306.  
  8307.         $toMultiplier 1;
  8308.         if (isset(self::$_conversionUnits[$toUOM])) {
  8309.             $unitGroup2 self::$_conversionUnits[$toUOM]['Group'];
  8310.         else {
  8311.             $toMultiplier substr($toUOM,0,1);
  8312.             $toUOM substr($toUOM,1);
  8313.             if (isset(self::$_conversionMultipliers[$toMultiplier])) {
  8314.                 $toMultiplier self::$_conversionMultipliers[$toMultiplier]['multiplier'];
  8315.             else {
  8316.                 return self::$_errorCodes['na'];
  8317.             }
  8318.             if ((isset(self::$_conversionUnits[$toUOM])) && (self::$_conversionUnits[$toUOM]['AllowPrefix'])) {
  8319.                 $unitGroup2 self::$_conversionUnits[$toUOM]['Group'];
  8320.             else {
  8321.                 return self::$_errorCodes['na'];
  8322.             }
  8323.         }
  8324.         if ($unitGroup1 != $unitGroup2{
  8325.             return self::$_errorCodes['na'];
  8326.         }
  8327.  
  8328.         if ($fromUOM == $toUOM{
  8329.             return 1.0;
  8330.         elseif ($unitGroup1 == 'Temperature'{
  8331.             if (($fromUOM == 'F'|| ($fromUOM == 'fah')) {
  8332.                 if (($toUOM == 'F'|| ($toUOM == 'fah')) {
  8333.                     return 1.0;
  8334.                 else {
  8335.                     $value (($value 321.8);
  8336.                     if (($toUOM == 'K'|| ($toUOM == 'kel')) {
  8337.                         $value += 273.15;
  8338.                     }
  8339.                     return $value;
  8340.                 }
  8341.             elseif ((($fromUOM == 'K'|| ($fromUOM == 'kel')) &&
  8342.                       (($toUOM == 'K'|| ($toUOM == 'kel'))) {
  8343.                         return 1.0;
  8344.             elseif ((($fromUOM == 'C'|| ($fromUOM == 'cel')) &&
  8345.                       (($toUOM == 'C'|| ($toUOM == 'cel'))) {
  8346.                     return 1.0;
  8347.             }
  8348.             if (($toUOM == 'F'|| ($toUOM == 'fah')) {
  8349.                 if (($fromUOM == 'K'|| ($fromUOM == 'kel')) {
  8350.                     $value -= 273.15;
  8351.                 }
  8352.                 return ($value 1.832;
  8353.             }
  8354.             if (($toUOM == 'C'|| ($toUOM == 'cel')) {
  8355.                 return $value 273.15;
  8356.             }
  8357.             return $value 273.15;
  8358.         }
  8359.         return ($value self::$_unitConversions[$unitGroup1][$fromUOM][$toUOM]$toMultiplier;
  8360.     }    //    function CONVERTUOM()
  8361.  
  8362.  
  8363.     /**
  8364.      * BESSELI
  8365.      *
  8366.      * Returns the modified Bessel function, which is equivalent to the Bessel function evaluated for purely imaginary arguments
  8367.      *
  8368.      * @param    float        $x 
  8369.      * @param    float        $n 
  8370.      * @return    int 
  8371.      */
  8372.     public static function BESSELI($x$n{
  8373.         $x    self::flattenSingleValue($x);
  8374.         $n    floor(self::flattenSingleValue($n));
  8375.  
  8376.         if ((is_numeric($x)) && (is_numeric($n))) {
  8377.             if ($n 0{
  8378.                 return self::$_errorCodes['num'];
  8379.             }
  8380.             $f_2_PI pi();
  8381.  
  8382.             if (abs($x<= 30{
  8383.                 $fTerm pow($x 2$nself::FACT($n);
  8384.                 $nK 1;
  8385.                 $fResult $fTerm;
  8386.                 $fSqrX ($x $x4;
  8387.                 do {
  8388.                     $fTerm *= $fSqrX;
  8389.                     $fTerm /= ($nK ($nK $n));
  8390.                     $fResult += $fTerm;
  8391.                 while ((abs($fTerm1e-10&& (++$nK 100));
  8392.             else {
  8393.                 $fXAbs abs($x);
  8394.                 $fResult exp($fXAbssqrt($f_2_PI $fXAbs);
  8395.                 if (($n && 1&& ($x 0)) {
  8396.                     $fResult = -$fResult;
  8397.                 }
  8398.             }
  8399.             return $fResult;
  8400.         }
  8401.         return self::$_errorCodes['value'];
  8402.     }    //    function BESSELI()
  8403.  
  8404.  
  8405.     /**
  8406.      * BESSELJ
  8407.      *
  8408.      * Returns the Bessel function
  8409.      *
  8410.      * @param    float        $x 
  8411.      * @param    float        $n 
  8412.      * @return    int 
  8413.      */
  8414.     public static function BESSELJ($x$n{
  8415.         $x    self::flattenSingleValue($x);
  8416.         $n    floor(self::flattenSingleValue($n));
  8417.  
  8418.         if ((is_numeric($x)) && (is_numeric($n))) {
  8419.             if ($n 0{
  8420.                 return self::$_errorCodes['num'];
  8421.             }
  8422.             $f_PI_DIV_2 M_PI 2;
  8423.             $f_PI_DIV_4 M_PI 4;
  8424.  
  8425.             $fResult 0;
  8426.             if (abs($x<= 30{
  8427.                 $fTerm pow($x 2$nself::FACT($n);
  8428.                 $nK 1;
  8429.                 $fResult $fTerm;
  8430.                 $fSqrX ($x $x/ -4;
  8431.                 do {
  8432.                     $fTerm *= $fSqrX;
  8433.                     $fTerm /= ($nK ($nK $n));
  8434.                     $fResult += $fTerm;
  8435.                 while ((abs($fTerm1e-10&& (++$nK 100));
  8436.             else {
  8437.                 $fXAbs abs($x);
  8438.                 $fResult sqrt(M_2DIVPI $fXAbscos($fXAbs $n $f_PI_DIV_2 $f_PI_DIV_4);
  8439.                 if (($n && 1&& ($x 0)) {
  8440.                     $fResult = -$fResult;
  8441.                 }
  8442.             }
  8443.             return $fResult;
  8444.         }
  8445.         return self::$_errorCodes['value'];
  8446.     }    //    function BESSELJ()
  8447.  
  8448.  
  8449.     private static function _Besselk0($fNum{
  8450.         if ($fNum <= 2{
  8451.             $fNum2 $fNum 0.5;
  8452.             $y ($fNum2 $fNum2);
  8453.             $fRet = -log($fNum2self::BESSELI($fNum0+
  8454.                     (-0.57721566 $y (0.42278420 $y (0.23069756 $y (0.3488590e-1 $y (0.262698e-2 $y *
  8455.                     (0.10750e-3 $y 0.74e-5))))));
  8456.         else {
  8457.             $y $fNum;
  8458.             $fRet exp(-$fNumsqrt($fNum*
  8459.                     (1.25331414 $y (-0.7832358e-1 $y (0.2189568e-1 $y (-0.1062446e-1 $y *
  8460.                     (0.587872e-2 $y (-0.251540e-2 $y 0.53208e-3))))));
  8461.         }
  8462.         return $fRet;
  8463.     }    //    function _Besselk0()
  8464.  
  8465.  
  8466.     private static function _Besselk1($fNum{
  8467.         if ($fNum <= 2{
  8468.             $fNum2 $fNum 0.5;
  8469.             $y ($fNum2 $fNum2);
  8470.             $fRet log($fNum2self::BESSELI($fNum1+
  8471.                     ($y (0.15443144 $y (-0.67278579 $y (-0.18156897 $y (-0.1919402e-1 $y *
  8472.                     (-0.110404e-2 $y (-0.4686e-4))))))) $fNum;
  8473.         else {
  8474.             $y $fNum;
  8475.             $fRet exp(-$fNumsqrt($fNum*
  8476.                     (1.25331414 $y (0.23498619 $y (-0.3655620e-1 $y (0.1504268e-1 $y (-0.780353e-2 $y *
  8477.                     (0.325614e-2 $y (-0.68245e-3)))))));
  8478.         }
  8479.         return $fRet;
  8480.     }    //    function _Besselk1()
  8481.  
  8482.  
  8483.     /**
  8484.      * BESSELK
  8485.      *
  8486.      * Returns the modified Bessel function, which is equivalent to the Bessel functions evaluated for purely imaginary arguments.
  8487.      *
  8488.      * @param    float        $x 
  8489.      * @param    float        $ord 
  8490.      * @return    float 
  8491.      */
  8492.     public static function BESSELK($x$ord{
  8493.         $x        self::flattenSingleValue($x);
  8494.         $ord    floor(self::flattenSingleValue($ord));
  8495.  
  8496.         if ((is_numeric($x)) && (is_numeric($ord))) {
  8497.             if ($ord 0{
  8498.                 return self::$_errorCodes['num'];
  8499.             }
  8500.  
  8501.             switch($ord{
  8502.                 case :    return self::_Besselk0($x);
  8503.                             break;
  8504.                 case :    return self::_Besselk1($x);
  8505.                             break;
  8506.                 default :    $fTox    $x;
  8507.                             $fBkm    self::_Besselk0($x);
  8508.                             $fBk    self::_Besselk1($x);
  8509.                             for ($n 1$n $ord++$n{
  8510.                                 $fBkp    $fBkm $n $fTox $fBk;
  8511.                                 $fBkm    $fBk;
  8512.                                 $fBk    $fBkp;
  8513.                             }
  8514.             }
  8515.             return $fBk;
  8516.         }
  8517.         return self::$_errorCodes['value'];
  8518.     }    //    function BESSELK()
  8519.  
  8520.  
  8521.     private static function _Bessely0($fNum{
  8522.         if ($fNum 8.0{
  8523.             $y ($fNum $fNum);
  8524.             $f1 = -2957821389.0 $y (7062834065.0 $y (-512359803.6 $y (10879881.29 $y (-86327.92757 $y 228.4622733))));
  8525.             $f2 40076544269.0 $y (745249964.8 $y (7189466.438 $y (47447.26470 $y (226.1030244 $y))));
  8526.             $fRet $f1 $f2 M_2DIVPI self::BESSELJ($fNum0log($fNum);
  8527.         else {
  8528.             $z 8.0 $fNum;
  8529.             $y ($z $z);
  8530.             $xx $fNum 0.785398164;
  8531.             $f1 $y (-0.1098628627e-2 $y (0.2734510407e-4 $y (-0.2073370639e-5 $y 0.2093887211e-6)));
  8532.             $f2 = -0.1562499995e-1 $y (0.1430488765e-3 $y (-0.6911147651e-5 $y (0.7621095161e-6 $y (-0.934945152e-7))));
  8533.             $fRet sqrt(M_2DIVPI $fNum(sin($xx$f1 $z cos($xx$f2);
  8534.         }
  8535.         return $fRet;
  8536.     }    //    function _Bessely0()
  8537.  
  8538.  
  8539.     private static function _Bessely1($fNum{
  8540.         if ($fNum 8.0{
  8541.             $y ($fNum $fNum);
  8542.             $f1 $fNum (-0.4900604943e13 $y (0.1275274390e13 $y (-0.5153438139e11 $y (0.7349264551e9 $y *
  8543.                 (-0.4237922726e7 $y 0.8511937935e4)))));
  8544.             $f2 0.2499580570e14 $y (0.4244419664e12 $y (0.3733650367e10 $y (0.2245904002e8 $y *
  8545.                 (0.1020426050e6 $y (0.3549632885e3 $y)))));
  8546.             $fRet $f1 $f2 M_2DIVPI self::BESSELJ($fNum1log($fNum$fNum);
  8547.         else {
  8548.             $z 8.0 $fNum;
  8549.             $y ($z $z);
  8550.             $xx $fNum 2.356194491;
  8551.             $f1 $y (0.183105e-2 $y (-0.3516396496e-4 $y (0.2457520174e-5 $y (-0.240337019e6))));
  8552.             $f2 0.04687499995 $y (-0.2002690873e-3 $y (0.8449199096e-5 $y (-0.88228987e-6 $y 0.105787412e-6)));
  8553.             $fRet sqrt(M_2DIVPI $fNum(sin($xx$f1 $z cos($xx$f2);
  8554.             #i12430# ...but this seems to work much better.
  8555. //            $fRet = sqrt(M_2DIVPI / $fNum) * sin($fNum - 2.356194491);
  8556.         }
  8557.         return $fRet;
  8558.     }    //    function _Bessely1()
  8559.  
  8560.  
  8561.     /**
  8562.      * BESSELY
  8563.      *
  8564.      * Returns the Bessel function, which is also called the Weber function or the Neumann function.
  8565.      *
  8566.      * @param    float        $x 
  8567.      * @param    float        $n 
  8568.      * @return    int 
  8569.      */
  8570.     public static function BESSELY($x$ord{
  8571.         $x        self::flattenSingleValue($x);
  8572.         $ord    floor(self::flattenSingleValue($ord));
  8573.  
  8574.         if ((is_numeric($x)) && (is_numeric($ord))) {
  8575.             if ($ord 0{
  8576.                 return self::$_errorCodes['num'];
  8577.             }
  8578.  
  8579.             switch($ord{
  8580.                 case :    return self::_Bessely0($x);
  8581.                             break;
  8582.                 case :    return self::_Bessely1($x);
  8583.                             break;
  8584.                 default:    $fTox    $x;
  8585.                             $fBym    self::_Bessely0($x);
  8586.                             $fBy    self::_Bessely1($x);
  8587.                             for ($n 1$n $ord++$n{
  8588.                                 $fByp    $n $fTox $fBy $fBym;
  8589.                                 $fBym    $fBy;
  8590.                                 $fBy    $fByp;
  8591.                             }
  8592.             }
  8593.             return $fBy;
  8594.         }
  8595.         return self::$_errorCodes['value'];
  8596.     }    //    function BESSELY()
  8597.  
  8598.  
  8599.     /**
  8600.      * DELTA
  8601.      *
  8602.      * Tests whether two values are equal. Returns 1 if number1 = number2; returns 0 otherwise.
  8603.      *
  8604.      * @param    float        $a 
  8605.      * @param    float        $b 
  8606.      * @return    int 
  8607.      */
  8608.     public static function DELTA($a$b=0{
  8609.         $a    self::flattenSingleValue($a);
  8610.         $b    self::flattenSingleValue($b);
  8611.  
  8612.         return (int) ($a == $b);
  8613.     }    //    function DELTA()
  8614.  
  8615.  
  8616.     /**
  8617.      * GESTEP
  8618.      *
  8619.      * Returns 1 if number = step; returns 0 (zero) otherwise
  8620.      *
  8621.      * @param    float        $number 
  8622.      * @param    float        $step 
  8623.      * @return    int 
  8624.      */
  8625.     public static function GESTEP($number$step=0{
  8626.         $number    self::flattenSingleValue($number);
  8627.         $step    self::flattenSingleValue($step);
  8628.  
  8629.         return (int) ($number >= $step);
  8630.     }    //    function GESTEP()
  8631.  
  8632.  
  8633.     //
  8634.     //    Private method to calculate the erf value
  8635.     //
  8636.     private static $_two_sqrtpi 1.128379167095512574;
  8637.  
  8638.     private static function _erfVal($x{
  8639.         if (abs($x2.2{
  8640.             return self::_erfcVal($x);
  8641.         }
  8642.         $sum $term $x;
  8643.         $xsqr ($x $x);
  8644.         $j 1;
  8645.         do {
  8646.             $term *= $xsqr $j;
  8647.             $sum -= $term ($j 1);
  8648.             ++$j;
  8649.             $term *= $xsqr $j;
  8650.             $sum += $term ($j 1);
  8651.             ++$j;
  8652.             if ($sum == 0.0{
  8653.                 break;
  8654.             }
  8655.         while (abs($term $sumPRECISION);
  8656.         return self::$_two_sqrtpi $sum;
  8657.     }    //    function _erfVal()
  8658.  
  8659.  
  8660.     /**
  8661.      * ERF
  8662.      *
  8663.      * Returns the error function integrated between lower_limit and upper_limit
  8664.      *
  8665.      * @param    float        $lower    lower bound for integrating ERF
  8666.      * @param    float        $upper    upper bound for integrating ERF.
  8667.      *                                 If omitted, ERF integrates between zero and lower_limit
  8668.      * @return    int 
  8669.      */
  8670.     public static function ERF($lower$upper null{
  8671.         $lower    self::flattenSingleValue($lower);
  8672.         $upper    self::flattenSingleValue($upper);
  8673.  
  8674.         if (is_numeric($lower)) {
  8675.             if ($lower 0{
  8676.                 return self::$_errorCodes['num'];
  8677.             }
  8678.             if (is_null($upper)) {
  8679.                 return self::_erfVal($lower);
  8680.             }
  8681.             if (is_numeric($upper)) {
  8682.                 if ($upper 0{
  8683.                     return self::$_errorCodes['num'];
  8684.                 }
  8685.                 return self::_erfVal($upperself::_erfVal($lower);
  8686.             }
  8687.         }
  8688.         return self::$_errorCodes['value'];
  8689.     }    //    function ERF()
  8690.  
  8691.  
  8692.     //
  8693.     //    Private method to calculate the erfc value
  8694.     //
  8695.     private static $_one_sqrtpi 0.564189583547756287;
  8696.  
  8697.     private static function _erfcVal($x{
  8698.         if (abs($x2.2{
  8699.             return self::_erfVal($x);
  8700.         }
  8701.         if ($x 0{
  8702.             return self::erfc(-$x);
  8703.         }
  8704.         $a $n 1;
  8705.         $b $c $x;
  8706.         $d ($x $x0.5;
  8707.         $q1 $q2 $b $d;
  8708.         $t 0;
  8709.         do {
  8710.             $t $a $n $b $x;
  8711.             $a $b;
  8712.             $b $t;
  8713.             $t $c $n $d $x;
  8714.             $c $d;
  8715.             $d $t;
  8716.             $n += 0.5;
  8717.             $q1 $q2;
  8718.             $q2 $b $d;
  8719.         while ((abs($q1 $q2$q2PRECISION);
  8720.         return self::$_one_sqrtpi exp(-$x $x$q2;
  8721.     }    //    function _erfcVal()
  8722.  
  8723.  
  8724.     /**
  8725.      * ERFC
  8726.      *
  8727.      * Returns the complementary ERF function integrated between x and infinity
  8728.      *
  8729.      * @param    float        $x        The lower bound for integrating ERF
  8730.      * @return    int 
  8731.      */
  8732.     public static function ERFC($x{
  8733.         $x    self::flattenSingleValue($x);
  8734.  
  8735.         if (is_numeric($x)) {
  8736.             if ($x 0{
  8737.                 return self::$_errorCodes['num'];
  8738.             }
  8739.             return self::_erfcVal($x);
  8740.         }
  8741.         return self::$_errorCodes['value'];
  8742.     }    //    function ERFC()
  8743.  
  8744.  
  8745.     /**
  8746.      *    LOWERCASE
  8747.      *
  8748.      *    Converts a string value to upper case.
  8749.      *
  8750.      *    @param    string        $mixedCaseString 
  8751.      *    @return    string 
  8752.      */
  8753.     public static function LOWERCASE($mixedCaseString{
  8754.         $mixedCaseString    self::flattenSingleValue($mixedCaseString);
  8755.  
  8756.         if (is_bool($mixedCaseString)) {
  8757.             $mixedCaseString ($mixedCaseString'TRUE' 'FALSE';
  8758.         }
  8759.  
  8760.         if (function_exists('mb_convert_case')) {
  8761.             return mb_convert_case($mixedCaseStringMB_CASE_LOWER'UTF-8');
  8762.         else {
  8763.             return strtoupper($mixedCaseString);
  8764.         }
  8765.     }    //    function LOWERCASE()
  8766.  
  8767.  
  8768.     /**
  8769.      *    UPPERCASE
  8770.      *
  8771.      *    Converts a string value to upper case.
  8772.      *
  8773.      *    @param    string        $mixedCaseString 
  8774.      *    @return    string 
  8775.      */
  8776.     public static function UPPERCASE($mixedCaseString{
  8777.         $mixedCaseString    self::flattenSingleValue($mixedCaseString);
  8778.  
  8779.         if (is_bool($mixedCaseString)) {
  8780.             $mixedCaseString ($mixedCaseString'TRUE' 'FALSE';
  8781.         }
  8782.  
  8783.         if (function_exists('mb_convert_case')) {
  8784.             return mb_convert_case($mixedCaseStringMB_CASE_UPPER'UTF-8');
  8785.         else {
  8786.             return strtoupper($mixedCaseString);
  8787.         }
  8788.     }    //    function UPPERCASE()
  8789.  
  8790.  
  8791.     /**
  8792.      *    PROPERCASE
  8793.      *
  8794.      *    Converts a string value to upper case.
  8795.      *
  8796.      *    @param    string        $mixedCaseString 
  8797.      *    @return    string 
  8798.      */
  8799.     public static function PROPERCASE($mixedCaseString{
  8800.         $mixedCaseString    self::flattenSingleValue($mixedCaseString);
  8801.  
  8802.         if (is_bool($mixedCaseString)) {
  8803.             $mixedCaseString ($mixedCaseString'TRUE' 'FALSE';
  8804.         }
  8805.  
  8806.         if (function_exists('mb_convert_case')) {
  8807.             return mb_convert_case($mixedCaseStringMB_CASE_TITLE'UTF-8');
  8808.         else {
  8809.             return ucwords($mixedCaseString);
  8810.         }
  8811.     }    //    function PROPERCASE()
  8812.  
  8813.  
  8814.     /**
  8815.      *    DOLLAR
  8816.      *
  8817.      *    This function converts a number to text using currency format, with the decimals rounded to the specified place.
  8818.      *    The format used is $#,##0.00_);($#,##0.00)..
  8819.      *
  8820.      *    @param    float    $value            The value to format
  8821.      *    @param    int        $decimals        The number of digits to display to the right of the decimal point.
  8822.      *                                     If decimals is negative, number is rounded to the left of the decimal point.
  8823.      *                                     If you omit decimals, it is assumed to be 2
  8824.      *    @return    string 
  8825.      */
  8826.     public static function DOLLAR($value 0$decimals 2{
  8827.         $value        self::flattenSingleValue($value);
  8828.         $decimals    is_null($decimalsself::flattenSingleValue($decimals);
  8829.  
  8830.         // Validate parameters
  8831.         if (!is_numeric($value|| !is_numeric($decimals)) {
  8832.             return self::$_errorCodes['num'];
  8833.         }
  8834.         $decimals floor($decimals);
  8835.  
  8836.         if ($decimals 0{
  8837.             return money_format('%.'.$decimals.'n',$value);
  8838.         else {
  8839.             $round pow(10,abs($decimals));
  8840.             if ($value 0$round 0-$round}
  8841.             $value self::MROUND($value,$round);
  8842.             //    The implementation of money_format used if the standard PHP function is not available can't handle decimal places of 0,
  8843.             //        so we display to 1 dp and chop off that character and the decimal separator using substr
  8844.             return substr(money_format('%.1n',$value),0,-2);
  8845.         }
  8846.     }    //    function DOLLAR()
  8847.  
  8848.  
  8849.     /**
  8850.      * DOLLARDE
  8851.      *
  8852.      * Converts a dollar price expressed as an integer part and a fraction part into a dollar price expressed as a decimal number.
  8853.      * Fractional dollar numbers are sometimes used for security prices.
  8854.      *
  8855.      * @param    float    $fractional_dollar    Fractional Dollar
  8856.      * @param    int        $fraction            Fraction
  8857.      * @return    float 
  8858.      */
  8859.     public static function DOLLARDE($fractional_dollar Null$fraction 0{
  8860.         $fractional_dollar    self::flattenSingleValue($fractional_dollar);
  8861.         $fraction            = (int)self::flattenSingleValue($fraction);
  8862.  
  8863.         // Validate parameters
  8864.         if (is_null($fractional_dollar|| $fraction 0{
  8865.             return self::$_errorCodes['num'];
  8866.         }
  8867.         if ($fraction == 0{
  8868.             return self::$_errorCodes['divisionbyzero'];
  8869.         }
  8870.  
  8871.         $dollars floor($fractional_dollar);
  8872.         $cents fmod($fractional_dollar,1);
  8873.         $cents /= $fraction;
  8874.         $cents *= pow(10,ceil(log10($fraction)));
  8875.         return $dollars $cents;
  8876.     }    //    function DOLLARDE()
  8877.  
  8878.  
  8879.     /**
  8880.      * DOLLARFR
  8881.      *
  8882.      * Converts a dollar price expressed as a decimal number into a dollar price expressed as a fraction.
  8883.      * Fractional dollar numbers are sometimes used for security prices.
  8884.      *
  8885.      * @param    float    $decimal_dollar        Decimal Dollar
  8886.      * @param    int        $fraction            Fraction
  8887.      * @return    float 
  8888.      */
  8889.     public static function DOLLARFR($decimal_dollar Null$fraction 0{
  8890.         $decimal_dollar    self::flattenSingleValue($decimal_dollar);
  8891.         $fraction        = (int)self::flattenSingleValue($fraction);
  8892.  
  8893.         // Validate parameters
  8894.         if (is_null($decimal_dollar|| $fraction 0{
  8895.             return self::$_errorCodes['num'];
  8896.         }
  8897.         if ($fraction == 0{
  8898.             return self::$_errorCodes['divisionbyzero'];
  8899.         }
  8900.  
  8901.         $dollars floor($decimal_dollar);
  8902.         $cents fmod($decimal_dollar,1);
  8903.         $cents *= $fraction;
  8904.         $cents *= pow(10,-ceil(log10($fraction)));
  8905.         return $dollars $cents;
  8906.     }    //    function DOLLARFR()
  8907.  
  8908.  
  8909.     /**
  8910.      * EFFECT
  8911.      *
  8912.      * Returns the effective interest rate given the nominal rate and the number of compounding payments per year.
  8913.      *
  8914.      * @param    float    $nominal_rate        Nominal interest rate
  8915.      * @param    int        $npery                Number of compounding payments per year
  8916.      * @return    float 
  8917.      */
  8918.     public static function EFFECT($nominal_rate 0$npery 0{
  8919.         $nominal_rate    self::flattenSingleValue($nominal_rate);
  8920.         $npery            = (int)self::flattenSingleValue($npery);
  8921.  
  8922.         // Validate parameters
  8923.         if ($nominal_rate <= || $npery 1{
  8924.             return self::$_errorCodes['num'];
  8925.         }
  8926.  
  8927.         return pow(($nominal_rate $npery)$npery1;
  8928.     }    //    function EFFECT()
  8929.  
  8930.  
  8931.     /**
  8932.      * NOMINAL
  8933.      *
  8934.      * Returns the nominal interest rate given the effective rate and the number of compounding payments per year.
  8935.      *
  8936.      * @param    float    $effect_rate    Effective interest rate
  8937.      * @param    int        $npery            Number of compounding payments per year
  8938.      * @return    float 
  8939.      */
  8940.     public static function NOMINAL($effect_rate 0$npery 0{
  8941.         $effect_rate    self::flattenSingleValue($effect_rate);
  8942.         $npery            = (int)self::flattenSingleValue($npery);
  8943.  
  8944.         // Validate parameters
  8945.         if ($effect_rate <= || $npery 1{
  8946.             return self::$_errorCodes['num'];
  8947.         }
  8948.  
  8949.         // Calculate
  8950.         return $npery (pow($effect_rate 1$npery1);
  8951.     }    //    function NOMINAL()
  8952.  
  8953.  
  8954.     /**
  8955.      * PV
  8956.      *
  8957.      * Returns the Present Value of a cash flow with constant payments and interest rate (annuities).
  8958.      *
  8959.      * @param    float    $rate    Interest rate per period
  8960.      * @param    int        $nper    Number of periods
  8961.      * @param    float    $pmt    Periodic payment (annuity)
  8962.      * @param    float    $fv        Future Value
  8963.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  8964.      * @return    float 
  8965.      */
  8966.     public static function PV($rate 0$nper 0$pmt 0$fv 0$type 0{
  8967.         $rate    self::flattenSingleValue($rate);
  8968.         $nper    self::flattenSingleValue($nper);
  8969.         $pmt    self::flattenSingleValue($pmt);
  8970.         $fv        self::flattenSingleValue($fv);
  8971.         $type    self::flattenSingleValue($type);
  8972.  
  8973.         // Validate parameters
  8974.         if ($type != && $type != 1{
  8975.             return self::$_errorCodes['num'];
  8976.         }
  8977.  
  8978.         // Calculate
  8979.         if (!is_null($rate&& $rate != 0{
  8980.             return (-$pmt ($rate $type((pow($rate$nper1$rate$fvpow($rate$nper);
  8981.         else {
  8982.             return -$fv $pmt $nper;
  8983.         }
  8984.     }    //    function PV()
  8985.  
  8986.  
  8987.     /**
  8988.      * FV
  8989.      *
  8990.      * Returns the Future Value of a cash flow with constant payments and interest rate (annuities).
  8991.      *
  8992.      * @param    float    $rate    Interest rate per period
  8993.      * @param    int        $nper    Number of periods
  8994.      * @param    float    $pmt    Periodic payment (annuity)
  8995.      * @param    float    $pv        Present Value
  8996.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  8997.      * @return    float 
  8998.      */
  8999.     public static function FV($rate 0$nper 0$pmt 0$pv 0$type 0{
  9000.         $rate    self::flattenSingleValue($rate);
  9001.         $nper    self::flattenSingleValue($nper);
  9002.         $pmt    self::flattenSingleValue($pmt);
  9003.         $pv        self::flattenSingleValue($pv);
  9004.         $type    self::flattenSingleValue($type);
  9005.  
  9006.         // Validate parameters
  9007.         if ($type != && $type != 1{
  9008.             return self::$_errorCodes['num'];
  9009.         }
  9010.  
  9011.         // Calculate
  9012.         if (!is_null($rate&& $rate != 0{
  9013.             return -$pv pow($rate$nper$pmt ($rate $type(pow($rate$nper1$rate;
  9014.         else {
  9015.             return -$pv $pmt $nper;
  9016.         }
  9017.     }    //    function FV()
  9018.  
  9019.  
  9020.     /**
  9021.      * FVSCHEDULE
  9022.      *
  9023.      */
  9024.     public static function FVSCHEDULE($principal$schedule{
  9025.         $principal    self::flattenSingleValue($principal);
  9026.         $schedule    self::flattenArray($schedule);
  9027.  
  9028.         foreach($schedule as $n{
  9029.             $principal *= $n;
  9030.         }
  9031.  
  9032.         return $principal;
  9033.     }    //    function FVSCHEDULE()
  9034.  
  9035.  
  9036.     /**
  9037.      * PMT
  9038.      *
  9039.      * Returns the constant payment (annuity) for a cash flow with a constant interest rate.
  9040.      *
  9041.      * @param    float    $rate    Interest rate per period
  9042.      * @param    int        $nper    Number of periods
  9043.      * @param    float    $pv        Present Value
  9044.      * @param    float    $fv        Future Value
  9045.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9046.      * @return    float 
  9047.      */
  9048.     public static function PMT($rate 0$nper 0$pv 0$fv 0$type 0{
  9049.         $rate    self::flattenSingleValue($rate);
  9050.         $nper    self::flattenSingleValue($nper);
  9051.         $pv        self::flattenSingleValue($pv);
  9052.         $fv        self::flattenSingleValue($fv);
  9053.         $type    self::flattenSingleValue($type);
  9054.  
  9055.         // Validate parameters
  9056.         if ($type != && $type != 1{
  9057.             return self::$_errorCodes['num'];
  9058.         }
  9059.  
  9060.         // Calculate
  9061.         if (!is_null($rate&& $rate != 0{
  9062.             return (-$fv $pv pow($rate$nper)) ($rate $type((pow($rate$nper1$rate);
  9063.         else {
  9064.             return (-$pv $fv$nper;
  9065.         }
  9066.     }    //    function PMT()
  9067.  
  9068.  
  9069.     /**
  9070.      * NPER
  9071.      *
  9072.      * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate.
  9073.      *
  9074.      *    @param    float    $rate    Interest rate per period
  9075.      *    @param    int        $pmt    Periodic payment (annuity)
  9076.      *    @param    float    $pv        Present Value
  9077.      *    @param    float    $fv        Future Value
  9078.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9079.      *    @return    float 
  9080.      */
  9081.     public static function NPER($rate 0$pmt 0$pv 0$fv 0$type 0{
  9082.         $rate    self::flattenSingleValue($rate);
  9083.         $pmt    self::flattenSingleValue($pmt);
  9084.         $pv        self::flattenSingleValue($pv);
  9085.         $fv        self::flattenSingleValue($fv);
  9086.         $type    self::flattenSingleValue($type);
  9087.  
  9088.         // Validate parameters
  9089.         if ($type != && $type != 1{
  9090.             return self::$_errorCodes['num'];
  9091.         }
  9092.  
  9093.         // Calculate
  9094.         if (!is_null($rate&& $rate != 0{
  9095.             if ($pmt == && $pv == 0{
  9096.                 return self::$_errorCodes['num'];
  9097.             }
  9098.             return log(($pmt ($rate $type$rate $fv($pv $pmt ($rate $type$rate)) log($rate);
  9099.         else {
  9100.             if ($pmt == 0{
  9101.                 return self::$_errorCodes['num'];
  9102.             }
  9103.             return (-$pv -$fv$pmt;
  9104.         }
  9105.     }    //    function NPER()
  9106.  
  9107.  
  9108.  
  9109.     private static function _interestAndPrincipal($rate=0$per=0$nper=0$pv=0$fv=0$type=0{
  9110.         $pmt self::PMT($rate$nper$pv$fv$type);
  9111.         $capital $pv;
  9112.         for ($i 1$i<= $per++$i{
  9113.             $interest ($type && $i == 1): -$capital $rate;
  9114.             $principal $pmt $interest;
  9115.             $capital += $principal;
  9116.         }
  9117.         return array($interest$principal);
  9118.     }    //    function _interestAndPrincipal()
  9119.  
  9120.  
  9121.     /**
  9122.      *    IPMT
  9123.      *
  9124.      *    Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
  9125.      *
  9126.      *    @param    float    $rate    Interest rate per period
  9127.      *    @param    int        $per    Period for which we want to find the interest
  9128.      *    @param    int        $nper    Number of periods
  9129.      *    @param    float    $pv        Present Value
  9130.      *    @param    float    $fv        Future Value
  9131.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9132.      *    @return    float 
  9133.      */
  9134.     public static function IPMT($rate$per$nper$pv$fv 0$type 0{
  9135.         $rate    self::flattenSingleValue($rate);
  9136.         $per    = (int) self::flattenSingleValue($per);
  9137.         $nper    = (int) self::flattenSingleValue($nper);
  9138.         $pv        self::flattenSingleValue($pv);
  9139.         $fv        self::flattenSingleValue($fv);
  9140.         $type    = (int) self::flattenSingleValue($type);
  9141.  
  9142.         // Validate parameters
  9143.         if ($type != && $type != 1{
  9144.             return self::$_errorCodes['num'];
  9145.         }
  9146.         if ($per <= || $per $nper{
  9147.             return self::$_errorCodes['value'];
  9148.         }
  9149.  
  9150.         // Calculate
  9151.         $interestAndPrincipal self::_interestAndPrincipal($rate$per$nper$pv$fv$type);
  9152.         return $interestAndPrincipal[0];
  9153.     }    //    function IPMT()
  9154.  
  9155.  
  9156.     /**
  9157.      *    CUMIPMT
  9158.      *
  9159.      *    Returns the cumulative interest paid on a loan between start_period and end_period.
  9160.      *
  9161.      *    @param    float    $rate    Interest rate per period
  9162.      *    @param    int        $nper    Number of periods
  9163.      *    @param    float    $pv        Present Value
  9164.      *    @param    int        start    The first period in the calculation.
  9165.      *                                 Payment periods are numbered beginning with 1.
  9166.      *    @param    int        end        The last period in the calculation.
  9167.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9168.      *    @return    float 
  9169.      */
  9170.     public static function CUMIPMT($rate$nper$pv$start$end$type 0{
  9171.         $rate    self::flattenSingleValue($rate);
  9172.         $nper    = (int) self::flattenSingleValue($nper);
  9173.         $pv        self::flattenSingleValue($pv);
  9174.         $start    = (int) self::flattenSingleValue($start);
  9175.         $end    = (int) self::flattenSingleValue($end);
  9176.         $type    = (int) self::flattenSingleValue($type);
  9177.  
  9178.         // Validate parameters
  9179.         if ($type != && $type != 1{
  9180.             return self::$_errorCodes['num'];
  9181.         }
  9182.         if ($start || $start $end{
  9183.             return self::$_errorCodes['value'];
  9184.         }
  9185.  
  9186.         // Calculate
  9187.         $interest 0;
  9188.         for ($per $start$per <= $end++$per{
  9189.             $interest += self::IPMT($rate$per$nper$pv0$type);
  9190.         }
  9191.  
  9192.         return $interest;
  9193.     }    //    function CUMIPMT()
  9194.  
  9195.  
  9196.     /**
  9197.      *    PPMT
  9198.      *
  9199.      *    Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
  9200.      *
  9201.      *    @param    float    $rate    Interest rate per period
  9202.      *    @param    int        $per    Period for which we want to find the interest
  9203.      *    @param    int        $nper    Number of periods
  9204.      *    @param    float    $pv        Present Value
  9205.      *    @param    float    $fv        Future Value
  9206.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9207.      *    @return    float 
  9208.      */
  9209.     public static function PPMT($rate$per$nper$pv$fv 0$type 0{
  9210.         $rate    self::flattenSingleValue($rate);
  9211.         $per    = (int) self::flattenSingleValue($per);
  9212.         $nper    = (int) self::flattenSingleValue($nper);
  9213.         $pv        self::flattenSingleValue($pv);
  9214.         $fv        self::flattenSingleValue($fv);
  9215.         $type    = (int) self::flattenSingleValue($type);
  9216.  
  9217.         // Validate parameters
  9218.         if ($type != && $type != 1{
  9219.             return self::$_errorCodes['num'];
  9220.         }
  9221.         if ($per <= || $per $nper{
  9222.             return self::$_errorCodes['value'];
  9223.         }
  9224.  
  9225.         // Calculate
  9226.         $interestAndPrincipal self::_interestAndPrincipal($rate$per$nper$pv$fv$type);
  9227.         return $interestAndPrincipal[1];
  9228.     }    //    function PPMT()
  9229.  
  9230.  
  9231.     /**
  9232.      *    CUMPRINC
  9233.      *
  9234.      *    Returns the cumulative principal paid on a loan between start_period and end_period.
  9235.      *
  9236.      *    @param    float    $rate    Interest rate per period
  9237.      *    @param    int        $nper    Number of periods
  9238.      *    @param    float    $pv        Present Value
  9239.      *    @param    int        start    The first period in the calculation.
  9240.      *                                 Payment periods are numbered beginning with 1.
  9241.      *    @param    int        end        The last period in the calculation.
  9242.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  9243.      *    @return    float 
  9244.      */
  9245.     public static function CUMPRINC($rate$nper$pv$start$end$type 0{
  9246.         $rate    self::flattenSingleValue($rate);
  9247.         $nper    = (int) self::flattenSingleValue($nper);
  9248.         $pv        self::flattenSingleValue($pv);
  9249.         $start    = (int) self::flattenSingleValue($start);
  9250.         $end    = (int) self::flattenSingleValue($end);
  9251.         $type    = (int) self::flattenSingleValue($type);
  9252.  
  9253.         // Validate parameters
  9254.         if ($type != && $type != 1{
  9255.             return self::$_errorCodes['num'];
  9256.         }
  9257.         if ($start || $start $end{
  9258.             return self::$_errorCodes['value'];
  9259.         }
  9260.  
  9261.         // Calculate
  9262.         $principal 0;
  9263.         for ($per $start$per <= $end++$per{
  9264.             $principal += self::PPMT($rate$per$nper$pv0$type);
  9265.         }
  9266.  
  9267.         return $principal;
  9268.     }    //    function CUMPRINC()
  9269.  
  9270.  
  9271.     /**
  9272.      *      ISPMT
  9273.      *
  9274.      *      Returns the interest payment for an investment based on an interest rate and a constant payment schedule.
  9275.      *
  9276.      *      Excel Function:
  9277.      *          =ISPMT(interest_rate, period, number_payments, PV)
  9278.      *
  9279.      *      interest_rate is the interest rate for the investment
  9280.      *
  9281.      *      period is the period to calculate the interest rate.  It must be betweeen 1 and number_payments.
  9282.      *
  9283.      *      number_payments is the number of payments for the annuity
  9284.      *
  9285.      *      PV is the loan amount or present value of the payments
  9286.      */
  9287.     public static function ISPMT({
  9288.         // Return value
  9289.         $returnValue 0;
  9290.  
  9291.         // Get the parameters
  9292.         $aArgs self::flattenArray(func_get_args());
  9293.         $interestRate array_shift($aArgs);
  9294.         $period array_shift($aArgs);
  9295.         $numberPeriods array_shift($aArgs);
  9296.         $principleRemaining array_shift($aArgs);
  9297.  
  9298.         // Calculate
  9299.         $principlePayment ($principleRemaining 1.0($numberPeriods 1.0);
  9300.         for($i=0$i <= $period++$i{
  9301.             $returnValue $interestRate $principleRemaining * -1;
  9302.             $principleRemaining -= $principlePayment;
  9303.             // principle needs to be 0 after the last payment, don't let floating point screw it up
  9304.             if($i == $numberPeriods{
  9305.                 $returnValue 0;
  9306.             }
  9307.         }
  9308.         return($returnValue);
  9309.     }    //    function ISPMT()
  9310.  
  9311.  
  9312.     /**
  9313.      * NPV
  9314.      *
  9315.      * Returns the Net Present Value of a cash flow series given a discount rate.
  9316.      *
  9317.      * @param    float    Discount interest rate
  9318.      * @param    array    Cash flow series
  9319.      * @return    float 
  9320.      */
  9321.     public static function NPV({
  9322.         // Return value
  9323.         $returnValue 0;
  9324.  
  9325.         // Loop through arguments
  9326.         $aArgs self::flattenArray(func_get_args());
  9327.  
  9328.         // Calculate
  9329.         $rate array_shift($aArgs);
  9330.         for ($i 1$i <= count($aArgs)++$i{
  9331.             // Is it a numeric value?
  9332.             if (is_numeric($aArgs[$i 1])) {
  9333.                 $returnValue += $aArgs[$i 1pow($rate$i);
  9334.             }
  9335.         }
  9336.  
  9337.         // Return
  9338.         return $returnValue;
  9339.     }    //    function NPV()
  9340.  
  9341.  
  9342.     /**
  9343.      *    XNPV
  9344.      *
  9345.      *    Returns the net present value for a schedule of cash flows that is not necessarily periodic.
  9346.      *    To calculate the net present value for a series of cash flows that is periodic, use the NPV function.
  9347.      *
  9348.      *    @param    float    Discount interest rate
  9349.      *    @param    array    Cash flow series
  9350.      *    @return    float 
  9351.      */
  9352.     public static function XNPV($rate$values$dates{
  9353.         if ((!is_array($values)) || (!is_array($dates))) return self::$_errorCodes['value'];
  9354.         $values    self::flattenArray($values);
  9355.         $dates    self::flattenArray($dates);
  9356.         $valCount count($values);
  9357.         if ($valCount != count($dates)) return self::$_errorCodes['num'];
  9358.  
  9359.         $xnpv 0.0;
  9360.         for ($i 0$i $valCount++$i{
  9361.             $xnpv += $values[$ipow($rateself::DATEDIF($dates[0],$dates[$i],'d'365);
  9362.         }
  9363.         return (is_finite($xnpv$xnpv self::$_errorCodes['value']);
  9364.     }    //    function XNPV()
  9365.  
  9366.  
  9367.     public static function IRR($values$guess 0.1{
  9368.         if (!is_array($values)) return self::$_errorCodes['value'];
  9369.         $values self::flattenArray($values);
  9370.         $guess self::flattenSingleValue($guess);
  9371.  
  9372.         // create an initial range, with a root somewhere between 0 and guess
  9373.         $x1 0.0;
  9374.         $x2 $guess;
  9375.         $f1 self::NPV($x1$values);
  9376.         $f2 self::NPV($x2$values);
  9377.         for ($i 0$i FINANCIAL_MAX_ITERATIONS++$i{
  9378.             if (($f1 $f20.0break;
  9379.             if (abs($f1abs($f2)) {
  9380.                 $f1 self::NPV($x1 += 1.6 ($x1 $x2)$values);
  9381.             else {
  9382.                 $f2 self::NPV($x2 += 1.6 ($x2 $x1)$values);
  9383.             }
  9384.         }
  9385.         if (($f1 $f20.0return self::$_errorCodes['value'];
  9386.  
  9387.         $f self::NPV($x1$values);
  9388.         if ($f 0.0{
  9389.             $rtb $x1;
  9390.             $dx $x2 $x1;
  9391.         else {
  9392.             $rtb $x2;
  9393.             $dx $x1 $x2;
  9394.         }
  9395.  
  9396.         for ($i 0;  $i FINANCIAL_MAX_ITERATIONS++$i{
  9397.             $dx *= 0.5;
  9398.             $x_mid $rtb $dx;
  9399.             $f_mid self::NPV($x_mid$values);
  9400.             if ($f_mid <= 0.0$rtb $x_mid;
  9401.             if ((abs($f_midFINANCIAL_PRECISION|| (abs($dxFINANCIAL_PRECISION)) return $x_mid;
  9402.         }
  9403.         return self::$_errorCodes['value'];
  9404.     }    //    function IRR()
  9405.  
  9406.  
  9407.     public static function MIRR($values$finance_rate$reinvestment_rate{
  9408.         if (!is_array($values)) return self::$_errorCodes['value'];
  9409.         $values                self::flattenArray($values);
  9410.         $finance_rate        self::flattenSingleValue($finance_rate);
  9411.         $reinvestment_rate    self::flattenSingleValue($reinvestment_rate);
  9412.         $n count($values);
  9413.  
  9414.         $rr 1.0 $reinvestment_rate;
  9415.         $fr 1.0 $finance_rate;
  9416.  
  9417.         $npv_pos $npv_neg 0.0;
  9418.         foreach($values as $i => $v{
  9419.             if ($v >= 0{
  9420.                 $npv_pos += $v pow($rr$i);
  9421.             else {
  9422.                 $npv_neg += $v pow($fr$i);
  9423.             }
  9424.         }
  9425.  
  9426.         if (($npv_neg == 0|| ($npv_pos == 0|| ($reinvestment_rate <= -1)) {
  9427.             return self::$_errorCodes['value'];
  9428.         }
  9429.  
  9430.         $mirr pow((-$npv_pos pow($rr$n))
  9431.                 / ($npv_neg ($rr))(1.0 ($n 1))) 1.0;
  9432.  
  9433.         return (is_finite($mirr$mirr self::$_errorCodes['value']);
  9434.     }    //    function MIRR()
  9435.  
  9436.  
  9437.     public static function XIRR($values$dates$guess 0.1{
  9438.         if ((!is_array($values)) && (!is_array($dates))) return self::$_errorCodes['value'];
  9439.         $values    self::flattenArray($values);
  9440.         $dates    self::flattenArray($dates);
  9441.         $guess self::flattenSingleValue($guess);
  9442.         if (count($values!= count($dates)) return self::$_errorCodes['num'];
  9443.  
  9444.         // create an initial range, with a root somewhere between 0 and guess
  9445.         $x1 0.0;
  9446.         $x2 $guess;
  9447.         $f1 self::XNPV($x1$values$dates);
  9448.         $f2 self::XNPV($x2$values$dates);
  9449.         for ($i 0$i FINANCIAL_MAX_ITERATIONS++$i{
  9450.             if (($f1 $f20.0break;
  9451.             if (abs($f1abs($f2)) {
  9452.                 $f1 self::XNPV($x1 += 1.6 ($x1 $x2)$values$dates);
  9453.             else {
  9454.                 $f2 self::XNPV($x2 += 1.6 ($x2 $x1)$values$dates);
  9455.             }
  9456.         }
  9457.         if (($f1 $f20.0return self::$_errorCodes['value'];
  9458.  
  9459.         $f self::XNPV($x1$values$dates);
  9460.         if ($f 0.0{
  9461.             $rtb $x1;
  9462.             $dx $x2 $x1;
  9463.         else {
  9464.             $rtb $x2;
  9465.             $dx $x1 $x2;
  9466.         }
  9467.  
  9468.         for ($i 0;  $i FINANCIAL_MAX_ITERATIONS++$i{
  9469.             $dx *= 0.5;
  9470.             $x_mid $rtb $dx;
  9471.             $f_mid self::XNPV($x_mid$values$dates);
  9472.             if ($f_mid <= 0.0$rtb $x_mid;
  9473.             if ((abs($f_midFINANCIAL_PRECISION|| (abs($dxFINANCIAL_PRECISION)) return $x_mid;
  9474.         }
  9475.         return self::$_errorCodes['value'];
  9476.     }
  9477.  
  9478.  
  9479.     /**
  9480.      * RATE
  9481.      *
  9482.      **/
  9483.  
  9484.     public static function RATE($nper$pmt$pv$fv 0.0$type 0$guess 0.1{
  9485.         $nper    = (int) self::flattenSingleValue($nper);
  9486.         $pmt    self::flattenSingleValue($pmt);
  9487.         $pv        self::flattenSingleValue($pv);
  9488.         $fv        (is_null($fv))    0.0    :    self::flattenSingleValue($fv);
  9489.         $type    (is_null($type))    0        :    (int) self::flattenSingleValue($type);
  9490.         $guess    (is_null($guess))    0.1    :    self::flattenSingleValue($guess);
  9491.  
  9492.         $rate $guess;
  9493.         if (abs($rateFINANCIAL_PRECISION{
  9494.             $y $pv ($nper $rate$pmt ($rate $type$nper $fv;
  9495.         else {
  9496.             $f exp($nper log($rate));
  9497.             $y $pv $f $pmt ($rate $type($f 1$fv;
  9498.         }
  9499.         $y0 $pv $pmt $nper $fv;
  9500.         $y1 $pv $f $pmt ($rate $type($f 1$fv;
  9501.  
  9502.         // find root by secant method
  9503.         $i  $x0 0.0;
  9504.         $x1 $rate;
  9505.         while ((abs($y0 $y1FINANCIAL_PRECISION&& ($i FINANCIAL_MAX_ITERATIONS)) {
  9506.             $rate ($y1 $x0 $y0 $x1($y1 $y0);
  9507.             $x0 $x1;
  9508.             $x1 $rate;
  9509.  
  9510.             if (abs($rateFINANCIAL_PRECISION{
  9511.                 $y $pv ($nper $rate$pmt ($rate $type$nper $fv;
  9512.             else {
  9513.                 $f exp($nper log($rate));
  9514.                 $y $pv $f $pmt ($rate $type($f 1$fv;
  9515.             }
  9516.  
  9517.             $y0 $y1;
  9518.             $y1 $y;
  9519.             ++$i;
  9520.         }
  9521.         return $rate;
  9522.     }    //    function RATE()
  9523.  
  9524.  
  9525.     /**
  9526.      *    DB
  9527.      *
  9528.      *    Returns the depreciation of an asset for a specified period using the fixed-declining balance method.
  9529.      *    This form of depreciation is used if you want to get a higher depreciation value at the beginning of the depreciation
  9530.      *        (as opposed to linear depreciation). The depreciation value is reduced with every depreciation period by the
  9531.      *        depreciation already deducted from the initial cost.
  9532.      *
  9533.      *    @param    float    cost        Initial cost of the asset.
  9534.      *    @param    float    salvage        Value at the end of the depreciation. (Sometimes called the salvage value of the asset)
  9535.      *    @param    int        life        Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset)
  9536.      *    @param    int        period        The period for which you want to calculate the depreciation. Period must use the same units as life.
  9537.      *    @param    float    month        Number of months in the first year. If month is omitted, it defaults to 12.
  9538.      *    @return    float 
  9539.      */
  9540.     public static function DB($cost$salvage$life$period$month=12{
  9541.         $cost        = (float) self::flattenSingleValue($cost);
  9542.         $salvage    = (float) self::flattenSingleValue($salvage);
  9543.         $life        = (int) self::flattenSingleValue($life);
  9544.         $period        = (int) self::flattenSingleValue($period);
  9545.         $month        = (int) self::flattenSingleValue($month);
  9546.  
  9547.         //    Validate
  9548.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($month))) {
  9549.             if ($cost == 0{
  9550.                 return 0.0;
  9551.             elseif (($cost 0|| (($salvage $cost0|| ($life <= 0|| ($period 1|| ($month 1)) {
  9552.                 return self::$_errorCodes['num'];
  9553.             }
  9554.             //    Set Fixed Depreciation Rate
  9555.             $fixedDepreciationRate pow(($salvage $cost)($life));
  9556.             $fixedDepreciationRate round($fixedDepreciationRate3);
  9557.  
  9558.             //    Loop through each period calculating the depreciation
  9559.             $previousDepreciation 0;
  9560.             for ($per 1$per <= $period++$per{
  9561.                 if ($per == 1{
  9562.                     $depreciation $cost $fixedDepreciationRate $month 12;
  9563.                 elseif ($per == ($life 1)) {
  9564.                     $depreciation ($cost $previousDepreciation$fixedDepreciationRate (12 $month12;
  9565.                 else {
  9566.                     $depreciation ($cost $previousDepreciation$fixedDepreciationRate;
  9567.                 }
  9568.                 $previousDepreciation += $depreciation;
  9569.             }
  9570.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  9571.                 $depreciation round($depreciation,2);
  9572.             }
  9573.             return $depreciation;
  9574.         }
  9575.         return self::$_errorCodes['value'];
  9576.     }    //    function DB()
  9577.  
  9578.  
  9579.     /**
  9580.      *    DDB
  9581.      *
  9582.      *    Returns the depreciation of an asset for a specified period using the double-declining balance method or some other method you specify.
  9583.      *
  9584.      *    @param    float    cost        Initial cost of the asset.
  9585.      *    @param    float    salvage        Value at the end of the depreciation. (Sometimes called the salvage value of the asset)
  9586.      *    @param    int        life        Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset)
  9587.      *    @param    int        period        The period for which you want to calculate the depreciation. Period must use the same units as life.
  9588.      *    @param    float    factor        The rate at which the balance declines.
  9589.      *                                 If factor is omitted, it is assumed to be 2 (the double-declining balance method).
  9590.      *    @return    float 
  9591.      */
  9592.     public static function DDB($cost$salvage$life$period$factor=2.0{
  9593.         $cost        = (float) self::flattenSingleValue($cost);
  9594.         $salvage    = (float) self::flattenSingleValue($salvage);
  9595.         $life        = (int) self::flattenSingleValue($life);
  9596.         $period        = (int) self::flattenSingleValue($period);
  9597.         $factor        = (float) self::flattenSingleValue($factor);
  9598.  
  9599.         //    Validate
  9600.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($factor))) {
  9601.             if (($cost <= 0|| (($salvage $cost0|| ($life <= 0|| ($period 1|| ($factor <= 0.0|| ($period $life)) {
  9602.                 return self::$_errorCodes['num'];
  9603.             }
  9604.             //    Set Fixed Depreciation Rate
  9605.             $fixedDepreciationRate pow(($salvage $cost)($life));
  9606.             $fixedDepreciationRate round($fixedDepreciationRate3);
  9607.  
  9608.             //    Loop through each period calculating the depreciation
  9609.             $previousDepreciation 0;
  9610.             for ($per 1$per <= $period++$per{
  9611.                 $depreciation min( ($cost $previousDepreciation($factor $life)($cost $salvage $previousDepreciation) );
  9612.                 $previousDepreciation += $depreciation;
  9613.             }
  9614.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  9615.                 $depreciation round($depreciation,2);
  9616.             }
  9617.             return $depreciation;
  9618.         }
  9619.         return self::$_errorCodes['value'];
  9620.     }    //    function DDB()
  9621.  
  9622.  
  9623.     private static function _daysPerYear($year,$basis{
  9624.         switch ($basis{
  9625.             case :
  9626.             case :
  9627.             case :
  9628.                 $daysPerYear 360;
  9629.                 break;
  9630.             case :
  9631.                 $daysPerYear 365;
  9632.                 break;
  9633.             case :
  9634.                 if (self::_isLeapYear(self::YEAR($year))) {
  9635.                     $daysPerYear 366;
  9636.                 else {
  9637.                     $daysPerYear 365;
  9638.                 }
  9639.                 break;
  9640.             default    :
  9641.                 return self::$_errorCodes['num'];
  9642.         }
  9643.         return $daysPerYear;
  9644.     }    //    function _daysPerYear()
  9645.  
  9646.  
  9647.     /**
  9648.      *    ACCRINT
  9649.      *
  9650.      *    Returns the discount rate for a security.
  9651.      *
  9652.      *    @param    mixed    issue        The security's issue date.
  9653.      *    @param    mixed    firstinter    The security's first interest date.
  9654.      *    @param    mixed    settlement    The security's settlement date.
  9655.      *    @param    float    rate        The security's annual coupon rate.
  9656.      *    @param    float    par            The security's par value.
  9657.      *    @param    int        basis        The type of day count to use.
  9658.      *                                         0 or omitted    US (NASD) 30/360
  9659.      *                                         1                Actual/actual
  9660.      *                                         2                Actual/360
  9661.      *                                         3                Actual/365
  9662.      *                                         4                European 30/360
  9663.      *    @return    float 
  9664.      */
  9665.     public static function ACCRINT($issue$firstinter$settlement$rate$par=1000$frequency=1$basis=0{
  9666.         $issue        self::flattenSingleValue($issue);
  9667.         $firstinter    self::flattenSingleValue($firstinter);
  9668.         $settlement    self::flattenSingleValue($settlement);
  9669.         $rate        = (float) self::flattenSingleValue($rate);
  9670.         $par        (is_null($par))        1000 :    (float) self::flattenSingleValue($par);
  9671.         $frequency    (is_null($frequency))    1    :         (int) self::flattenSingleValue($frequency);
  9672.         $basis        (is_null($basis))        0    :        (int) self::flattenSingleValue($basis);
  9673.  
  9674.         //    Validate
  9675.         if ((is_numeric($rate)) && (is_numeric($par))) {
  9676.             if (($rate <= 0|| ($par <= 0)) {
  9677.                 return self::$_errorCodes['num'];
  9678.             }
  9679.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  9680.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  9681.                 return $daysBetweenIssueAndSettlement;
  9682.             }
  9683.             $daysPerYear self::_daysPerYear(self::YEAR($issue),$basis);
  9684.             if (!is_numeric($daysPerYear)) {
  9685.                 return $daysPerYear;
  9686.             }
  9687.             $daysBetweenIssueAndSettlement *= $daysPerYear;
  9688.  
  9689.             return $par $rate ($daysBetweenIssueAndSettlement $daysPerYear);
  9690.         }
  9691.         return self::$_errorCodes['value'];
  9692.     }    //    function ACCRINT()
  9693.  
  9694.  
  9695.     /**
  9696.      *    ACCRINTM
  9697.      *
  9698.      *    Returns the discount rate for a security.
  9699.      *
  9700.      *    @param    mixed    issue        The security's issue date.
  9701.      *    @param    mixed    settlement    The security's settlement date.
  9702.      *    @param    float    rate        The security's annual coupon rate.
  9703.      *    @param    float    par            The security's par value.
  9704.      *    @param    int        basis        The type of day count to use.
  9705.      *                                         0 or omitted    US (NASD) 30/360
  9706.      *                                         1                Actual/actual
  9707.      *                                         2                Actual/360
  9708.      *                                         3                Actual/365
  9709.      *                                         4                European 30/360
  9710.      *    @return    float 
  9711.      */
  9712.     public static function ACCRINTM($issue$settlement$rate$par=1000$basis=0{
  9713.         $issue        self::flattenSingleValue($issue);
  9714.         $settlement    self::flattenSingleValue($settlement);
  9715.         $rate        = (float) self::flattenSingleValue($rate);
  9716.         $par        (is_null($par))    1000 :    (float) self::flattenSingleValue($par);
  9717.         $basis        (is_null($basis))    :        (int) self::flattenSingleValue($basis);
  9718.  
  9719.         //    Validate
  9720.         if ((is_numeric($rate)) && (is_numeric($par))) {
  9721.             if (($rate <= 0|| ($par <= 0)) {
  9722.                 return self::$_errorCodes['num'];
  9723.             }
  9724.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  9725.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  9726.                 return $daysBetweenIssueAndSettlement;
  9727.             }
  9728.             $daysPerYear self::_daysPerYear(self::YEAR($issue),$basis);
  9729.             if (!is_numeric($daysPerYear)) {
  9730.                 return $daysPerYear;
  9731.             }
  9732.             $daysBetweenIssueAndSettlement *= $daysPerYear;
  9733.  
  9734.             return $par $rate ($daysBetweenIssueAndSettlement $daysPerYear);
  9735.         }
  9736.         return self::$_errorCodes['value'];
  9737.     }    //    function ACCRINTM()
  9738.  
  9739.  
  9740.     public static function AMORDEGRC($cost$purchased$firstPeriod$salvage$period$rate$basis=0{
  9741.         $cost            self::flattenSingleValue($cost);
  9742.         $purchased        self::flattenSingleValue($purchased);
  9743.         $firstPeriod    self::flattenSingleValue($firstPeriod);
  9744.         $salvage        self::flattenSingleValue($salvage);
  9745.         $period            floor(self::flattenSingleValue($period));
  9746.         $rate            self::flattenSingleValue($rate);
  9747.         $basis            floor(self::flattenSingleValue($basis));
  9748.  
  9749.         $fUsePer 1.0 $rate;
  9750.  
  9751.         if ($fUsePer 3.0{
  9752.             $amortiseCoeff 1.0;
  9753.         elseif ($fUsePer 5.0{
  9754.             $amortiseCoeff 1.5;
  9755.         elseif ($fUsePer <= 6.0{
  9756.             $amortiseCoeff 2.0;
  9757.         else {
  9758.             $amortiseCoeff 2.5;
  9759.         }
  9760.  
  9761.         $rate *= $amortiseCoeff;
  9762.         $fNRate floor((self::YEARFRAC($purchased$firstPeriod$basis$rate $cost0.5);
  9763.         $cost -= $fNRate;
  9764.         $fRest $cost $salvage;
  9765.  
  9766.         for ($n 0$n $period++$n{
  9767.             $fNRate floor(($rate $cost0.5);
  9768.             $fRest -= $fNRate;
  9769.  
  9770.             if ($fRest 0.0{
  9771.                 switch ($period $n{
  9772.                     case 0    :
  9773.                     case 1    return floor(($cost 0.50.5);
  9774.                               break;
  9775.                     default    return 0.0;
  9776.                               break;
  9777.                 }
  9778.             }
  9779.             $cost -= $fNRate;
  9780.         }
  9781.         return $fNRate;
  9782.     }    //    function AMORDEGRC()
  9783.  
  9784.  
  9785.     public static function AMORLINC($cost$purchased$firstPeriod$salvage$period$rate$basis=0{
  9786.         $cost            self::flattenSingleValue($cost);
  9787.         $purchased        self::flattenSingleValue($purchased);
  9788.         $firstPeriod    self::flattenSingleValue($firstPeriod);
  9789.         $salvage        self::flattenSingleValue($salvage);
  9790.         $period            self::flattenSingleValue($period);
  9791.         $rate            self::flattenSingleValue($rate);
  9792.         $basis            self::flattenSingleValue($basis);
  9793.  
  9794.         $fOneRate $cost $rate;
  9795.         $fCostDelta $cost $salvage;
  9796.         $f0Rate self::YEARFRAC($purchased$firstPeriod$basis$rate $cost;
  9797.         $nNumOfFullPeriods intval(($cost $salvage $f0Rate$fOneRate);
  9798.  
  9799.         if ($period == 0{
  9800.             return $f0Rate;
  9801.         elseif ($period <= $nNumOfFullPeriods{
  9802.             return $fOneRate;
  9803.         elseif ($period == ($nNumOfFullPeriods 1)) {
  9804.             return ($fCostDelta $fOneRate $nNumOfFullPeriods $f0Rate);
  9805.         else {
  9806.             return 0.0;
  9807.         }
  9808.     }    //    function AMORLINC()
  9809.  
  9810.  
  9811.     public static function COUPNUM($settlement$maturity$frequency$basis=0{
  9812.         $settlement    self::flattenSingleValue($settlement);
  9813.         $maturity    self::flattenSingleValue($maturity);
  9814.         $frequency    self::flattenSingleValue($frequency);
  9815.         $basis        self::flattenSingleValue($basis);
  9816.  
  9817.         $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis365;
  9818.  
  9819.         switch ($frequency{
  9820.             case 1// annual payments
  9821.                     return ceil($daysBetweenSettlementAndMaturity 360);
  9822.             case 2// half-yearly
  9823.                     return ceil($daysBetweenSettlementAndMaturity 180);
  9824.             case 4// quarterly
  9825.                     return ceil($daysBetweenSettlementAndMaturity 90);
  9826.         }
  9827.         return self::$_errorCodes['value'];
  9828.     }    //    function COUPNUM()
  9829.  
  9830.  
  9831.     public static function COUPDAYBS($settlement$maturity$frequency$basis=0{
  9832.         $settlement    self::flattenSingleValue($settlement);
  9833.         $maturity    self::flattenSingleValue($maturity);
  9834.         $frequency    self::flattenSingleValue($frequency);
  9835.         $basis        self::flattenSingleValue($basis);
  9836.  
  9837.         $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis365;
  9838.  
  9839.         switch ($frequency{
  9840.             case 1// annual payments
  9841.                     return 365 ($daysBetweenSettlementAndMaturity 360);
  9842.             case 2// half-yearly
  9843.                     return 365 ($daysBetweenSettlementAndMaturity 360);
  9844.             case 4// quarterly
  9845.                     return self::DATEDIF($maturity$settlement);
  9846.         }
  9847.         return self::$_errorCodes['value'];
  9848.     }    //    function COUPDAYBS()
  9849.  
  9850.  
  9851.     /**
  9852.      *    DISC
  9853.      *
  9854.      *    Returns the discount rate for a security.
  9855.      *
  9856.      *    @param    mixed    settlement    The security's settlement date.
  9857.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  9858.      *    @param    mixed    maturity    The security's maturity date.
  9859.      *                                 The maturity date is the date when the security expires.
  9860.      *    @param    int        price        The security's price per $100 face value.
  9861.      *    @param    int        redemption    the security's redemption value per $100 face value.
  9862.      *    @param    int        basis        The type of day count to use.
  9863.      *                                         0 or omitted    US (NASD) 30/360
  9864.      *                                         1                Actual/actual
  9865.      *                                         2                Actual/360
  9866.      *                                         3                Actual/365
  9867.      *                                         4                European 30/360
  9868.      *    @return    float 
  9869.      */
  9870.     public static function DISC($settlement$maturity$price$redemption$basis=0{
  9871.         $settlement    self::flattenSingleValue($settlement);
  9872.         $maturity    self::flattenSingleValue($maturity);
  9873.         $price        = (float) self::flattenSingleValue($price);
  9874.         $redemption    = (float) self::flattenSingleValue($redemption);
  9875.         $basis        = (int) self::flattenSingleValue($basis);
  9876.  
  9877.         //    Validate
  9878.         if ((is_numeric($price)) && (is_numeric($redemption)) && (is_numeric($basis))) {
  9879.             if (($price <= 0|| ($redemption <= 0)) {
  9880.                 return self::$_errorCodes['num'];
  9881.             }
  9882.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  9883.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9884.                 return $daysBetweenSettlementAndMaturity;
  9885.             }
  9886.  
  9887.             return (($price $redemption$daysBetweenSettlementAndMaturity);
  9888.         }
  9889.         return self::$_errorCodes['value'];
  9890.     }    //    function DISC()
  9891.  
  9892.  
  9893.     /**
  9894.      *    PRICEDISC
  9895.      *
  9896.      *    Returns the price per $100 face value of a discounted security.
  9897.      *
  9898.      *    @param    mixed    settlement    The security's settlement date.
  9899.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  9900.      *    @param    mixed    maturity    The security's maturity date.
  9901.      *                                 The maturity date is the date when the security expires.
  9902.      *    @param    int        discount    The security's discount rate.
  9903.      *    @param    int        redemption    The security's redemption value per $100 face value.
  9904.      *    @param    int        basis        The type of day count to use.
  9905.      *                                         0 or omitted    US (NASD) 30/360
  9906.      *                                         1                Actual/actual
  9907.      *                                         2                Actual/360
  9908.      *                                         3                Actual/365
  9909.      *                                         4                European 30/360
  9910.      *    @return    float 
  9911.      */
  9912.     public static function PRICEDISC($settlement$maturity$discount$redemption$basis=0{
  9913.         $settlement    self::flattenSingleValue($settlement);
  9914.         $maturity    self::flattenSingleValue($maturity);
  9915.         $discount    = (float) self::flattenSingleValue($discount);
  9916.         $redemption    = (float) self::flattenSingleValue($redemption);
  9917.         $basis        = (int) self::flattenSingleValue($basis);
  9918.  
  9919.         //    Validate
  9920.         if ((is_numeric($discount)) && (is_numeric($redemption)) && (is_numeric($basis))) {
  9921.             if (($discount <= 0|| ($redemption <= 0)) {
  9922.                 return self::$_errorCodes['num'];
  9923.             }
  9924.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  9925.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9926.                 return $daysBetweenSettlementAndMaturity;
  9927.             }
  9928.  
  9929.             return $redemption ($discount $daysBetweenSettlementAndMaturity);
  9930.         }
  9931.         return self::$_errorCodes['value'];
  9932.     }    //    function PRICEDISC()
  9933.  
  9934.  
  9935.     /**
  9936.      *    PRICEMAT
  9937.      *
  9938.      *    Returns the price per $100 face value of a security that pays interest at maturity.
  9939.      *
  9940.      *    @param    mixed    settlement    The security's settlement date.
  9941.      *                                 The security's settlement date is the date after the issue date when the security is traded to the buyer.
  9942.      *    @param    mixed    maturity    The security's maturity date.
  9943.      *                                 The maturity date is the date when the security expires.
  9944.      *    @param    mixed    issue        The security's issue date.
  9945.      *    @param    int        rate        The security's interest rate at date of issue.
  9946.      *    @param    int        yield        The security's annual yield.
  9947.      *    @param    int        basis        The type of day count to use.
  9948.      *                                         0 or omitted    US (NASD) 30/360
  9949.      *                                         1                Actual/actual
  9950.      *                                         2                Actual/360
  9951.      *                                         3                Actual/365
  9952.      *                                         4                European 30/360
  9953.      *    @return    float 
  9954.      */
  9955.     public static function PRICEMAT($settlement$maturity$issue$rate$yield$basis=0{
  9956.         $settlement    self::flattenSingleValue($settlement);
  9957.         $maturity    self::flattenSingleValue($maturity);
  9958.         $issue        self::flattenSingleValue($issue);
  9959.         $rate        self::flattenSingleValue($rate);
  9960.         $yield        self::flattenSingleValue($yield);
  9961.         $basis        = (int) self::flattenSingleValue($basis);
  9962.  
  9963.         //    Validate
  9964.         if (is_numeric($rate&& is_numeric($yield)) {
  9965.             if (($rate <= 0|| ($yield <= 0)) {
  9966.                 return self::$_errorCodes['num'];
  9967.             }
  9968.             $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  9969.             if (!is_numeric($daysPerYear)) {
  9970.                 return $daysPerYear;
  9971.             }
  9972.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  9973.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  9974.                 return $daysBetweenIssueAndSettlement;
  9975.             }
  9976.             $daysBetweenIssueAndSettlement *= $daysPerYear;
  9977.             $daysBetweenIssueAndMaturity self::YEARFRAC($issue$maturity$basis);
  9978.             if (!is_numeric($daysBetweenIssueAndMaturity)) {
  9979.                 return $daysBetweenIssueAndMaturity;
  9980.             }
  9981.             $daysBetweenIssueAndMaturity *= $daysPerYear;
  9982.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  9983.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9984.                 return $daysBetweenSettlementAndMaturity;
  9985.             }
  9986.             $daysBetweenSettlementAndMaturity *= $daysPerYear;
  9987.  
  9988.             return ((100 (($daysBetweenIssueAndMaturity $daysPerYear$rate 100)) /
  9989.                    ((($daysBetweenSettlementAndMaturity $daysPerYear$yield)) -
  9990.                    (($daysBetweenIssueAndSettlement $daysPerYear$rate 100));
  9991.         }
  9992.         return self::$_errorCodes['value'];
  9993.     }    //    function PRICEMAT()
  9994.  
  9995.  
  9996.     /**
  9997.      *    RECEIVED
  9998.      *
  9999.      *    Returns the price per $100 face value of a discounted security.
  10000.      *
  10001.      *    @param    mixed    settlement    The security's settlement date.
  10002.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  10003.      *    @param    mixed    maturity    The security's maturity date.
  10004.      *                                 The maturity date is the date when the security expires.
  10005.      *    @param    int        investment    The amount invested in the security.
  10006.      *    @param    int        discount    The security's discount rate.
  10007.      *    @param    int        basis        The type of day count to use.
  10008.      *                                         0 or omitted    US (NASD) 30/360
  10009.      *                                         1                Actual/actual
  10010.      *                                         2                Actual/360
  10011.      *                                         3                Actual/365
  10012.      *                                         4                European 30/360
  10013.      *    @return    float 
  10014.      */
  10015.     public static function RECEIVED($settlement$maturity$investment$discount$basis=0{
  10016.         $settlement    self::flattenSingleValue($settlement);
  10017.         $maturity    self::flattenSingleValue($maturity);
  10018.         $investment    = (float) self::flattenSingleValue($investment);
  10019.         $discount    = (float) self::flattenSingleValue($discount);
  10020.         $basis        = (int) self::flattenSingleValue($basis);
  10021.  
  10022.         //    Validate
  10023.         if ((is_numeric($investment)) && (is_numeric($discount)) && (is_numeric($basis))) {
  10024.             if (($investment <= 0|| ($discount <= 0)) {
  10025.                 return self::$_errorCodes['num'];
  10026.             }
  10027.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  10028.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10029.                 return $daysBetweenSettlementAndMaturity;
  10030.             }
  10031.  
  10032.             return $investment ($discount $daysBetweenSettlementAndMaturity));
  10033.         }
  10034.         return self::$_errorCodes['value'];
  10035.     }    //    function RECEIVED()
  10036.  
  10037.  
  10038.     /**
  10039.      *    INTRATE
  10040.      *
  10041.      *    Returns the interest rate for a fully invested security.
  10042.      *
  10043.      *    @param    mixed    settlement    The security's settlement date.
  10044.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  10045.      *    @param    mixed    maturity    The security's maturity date.
  10046.      *                                 The maturity date is the date when the security expires.
  10047.      *    @param    int        investment    The amount invested in the security.
  10048.      *    @param    int        redemption    The amount to be received at maturity.
  10049.      *    @param    int        basis        The type of day count to use.
  10050.      *                                         0 or omitted    US (NASD) 30/360
  10051.      *                                         1                Actual/actual
  10052.      *                                         2                Actual/360
  10053.      *                                         3                Actual/365
  10054.      *                                         4                European 30/360
  10055.      *    @return    float 
  10056.      */
  10057.     public static function INTRATE($settlement$maturity$investment$redemption$basis=0{
  10058.         $settlement    self::flattenSingleValue($settlement);
  10059.         $maturity    self::flattenSingleValue($maturity);
  10060.         $investment    = (float) self::flattenSingleValue($investment);
  10061.         $redemption    = (float) self::flattenSingleValue($redemption);
  10062.         $basis        = (int) self::flattenSingleValue($basis);
  10063.  
  10064.         //    Validate
  10065.         if ((is_numeric($investment)) && (is_numeric($redemption)) && (is_numeric($basis))) {
  10066.             if (($investment <= 0|| ($redemption <= 0)) {
  10067.                 return self::$_errorCodes['num'];
  10068.             }
  10069.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  10070.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10071.                 return $daysBetweenSettlementAndMaturity;
  10072.             }
  10073.  
  10074.             return (($redemption $investment1($daysBetweenSettlementAndMaturity);
  10075.         }
  10076.         return self::$_errorCodes['value'];
  10077.     }    //    function INTRATE()
  10078.  
  10079.  
  10080.     /**
  10081.      *    TBILLEQ
  10082.      *
  10083.      *    Returns the bond-equivalent yield for a Treasury bill.
  10084.      *
  10085.      *    @param    mixed    settlement    The Treasury bill's settlement date.
  10086.      *                                 The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  10087.      *    @param    mixed    maturity    The Treasury bill's maturity date.
  10088.      *                                 The maturity date is the date when the Treasury bill expires.
  10089.      *    @param    int        discount    The Treasury bill's discount rate.
  10090.      *    @return    float 
  10091.      */
  10092.     public static function TBILLEQ($settlement$maturity$discount{
  10093.         $settlement    self::flattenSingleValue($settlement);
  10094.         $maturity    self::flattenSingleValue($maturity);
  10095.         $discount    self::flattenSingleValue($discount);
  10096.  
  10097.         //    Use TBILLPRICE for validation
  10098.         $testValue self::TBILLPRICE($settlement$maturity$discount);
  10099.         if (is_string($testValue)) {
  10100.             return $testValue;
  10101.         }
  10102.  
  10103.         if (is_string($maturity self::_getDateValue($maturity))) {
  10104.             return self::$_errorCodes['value'];
  10105.         }
  10106.  
  10107.         if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  10108.             ++$maturity;
  10109.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity360;
  10110.         else {
  10111.             $daysBetweenSettlementAndMaturity (self::_getDateValue($maturityself::_getDateValue($settlement));
  10112.         }
  10113.  
  10114.         return (365 $discount(360 $discount $daysBetweenSettlementAndMaturity);
  10115.     }    //    function TBILLEQ()
  10116.  
  10117.  
  10118.     /**
  10119.      *    TBILLPRICE
  10120.      *
  10121.      *    Returns the yield for a Treasury bill.
  10122.      *
  10123.      *    @param    mixed    settlement    The Treasury bill's settlement date.
  10124.      *                                 The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  10125.      *    @param    mixed    maturity    The Treasury bill's maturity date.
  10126.      *                                 The maturity date is the date when the Treasury bill expires.
  10127.      *    @param    int        discount    The Treasury bill's discount rate.
  10128.      *    @return    float 
  10129.      */
  10130.     public static function TBILLPRICE($settlement$maturity$discount{
  10131.         $settlement    self::flattenSingleValue($settlement);
  10132.         $maturity    self::flattenSingleValue($maturity);
  10133.         $discount    self::flattenSingleValue($discount);
  10134.  
  10135.         if (is_string($maturity self::_getDateValue($maturity))) {
  10136.             return self::$_errorCodes['value'];
  10137.         }
  10138.  
  10139.         //    Validate
  10140.         if (is_numeric($discount)) {
  10141.             if ($discount <= 0{
  10142.                 return self::$_errorCodes['num'];
  10143.             }
  10144.  
  10145.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  10146.                 ++$maturity;
  10147.                 $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity360;
  10148.                 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10149.                     return $daysBetweenSettlementAndMaturity;
  10150.                 }
  10151.             else {
  10152.                 $daysBetweenSettlementAndMaturity (self::_getDateValue($maturityself::_getDateValue($settlement));
  10153.             }
  10154.  
  10155.             if ($daysBetweenSettlementAndMaturity 360{
  10156.                 return self::$_errorCodes['num'];
  10157.             }
  10158.  
  10159.             $price 100 ((($discount $daysBetweenSettlementAndMaturity360));
  10160.             if ($price <= 0{
  10161.                 return self::$_errorCodes['num'];
  10162.             }
  10163.             return $price;
  10164.         }
  10165.         return self::$_errorCodes['value'];
  10166.     }    //    function TBILLPRICE()
  10167.  
  10168.  
  10169.     /**
  10170.      *    TBILLYIELD
  10171.      *
  10172.      *    Returns the yield for a Treasury bill.
  10173.      *
  10174.      *    @param    mixed    settlement    The Treasury bill's settlement date.
  10175.      *                                 The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  10176.      *    @param    mixed    maturity    The Treasury bill's maturity date.
  10177.      *                                 The maturity date is the date when the Treasury bill expires.
  10178.      *    @param    int        price        The Treasury bill's price per $100 face value.
  10179.      *    @return    float 
  10180.      */
  10181.     public static function TBILLYIELD($settlement$maturity$price{
  10182.         $settlement    self::flattenSingleValue($settlement);
  10183.         $maturity    self::flattenSingleValue($maturity);
  10184.         $price        self::flattenSingleValue($price);
  10185.  
  10186.         //    Validate
  10187.         if (is_numeric($price)) {
  10188.             if ($price <= 0{
  10189.                 return self::$_errorCodes['num'];
  10190.             }
  10191.  
  10192.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  10193.                 ++$maturity;
  10194.                 $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity360;
  10195.                 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10196.                     return $daysBetweenSettlementAndMaturity;
  10197.                 }
  10198.             else {
  10199.                 $daysBetweenSettlementAndMaturity (self::_getDateValue($maturityself::_getDateValue($settlement));
  10200.             }
  10201.  
  10202.             if ($daysBetweenSettlementAndMaturity 360{
  10203.                 return self::$_errorCodes['num'];
  10204.             }
  10205.  
  10206.             return ((100 $price$price(360 $daysBetweenSettlementAndMaturity);
  10207.         }
  10208.         return self::$_errorCodes['value'];
  10209.     }    //    function TBILLYIELD()
  10210.  
  10211.  
  10212.     /**
  10213.      * SLN
  10214.      *
  10215.      * Returns the straight-line depreciation of an asset for one period
  10216.      *
  10217.      * @param    cost        Initial cost of the asset
  10218.      * @param    salvage        Value at the end of the depreciation
  10219.      * @param    life        Number of periods over which the asset is depreciated
  10220.      * @return    float 
  10221.      */
  10222.     public static function SLN($cost$salvage$life{
  10223.         $cost        self::flattenSingleValue($cost);
  10224.         $salvage    self::flattenSingleValue($salvage);
  10225.         $life        self::flattenSingleValue($life);
  10226.  
  10227.         // Calculate
  10228.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life))) {
  10229.             if ($life 0{
  10230.                 return self::$_errorCodes['num'];
  10231.             }
  10232.             return ($cost $salvage$life;
  10233.         }
  10234.         return self::$_errorCodes['value'];
  10235.     }    //    function SLN()
  10236.  
  10237.  
  10238.     /**
  10239.      *    YIELDMAT
  10240.      *
  10241.      *    Returns the annual yield of a security that pays interest at maturity.
  10242.      *
  10243.      *    @param    mixed    settlement    The security's settlement date.
  10244.      *                                 The security's settlement date is the date after the issue date when the security is traded to the buyer.
  10245.      *    @param    mixed    maturity    The security's maturity date.
  10246.      *                                 The maturity date is the date when the security expires.
  10247.      *    @param    mixed    issue        The security's issue date.
  10248.      *    @param    int        rate        The security's interest rate at date of issue.
  10249.      *    @param    int        price        The security's price per $100 face value.
  10250.      *    @param    int        basis        The type of day count to use.
  10251.      *                                         0 or omitted    US (NASD) 30/360
  10252.      *                                         1                Actual/actual
  10253.      *                                         2                Actual/360
  10254.      *                                         3                Actual/365
  10255.      *                                         4                European 30/360
  10256.      *    @return    float 
  10257.      */
  10258.     public static function YIELDMAT($settlement$maturity$issue$rate$price$basis=0{
  10259.         $settlement    self::flattenSingleValue($settlement);
  10260.         $maturity    self::flattenSingleValue($maturity);
  10261.         $issue        self::flattenSingleValue($issue);
  10262.         $rate        self::flattenSingleValue($rate);
  10263.         $price        self::flattenSingleValue($price);
  10264.         $basis        = (int) self::flattenSingleValue($basis);
  10265.  
  10266.         //    Validate
  10267.         if (is_numeric($rate&& is_numeric($price)) {
  10268.             if (($rate <= 0|| ($price <= 0)) {
  10269.                 return self::$_errorCodes['num'];
  10270.             }
  10271.             $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  10272.             if (!is_numeric($daysPerYear)) {
  10273.                 return $daysPerYear;
  10274.             }
  10275.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  10276.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  10277.                 return $daysBetweenIssueAndSettlement;
  10278.             }
  10279.             $daysBetweenIssueAndSettlement *= $daysPerYear;
  10280.             $daysBetweenIssueAndMaturity self::YEARFRAC($issue$maturity$basis);
  10281.             if (!is_numeric($daysBetweenIssueAndMaturity)) {
  10282.                 return $daysBetweenIssueAndMaturity;
  10283.             }
  10284.             $daysBetweenIssueAndMaturity *= $daysPerYear;
  10285.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  10286.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10287.                 return $daysBetweenSettlementAndMaturity;
  10288.             }
  10289.             $daysBetweenSettlementAndMaturity *= $daysPerYear;
  10290.  
  10291.             return (((($daysBetweenIssueAndMaturity $daysPerYear$rate(($price 100(($daysBetweenIssueAndSettlement $daysPerYear$rate))) /
  10292.                    (($price 100(($daysBetweenIssueAndSettlement $daysPerYear$rate))) *
  10293.                    ($daysPerYear $daysBetweenSettlementAndMaturity);
  10294.         }
  10295.         return self::$_errorCodes['value'];
  10296.     }    //    function YIELDMAT()
  10297.  
  10298.  
  10299.     /**
  10300.      *    YIELDDISC
  10301.      *
  10302.      *    Returns the annual yield of a security that pays interest at maturity.
  10303.      *
  10304.      *    @param    mixed    settlement    The security's settlement date.
  10305.      *                                 The security's settlement date is the date after the issue date when the security is traded to the buyer.
  10306.      *    @param    mixed    maturity    The security's maturity date.
  10307.      *                                 The maturity date is the date when the security expires.
  10308.      *    @param    int        price        The security's price per $100 face value.
  10309.      *    @param    int        redemption    The security's redemption value per $100 face value.
  10310.      *    @param    int        basis        The type of day count to use.
  10311.      *                                         0 or omitted    US (NASD) 30/360
  10312.      *                                         1                Actual/actual
  10313.      *                                         2                Actual/360
  10314.      *                                         3                Actual/365
  10315.      *                                         4                European 30/360
  10316.      *    @return    float 
  10317.      */
  10318.     public static function YIELDDISC($settlement$maturity$price$redemption$basis=0{
  10319.         $settlement    self::flattenSingleValue($settlement);
  10320.         $maturity    self::flattenSingleValue($maturity);
  10321.         $price        self::flattenSingleValue($price);
  10322.         $redemption    self::flattenSingleValue($redemption);
  10323.         $basis        = (int) self::flattenSingleValue($basis);
  10324.  
  10325.         //    Validate
  10326.         if (is_numeric($price&& is_numeric($redemption)) {
  10327.             if (($price <= 0|| ($redemption <= 0)) {
  10328.                 return self::$_errorCodes['num'];
  10329.             }
  10330.             $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  10331.             if (!is_numeric($daysPerYear)) {
  10332.                 return $daysPerYear;
  10333.             }
  10334.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity,$basis);
  10335.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  10336.                 return $daysBetweenSettlementAndMaturity;
  10337.             }
  10338.             $daysBetweenSettlementAndMaturity *= $daysPerYear;
  10339.  
  10340.             return (($redemption $price$price($daysPerYear $daysBetweenSettlementAndMaturity);
  10341.         }
  10342.         return self::$_errorCodes['value'];
  10343.     }    //    function YIELDDISC()
  10344.  
  10345.  
  10346.     /**
  10347.      *    CELL_ADDRESS
  10348.      *
  10349.      *    Creates a cell address as text, given specified row and column numbers.
  10350.      *
  10351.      *    @param    row                Row number to use in the cell reference
  10352.      *    @param    column            Column number to use in the cell reference
  10353.      *    @param    relativity        Flag indicating the type of reference to return
  10354.      *                                 1 or omitted    Absolute
  10355.      *                                 2                Absolute row; relative column
  10356.      *                                 3                Relative row; absolute column
  10357.      *                                 4                Relative
  10358.      *    @param    referenceStyle    A logical value that specifies the A1 or R1C1 reference style.
  10359.      *                                 TRUE or omitted        CELL_ADDRESS returns an A1-style reference
  10360.      *                                 FALSE                CELL_ADDRESS returns an R1C1-style reference
  10361.      *    @param    sheetText        Optional Name of worksheet to use
  10362.      *    @return    string 
  10363.      */
  10364.     public static function CELL_ADDRESS($row$column$relativity=1$referenceStyle=True$sheetText=''{
  10365.         $row        self::flattenSingleValue($row);
  10366.         $column        self::flattenSingleValue($column);
  10367.         $relativity    self::flattenSingleValue($relativity);
  10368.         $sheetText    self::flattenSingleValue($sheetText);
  10369.  
  10370.         if (($row 1|| ($column 1)) {
  10371.             return self::$_errorCodes['value'];
  10372.         }
  10373.  
  10374.         if ($sheetText ''{
  10375.             if (strpos($sheetText,' '!== False$sheetText "'".$sheetText."'"}
  10376.             $sheetText .='!';
  10377.         }
  10378.         if ((!is_bool($referenceStyle)) || $referenceStyle{
  10379.             $rowRelative $columnRelative '$';
  10380.             $column PHPExcel_Cell::stringFromColumnIndex($column-1);
  10381.             if (($relativity == 2|| ($relativity == 4)) $columnRelative ''}
  10382.             if (($relativity == 3|| ($relativity == 4)) $rowRelative ''}
  10383.             return $sheetText.$columnRelative.$column.$rowRelative.$row;
  10384.         else {
  10385.             if (($relativity == 2|| ($relativity == 4)) $column '['.$column.']'}
  10386.             if (($relativity == 3|| ($relativity == 4)) $row '['.$row.']'}
  10387.             return $sheetText.'R'.$row.'C'.$column;
  10388.         }
  10389.     }    //    function CELL_ADDRESS()
  10390.  
  10391.  
  10392.     /**
  10393.      *    COLUMN
  10394.      *
  10395.      *    Returns the column number of the given cell reference
  10396.      *    If the cell reference is a range of cells, COLUMN returns the column numbers of each column in the reference as a horizontal array.
  10397.      *    If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the
  10398.      *        reference of the cell in which the COLUMN function appears; otherwise this function returns 0.
  10399.      *
  10400.      *    @param    cellAddress        A reference to a range of cells for which you want the column numbers
  10401.      *    @return    integer or array of integer
  10402.      */
  10403.     public static function COLUMN($cellAddress=Null{
  10404.         if (is_null($cellAddress|| trim($cellAddress=== ''return 0}
  10405.  
  10406.         if (is_array($cellAddress)) {
  10407.             foreach($cellAddress as $columnKey => $value{
  10408.                 $columnKey preg_replace('/[^a-z]/i','',$columnKey);
  10409.                 return (integer) PHPExcel_Cell::columnIndexFromString($columnKey);
  10410.             }
  10411.         else {
  10412.             if (strpos($cellAddress,'!'!== false{
  10413.                 list($sheet,$cellAddressexplode('!',$cellAddress);
  10414.             }
  10415.             if (strpos($cellAddress,':'!== false{
  10416.                 list($startAddress,$endAddressexplode(':',$cellAddress);
  10417.                 $startAddress preg_replace('/[^a-z]/i','',$startAddress);
  10418.                 $endAddress preg_replace('/[^a-z]/i','',$endAddress);
  10419.                 $returnValue array();
  10420.                 do {
  10421.                     $returnValue[= (integer) PHPExcel_Cell::columnIndexFromString($startAddress);
  10422.                 while ($startAddress++ != $endAddress);
  10423.                 return $returnValue;
  10424.             else {
  10425.                 $cellAddress preg_replace('/[^a-z]/i','',$cellAddress);
  10426.                 return (integer) PHPExcel_Cell::columnIndexFromString($cellAddress);
  10427.             }
  10428.         }
  10429.     }    //    function COLUMN()
  10430.  
  10431.  
  10432.     /**
  10433.      *    COLUMNS
  10434.      *
  10435.      *    Returns the number of columns in an array or reference.
  10436.      *
  10437.      *    @param    cellAddress        An array or array formula, or a reference to a range of cells for which you want the number of columns
  10438.      *    @return    integer 
  10439.      */
  10440.     public static function COLUMNS($cellAddress=Null{
  10441.         if (is_null($cellAddress|| $cellAddress === ''{
  10442.             return 1;
  10443.         elseif (!is_array($cellAddress)) {
  10444.             return self::$_errorCodes['value'];
  10445.         }
  10446.  
  10447.         $isMatrix (is_numeric(array_shift(array_keys($cellAddress))));
  10448.         list($columns,$rowsPHPExcel_Calculation::_getMatrixDimensions($cellAddress);
  10449.  
  10450.         if ($isMatrix{
  10451.             return $rows;
  10452.         else {
  10453.             return $columns;
  10454.         }
  10455.     }    //    function COLUMNS()
  10456.  
  10457.  
  10458.     /**
  10459.      *    ROW
  10460.      *
  10461.      *    Returns the row number of the given cell reference
  10462.      *    If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference as a vertical array.
  10463.      *    If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the
  10464.      *        reference of the cell in which the ROW function appears; otherwise this function returns 0.
  10465.      *
  10466.      *    @param    cellAddress        A reference to a range of cells for which you want the row numbers
  10467.      *    @return    integer or array of integer
  10468.      */
  10469.     public static function ROW($cellAddress=Null{
  10470.         if (is_null($cellAddress|| trim($cellAddress=== ''return 0}
  10471.  
  10472.         if (is_array($cellAddress)) {
  10473.             foreach($cellAddress as $columnKey => $rowValue{
  10474.                 foreach($rowValue as $rowKey => $cellValue{
  10475.                     return (integer) preg_replace('/[^0-9]/i','',$rowKey);
  10476.                 }
  10477.             }
  10478.         else {
  10479.             if (strpos($cellAddress,'!'!== false{
  10480.                 list($sheet,$cellAddressexplode('!',$cellAddress);
  10481.             }
  10482.             if (strpos($cellAddress,':'!== false{
  10483.                 list($startAddress,$endAddressexplode(':',$cellAddress);
  10484.                 $startAddress preg_replace('/[^0-9]/','',$startAddress);
  10485.                 $endAddress preg_replace('/[^0-9]/','',$endAddress);
  10486.                 $returnValue array();
  10487.                 do {
  10488.                     $returnValue[][= (integer) $startAddress;
  10489.                 while ($startAddress++ != $endAddress);
  10490.                 return $returnValue;
  10491.             else {
  10492.                 list($cellAddressexplode(':',$cellAddress);
  10493.                 return (integer) preg_replace('/[^0-9]/','',$cellAddress);
  10494.             }
  10495.         }
  10496.     }    //    function ROW()
  10497.  
  10498.  
  10499.     /**
  10500.      *    ROWS
  10501.      *
  10502.      *    Returns the number of rows in an array or reference.
  10503.      *
  10504.      *    @param    cellAddress        An array or array formula, or a reference to a range of cells for which you want the number of rows
  10505.      *    @return    integer 
  10506.      */
  10507.     public static function ROWS($cellAddress=Null{
  10508.         if (is_null($cellAddress|| $cellAddress === ''{
  10509.             return 1;
  10510.         elseif (!is_array($cellAddress)) {
  10511.             return self::$_errorCodes['value'];
  10512.         }
  10513.  
  10514.         $isMatrix (is_numeric(array_shift(array_keys($cellAddress))));
  10515.         list($columns,$rowsPHPExcel_Calculation::_getMatrixDimensions($cellAddress);
  10516.  
  10517.         if ($isMatrix{
  10518.             return $columns;
  10519.         else {
  10520.             return $rows;
  10521.         }
  10522.     }    //    function ROWS()
  10523.  
  10524.  
  10525.     /**
  10526.      *    INDIRECT
  10527.      *
  10528.      *    Returns the number of rows in an array or reference.
  10529.      *
  10530.      *    @param    cellAddress        An array or array formula, or a reference to a range of cells for which you want the number of rows
  10531.      *    @return    integer 
  10532.      */
  10533.     public static function INDIRECT($cellAddress=NullPHPExcel_Cell $pCell null{
  10534.         $cellAddress    self::flattenSingleValue($cellAddress);
  10535.         if (is_null($cellAddress|| $cellAddress === ''{
  10536.             return self::REF();
  10537.         }
  10538.  
  10539.         $cellAddress1 $cellAddress;
  10540.         $cellAddress2 NULL;
  10541.         if (strpos($cellAddress,':'!== false{
  10542.             list($cellAddress1,$cellAddress2explode(':',$cellAddress);
  10543.         }
  10544.  
  10545.         if ((!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i'$cellAddress1$matches)) ||
  10546.             ((!is_null($cellAddress2)) && (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i'$cellAddress2$matches)))) {
  10547.             return self::REF();
  10548.         }
  10549.  
  10550.         if (strpos($cellAddress,'!'!== false{
  10551.             list($sheetName,$cellAddressexplode('!',$cellAddress);
  10552.             $pSheet $pCell->getParent()->getParent()->getSheetByName($sheetName);
  10553.         else {
  10554.             $pSheet $pCell->getParent();
  10555.         }
  10556.  
  10557.         return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress$pSheetFalse);
  10558.     }    //    function INDIRECT()
  10559.  
  10560.  
  10561.     /**
  10562.      *    OFFSET
  10563.      *
  10564.      *    Returns a reference to a range that is a specified number of rows and columns from a cell or range of cells.
  10565.      *    The reference that is returned can be a single cell or a range of cells. You can specify the number of rows and
  10566.      *    the number of columns to be returned.
  10567.      *
  10568.      *    @param    cellAddress        The reference from which you want to base the offset. Reference must refer to a cell or
  10569.      *                                 range of adjacent cells; otherwise, OFFSET returns the #VALUE! error value.
  10570.      *    @param    rows            The number of rows, up or down, that you want the upper-left cell to refer to.
  10571.      *                                 Using 5 as the rows argument specifies that the upper-left cell in the reference is
  10572.      *                                 five rows below reference. Rows can be positive (which means below the starting reference)
  10573.      *                                 or negative (which means above the starting reference).
  10574.      *    @param    cols            The number of columns, to the left or right, that you want the upper-left cell of the result
  10575.      *                                 to refer to. Using 5 as the cols argument specifies that the upper-left cell in the
  10576.      *                                 reference is five columns to the right of reference. Cols can be positive (which means
  10577.      *                                 to the right of the starting reference) or negative (which means to the left of the
  10578.      *                                 starting reference).
  10579.      *    @param    height            The height, in number of rows, that you want the returned reference to be. Height must be a positive number.
  10580.      *    @param    width            The width, in number of columns, that you want the returned reference to be. Width must be a positive number.
  10581.      *    @return    string            A reference to a cell or range of cells
  10582.      */
  10583.     public static function OFFSET($cellAddress=Null,$rows=0,$columns=0,$height=null,$width=null{
  10584.         if ($cellAddress == Null{
  10585.             return 0;
  10586.         }
  10587.  
  10588.         $pCell array_pop(func_get_args());
  10589.         if (!is_object($pCell)) {
  10590.             return self::$_errorCodes['reference'];
  10591.         }
  10592.  
  10593.         $sheetName null;
  10594.         if (strpos($cellAddress,"!")) {
  10595.             list($sheetName,$cellAddressexplode("!",$cellAddress);
  10596.         }
  10597.         if (strpos($cellAddress,":")) {
  10598.             list($startCell,$endCellexplode(":",$cellAddress);
  10599.         else {
  10600.             $startCell $endCell $cellAddress;
  10601.         }
  10602.         list($startCellColumn,$startCellRowPHPExcel_Cell::coordinateFromString($startCell);
  10603.         list($endCellColumn,$endCellRowPHPExcel_Cell::coordinateFromString($endCell);
  10604.  
  10605.         $startCellRow += $rows;
  10606.         $startCellColumn PHPExcel_Cell::columnIndexFromString($startCellColumn1;
  10607.         $startCellColumn += $columns;
  10608.  
  10609.         if (($startCellRow <= 0|| ($startCellColumn 0)) {
  10610.             return self::$_errorCodes['reference'];
  10611.         }
  10612.         $endCellColumn PHPExcel_Cell::columnIndexFromString($endCellColumn1;
  10613.         if (($width != null&& (!is_object($width))) {
  10614.             $endCellColumn $startCellColumn $width 1;
  10615.         else {
  10616.             $endCellColumn += $columns;
  10617.         }
  10618.         $startCellColumn PHPExcel_Cell::stringFromColumnIndex($startCellColumn);
  10619.  
  10620.         if (($height != null&& (!is_object($height))) {
  10621.             $endCellRow $startCellRow $height 1;
  10622.         else {
  10623.             $endCellRow += $rows;
  10624.         }
  10625.  
  10626.         if (($endCellRow <= 0|| ($endCellColumn 0)) {
  10627.             return self::$_errorCodes['reference'];
  10628.         }
  10629.         $endCellColumn PHPExcel_Cell::stringFromColumnIndex($endCellColumn);
  10630.  
  10631.         $cellAddress $startCellColumn.$startCellRow;
  10632.         if (($startCellColumn != $endCellColumn|| ($startCellRow != $endCellRow)) {
  10633.             $cellAddress .= ':'.$endCellColumn.$endCellRow;
  10634.         }
  10635.  
  10636.         if ($sheetName !== null{
  10637.             $pSheet $pCell->getParent()->getParent()->getSheetByName($sheetName);
  10638.         else {
  10639.             $pSheet $pCell->getParent();
  10640.         }
  10641.  
  10642.         return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress$pSheetFalse);
  10643.     }    //    function OFFSET()
  10644.  
  10645.  
  10646.     public static function CHOOSE({
  10647.         $chooseArgs func_get_args();
  10648.         $chosenEntry self::flattenArray(array_shift($chooseArgs));
  10649.         $entryCount count($chooseArgs1;
  10650.  
  10651.         if(is_array($chosenEntry)) {
  10652.             $chosenEntry array_shift($chosenEntry);
  10653.         }
  10654.         if ((is_numeric($chosenEntry)) && (!is_bool($chosenEntry))) {
  10655.             --$chosenEntry;
  10656.         else {
  10657.             return self::$_errorCodes['value'];
  10658.         }
  10659.         $chosenEntry floor($chosenEntry);
  10660.         if (($chosenEntry <= 0|| ($chosenEntry $entryCount)) {
  10661.             return self::$_errorCodes['value'];
  10662.         }
  10663.  
  10664.         if (is_array($chooseArgs[$chosenEntry])) {
  10665.             return self::flattenArray($chooseArgs[$chosenEntry]);
  10666.         else {
  10667.             return $chooseArgs[$chosenEntry];
  10668.         }
  10669.     }    //    function CHOOSE()
  10670.  
  10671.  
  10672.     /**
  10673.      *    MATCH
  10674.      *
  10675.      *    The MATCH function searches for a specified item in a range of cells
  10676.      *
  10677.      *    @param    lookup_value    The value that you want to match in lookup_array
  10678.      *    @param    lookup_array    The range of cells being searched
  10679.      *    @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.
  10680.      *    @return    integer            The relative position of the found item
  10681.      */
  10682.     public static function MATCH($lookup_value$lookup_array$match_type=1{
  10683.  
  10684.         // flatten the lookup_array
  10685.         $lookup_array self::flattenArray($lookup_array);
  10686.  
  10687.         // flatten lookup_value since it may be a cell reference to a value or the value itself
  10688.         $lookup_value self::flattenSingleValue($lookup_value);
  10689.  
  10690.         // MATCH is not case sensitive
  10691.         $lookup_value strtolower($lookup_value);
  10692.  
  10693.         /*
  10694.         echo "--------------------<br>looking for $lookup_value in <br>";
  10695.         print_r($lookup_array);
  10696.         echo "<br>";
  10697.         //return 1;
  10698.         /**/
  10699.  
  10700.         // **
  10701.         // check inputs
  10702.         // **
  10703.         // lookup_value type has to be number, text, or logical values
  10704.         if (!is_numeric($lookup_value&& !is_string($lookup_value&& !is_bool($lookup_value)){
  10705.             // error: lookup_array should contain only number, text, or logical values
  10706.             //echo "error: lookup_array should contain only number, text, or logical values<br>";
  10707.             return self::$_errorCodes['na'];
  10708.         }
  10709.  
  10710.         // match_type is 0, 1 or -1
  10711.         if ($match_type!==&& $match_type!==-&& $match_type!==1){
  10712.             // error: wrong value for match_type
  10713.             //echo "error: wrong value for match_type<br>";
  10714.             return self::$_errorCodes['na'];
  10715.         }
  10716.  
  10717.         // lookup_array should not be empty
  10718.         if (sizeof($lookup_array)<=0){
  10719.             // error: empty range
  10720.             //echo "error: empty range ".sizeof($lookup_array)."<br>";
  10721.             return self::$_errorCodes['na'];
  10722.         }
  10723.  
  10724.         // lookup_array should contain only number, text, or logical values
  10725.         for ($i=0;$i<sizeof($lookup_array);++$i){
  10726.             // check the type of the value
  10727.             if (!is_numeric($lookup_array[$i]&& !is_string($lookup_array[$i]&& !is_bool($lookup_array[$i])){
  10728.                 // error: lookup_array should contain only number, text, or logical values
  10729.                 //echo "error: lookup_array should contain only number, text, or logical values<br>";
  10730.                 return self::$_errorCodes['na'];
  10731.             }
  10732.             // convert tpo lowercase
  10733.             if (is_string($lookup_array[$i]))
  10734.                 $lookup_array[$istrtolower($lookup_array[$i]);
  10735.         }
  10736.  
  10737.         // if match_type is 1 or -1, the list has to be ordered
  10738.         if($match_type==|| $match_type==-1){
  10739.             // **
  10740.             // iniitialization
  10741.             // store the last value
  10742.             $iLastValue=$lookup_array[0];
  10743.             // **
  10744.             // loop on the cells
  10745.             for ($i=0;$i<sizeof($lookup_array);++$i){
  10746.                 // check ascending order
  10747.                 if(($match_type==&& $lookup_array[$i]<$iLastValue)
  10748.                     // OR check descending order
  10749.                     || ($match_type==-&& $lookup_array[$i]>$iLastValue)){
  10750.                     // error: list is not ordered correctly
  10751.                     //echo "error: list is not ordered correctly<br>";
  10752.                     return self::$_errorCodes['na'];
  10753.                 }
  10754.             }
  10755.         }
  10756.         // **
  10757.         // find the match
  10758.         // **
  10759.         // loop on the cells
  10760.         for ($i=0$i sizeof($lookup_array)++$i){
  10761.             // if match_type is 0 <=> find the first value that is exactly equal to lookup_value
  10762.             if ($match_type==&& $lookup_array[$i]==$lookup_value){
  10763.                 // this is the exact match
  10764.                 return $i+1;
  10765.             }
  10766.             // if match_type is -1 <=> find the smallest value that is greater than or equal to lookup_value
  10767.             if ($match_type==-&& $lookup_array[$i$lookup_value){
  10768.                 if ($i<1){
  10769.                     // 1st cell was allready smaller than the lookup_value
  10770.                     break;
  10771.                 }
  10772.                 else
  10773.                     // the previous cell was the match
  10774.                     return $i;
  10775.             }
  10776.             // if match_type is 1 <=> find the largest value that is less than or equal to lookup_value
  10777.             if ($match_type==&& $lookup_array[$i$lookup_value){
  10778.                 if ($i<1){
  10779.                     // 1st cell was allready bigger than the lookup_value
  10780.                     break;
  10781.                 }
  10782.                 else
  10783.                     // the previous cell was the match
  10784.                     return $i;
  10785.             }
  10786.         }
  10787.         // unsuccessful in finding a match, return #N/A error value
  10788.         //echo "unsuccessful in finding a match<br>";
  10789.         return self::$_errorCodes['na'];
  10790.     }    //    function MATCH()
  10791.  
  10792.  
  10793.     /**
  10794.      * Uses an index to choose a value from a reference or array
  10795.      * implemented: Return the value of a specified cell or array of cells    Array form
  10796.      * not implemented: Return a reference to specified cells    Reference form
  10797.      *
  10798.      * @param    range_array    a range of cells or an array constant
  10799.      * @param    row_num        selects the row in array from which to return a value. If row_num is omitted, column_num is required.
  10800.      * @param    column_num    selects the column in array from which to return a value. If column_num is omitted, row_num is required.
  10801.      */
  10802.     public static function INDEX($arrayValues,$rowNum 0,$columnNum 0{
  10803.  
  10804.         if (($rowNum 0|| ($columnNum 0)) {
  10805.             return self::$_errorCodes['value'];
  10806.         }
  10807.  
  10808.         $rowKeys array_keys($arrayValues);
  10809.         $columnKeys @array_keys($arrayValues[$rowKeys[0]]);
  10810.  
  10811.         if ($columnNum count($columnKeys)) {
  10812.             return self::$_errorCodes['value'];
  10813.         elseif ($columnNum == 0{
  10814.             if ($rowNum == 0{
  10815.                 return $arrayValues;
  10816.             }
  10817.             $rowNum $rowKeys[--$rowNum];
  10818.             $returnArray array();
  10819.             foreach($arrayValues as $arrayColumn{
  10820.                 if (is_array($arrayColumn)) {
  10821.                     if (isset($arrayColumn[$rowNum])) {
  10822.                         $returnArray[$arrayColumn[$rowNum];
  10823.                     else {
  10824.                         return $arrayValues[$rowNum];
  10825.                     }
  10826.                 else {
  10827.                     return $arrayValues[$rowNum];
  10828.                 }
  10829.             }
  10830.             return $returnArray;
  10831.         }
  10832.         $columnNum $columnKeys[--$columnNum];
  10833.         if ($rowNum count($rowKeys)) {
  10834.             return self::$_errorCodes['value'];
  10835.         elseif ($rowNum == 0{
  10836.             return $arrayValues[$columnNum];
  10837.         }
  10838.         $rowNum $rowKeys[--$rowNum];
  10839.  
  10840.         return $arrayValues[$rowNum][$columnNum];
  10841.     }    //    function INDEX()
  10842.  
  10843.  
  10844.     /**
  10845.      * SYD
  10846.      *
  10847.      * Returns the sum-of-years' digits depreciation of an asset for a specified period.
  10848.      *
  10849.      * @param    cost        Initial cost of the asset
  10850.      * @param    salvage        Value at the end of the depreciation
  10851.      * @param    life        Number of periods over which the asset is depreciated
  10852.      * @param    period        Period
  10853.      * @return    float 
  10854.      */
  10855.     public static function SYD($cost$salvage$life$period{
  10856.         $cost        self::flattenSingleValue($cost);
  10857.         $salvage    self::flattenSingleValue($salvage);
  10858.         $life        self::flattenSingleValue($life);
  10859.         $period        self::flattenSingleValue($period);
  10860.  
  10861.         // Calculate
  10862.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period))) {
  10863.             if (($life 1|| ($period $life)) {
  10864.                 return self::$_errorCodes['num'];
  10865.             }
  10866.             return (($cost $salvage($life $period 12($life ($life 1));
  10867.         }
  10868.         return self::$_errorCodes['value'];
  10869.     }    //    function SYD()
  10870.  
  10871.  
  10872.     /**
  10873.      * TRANSPOSE
  10874.      *
  10875.      * @param    array    $matrixData    A matrix of values
  10876.      * @return    array 
  10877.      *
  10878.      *  Unlike the Excel TRANSPOSE function, which will only work on a single row or column, this function will transpose a full matrix.
  10879.      */
  10880.     public static function TRANSPOSE($matrixData{
  10881.         $returnMatrix array();
  10882.         if (!is_array($matrixData)) $matrixData array(array($matrixData))}
  10883.  
  10884.         $column 0;
  10885.         foreach($matrixData as $matrixRow{
  10886.             $row 0;
  10887.             foreach($matrixRow as $matrixCell{
  10888.                 $returnMatrix[$row][$column$matrixCell;
  10889.                 ++$row;
  10890.             }
  10891.             ++$column;
  10892.         }
  10893.         return $returnMatrix;
  10894.     }    //    function TRANSPOSE()
  10895.  
  10896.  
  10897.     /**
  10898.      * MMULT
  10899.      *
  10900.      * @param    array    $matrixData1    A matrix of values
  10901.      * @param    array    $matrixData2    A matrix of values
  10902.      * @return    array 
  10903.      */
  10904.     public static function MMULT($matrixData1,$matrixData2{
  10905.         $matrixAData $matrixBData array();
  10906.         if (!is_array($matrixData1)) $matrixData1 array(array($matrixData1))}
  10907.         if (!is_array($matrixData2)) $matrixData2 array(array($matrixData2))}
  10908.  
  10909.         $rowA 0;
  10910.         foreach($matrixData1 as $matrixRow{
  10911.             $columnA 0;
  10912.             foreach($matrixRow as $matrixCell{
  10913.                 if ((is_string($matrixCell)) || ($matrixCell === null)) {
  10914.                     return self::$_errorCodes['value'];
  10915.                 }
  10916.                 $matrixAData[$rowA][$columnA$matrixCell;
  10917.                 ++$columnA;
  10918.             }
  10919.             ++$rowA;
  10920.         }
  10921.         try {
  10922.             $matrixA new Matrix($matrixAData);
  10923.             $rowB 0;
  10924.             foreach($matrixData2 as $matrixRow{
  10925.                 $columnB 0;
  10926.                 foreach($matrixRow as $matrixCell{
  10927.                     if ((is_string($matrixCell)) || ($matrixCell === null)) {
  10928.                         return self::$_errorCodes['value'];
  10929.                     }
  10930.                     $matrixBData[$rowB][$columnB$matrixCell;
  10931.                     ++$columnB;
  10932.                 }
  10933.                 ++$rowB;
  10934.             }
  10935.             $matrixB new Matrix($matrixBData);
  10936.  
  10937.             if (($rowA != $columnB|| ($rowB != $columnA)) {
  10938.                 return self::$_errorCodes['value'];
  10939.             }
  10940.  
  10941.             return $matrixA->times($matrixB)->getArray();
  10942.         catch (Exception $ex{
  10943.             return self::$_errorCodes['value'];
  10944.         }
  10945.     }    //    function MMULT()
  10946.  
  10947.  
  10948.     /**
  10949.      * MINVERSE
  10950.      *
  10951.      * @param    array    $matrixValues    A matrix of values
  10952.      * @return    array 
  10953.      */
  10954.     public static function MINVERSE($matrixValues{
  10955.         $matrixData array();
  10956.         if (!is_array($matrixValues)) $matrixValues array(array($matrixValues))}
  10957.  
  10958.         $row $maxColumn 0;
  10959.         foreach($matrixValues as $matrixRow{
  10960.             $column 0;
  10961.             foreach($matrixRow as $matrixCell{
  10962.                 if ((is_string($matrixCell)) || ($matrixCell === null)) {
  10963.                     return self::$_errorCodes['value'];
  10964.                 }
  10965.                 $matrixData[$column][$row$matrixCell;
  10966.                 ++$column;
  10967.             }
  10968.             if ($column $maxColumn$maxColumn $column}
  10969.             ++$row;
  10970.         }
  10971.         if ($row != $maxColumnreturn self::$_errorCodes['value']}
  10972.  
  10973.         try {
  10974.             $matrix new Matrix($matrixData);
  10975.             return $matrix->inverse()->getArray();
  10976.         catch (Exception $ex{
  10977.             return self::$_errorCodes['value'];
  10978.         }
  10979.     }    //    function MINVERSE()
  10980.  
  10981.  
  10982.     /**
  10983.      * MDETERM
  10984.      *
  10985.      * @param    array    $matrixValues    A matrix of values
  10986.      * @return    float 
  10987.      */
  10988.     public static function MDETERM($matrixValues{
  10989.         $matrixData array();
  10990.         if (!is_array($matrixValues)) $matrixValues array(array($matrixValues))}
  10991.  
  10992.         $row $maxColumn 0;
  10993.         foreach($matrixValues as $matrixRow{
  10994.             $column 0;
  10995.             foreach($matrixRow as $matrixCell{
  10996.                 if ((is_string($matrixCell)) || ($matrixCell === null)) {
  10997.                     return self::$_errorCodes['value'];
  10998.                 }
  10999.                 $matrixData[$column][$row$matrixCell;
  11000.                 ++$column;
  11001.             }
  11002.             if ($column $maxColumn$maxColumn $column}
  11003.             ++$row;
  11004.         }
  11005.         if ($row != $maxColumnreturn self::$_errorCodes['value']}
  11006.  
  11007.         try {
  11008.             $matrix new Matrix($matrixData);
  11009.             return $matrix->det();
  11010.         catch (Exception $ex{
  11011.             return self::$_errorCodes['value'];
  11012.         }
  11013.     }    //    function MDETERM()
  11014.  
  11015.  
  11016.     /**
  11017.      * SUMPRODUCT
  11018.      *
  11019.      * @param    mixed    $value    Value to check
  11020.      * @return    float 
  11021.      */
  11022.     public static function SUMPRODUCT({
  11023.         $arrayList func_get_args();
  11024.  
  11025.         $wrkArray self::flattenArray(array_shift($arrayList));
  11026.         $wrkCellCount count($wrkArray);
  11027.  
  11028.         foreach($arrayList as $matrixData{
  11029.             $array2 self::flattenArray($matrixData);
  11030.             $count count($array2);
  11031.             if ($wrkCellCount != $count{
  11032.                 return self::$_errorCodes['value'];
  11033.             }
  11034.  
  11035.             foreach ($array2 as $i => $val{
  11036.                 if (((is_numeric($wrkArray[$i])) && (!is_string($wrkArray[$i]))) &&
  11037.                     ((is_numeric($val)) && (!is_string($val)))) {
  11038.                     $wrkArray[$i*= $val;
  11039.                 }
  11040.             }
  11041.         }
  11042.  
  11043.         return array_sum($wrkArray);
  11044.     }    //    function SUMPRODUCT()
  11045.  
  11046.  
  11047.     /**
  11048.      * SUMX2MY2
  11049.      *
  11050.      * @param    mixed    $value    Value to check
  11051.      * @return    float 
  11052.      */
  11053.     public static function SUMX2MY2($matrixData1,$matrixData2{
  11054.         $array1 self::flattenArray($matrixData1);
  11055.         $array2 self::flattenArray($matrixData2);
  11056.         $count1 count($array1);
  11057.         $count2 count($array2);
  11058.         if ($count1 $count2{
  11059.             $count $count1;
  11060.         else {
  11061.             $count $count2;
  11062.         }
  11063.  
  11064.         $result 0;
  11065.         for ($i 0$i $count++$i{
  11066.             if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
  11067.                 ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
  11068.                 $result += ($array1[$i$array1[$i]($array2[$i$array2[$i]);
  11069.             }
  11070.         }
  11071.  
  11072.         return $result;
  11073.     }    //    function SUMX2MY2()
  11074.  
  11075.  
  11076.     /**
  11077.      * SUMX2PY2
  11078.      *
  11079.      * @param    mixed    $value    Value to check
  11080.      * @return    float 
  11081.      */
  11082.     public static function SUMX2PY2($matrixData1,$matrixData2{
  11083.         $array1 self::flattenArray($matrixData1);
  11084.         $array2 self::flattenArray($matrixData2);
  11085.         $count1 count($array1);
  11086.         $count2 count($array2);
  11087.         if ($count1 $count2{
  11088.             $count $count1;
  11089.         else {
  11090.             $count $count2;
  11091.         }
  11092.  
  11093.         $result 0;
  11094.         for ($i 0$i $count++$i{
  11095.             if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
  11096.                 ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
  11097.                 $result += ($array1[$i$array1[$i]($array2[$i$array2[$i]);
  11098.             }
  11099.         }
  11100.  
  11101.         return $result;
  11102.     }    //    function SUMX2PY2()
  11103.  
  11104.  
  11105.     /**
  11106.      * SUMXMY2
  11107.      *
  11108.      * @param    mixed    $value    Value to check
  11109.      * @return    float 
  11110.      */
  11111.     public static function SUMXMY2($matrixData1,$matrixData2{
  11112.         $array1 self::flattenArray($matrixData1);
  11113.         $array2 self::flattenArray($matrixData2);
  11114.         $count1 count($array1);
  11115.         $count2 count($array2);
  11116.         if ($count1 $count2{
  11117.             $count $count1;
  11118.         else {
  11119.             $count $count2;
  11120.         }
  11121.  
  11122.         $result 0;
  11123.         for ($i 0$i $count++$i{
  11124.             if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
  11125.                 ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
  11126.                 $result += ($array1[$i$array2[$i]($array1[$i$array2[$i]);
  11127.             }
  11128.         }
  11129.  
  11130.         return $result;
  11131.     }    //    function SUMXMY2()
  11132.  
  11133.  
  11134.     private static function _vlookupSort($a,$b{
  11135.         $firstColumn array_shift(array_keys($a));
  11136.         if (strtolower($a[$firstColumn]== strtolower($b[$firstColumn])) {
  11137.             return 0;
  11138.         }
  11139.         return (strtolower($a[$firstColumn]strtolower($b[$firstColumn])) ? -1;
  11140.     }    //    function _vlookupSort()
  11141.  
  11142.  
  11143.     /**
  11144.     * VLOOKUP
  11145.     * 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.
  11146.     * @param    lookup_value    The value that you want to match in lookup_array
  11147.     * @param    lookup_array    The range of cells being searched
  11148.     * @param    index_number    The column number in table_array from which the matching value must be returned. The first column is 1.
  11149.     * @param    not_exact_match    Determines if you are looking for an exact match based on lookup_value.
  11150.     * @return    mixed            The value of the found cell
  11151.     */
  11152.     public static function VLOOKUP($lookup_value$lookup_array$index_number$not_exact_match=true{
  11153.         // index_number must be greater than or equal to 1
  11154.         if ($index_number 1{
  11155.             return self::$_errorCodes['value'];
  11156.         }
  11157.  
  11158.         // index_number must be less than or equal to the number of columns in lookup_array
  11159.         if ((!is_array($lookup_array)) || (count($lookup_array1)) {
  11160.             return self::$_errorCodes['reference'];
  11161.         else {
  11162.             $firstRow array_pop(array_keys($lookup_array));
  11163.             if ((!is_array($lookup_array[$firstRow])) || ($index_number count($lookup_array[$firstRow]))) {
  11164.                 return self::$_errorCodes['reference'];
  11165.             else {
  11166.                 $columnKeys array_keys($lookup_array[$firstRow]);
  11167.                 $returnColumn $columnKeys[--$index_number];
  11168.                 $firstColumn array_shift($columnKeys);
  11169.             }
  11170.         }
  11171.  
  11172.         if (!$not_exact_match{
  11173.             uasort($lookup_array,array('self','_vlookupSort'));
  11174.         }
  11175.  
  11176.         $rowNumber $rowValue False;
  11177.         foreach($lookup_array as $rowKey => $rowData{
  11178.             if (strtolower($rowData[$firstColumn]strtolower($lookup_value)) {
  11179.                 break;
  11180.             }
  11181.             $rowNumber $rowKey;
  11182.             $rowValue $rowData[$firstColumn];
  11183.         }
  11184.  
  11185.         if ($rowNumber !== false{
  11186.             if ((!$not_exact_match&& ($rowValue != $lookup_value)) {
  11187.                 //    if an exact match is required, we have what we need to return an appropriate response
  11188.                 return self::$_errorCodes['na'];
  11189.             else {
  11190.                 //    otherwise return the appropriate value
  11191.                 return $lookup_array[$rowNumber][$returnColumn];
  11192.             }
  11193.         }
  11194.  
  11195.         return self::$_errorCodes['na'];
  11196.     }    //    function VLOOKUP()
  11197.  
  11198.  
  11199.     /**
  11200.      * LOOKUP
  11201.      * The LOOKUP function searches for value either from a one-row or one-column range or from an array.
  11202.      * @param    lookup_value    The value that you want to match in lookup_array
  11203.      * @param    lookup_vector    The range of cells being searched
  11204.      * @param    result_vector    The column from which the matching value must be returned
  11205.      * @return    mixed            The value of the found cell
  11206.      */
  11207.     public static function LOOKUP($lookup_value$lookup_vector$result_vector=null{
  11208.         $lookup_value    self::flattenSingleValue($lookup_value);
  11209.  
  11210.         if (!is_array($lookup_vector)) {
  11211.             return self::$_errorCodes['na'];
  11212.         }
  11213.         $lookupRows count($lookup_vector);
  11214.         $lookupColumns count($lookup_vector[array_shift(array_keys($lookup_vector))]);
  11215.         if ((($lookupRows == 1&& ($lookupColumns 1)) || (($lookupRows == 2&& ($lookupColumns != 2))) {
  11216.             $lookup_vector self::TRANSPOSE($lookup_vector);
  11217.             $lookupRows count($lookup_vector);
  11218.             $lookupColumns count($lookup_vector[array_shift(array_keys($lookup_vector))]);
  11219.         }
  11220.  
  11221.         if (is_null($result_vector)) {
  11222.             $result_vector $lookup_vector;
  11223.         }
  11224.         $resultRows count($result_vector);
  11225.         $resultColumns count($result_vector[array_shift(array_keys($result_vector))]);
  11226.         if ((($resultRows == 1&& ($resultColumns 1)) || (($resultRows == 2&& ($resultColumns != 2))) {
  11227.             $result_vector self::TRANSPOSE($result_vector);
  11228.             $resultRows count($result_vector);
  11229.             $resultColumns count($result_vector[array_shift(array_keys($result_vector))]);
  11230.         }
  11231.  
  11232.         if ($lookupRows == 2{
  11233.             $result_vector array_pop($lookup_vector);
  11234.             $lookup_vector array_shift($lookup_vector);
  11235.         }
  11236.         if ($lookupColumns != 2{
  11237.             foreach($lookup_vector as &$value{
  11238.                 if (is_array($value)) {
  11239.                     $key1 $key2 array_shift(array_keys($value));
  11240.                     $key2++;
  11241.                     $dataValue1 $value[$key1];
  11242.                 else {
  11243.                     $key1 0;
  11244.                     $key2 1;
  11245.                     $dataValue1 $value;
  11246.                 }
  11247.                 $dataValue2 array_shift($result_vector);
  11248.                 if (is_array($dataValue2)) {
  11249.                     $dataValue2 array_shift($dataValue2);
  11250.                 }
  11251.                 $value array($key1 => $dataValue1$key2 => $dataValue2);
  11252.             }
  11253.             unset($value);
  11254.         }
  11255.  
  11256.         return self::VLOOKUP($lookup_value,$lookup_vector,2);
  11257.      }    //    function LOOKUP()
  11258.  
  11259.  
  11260.     /**
  11261.      *    Convert a multi-dimensional array to a simple 1-dimensional array
  11262.      *
  11263.      *    @param    array    $array    Array to be flattened
  11264.      *    @return    array    Flattened array
  11265.      */
  11266.     public static function flattenArray($array{
  11267.         if (!is_array($array)) {
  11268.             return (array) $array;
  11269.         }
  11270.  
  11271.         $arrayValues array();
  11272.         foreach ($array as $value{
  11273.             if (is_array($value)) {
  11274.                 foreach ($value as $val{
  11275.                     if (is_array($val)) {
  11276.                         foreach ($val as $v{
  11277.                             $arrayValues[$v;
  11278.                         }
  11279.                     else {
  11280.                         $arrayValues[$val;
  11281.                     }
  11282.                 }
  11283.             else {
  11284.                 $arrayValues[$value;
  11285.             }
  11286.         }
  11287.  
  11288.         return $arrayValues;
  11289.     }    //    function flattenArray()
  11290.  
  11291.  
  11292.     /**
  11293.      *    Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing
  11294.      *
  11295.      *    @param    array    $array    Array to be flattened
  11296.      *    @return    array    Flattened array
  11297.      */
  11298.     public static function flattenArrayIndexed($array{
  11299.         if (!is_array($array)) {
  11300.             return (array) $array;
  11301.         }
  11302.  
  11303.         $arrayValues array();
  11304.         foreach ($array as $k1 => $value{
  11305.             if (is_array($value)) {
  11306.                 foreach ($value as $k2 => $val{
  11307.                     if (is_array($val)) {
  11308.                         foreach ($val as $k3 => $v{
  11309.                             $arrayValues[$k1.'.'.$k2.'.'.$k3$v;
  11310.                         }
  11311.                     else {
  11312.                         $arrayValues[$k1.'.'.$k2$val;
  11313.                     }
  11314.                 }
  11315.             else {
  11316.                 $arrayValues[$k1$value;
  11317.             }
  11318.         }
  11319.  
  11320.         return $arrayValues;
  11321.     }    //    function flattenArrayIndexed()
  11322.  
  11323.  
  11324.     /**
  11325.      *    Convert an array to a single scalar value by extracting the first element
  11326.      *
  11327.      *    @param    mixed        $value        Array or scalar value
  11328.      *    @return    mixed 
  11329.      */
  11330.     public static function flattenSingleValue($value ''{
  11331.         if (is_array($value)) {
  11332.             return self::flattenSingleValue(array_pop($value));
  11333.         }
  11334.         return $value;
  11335.     }    //    function flattenSingleValue()
  11336.  
  11337. }    //    class PHPExcel_Calculation_Functions
  11338.  
  11339.  
  11340. //
  11341. //    There are a few mathematical functions that aren't available on all versions of PHP for all platforms
  11342. //    These functions aren't available in Windows implementations of PHP prior to version 5.3.0
  11343. //    So we test if they do exist for this version of PHP/operating platform; and if not we create them
  11344. //
  11345. if (!function_exists('acosh')) {
  11346.     function acosh($x{
  11347.         return log(sqrt(($x 12sqrt(($x 12));
  11348.     }    //    function acosh()
  11349. }
  11350.  
  11351. if (!function_exists('asinh')) {
  11352.     function asinh($x{
  11353.         return log($x sqrt($x $x));
  11354.     }    //    function asinh()
  11355. }
  11356.  
  11357. if (!function_exists('atanh')) {
  11358.     function atanh($x{
  11359.         return (log($xlog($x)) 2;
  11360.     }    //    function atanh()
  11361. }
  11362.  
  11363. if (!function_exists('money_format')) {
  11364.     function money_format($format$number{
  11365.         $regex array'/%((?:[\^!\-]|\+|\(|\=.)*)([0-9]+)?(?:#([0-9]+))?',
  11366.                          '(?:\.([0-9]+))?([in%])/'
  11367.                       );
  11368.         $regex implode(''$regex);
  11369.         if (setlocale(LC_MONETARYnull== ''{
  11370.             setlocale(LC_MONETARY'');
  11371.         }
  11372.         $locale localeconv();
  11373.         $number floatval($number);
  11374.         if (!preg_match($regex$format$fmatch)) {
  11375.             trigger_error("No format specified or invalid format"E_USER_WARNING);
  11376.             return $number;
  11377.         }
  11378.         $flags array'fillchar'    => preg_match('/\=(.)/'$fmatch[1]$match$match[1' ',
  11379.                         'nogroup'    => preg_match('/\^/'$fmatch[1]0,
  11380.                         'usesignal'    => preg_match('/\+|\(/'$fmatch[1]$match$match[0'+',
  11381.                         'nosimbol'    => preg_match('/\!/'$fmatch[1]0,
  11382.                         'isleft'    => preg_match('/\-/'$fmatch[1]0
  11383.                       );
  11384.         $width    trim($fmatch[2]? (int)$fmatch[20;
  11385.         $left    trim($fmatch[3]? (int)$fmatch[30;
  11386.         $right    trim($fmatch[4]? (int)$fmatch[4$locale['int_frac_digits'];
  11387.         $conversion $fmatch[5];
  11388.         $positive true;
  11389.         if ($number 0{
  11390.             $positive false;
  11391.             $number *= -1;
  11392.         }
  11393.         $letter $positive 'p' 'n';
  11394.         $prefix $suffix $cprefix $csuffix $signal '';
  11395.         if (!$positive{
  11396.             $signal $locale['negative_sign'];
  11397.             switch (true{
  11398.                 case $locale['n_sign_posn'== || $flags['usesignal'== '(':
  11399.                     $prefix '(';
  11400.                     $suffix ')';
  11401.                     break;
  11402.                 case $locale['n_sign_posn'== 1:
  11403.                     $prefix $signal;
  11404.                     break;
  11405.                 case $locale['n_sign_posn'== 2:
  11406.                     $suffix $signal;
  11407.                     break;
  11408.                 case $locale['n_sign_posn'== 3:
  11409.                     $cprefix $signal;
  11410.                     break;
  11411.                 case $locale['n_sign_posn'== 4:
  11412.                     $csuffix $signal;
  11413.                     break;
  11414.             }
  11415.         }
  11416.         if (!$flags['nosimbol']{
  11417.             $currency $cprefix;
  11418.             $currency .= ($conversion == 'i' $locale['int_curr_symbol'$locale['currency_symbol']);
  11419.             $currency .= $csuffix;
  11420.             $currency iconv('ISO-8859-1','UTF-8',$currency);
  11421.         else {
  11422.             $currency '';
  11423.         }
  11424.         $space $locale["{$letter}_sep_by_space"' ' '';
  11425.  
  11426.         $number number_format($number$right$locale['mon_decimal_point']$flags['nogroup''' $locale['mon_thousands_sep');
  11427.         $number explode($locale['mon_decimal_point']$number);
  11428.  
  11429.         $n strlen($prefixstrlen($currency);
  11430.         if ($left && $left $n{
  11431.             if ($flags['isleft']{
  11432.                 $number[0.= str_repeat($flags['fillchar']$left $n);
  11433.             else {
  11434.                 $number[0str_repeat($flags['fillchar']$left $n$number[0];
  11435.             }
  11436.         }
  11437.         $number implode($locale['mon_decimal_point']$number);
  11438.         if ($locale["{$letter}_cs_precedes"]{
  11439.             $number $prefix $currency $space $number $suffix;
  11440.         else {
  11441.             $number $prefix $number $space $currency $suffix;
  11442.         }
  11443.         if ($width 0{
  11444.             $number str_pad($number$width$flags['fillchar']$flags['isleft'STR_PAD_RIGHT STR_PAD_LEFT);
  11445.         }
  11446.         $format str_replace($fmatch[0]$number$format);
  11447.         return $format;
  11448.     }    //    function money_format()
  11449. }
  11450.  
  11451.  
  11452. //
  11453. //    Strangely, PHP doesn't have a mb_str_replace multibyte function
  11454. //    As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set
  11455. //
  11456. if ((!function_exists('mb_str_replace')) &&
  11457.     (function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos'))) {
  11458.     function mb_str_replace($search$replace$subject{
  11459.         if(is_array($subject)) {
  11460.             $ret array();
  11461.             foreach($subject as $key => $val{
  11462.                 $ret[$keymb_str_replace($search$replace$val);
  11463.             }
  11464.             return $ret;
  11465.         }
  11466.  
  11467.         foreach((array) $search as $key => $s{
  11468.             if($s == ''{
  11469.                 continue;
  11470.             }
  11471.             $r !is_array($replace$replace (array_key_exists($key$replace$replace[$key'');
  11472.             $pos mb_strpos($subject$s0'UTF-8');
  11473.             while($pos !== false{
  11474.                 $subject mb_substr($subject0$pos'UTF-8'$r mb_substr($subject$pos mb_strlen($s'UTF-8')65535'UTF-8');
  11475.                 $pos mb_strpos($subject$s$pos mb_strlen($r'UTF-8')'UTF-8');
  11476.             }
  11477.         }
  11478.         return $subject;
  11479.     }
  11480. }

Documentation generated on Mon, 11 Jan 2010 08:10:57 +0100 by phpDocumentor 1.4.1