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 - 2009 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 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
  24.  * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
  25.  * @version        1.7.0, 2009-08-10
  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. /** XMININ */
  42. define('XMININ'2.23e-308);
  43.  
  44. /** MAX_ITERATIONS */
  45. define('MAX_ITERATIONS'150);
  46.  
  47. /** PRECISION */
  48. define('PRECISION'8.88E-016);
  49.  
  50. /** EULER */
  51. define('EULER'2.71828182845904523536);
  52.  
  53. $savedPrecision ini_get('precision');
  54. if ($savedPrecision 16{
  55.     ini_set('precision',16);
  56. }
  57.  
  58.  
  59. /** PHPExcel root directory */
  60. if (!defined('PHPEXCEL_ROOT')) {
  61.     /**
  62.      * @ignore
  63.      */
  64.     define('PHPEXCEL_ROOT'dirname(__FILE__'/../../');
  65. }
  66.  
  67. /** PHPExcel_Cell */
  68. require_once PHPEXCEL_ROOT 'PHPExcel/Cell.php';
  69.  
  70. /** PHPExcel_Cell_DataType */
  71. require_once PHPEXCEL_ROOT 'PHPExcel/Cell/DataType.php';
  72.  
  73. /** PHPExcel_Style_NumberFormat */
  74. require_once PHPEXCEL_ROOT 'PHPExcel/Style/NumberFormat.php';
  75.  
  76. /** PHPExcel_Shared_Date */
  77. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/Date.php';
  78.  
  79. /** Matrix */
  80. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/JAMA/Matrix.php';
  81. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/trend/trendClass.php';
  82.  
  83.  
  84. /**
  85.  * PHPExcel_Calculation_Functions
  86.  *
  87.  * @category    PHPExcel
  88.  * @package        PHPExcel_Calculation
  89.  * @copyright    Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
  90.  */
  91.  
  92.     /** constants */
  93.     const COMPATIBILITY_EXCEL        'Excel';
  94.     const COMPATIBILITY_GNUMERIC    'Gnumeric';
  95.     const COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc';
  96.  
  97.     const RETURNDATE_PHP_NUMERIC    'P';
  98.     const RETURNDATE_PHP_OBJECT        'O';
  99.     const RETURNDATE_EXCEL            'E';
  100.  
  101.  
  102.     /**
  103.      *    Compatibility mode to use for error checking and responses
  104.      *
  105.      *    @access    private
  106.      *    @var string 
  107.      */
  108.     private static $compatibilityMode    self::COMPATIBILITY_EXCEL;
  109.  
  110.     /**
  111.      *    Data Type to use when returning date values
  112.      *
  113.      *    @access    private
  114.      *    @var integer 
  115.      */
  116.     private static $ReturnDateType    self::RETURNDATE_EXCEL;
  117.  
  118.     /**
  119.      *    List of error codes
  120.      *
  121.      *    @access    private
  122.      *    @var array 
  123.      */
  124.     private static $_errorCodes    array'null'                => '#NULL!',
  125.                                          'divisionbyzero'    => '#DIV/0!',
  126.                                          'value'            => '#VALUE!',
  127.                                          'reference'        => '#REF!',
  128.                                          'name'                => '#NAME?',
  129.                                          'num'                => '#NUM!',
  130.                                          'na'                => '#N/A',
  131.                                          'gettingdata'        => '#GETTING_DATA'
  132.                                        );
  133.  
  134.  
  135.     /**
  136.      *    Set the Compatibility Mode
  137.      *
  138.      *    @access    public
  139.      *    @category Function Configuration
  140.      *    @param     string        $compatibilityMode        Compatibility Mode
  141.      *                                                 Permitted values are:
  142.      *                                                     PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL            'Excel'
  143.      *                                                     PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
  144.      *                                                     PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
  145.      *    @return     boolean    (Success or Failure)
  146.      */
  147.     public static function setCompatibilityMode($compatibilityMode{
  148.         if (($compatibilityMode == self::COMPATIBILITY_EXCEL||
  149.             ($compatibilityMode == self::COMPATIBILITY_GNUMERIC||
  150.             ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  151.             self::$compatibilityMode $compatibilityMode;
  152.             return True;
  153.         }
  154.         return False;
  155.     }    //    function setCompatibilityMode()
  156.  
  157.  
  158.     /**
  159.      *    Return the current Compatibility Mode
  160.      *
  161.      *    @access    public
  162.      *    @category Function Configuration
  163.      *    @return     string        Compatibility Mode
  164.      *                             Possible Return values are:
  165.      *                                 PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL            'Excel'
  166.      *                                 PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
  167.      *                                 PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
  168.      */
  169.     public static function getCompatibilityMode({
  170.         return self::$compatibilityMode;
  171.     }    //    function getCompatibilityMode()
  172.  
  173.  
  174.     /**
  175.      *    Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
  176.      *
  177.      *    @access    public
  178.      *    @category Function Configuration
  179.      *    @param     string    $returnDateType            Return Date Format
  180.      *                                                 Permitted values are:
  181.      *                                                     PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC        'P'
  182.      *                                                     PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT        'O'
  183.      *                                                     PHPExcel_Calculation_Functions::RETURNDATE_EXCEL            'E'
  184.      *    @return     boolean                            Success or failure
  185.      */
  186.     public static function setReturnDateType($returnDateType{
  187.         if (($returnDateType == self::RETURNDATE_PHP_NUMERIC||
  188.             ($returnDateType == self::RETURNDATE_PHP_OBJECT||
  189.             ($returnDateType == self::RETURNDATE_EXCEL)) {
  190.             self::$ReturnDateType $returnDateType;
  191.             return True;
  192.         }
  193.         return False;
  194.     }    //    function setReturnDateType()
  195.  
  196.  
  197.     /**
  198.      *    Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
  199.      *
  200.      *    @access    public
  201.      *    @category Function Configuration
  202.      *    @return     string        Return Date Format
  203.      *                             Possible Return values are:
  204.      *                                 PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC        'P'
  205.      *                                 PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT        'O'
  206.      *                                 PHPExcel_Calculation_Functions::RETURNDATE_EXCEL            'E'
  207.      */
  208.     public static function getReturnDateType({
  209.         return self::$ReturnDateType;
  210.     }    //    function getReturnDateType()
  211.  
  212.  
  213.     /**
  214.      *    DUMMY
  215.      *
  216.      *    @access    public
  217.      *    @category Error Returns
  218.      *    @return    string    #Not Yet Implemented
  219.      */
  220.     public static function DUMMY({
  221.         return '#Not Yet Implemented';
  222.     }    //    function DUMMY()
  223.  
  224.  
  225.     /**
  226.      *    NA
  227.      *
  228.      *    @access    public
  229.      *    @category Error Returns
  230.      *    @return    string    #N/A!
  231.      */
  232.     public static function NA({
  233.         return self::$_errorCodes['na'];
  234.     }    //    function NA()
  235.  
  236.  
  237.     /**
  238.      *    NAN
  239.      *
  240.      *    @access    public
  241.      *    @category Error Returns
  242.      *    @return    string    #NUM!
  243.      */
  244.     public static function NaN({
  245.         return self::$_errorCodes['num'];
  246.     }    //    function NAN()
  247.  
  248.  
  249.     /**
  250.      *    NAME
  251.      *
  252.      *    @access    public
  253.      *    @category Error Returns
  254.      *    @return    string    #NAME!
  255.      */
  256.     public static function NAME({
  257.         return self::$_errorCodes['name'];
  258.     }    //    function NAME()
  259.  
  260.  
  261.     /**
  262.      *    REF
  263.      *
  264.      *    @access    public
  265.      *    @category Error Returns
  266.      *    @return    string    #REF!
  267.      */
  268.     public static function REF({
  269.         return self::$_errorCodes['reference'];
  270.     }    //    function REF()
  271.  
  272.  
  273.     /**
  274.      *    LOGICAL_AND
  275.      *
  276.      *    Returns boolean TRUE if all its arguments are TRUE; returns FALSE if one or more argument is FALSE.
  277.      *
  278.      *    Excel Function:
  279.      *        AND(logical1[,logical2[, ...]])
  280.      *
  281.      *        The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
  282.      *            or references that contain logical values.
  283.      *
  284.      *        Booleans arguments are treated as True or False as appropriate
  285.      *        Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  286.      *        If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds the value TRUE or FALSE,
  287.      *            holds the value TRUE or FALSE, in which case it is evaluated as a boolean
  288.      *
  289.      *    @access    public
  290.      *    @category Logical Functions
  291.      *    @param    mixed        $arg,...        Data values
  292.      *    @return    boolean        The logical AND of the arguments.
  293.      */
  294.     public static function LOGICAL_AND({
  295.         // Return value
  296.         $returnValue True;
  297.  
  298.         // Loop through the arguments
  299.         $aArgs self::flattenArray(func_get_args());
  300.         $argCount 0;
  301.         foreach ($aArgs as $arg{
  302.             // Is it a boolean value?
  303.             if (is_bool($arg)) {
  304.                 $returnValue $returnValue && $arg;
  305.                 ++$argCount;
  306.             elseif ((is_numeric($arg)) && (!is_string($arg))) {
  307.                 $returnValue $returnValue && ($arg != 0);
  308.                 ++$argCount;
  309.             elseif (is_string($arg)) {
  310.                 $arg strtoupper($arg);
  311.                 if ($arg == 'TRUE'{
  312.                     $arg 1;
  313.                 elseif ($arg == 'FALSE'{
  314.                     $arg 0;
  315.                 else {
  316.                     return self::$_errorCodes['value'];
  317.                 }
  318.                 $returnValue $returnValue && ($arg != 0);
  319.                 ++$argCount;
  320.             }
  321.         }
  322.  
  323.         // Return
  324.         if ($argCount == 0{
  325.             return self::$_errorCodes['value'];
  326.         }
  327.         return $returnValue;
  328.     }    //    function LOGICAL_AND()
  329.  
  330.  
  331.     /**
  332.      *    LOGICAL_OR
  333.      *
  334.      *    Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE.
  335.      *
  336.      *    Excel Function:
  337.      *        OR(logical1[,logical2[, ...]])
  338.      *
  339.      *        The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
  340.      *            or references that contain logical values.
  341.      *
  342.      *        Booleans arguments are treated as True or False as appropriate
  343.      *        Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  344.      *        If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string
  345.      *            holds the value TRUE or FALSE, in which case it is evaluated as a boolean
  346.      *
  347.      *    @access    public
  348.      *    @category Logical Functions
  349.      *    @param    mixed        $arg,...        Data values
  350.      *    @return    boolean        The logical OR of the arguments.
  351.      */
  352.     public static function LOGICAL_OR({
  353.         // Return value
  354.         $returnValue False;
  355.  
  356.         // Loop through the arguments
  357.         $aArgs self::flattenArray(func_get_args());
  358.         $argCount 0;
  359.         foreach ($aArgs as $arg{
  360.             // Is it a boolean value?
  361.             if (is_bool($arg)) {
  362.                 $returnValue $returnValue || $arg;
  363.                 ++$argCount;
  364.             elseif ((is_numeric($arg)) && (!is_string($arg))) {
  365.                 $returnValue $returnValue || ($arg != 0);
  366.                 ++$argCount;
  367.             elseif (is_string($arg)) {
  368.                 $arg strtoupper($arg);
  369.                 if ($arg == 'TRUE'{
  370.                     $arg 1;
  371.                 elseif ($arg == 'FALSE'{
  372.                     $arg 0;
  373.                 else {
  374.                     return self::$_errorCodes['value'];
  375.                 }
  376.                 $returnValue $returnValue || ($arg != 0);
  377.                 ++$argCount;
  378.             }
  379.         }
  380.  
  381.         // Return
  382.         if ($argCount == 0{
  383.             return self::$_errorCodes['value'];
  384.         }
  385.         return $returnValue;
  386.     }    //    function LOGICAL_OR()
  387.  
  388.  
  389.     /**
  390.      *    LOGICAL_FALSE
  391.      *
  392.      *    Returns the boolean FALSE.
  393.      *
  394.      *    Excel Function:
  395.      *        FALSE()
  396.      *
  397.      *    @access    public
  398.      *    @category Logical Functions
  399.      *    @return    boolean        False
  400.      */
  401.     public static function LOGICAL_FALSE({
  402.         return False;
  403.     }    //    function LOGICAL_FALSE()
  404.  
  405.  
  406.     /**
  407.      *    LOGICAL_TRUE
  408.      *
  409.      *    Returns the boolean TRUE.
  410.      *
  411.      *    Excel Function:
  412.      *        TRUE()
  413.      *
  414.      *    @access    public
  415.      *    @category Logical Functions
  416.      *    @return    boolean        True
  417.      */
  418.     public static function LOGICAL_TRUE({
  419.         return True;
  420.     }    //    function LOGICAL_TRUE()
  421.  
  422.  
  423.     /**
  424.      *    LOGICAL_NOT
  425.      *
  426.      *    Returns the boolean inverse of the argument.
  427.      *
  428.      *    Excel Function:
  429.      *        NOT(logical)
  430.      *
  431.      *    @access    public
  432.      *    @category Logical Functions
  433.      *    @param    mixed        $logical    A value or expression that can be evaluated to TRUE or FALSE
  434.      *    @return    boolean        The boolean inverse of the argument.
  435.      */
  436.     public static function LOGICAL_NOT($logical{
  437.         return !$logical;
  438.     }    //    function LOGICAL_NOT()
  439.  
  440.  
  441.     /**
  442.      *    STATEMENT_IF
  443.      *
  444.      *    Returns one value if a condition you specify evaluates to TRUE and another value if it evaluates to FALSE.
  445.      *
  446.      *    Excel Function:
  447.      *        IF(condition[,returnIfTrue[,returnIfFalse]])
  448.      *
  449.      *        Condition is any value or expression that can be evaluated to TRUE or FALSE.
  450.      *            For example, A10=100 is a logical expression; if the value in cell A10 is equal to 100,
  451.      *            the expression evaluates to TRUE. Otherwise, the expression evaluates to FALSE.
  452.      *            This argument can use any comparison calculation operator.
  453.      *        ReturnIfTrue is the value that is returned if condition evaluates to TRUE.
  454.      *            For example, if this argument is the text string "Within budget" and the condition argument evaluates to TRUE,
  455.      *            then the IF function returns the text "Within budget"
  456.      *            If condition is TRUE and ReturnIfTrue is blank, this argument returns 0 (zero). To display the word TRUE, use
  457.      *            the logical value TRUE for this argument.
  458.      *            ReturnIfTrue can be another formula.
  459.      *        ReturnIfFalse is the value that is returned if condition evaluates to FALSE.
  460.      *            For example, if this argument is the text string "Over budget" and the condition argument evaluates to FALSE,
  461.      *            then the IF function returns the text "Over budget".
  462.      *            If condition is FALSE and ReturnIfFalse is omitted, then the logical value FALSE is returned.
  463.      *            If condition is FALSE and ReturnIfFalse is blank, then the value 0 (zero) is returned.
  464.      *            ReturnIfFalse can be another formula.
  465.      *
  466.      *    @param    mixed    $condition        Condition to evaluate
  467.      *    @param    mixed    $returnIfTrue    Value to return when condition is true
  468.      *    @param    mixed    $returnIfFalse    Value to return when condition is false
  469.      *    @return    mixed    The value of returnIfTrue or returnIfFalse determined by condition
  470.      */
  471.     public static function STATEMENT_IF($condition true$returnIfTrue 0$returnIfFalse False{
  472.         $condition        self::flattenSingleValue($condition);
  473.         $returnIfTrue    self::flattenSingleValue($returnIfTrue);
  474.         $returnIfFalse    self::flattenSingleValue($returnIfFalse);
  475.         if (is_null($returnIfTrue)) $returnIfTrue 0}
  476.         if (is_null($returnIfFalse)) $returnIfFalse 0}
  477.  
  478.         return ($condition $returnIfTrue $returnIfFalse);
  479.     }    //    function STATEMENT_IF()
  480.  
  481.  
  482.     /**
  483.      *    STATEMENT_IFERROR
  484.      *
  485.      *    @param    mixed    $value        Value to check , is also value when no error
  486.      *    @param    mixed    $errorpart    Value when error
  487.      *    @return    mixed 
  488.      */
  489.     public static function STATEMENT_IFERROR($value ''$errorpart ''{
  490.         return self::STATEMENT_IF(self::IS_ERROR($value)$errorpart$value);
  491.     }    //    function STATEMENT_IFERROR()
  492.  
  493.  
  494.     /**
  495.      *    ATAN2
  496.      *
  497.      *    This function calculates the arc tangent of the two variables x and y. It is similar to
  498.      *        calculating the arc tangent of y ÷ x, except that the signs of both arguments are used
  499.      *        to determine the quadrant of the result.
  500.      *    The arctangent is the angle from the x-axis to a line containing the origin (0, 0) and a
  501.      *        point with coordinates (xCoordinate, yCoordinate). The angle is given in radians between
  502.      *        -pi and pi, excluding -pi.
  503.      *
  504.      *    Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard
  505.      *        PHP atan2() function, so we need to reverse them here before calling the PHP atan() function.
  506.      *
  507.      *    Excel Function:
  508.      *        ATAN2(xCoordinate,yCoordinate)
  509.      *
  510.      *    @access    public
  511.      *    @category Mathematical and Trigonometric Functions
  512.      *    @param    float    $xCoordinate        The x-coordinate of the point.
  513.      *    @param    float    $yCoordinate        The y-coordinate of the point.
  514.      *    @return    float    The inverse tangent of the specified x- and y-coordinates.
  515.      */
  516.     public static function REVERSE_ATAN2($xCoordinate$yCoordinate{
  517.         $xCoordinate    = (float) self::flattenSingleValue($xCoordinate);
  518.         $yCoordinate    = (float) self::flattenSingleValue($yCoordinate);
  519.  
  520.         if (($xCoordinate == 0&& ($yCoordinate == 0)) {
  521.             return self::$_errorCodes['divisionbyzero'];
  522.         }
  523.  
  524.         return atan2($yCoordinate$xCoordinate);
  525.     }    //    function REVERSE_ATAN2()
  526.  
  527.  
  528.     /**
  529.      *    LOG_BASE
  530.      *
  531.      *    Returns the logarithm of a number to a specified base. The default base is 10.
  532.      *
  533.      *    Excel Function:
  534.      *        LOG(number[,base])
  535.      *
  536.      *    @access    public
  537.      *    @category Mathematical and Trigonometric Functions
  538.      *    @param    float    $value        The positive real number for which you want the logarithm
  539.      *    @param    float    $base        The base of the logarithm. If base is omitted, it is assumed to be 10.
  540.      *    @return    float 
  541.      */
  542.     public static function LOG_BASE($number$base=10{
  543.         $number    self::flattenSingleValue($number);
  544.         $base    self::flattenSingleValue($base);
  545.  
  546.         return log($number$base);
  547.     }    //    function LOG_BASE()
  548.  
  549.  
  550.     /**
  551.      *    SUM
  552.      *
  553.      *    SUM computes the sum of all the values and cells referenced in the argument list.
  554.      *
  555.      *    Excel Function:
  556.      *        SUM(value1[,value2[, ...]])
  557.      *
  558.      *    @access    public
  559.      *    @category Mathematical and Trigonometric Functions
  560.      *    @param    mixed        $arg,...        Data values
  561.      *    @return    float 
  562.      */
  563.     public static function SUM({
  564.         // Return value
  565.         $returnValue 0;
  566.  
  567.         // Loop through the arguments
  568.         $aArgs self::flattenArray(func_get_args());
  569.         foreach ($aArgs as $arg{
  570.             // Is it a numeric value?
  571.             if ((is_numeric($arg)) && (!is_string($arg))) {
  572.                 $returnValue += $arg;
  573.             }
  574.         }
  575.  
  576.         // Return
  577.         return $returnValue;
  578.     }    //    function SUM()
  579.  
  580.  
  581.     /**
  582.      *    SUMSQ
  583.      *
  584.      *    SUMSQ returns the sum of the squares of the arguments
  585.      *
  586.      *    Excel Function:
  587.      *        SUMSQ(value1[,value2[, ...]])
  588.      *
  589.      *    @access    public
  590.      *    @category Mathematical and Trigonometric Functions
  591.      *    @param    mixed        $arg,...        Data values
  592.      *    @return    float 
  593.      */
  594.     public static function SUMSQ({
  595.         // Return value
  596.         $returnValue 0;
  597.  
  598.         // Loop trough arguments
  599.         $aArgs self::flattenArray(func_get_args());
  600.         foreach ($aArgs as $arg{
  601.             // Is it a numeric value?
  602.             if ((is_numeric($arg)) && (!is_string($arg))) {
  603.                 $returnValue += pow($arg,2);
  604.             }
  605.         }
  606.  
  607.         // Return
  608.         return $returnValue;
  609.     }    //    function SUMSQ()
  610.  
  611.  
  612.     /**
  613.      *    PRODUCT
  614.      *
  615.      *    PRODUCT returns the product of all the values and cells referenced in the argument list.
  616.      *
  617.      *    Excel Function:
  618.      *        PRODUCT(value1[,value2[, ...]])
  619.      *
  620.      *    @access    public
  621.      *    @category Mathematical and Trigonometric Functions
  622.      *    @param    mixed        $arg,...        Data values
  623.      *    @return    float 
  624.      */
  625.     public static function PRODUCT({
  626.         // Return value
  627.         $returnValue null;
  628.  
  629.         // Loop trough arguments
  630.         $aArgs self::flattenArray(func_get_args());
  631.         foreach ($aArgs as $arg{
  632.             // Is it a numeric value?
  633.             if ((is_numeric($arg)) && (!is_string($arg))) {
  634.                 if (is_null($returnValue)) {
  635.                     $returnValue $arg;
  636.                 else {
  637.                     $returnValue *= $arg;
  638.                 }
  639.             }
  640.         }
  641.  
  642.         // Return
  643.         if (is_null($returnValue)) {
  644.             return 0;
  645.         }
  646.         return $returnValue;
  647.     }    //    function PRODUCT()
  648.  
  649.  
  650.     /**
  651.      *    QUOTIENT
  652.      *
  653.      *    QUOTIENT function returns the integer portion of a division. Numerator is the divided number
  654.      *        and denominator is the divisor.
  655.      *
  656.      *    Excel Function:
  657.      *        QUOTIENT(value1[,value2[, ...]])
  658.      *
  659.      *    @access    public
  660.      *    @category Mathematical and Trigonometric Functions
  661.      *    @param    mixed        $arg,...        Data values
  662.      *    @return    float 
  663.      */
  664.     public static function QUOTIENT({
  665.         // Return value
  666.         $returnValue null;
  667.  
  668.         // Loop trough arguments
  669.         $aArgs self::flattenArray(func_get_args());
  670.         foreach ($aArgs as $arg{
  671.             // Is it a numeric value?
  672.             if ((is_numeric($arg)) && (!is_string($arg))) {
  673.                 if (is_null($returnValue)) {
  674.                     $returnValue ($arg == 0$arg;
  675.                 else {
  676.                     if (($returnValue == 0|| ($arg == 0)) {
  677.                         $returnValue 0;
  678.                     else {
  679.                         $returnValue /= $arg;
  680.                     }
  681.                 }
  682.             }
  683.         }
  684.  
  685.         // Return
  686.         return intval($returnValue);
  687.     }    //    function QUOTIENT()
  688.  
  689.  
  690.     /**
  691.      *    MIN
  692.      *
  693.      *    MIN returns the value of the element of the values passed that has the smallest value,
  694.      *        with negative numbers considered smaller than positive numbers.
  695.      *
  696.      *    Excel Function:
  697.      *        MIN(value1[,value2[, ...]])
  698.      *
  699.      *    @access    public
  700.      *    @category Statistical Functions
  701.      *    @param    mixed        $arg,...        Data values
  702.      *    @return    float 
  703.      */
  704.     public static function MIN({
  705.         // Return value
  706.         $returnValue null;
  707.  
  708.         // Loop trough arguments
  709.         $aArgs self::flattenArray(func_get_args());
  710.         foreach ($aArgs as $arg{
  711.             // Is it a numeric value?
  712.             if ((is_numeric($arg)) && (!is_string($arg))) {
  713.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  714.                     $returnValue $arg;
  715.                 }
  716.             }
  717.         }
  718.  
  719.         // Return
  720.         if(is_null($returnValue)) {
  721.             return 0;
  722.         }
  723.         return $returnValue;
  724.     }    //    function MIN()
  725.  
  726.  
  727.     /**
  728.      *    MINA
  729.      *
  730.      *    Returns the smallest value in a list of arguments, including numbers, text, and logical values
  731.      *
  732.      *    Excel Function:
  733.      *        MINA(value1[,value2[, ...]])
  734.      *
  735.      *    @access    public
  736.      *    @category Statistical Functions
  737.      *    @param    mixed        $arg,...        Data values
  738.      *    @return    float 
  739.      */
  740.     public static function MINA({
  741.         // Return value
  742.         $returnValue null;
  743.  
  744.         // Loop through arguments
  745.         $aArgs self::flattenArray(func_get_args());
  746.         foreach ($aArgs as $arg{
  747.             // Is it a numeric value?
  748.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  749.                 if (is_bool($arg)) {
  750.                     $arg = (integer) $arg;
  751.                 elseif (is_string($arg)) {
  752.                     $arg 0;
  753.                 }
  754.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  755.                     $returnValue $arg;
  756.                 }
  757.             }
  758.         }
  759.  
  760.         // Return
  761.         if(is_null($returnValue)) {
  762.             return 0;
  763.         }
  764.         return $returnValue;
  765.     }    //    function MINA()
  766.  
  767.  
  768.     /**
  769.      *    SMALL
  770.      *
  771.      *    Returns the nth smallest value in a data set. You can use this function to
  772.      *        select a value based on its relative standing.
  773.      *
  774.      *    Excel Function:
  775.      *        SMALL(value1[,value2[, ...]],entry)
  776.      *
  777.      *    @access    public
  778.      *    @category Statistical Functions
  779.      *    @param    mixed        $arg,...        Data values
  780.      *    @param    int            $entry            Position (ordered from the smallest) in the array or range of data to return
  781.      *    @return    float 
  782.      */
  783.     public static function SMALL({
  784.         $aArgs self::flattenArray(func_get_args());
  785.  
  786.         // Calculate
  787.         $n array_pop($aArgs);
  788.  
  789.         if ((is_numeric($n)) && (!is_string($n))) {
  790.             $mArgs array();
  791.             foreach ($aArgs as $arg{
  792.                 // Is it a numeric value?
  793.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  794.                     $mArgs[$arg;
  795.                 }
  796.             }
  797.             $count self::COUNT($mArgs);
  798.             $n floor(--$n);
  799.             if (($n 0|| ($n >= $count|| ($count == 0)) {
  800.                 return self::$_errorCodes['num'];
  801.             }
  802.             sort($mArgs);
  803.             return $mArgs[$n];
  804.         }
  805.         return self::$_errorCodes['value'];
  806.     }    //    function SMALL()
  807.  
  808.  
  809.     /**
  810.      *    MAX
  811.      *
  812.      *    MAX returns the value of the element of the values passed that has the highest value,
  813.      *        with negative numbers considered smaller than positive numbers.
  814.      *
  815.      *    Excel Function:
  816.      *        MAX(value1[,value2[, ...]])
  817.      *
  818.      *    @access    public
  819.      *    @category Statistical Functions
  820.      *    @param    mixed        $arg,...        Data values
  821.      *    @return    float 
  822.      */
  823.     public static function MAX({
  824.         // Return value
  825.         $returnValue null;
  826.  
  827.         // Loop trough arguments
  828.         $aArgs self::flattenArray(func_get_args());
  829.         foreach ($aArgs as $arg{
  830.             // Is it a numeric value?
  831.             if ((is_numeric($arg)) && (!is_string($arg))) {
  832.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  833.                     $returnValue $arg;
  834.                 }
  835.             }
  836.         }
  837.  
  838.         // Return
  839.         if(is_null($returnValue)) {
  840.             return 0;
  841.         }
  842.         return $returnValue;
  843.     }    //    function MAX()
  844.  
  845.  
  846.     /**
  847.      *    MAXA
  848.      *
  849.      *    Returns the greatest value in a list of arguments, including numbers, text, and logical values
  850.      *
  851.      *    Excel Function:
  852.      *        MAXA(value1[,value2[, ...]])
  853.      *
  854.      *    @access    public
  855.      *    @category Statistical Functions
  856.      *    @param    mixed        $arg,...        Data values
  857.      *    @return    float 
  858.      */
  859.     public static function MAXA({
  860.         // Return value
  861.         $returnValue null;
  862.  
  863.         // Loop through arguments
  864.         $aArgs self::flattenArray(func_get_args());
  865.         foreach ($aArgs as $arg{
  866.             // Is it a numeric value?
  867.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  868.                 if (is_bool($arg)) {
  869.                     $arg = (integer) $arg;
  870.                 elseif (is_string($arg)) {
  871.                     $arg 0;
  872.                 }
  873.                 if ((is_null($returnValue)) || ($arg $returnValue)) {
  874.                     $returnValue $arg;
  875.                 }
  876.             }
  877.         }
  878.  
  879.         // Return
  880.         if(is_null($returnValue)) {
  881.             return 0;
  882.         }
  883.         return $returnValue;
  884.     }    //    function MAXA()
  885.  
  886.  
  887.     /**
  888.      *    LARGE
  889.      *
  890.      *    Returns the nth largest value in a data set. You can use this function to
  891.      *        select a value based on its relative standing.
  892.      *
  893.      *    Excel Function:
  894.      *        LARGE(value1[,value2[, ...]],entry)
  895.      *
  896.      *    @access    public
  897.      *    @category Statistical Functions
  898.      *    @param    mixed        $arg,...        Data values
  899.      *    @param    int            $entry            Position (ordered from the largest) in the array or range of data to return
  900.      *    @return    float 
  901.      *
  902.      */
  903.     public static function LARGE({
  904.         $aArgs self::flattenArray(func_get_args());
  905.  
  906.         // Calculate
  907.         $n floor(array_pop($aArgs));
  908.  
  909.         if ((is_numeric($n)) && (!is_string($n))) {
  910.             $mArgs array();
  911.             foreach ($aArgs as $arg{
  912.                 // Is it a numeric value?
  913.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  914.                     $mArgs[$arg;
  915.                 }
  916.             }
  917.             $count self::COUNT($mArgs);
  918.             $n floor(--$n);
  919.             if (($n 0|| ($n >= $count|| ($count == 0)) {
  920.                 return self::$_errorCodes['num'];
  921.             }
  922.             rsort($mArgs);
  923.             return $mArgs[$n];
  924.         }
  925.         return self::$_errorCodes['value'];
  926.     }    //    function LARGE()
  927.  
  928.  
  929.     /**
  930.      *    PERCENTILE
  931.      *
  932.      *    Returns the nth percentile of values in a range..
  933.      *
  934.      *    Excel Function:
  935.      *        PERCENTILE(value1[,value2[, ...]],entry)
  936.      *
  937.      *    @access    public
  938.      *    @category Statistical Functions
  939.      *    @param    mixed        $arg,...        Data values
  940.      *    @param    float        $entry            Percentile value in the range 0..1, inclusive.
  941.      *    @return    float 
  942.      */
  943.     public static function PERCENTILE({
  944.         $aArgs self::flattenArray(func_get_args());
  945.  
  946.         // Calculate
  947.         $entry array_pop($aArgs);
  948.  
  949.         if ((is_numeric($entry)) && (!is_string($entry))) {
  950.             if (($entry 0|| ($entry 1)) {
  951.                 return self::$_errorCodes['num'];
  952.             }
  953.             $mArgs array();
  954.             foreach ($aArgs as $arg{
  955.                 // Is it a numeric value?
  956.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  957.                     $mArgs[$arg;
  958.                 }
  959.             }
  960.             $mValueCount count($mArgs);
  961.             if ($mValueCount 0{
  962.                 sort($mArgs);
  963.                 $count self::COUNT($mArgs);
  964.                 $index $entry ($count-1);
  965.                 $iBase floor($index);
  966.                 if ($index == $iBase{
  967.                     return $mArgs[$index];
  968.                 else {
  969.                     $iNext $iBase 1;
  970.                     $iProportion $index $iBase;
  971.                     return $mArgs[$iBase(($mArgs[$iNext$mArgs[$iBase]$iProportion;
  972.                 }
  973.             }
  974.         }
  975.         return self::$_errorCodes['value'];
  976.     }    //    function PERCENTILE()
  977.  
  978.  
  979.     /**
  980.      *    QUARTILE
  981.      *
  982.      *    Returns the quartile of a data set.
  983.      *
  984.      *    Excel Function:
  985.      *        QUARTILE(value1[,value2[, ...]],entry)
  986.      *
  987.      *    @access    public
  988.      *    @category Statistical Functions
  989.      *    @param    mixed        $arg,...        Data values
  990.      *    @param    int            $entry            Quartile value in the range 1..3, inclusive.
  991.      *    @return    float 
  992.      */
  993.     public static function QUARTILE({
  994.         $aArgs self::flattenArray(func_get_args());
  995.  
  996.         // Calculate
  997.         $entry floor(array_pop($aArgs));
  998.  
  999.         if ((is_numeric($entry)) && (!is_string($entry))) {
  1000.             $entry /= 4;
  1001.             if (($entry 0|| ($entry 1)) {
  1002.                 return self::$_errorCodes['num'];
  1003.             }
  1004.             return self::PERCENTILE($aArgs,$entry);
  1005.         }
  1006.         return self::$_errorCodes['value'];
  1007.     }    //    function QUARTILE()
  1008.  
  1009.  
  1010.     /**
  1011.      *    COUNT
  1012.      *
  1013.      *    Counts the number of cells that contain numbers within the list of arguments
  1014.      *
  1015.      *    Excel Function:
  1016.      *        COUNT(value1[,value2[, ...]])
  1017.      *
  1018.      *    @access    public
  1019.      *    @category Statistical Functions
  1020.      *    @param    mixed        $arg,...        Data values
  1021.      *    @return    int 
  1022.      */
  1023.     public static function COUNT({
  1024.         // Return value
  1025.         $returnValue 0;
  1026.  
  1027.         // Loop trough arguments
  1028.         $aArgs self::flattenArray(func_get_args());
  1029.         foreach ($aArgs as $arg{
  1030.             if ((is_bool($arg)) && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  1031.                 $arg = (int) $arg;
  1032.             }
  1033.             // Is it a numeric value?
  1034.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1035.                 ++$returnValue;
  1036.             }
  1037.         }
  1038.  
  1039.         // Return
  1040.         return $returnValue;
  1041.     }    //    function COUNT()
  1042.  
  1043.  
  1044.     /**
  1045.      *    COUNTBLANK
  1046.      *
  1047.      *    Counts the number of empty cells within the list of arguments
  1048.      *
  1049.      *    Excel Function:
  1050.      *        COUNTBLANK(value1[,value2[, ...]])
  1051.      *
  1052.      *    @access    public
  1053.      *    @category Statistical Functions
  1054.      *    @param    mixed        $arg,...        Data values
  1055.      *    @return    int 
  1056.      */
  1057.     public static function COUNTBLANK({
  1058.         // Return value
  1059.         $returnValue 0;
  1060.  
  1061.         // Loop trough arguments
  1062.         $aArgs self::flattenArray(func_get_args());
  1063.         foreach ($aArgs as $arg{
  1064.             // Is it a blank cell?
  1065.             if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) {
  1066.                 ++$returnValue;
  1067.             }
  1068.         }
  1069.  
  1070.         // Return
  1071.         return $returnValue;
  1072.     }    //    function COUNTBLANK()
  1073.  
  1074.  
  1075.     /**
  1076.      *    COUNTA
  1077.      *
  1078.      *    Counts the number of cells that are not empty within the list of arguments
  1079.      *
  1080.      *    Excel Function:
  1081.      *        COUNTA(value1[,value2[, ...]])
  1082.      *
  1083.      *    @access    public
  1084.      *    @category Statistical Functions
  1085.      *    @param    mixed        $arg,...        Data values
  1086.      *    @return    int 
  1087.      */
  1088.     public static function COUNTA({
  1089.         // Return value
  1090.         $returnValue 0;
  1091.  
  1092.         // Loop through arguments
  1093.         $aArgs self::flattenArray(func_get_args());
  1094.         foreach ($aArgs as $arg{
  1095.             // Is it a numeric, boolean or string value?
  1096.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  1097.                 ++$returnValue;
  1098.             }
  1099.         }
  1100.  
  1101.         // Return
  1102.         return $returnValue;
  1103.     }    //    function COUNTA()
  1104.  
  1105.  
  1106.     /**
  1107.      *    COUNTIF
  1108.      *
  1109.      *    Counts the number of cells that contain numbers within the list of arguments
  1110.      *
  1111.      *    Excel Function:
  1112.      *        COUNTIF(value1[,value2[, ...]],condition)
  1113.      *
  1114.      *    @access    public
  1115.      *    @category Statistical Functions
  1116.      *    @param    mixed        $arg,...        Data values
  1117.      *    @param    string        $condition        The criteria that defines which cells will be counted.
  1118.      *    @return    int 
  1119.      */
  1120.     public static function COUNTIF($aArgs,$condition{
  1121.         // Return value
  1122.         $returnValue 0;
  1123.  
  1124.         $aArgs self::flattenArray($aArgs);
  1125.         if (!in_array($condition{0},array('>''<''='))) {
  1126.             if (!is_numeric($condition)) $condition PHPExcel_Calculation::_wrapResult(strtoupper($condition))}
  1127.             $condition '='.$condition;
  1128.         }
  1129.         // Loop through arguments
  1130.         foreach ($aArgs as $arg{
  1131.             if (!is_numeric($arg)) $arg PHPExcel_Calculation::_wrapResult(strtoupper($arg))}
  1132.             $testCondition '='.$arg.$condition;
  1133.             if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
  1134.                 // Is it a value within our criteria
  1135.                 ++$returnValue;
  1136.             }
  1137.         }
  1138.  
  1139.         // Return
  1140.         return $returnValue;
  1141.     }    //    function COUNTIF()
  1142.  
  1143.  
  1144.     /**
  1145.      *    SUMIF
  1146.      *
  1147.      *    Counts the number of cells that contain numbers within the list of arguments
  1148.      *
  1149.      *    Excel Function:
  1150.      *        SUMIF(value1[,value2[, ...]],condition)
  1151.      *
  1152.      *    @access    public
  1153.      *    @category Mathematical and Trigonometric Functions
  1154.      *    @param    mixed        $arg,...        Data values
  1155.      *    @param    string        $condition        The criteria that defines which cells will be summed.
  1156.      *    @return    float 
  1157.      */
  1158.     public static function SUMIF($aArgs,$condition,$sumArgs array()) {
  1159.         // Return value
  1160.         $returnValue 0;
  1161.  
  1162.         $aArgs self::flattenArray($aArgs);
  1163.         $sumArgs self::flattenArray($sumArgs);
  1164.         if (count($sumArgs== 0{
  1165.             $sumArgs $aArgs;
  1166.         }
  1167.         if (!in_array($condition{0},array('>''<''='))) {
  1168.             if (!is_numeric($condition)) $condition PHPExcel_Calculation::_wrapResult(strtoupper($condition))}
  1169.             $condition '='.$condition;
  1170.         }
  1171.         // Loop through arguments
  1172.         foreach ($aArgs as $key => $arg{
  1173.             if (!is_numeric($arg)) $arg PHPExcel_Calculation::_wrapResult(strtoupper($arg))}
  1174.             $testCondition '='.$arg.$condition;
  1175.             if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
  1176.                 // Is it a value within our criteria
  1177.                 $returnValue += $sumArgs[$key];
  1178.             }
  1179.         }
  1180.  
  1181.         // Return
  1182.         return $returnValue;
  1183.     }    //    function SUMIF()
  1184.  
  1185.  
  1186.     /**
  1187.      *    AVERAGE
  1188.      *
  1189.      *    Returns the average (arithmetic mean) of the arguments
  1190.      *
  1191.      *    Excel Function:
  1192.      *        AVERAGE(value1[,value2[, ...]])
  1193.      *
  1194.      *    @access    public
  1195.      *    @category Statistical Functions
  1196.      *    @param    mixed        $arg,...        Data values
  1197.      *    @return    float 
  1198.      */
  1199.     public static function AVERAGE({
  1200.         // Return value
  1201.         $returnValue 0;
  1202.  
  1203.         // Loop through arguments
  1204.         $aArgs self::flattenArray(func_get_args());
  1205.         $aCount 0;
  1206.         foreach ($aArgs as $arg{
  1207.             if ((is_bool($arg)) && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  1208.                 $arg = (integer) $arg;
  1209.             }
  1210.             // Is it a numeric value?
  1211.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1212.                 if (is_null($returnValue)) {
  1213.                     $returnValue $arg;
  1214.                 else {
  1215.                     $returnValue += $arg;
  1216.                 }
  1217.                 ++$aCount;
  1218.             }
  1219.         }
  1220.  
  1221.         // Return
  1222.         if ($aCount 0{
  1223.             return $returnValue $aCount;
  1224.         else {
  1225.             return self::$_errorCodes['divisionbyzero'];
  1226.         }
  1227.     }    //    function AVERAGE()
  1228.  
  1229.  
  1230.     /**
  1231.      *    AVERAGEA
  1232.      *
  1233.      *    Returns the average of its arguments, including numbers, text, and logical values
  1234.      *
  1235.      *    Excel Function:
  1236.      *        AVERAGEA(value1[,value2[, ...]])
  1237.      *
  1238.      *    @access    public
  1239.      *    @category Statistical Functions
  1240.      *    @param    mixed        $arg,...        Data values
  1241.      *    @return    float 
  1242.      */
  1243.     public static function AVERAGEA({
  1244.         // Return value
  1245.         $returnValue null;
  1246.  
  1247.         // Loop through arguments
  1248.         $aArgs self::flattenArray(func_get_args());
  1249.         $aCount 0;
  1250.         foreach ($aArgs as $arg{
  1251.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg&& ($arg != '')))) {
  1252.                 if (is_bool($arg)) {
  1253.                     $arg = (integer) $arg;
  1254.                 elseif (is_string($arg)) {
  1255.                     $arg 0;
  1256.                 }
  1257.                 if (is_null($returnValue)) {
  1258.                     $returnValue $arg;
  1259.                 else {
  1260.                     $returnValue += $arg;
  1261.                 }
  1262.                 ++$aCount;
  1263.             }
  1264.         }
  1265.  
  1266.         // Return
  1267.         if ($aCount 0{
  1268.             return $returnValue $aCount;
  1269.         else {
  1270.             return self::$_errorCodes['divisionbyzero'];
  1271.         }
  1272.     }    //    function AVERAGEA()
  1273.  
  1274.  
  1275.     /**
  1276.      *    MEDIAN
  1277.      *
  1278.      *    Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
  1279.      *
  1280.      *    Excel Function:
  1281.      *        MEDIAN(value1[,value2[, ...]])
  1282.      *
  1283.      *    @access    public
  1284.      *    @category Statistical Functions
  1285.      *    @param    mixed        $arg,...        Data values
  1286.      *    @return    float 
  1287.      */
  1288.     public static function MEDIAN({
  1289.         // Return value
  1290.         $returnValue self::$_errorCodes['num'];
  1291.  
  1292.         $mArgs array();
  1293.         // Loop through arguments
  1294.         $aArgs self::flattenArray(func_get_args());
  1295.         foreach ($aArgs as $arg{
  1296.             // Is it a numeric value?
  1297.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1298.                 $mArgs[$arg;
  1299.             }
  1300.         }
  1301.  
  1302.         $mValueCount count($mArgs);
  1303.         if ($mValueCount 0{
  1304.             sort($mArgs,SORT_NUMERIC);
  1305.             $mValueCount $mValueCount 2;
  1306.             if ($mValueCount == floor($mValueCount)) {
  1307.                 $returnValue ($mArgs[$mValueCount--$mArgs[$mValueCount]2;
  1308.             else {
  1309.                 $mValueCount == floor($mValueCount);
  1310.                 $returnValue $mArgs[$mValueCount];
  1311.             }
  1312.         }
  1313.  
  1314.         // Return
  1315.         return $returnValue;
  1316.     }    //    function MEDIAN()
  1317.  
  1318.  
  1319.     //
  1320.     //    Special variant of array_count_values that isn't limited to strings and integers,
  1321.     //        but can work with floating point numbers as values
  1322.     //
  1323.     private static function _modeCalc($data{
  1324.         $frequencyArray array();
  1325.         foreach($data as $datum{
  1326.             $found False;
  1327.             foreach($frequencyArray as $key => $value{
  1328.                 if ((string) $value['value'== (string) $datum{
  1329.                     ++$frequencyArray[$key]['frequency'];
  1330.                     $found True;
  1331.                     break;
  1332.                 }
  1333.             }
  1334.             if (!$found{
  1335.                 $frequencyArray[array('value'        => $datum,
  1336.                                           'frequency'    =>    );
  1337.             }
  1338.         }
  1339.  
  1340.         foreach($frequencyArray as $key => $value{
  1341.             $frequencyList[$key$value['frequency'];
  1342.             $valueList[$key$value['value'];
  1343.         }
  1344.         array_multisort($frequencyListSORT_DESC$valueListSORT_ASCSORT_NUMERIC$frequencyArray);
  1345.  
  1346.         if ($frequencyArray[0]['frequency'== 1{
  1347.             return self::NA();
  1348.         }
  1349.         return $frequencyArray[0]['value'];
  1350.     }    //    function _modeCalc()
  1351.  
  1352.  
  1353.     /**
  1354.      *    MODE
  1355.      *
  1356.      *    Returns the most frequently occurring, or repetitive, value in an array or range of data
  1357.      *
  1358.      *    Excel Function:
  1359.      *        MODE(value1[,value2[, ...]])
  1360.      *
  1361.      *    @access    public
  1362.      *    @category Statistical Functions
  1363.      *    @param    mixed        $arg,...        Data values
  1364.      *    @return    float 
  1365.      */
  1366.     public static function MODE({
  1367.         // Return value
  1368.         $returnValue self::NA();
  1369.  
  1370.         // Loop through arguments
  1371.         $aArgs self::flattenArray(func_get_args());
  1372.  
  1373.         $mArgs array();
  1374.         foreach ($aArgs as $arg{
  1375.             // Is it a numeric value?
  1376.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1377.                 $mArgs[$arg;
  1378.             }
  1379.         }
  1380.  
  1381.         if (count($mArgs0{
  1382.             return self::_modeCalc($mArgs);
  1383.         }
  1384.  
  1385.         // Return
  1386.         return $returnValue;
  1387.     }    //    function MODE()
  1388.  
  1389.  
  1390.     /**
  1391.      *    DEVSQ
  1392.      *
  1393.      *    Returns the sum of squares of deviations of data points from their sample mean.
  1394.      *
  1395.      *    Excel Function:
  1396.      *        DEVSQ(value1[,value2[, ...]])
  1397.      *
  1398.      *    @access    public
  1399.      *    @category Statistical Functions
  1400.      *    @param    mixed        $arg,...        Data values
  1401.      *    @return    float 
  1402.      */
  1403.     public static function DEVSQ({
  1404.         // Return value
  1405.         $returnValue null;
  1406.  
  1407.         $aMean self::AVERAGE(func_get_args());
  1408.         if (!is_null($aMean)) {
  1409.             $aArgs self::flattenArray(func_get_args());
  1410.  
  1411.             $aCount = -1;
  1412.             foreach ($aArgs as $arg{
  1413.                 // Is it a numeric value?
  1414.                 if ((is_bool($arg)) && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  1415.                     $arg = (int) $arg;
  1416.                 }
  1417.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1418.                     if (is_null($returnValue)) {
  1419.                         $returnValue pow(($arg $aMean),2);
  1420.                     else {
  1421.                         $returnValue += pow(($arg $aMean),2);
  1422.                     }
  1423.                     ++$aCount;
  1424.                 }
  1425.             }
  1426.  
  1427.             // Return
  1428.             if (is_null($returnValue)) {
  1429.                 return self::$_errorCodes['num'];
  1430.             else {
  1431.                 return $returnValue;
  1432.             }
  1433.         }
  1434.         return self::NA();
  1435.     }    //    function DEVSQ()
  1436.  
  1437.  
  1438.     /**
  1439.      *    AVEDEV
  1440.      *
  1441.      *    Returns the average of the absolute deviations of data points from their mean.
  1442.      *    AVEDEV is a measure of the variability in a data set.
  1443.      *
  1444.      *    Excel Function:
  1445.      *        AVEDEV(value1[,value2[, ...]])
  1446.      *
  1447.      *    @access    public
  1448.      *    @category Statistical Functions
  1449.      *    @param    mixed        $arg,...        Data values
  1450.      *    @return    float 
  1451.      */
  1452.     public static function AVEDEV({
  1453.         $aArgs self::flattenArray(func_get_args());
  1454.  
  1455.         // Return value
  1456.         $returnValue null;
  1457.  
  1458.         $aMean self::AVERAGE($aArgs);
  1459.         if ($aMean != self::$_errorCodes['divisionbyzero']{
  1460.             $aCount 0;
  1461.             foreach ($aArgs as $arg{
  1462.                 if ((is_bool($arg)) && (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
  1463.                     $arg = (integer) $arg;
  1464.                 }
  1465.                 // Is it a numeric value?
  1466.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1467.                     if (is_null($returnValue)) {
  1468.                         $returnValue abs($arg $aMean);
  1469.                     else {
  1470.                         $returnValue += abs($arg $aMean);
  1471.                     }
  1472.                     ++$aCount;
  1473.                 }
  1474.             }
  1475.  
  1476.             // Return
  1477.             return $returnValue $aCount ;
  1478.         }
  1479.         return self::$_errorCodes['num'];
  1480.     }    //    function AVEDEV()
  1481.  
  1482.  
  1483.     /**
  1484.      *    GEOMEAN
  1485.      *
  1486.      *    Returns the geometric mean of an array or range of positive data. For example, you
  1487.      *        can use GEOMEAN to calculate average growth rate given compound interest with
  1488.      *        variable rates.
  1489.      *
  1490.      *    Excel Function:
  1491.      *        GEOMEAN(value1[,value2[, ...]])
  1492.      *
  1493.      *    @access    public
  1494.      *    @category Statistical Functions
  1495.      *    @param    mixed        $arg,...        Data values
  1496.      *    @return    float 
  1497.      */
  1498.     public static function GEOMEAN({
  1499.         $aMean self::PRODUCT(func_get_args());
  1500.         if (is_numeric($aMean&& ($aMean 0)) {
  1501.             $aArgs self::flattenArray(func_get_args());
  1502.             $aCount self::COUNT($aArgs;
  1503.             if (self::MIN($aArgs0{
  1504.                 return pow($aMean($aCount));
  1505.             }
  1506.         }
  1507.         return self::$_errorCodes['num'];
  1508.     }    //    GEOMEAN()
  1509.  
  1510.  
  1511.     /**
  1512.      *    HARMEAN
  1513.      *
  1514.      *    Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the
  1515.      *        arithmetic mean of reciprocals.
  1516.      *
  1517.      *    Excel Function:
  1518.      *        HARMEAN(value1[,value2[, ...]])
  1519.      *
  1520.      *    @access    public
  1521.      *    @category Statistical Functions
  1522.      *    @param    mixed        $arg,...        Data values
  1523.      *    @return    float 
  1524.      */
  1525.     public static function HARMEAN({
  1526.         // Return value
  1527.         $returnValue self::NA();
  1528.  
  1529.         // Loop through arguments
  1530.         $aArgs self::flattenArray(func_get_args());
  1531.         if (self::MIN($aArgs0{
  1532.             return self::$_errorCodes['num'];
  1533.         }
  1534.         $aCount 0;
  1535.         foreach ($aArgs as $arg{
  1536.             // Is it a numeric value?
  1537.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1538.                 if ($arg <= 0{
  1539.                     return self::$_errorCodes['num'];
  1540.                 }
  1541.                 if (is_null($returnValue)) {
  1542.                     $returnValue ($arg);
  1543.                 else {
  1544.                     $returnValue += ($arg);
  1545.                 }
  1546.                 ++$aCount;
  1547.             }
  1548.         }
  1549.  
  1550.         // Return
  1551.         if ($aCount 0{
  1552.             return ($returnValue $aCount);
  1553.         else {
  1554.             return $returnValue;
  1555.         }
  1556.     }    //    function HARMEAN()
  1557.  
  1558.  
  1559.     /**
  1560.      *    TRIMMEAN
  1561.      *
  1562.      *    Returns the mean of the interior of a data set. TRIMMEAN calculates the mean
  1563.      *    taken by excluding a percentage of data points from the top and bottom tails
  1564.      *    of a data set.
  1565.      *
  1566.      *    Excel Function:
  1567.      *        TRIMEAN(value1[,value2[, ...]],$discard)
  1568.      *
  1569.      *    @access    public
  1570.      *    @category Statistical Functions
  1571.      *    @param    mixed        $arg,...        Data values
  1572.      *    @param    float        $discard        Percentage to discard
  1573.      *    @return    float 
  1574.      */
  1575.     public static function TRIMMEAN({
  1576.         $aArgs self::flattenArray(func_get_args());
  1577.  
  1578.         // Calculate
  1579.         $percent array_pop($aArgs);
  1580.  
  1581.         if ((is_numeric($percent)) && (!is_string($percent))) {
  1582.             if (($percent 0|| ($percent 1)) {
  1583.                 return self::$_errorCodes['num'];
  1584.             }
  1585.             $mArgs array();
  1586.             foreach ($aArgs as $arg{
  1587.                 // Is it a numeric value?
  1588.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1589.                     $mArgs[$arg;
  1590.                 }
  1591.             }
  1592.             $discard floor(self::COUNT($mArgs$percent 2);
  1593.             sort($mArgs);
  1594.             for ($i=0$i $discard++$i{
  1595.                 array_pop($mArgs);
  1596.                 array_shift($mArgs);
  1597.             }
  1598.             return self::AVERAGE($mArgs);
  1599.         }
  1600.         return self::$_errorCodes['value'];
  1601.     }    //    function TRIMMEAN()
  1602.  
  1603.  
  1604.     /**
  1605.      *    STDEV
  1606.      *
  1607.      *    Estimates standard deviation based on a sample. The standard deviation is a measure of how
  1608.      *    widely values are dispersed from the average value (the mean).
  1609.      *
  1610.      *    Excel Function:
  1611.      *        STDEV(value1[,value2[, ...]])
  1612.      *
  1613.      *    @access    public
  1614.      *    @category Statistical Functions
  1615.      *    @param    mixed        $arg,...        Data values
  1616.      *    @return    float 
  1617.      */
  1618.     public static function STDEV({
  1619.         // Return value
  1620.         $returnValue null;
  1621.  
  1622.         $aMean self::AVERAGE(func_get_args());
  1623.         if (!is_null($aMean)) {
  1624.             $aArgs self::flattenArray(func_get_args());
  1625.  
  1626.             $aCount = -1;
  1627.             foreach ($aArgs as $arg{
  1628.                 // Is it a numeric value?
  1629.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1630.                     if (is_null($returnValue)) {
  1631.                         $returnValue pow(($arg $aMean),2);
  1632.                     else {
  1633.                         $returnValue += pow(($arg $aMean),2);
  1634.                     }
  1635.                     ++$aCount;
  1636.                 }
  1637.             }
  1638.  
  1639.             // Return
  1640.             if (($aCount 0&& ($returnValue 0)) {
  1641.                 return sqrt($returnValue $aCount);
  1642.             }
  1643.         }
  1644.         return self::$_errorCodes['divisionbyzero'];
  1645.     }    //    function STDEV()
  1646.  
  1647.  
  1648.     /**
  1649.      *    STDEVA
  1650.      *
  1651.      *    Estimates standard deviation based on a sample, including numbers, text, and logical values
  1652.      *
  1653.      *    Excel Function:
  1654.      *        STDEVA(value1[,value2[, ...]])
  1655.      *
  1656.      *    @access    public
  1657.      *    @category Statistical Functions
  1658.      *    @param    mixed        $arg,...        Data values
  1659.      *    @return    float 
  1660.      */
  1661.     public static function STDEVA({
  1662.         // Return value
  1663.         $returnValue null;
  1664.  
  1665.         $aMean self::AVERAGEA(func_get_args());
  1666.         if (!is_null($aMean)) {
  1667.             $aArgs self::flattenArray(func_get_args());
  1668.  
  1669.             $aCount = -1;
  1670.             foreach ($aArgs as $arg{
  1671.                 // Is it a numeric value?
  1672.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1673.                     if (is_bool($arg)) {
  1674.                         $arg = (integer) $arg;
  1675.                     elseif (is_string($arg)) {
  1676.                         $arg 0;
  1677.                     }
  1678.                     if (is_null($returnValue)) {
  1679.                         $returnValue pow(($arg $aMean),2);
  1680.                     else {
  1681.                         $returnValue += pow(($arg $aMean),2);
  1682.                     }
  1683.                     ++$aCount;
  1684.                 }
  1685.             }
  1686.  
  1687.             // Return
  1688.             if (($aCount 0&& ($returnValue 0)) {
  1689.                 return sqrt($returnValue $aCount);
  1690.             }
  1691.         }
  1692.         return self::$_errorCodes['divisionbyzero'];
  1693.     }    //    function STDEVA()
  1694.  
  1695.  
  1696.     /**
  1697.      *    STDEVP
  1698.      *
  1699.      *    Calculates standard deviation based on the entire population
  1700.      *
  1701.      *    Excel Function:
  1702.      *        STDEVP(value1[,value2[, ...]])
  1703.      *
  1704.      *    @access    public
  1705.      *    @category Statistical Functions
  1706.      *    @param    mixed        $arg,...        Data values
  1707.      *    @return    float 
  1708.      */
  1709.     public static function STDEVP({
  1710.         // Return value
  1711.         $returnValue null;
  1712.  
  1713.         $aMean self::AVERAGE(func_get_args());
  1714.         if (!is_null($aMean)) {
  1715.             $aArgs self::flattenArray(func_get_args());
  1716.  
  1717.             $aCount 0;
  1718.             foreach ($aArgs as $arg{
  1719.                 // Is it a numeric value?
  1720.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  1721.                     if (is_null($returnValue)) {
  1722.                         $returnValue pow(($arg $aMean),2);
  1723.                     else {
  1724.                         $returnValue += pow(($arg $aMean),2);
  1725.                     }
  1726.                     ++$aCount;
  1727.                 }
  1728.             }
  1729.  
  1730.             // Return
  1731.             if (($aCount 0&& ($returnValue 0)) {
  1732.                 return sqrt($returnValue $aCount);
  1733.             }
  1734.         }
  1735.         return self::$_errorCodes['divisionbyzero'];
  1736.     }    //    function STDEVP()
  1737.  
  1738.  
  1739.     /**
  1740.      *    STDEVPA
  1741.      *
  1742.      *    Calculates standard deviation based on the entire population, including numbers, text, and logical values
  1743.      *
  1744.      *    Excel Function:
  1745.      *        STDEVPA(value1[,value2[, ...]])
  1746.      *
  1747.      *    @access    public
  1748.      *    @category Statistical Functions
  1749.      *    @param    mixed        $arg,...        Data values
  1750.      *    @return    float 
  1751.      */
  1752.     public static function STDEVPA({
  1753.         // Return value
  1754.         $returnValue null;
  1755.  
  1756.         $aMean self::AVERAGEA(func_get_args());
  1757.         if (!is_null($aMean)) {
  1758.             $aArgs self::flattenArray(func_get_args());
  1759.  
  1760.             $aCount 0;
  1761.             foreach ($aArgs as $arg{
  1762.                 // Is it a numeric value?
  1763.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1764.                     if (is_bool($arg)) {
  1765.                         $arg = (integer) $arg;
  1766.                     elseif (is_string($arg)) {
  1767.                         $arg 0;
  1768.                     }
  1769.                     if (is_null($returnValue)) {
  1770.                         $returnValue pow(($arg $aMean),2);
  1771.                     else {
  1772.                         $returnValue += pow(($arg $aMean),2);
  1773.                     }
  1774.                     ++$aCount;
  1775.                 }
  1776.             }
  1777.  
  1778.             // Return
  1779.             if (($aCount 0&& ($returnValue 0)) {
  1780.                 return sqrt($returnValue $aCount);
  1781.             }
  1782.         }
  1783.         return self::$_errorCodes['divisionbyzero'];
  1784.     }    //    function STDEVPA()
  1785.  
  1786.  
  1787.     /**
  1788.      *    VARFunc
  1789.      *
  1790.      *    Estimates variance based on a sample.
  1791.      *
  1792.      *    Excel Function:
  1793.      *        VAR(value1[,value2[, ...]])
  1794.      *
  1795.      *    @access    public
  1796.      *    @category Statistical Functions
  1797.      *    @param    mixed        $arg,...        Data values
  1798.      *    @return    float 
  1799.      */
  1800.     public static function VARFunc({
  1801.         // Return value
  1802.         $returnValue self::$_errorCodes['divisionbyzero'];
  1803.  
  1804.         $summerA $summerB 0;
  1805.  
  1806.         // Loop through arguments
  1807.         $aArgs self::flattenArray(func_get_args());
  1808.         $aCount 0;
  1809.         foreach ($aArgs as $arg{
  1810.             // Is it a numeric value?
  1811.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1812.                 $summerA += ($arg $arg);
  1813.                 $summerB += $arg;
  1814.                 ++$aCount;
  1815.             }
  1816.         }
  1817.  
  1818.         // Return
  1819.         if ($aCount 1{
  1820.             $summerA $summerA $aCount;
  1821.             $summerB ($summerB $summerB);
  1822.             $returnValue ($summerA $summerB($aCount ($aCount 1));
  1823.         }
  1824.         return $returnValue;
  1825.     }    //    function VARFunc()
  1826.  
  1827.  
  1828.     /**
  1829.      *    VARA
  1830.      *
  1831.      *    Estimates variance based on a sample, including numbers, text, and logical values
  1832.      *
  1833.      *    Excel Function:
  1834.      *        VARA(value1[,value2[, ...]])
  1835.      *
  1836.      *    @access    public
  1837.      *    @category Statistical Functions
  1838.      *    @param    mixed        $arg,...        Data values
  1839.      *    @return    float 
  1840.      */
  1841.     public static function VARA({
  1842.         // Return value
  1843.         $returnValue self::$_errorCodes['divisionbyzero'];
  1844.  
  1845.         $summerA $summerB 0;
  1846.  
  1847.         // Loop through arguments
  1848.         $aArgs self::flattenArray(func_get_args());
  1849.         $aCount 0;
  1850.         foreach ($aArgs as $arg{
  1851.             // Is it a numeric value?
  1852.                 if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1853.                 if (is_bool($arg)) {
  1854.                     $arg = (integer) $arg;
  1855.                 elseif (is_string($arg)) {
  1856.                     $arg 0;
  1857.                 }
  1858.                 $summerA += ($arg $arg);
  1859.                 $summerB += $arg;
  1860.                 ++$aCount;
  1861.             }
  1862.         }
  1863.  
  1864.         // Return
  1865.         if ($aCount 1{
  1866.             $summerA $summerA $aCount;
  1867.             $summerB ($summerB $summerB);
  1868.             $returnValue ($summerA $summerB($aCount ($aCount 1));
  1869.         }
  1870.         return $returnValue;
  1871.     }    //    function VARA()
  1872.  
  1873.  
  1874.     /**
  1875.      *    VARP
  1876.      *
  1877.      *    Calculates variance based on the entire population
  1878.      *
  1879.      *    Excel Function:
  1880.      *        VARP(value1[,value2[, ...]])
  1881.      *
  1882.      *    @access    public
  1883.      *    @category Statistical Functions
  1884.      *    @param    mixed        $arg,...        Data values
  1885.      *    @return    float 
  1886.      */
  1887.     public static function VARP({
  1888.         // Return value
  1889.         $returnValue self::$_errorCodes['divisionbyzero'];
  1890.  
  1891.         $summerA $summerB 0;
  1892.  
  1893.         // Loop through arguments
  1894.         $aArgs self::flattenArray(func_get_args());
  1895.         $aCount 0;
  1896.         foreach ($aArgs as $arg{
  1897.             // Is it a numeric value?
  1898.             if ((is_numeric($arg)) && (!is_string($arg))) {
  1899.                 $summerA += ($arg $arg);
  1900.                 $summerB += $arg;
  1901.                 ++$aCount;
  1902.             }
  1903.         }
  1904.  
  1905.         // Return
  1906.         if ($aCount 0{
  1907.             $summerA $summerA $aCount;
  1908.             $summerB ($summerB $summerB);
  1909.             $returnValue ($summerA $summerB($aCount $aCount);
  1910.         }
  1911.         return $returnValue;
  1912.     }    //    function VARP()
  1913.  
  1914.  
  1915.     /**
  1916.      *    VARPA
  1917.      *
  1918.      *    Calculates variance based on the entire population, including numbers, text, and logical values
  1919.      *
  1920.      *    Excel Function:
  1921.      *        VARPA(value1[,value2[, ...]])
  1922.      *
  1923.      *    @access    public
  1924.      *    @category Statistical Functions
  1925.      *    @param    mixed        $arg,...        Data values
  1926.      *    @return    float 
  1927.      */
  1928.     public static function VARPA({
  1929.         // Return value
  1930.         $returnValue self::$_errorCodes['divisionbyzero'];
  1931.  
  1932.         $summerA $summerB 0;
  1933.  
  1934.         // Loop through arguments
  1935.         $aArgs self::flattenArray(func_get_args());
  1936.         $aCount 0;
  1937.         foreach ($aArgs as $arg{
  1938.             // Is it a numeric value?
  1939.             if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg($arg != '')))) {
  1940.                 if (is_bool($arg)) {
  1941.                     $arg = (integer) $arg;
  1942.                 elseif (is_string($arg)) {
  1943.                     $arg 0;
  1944.                 }
  1945.                 $summerA += ($arg $arg);
  1946.                 $summerB += $arg;
  1947.                 ++$aCount;
  1948.             }
  1949.         }
  1950.  
  1951.         // Return
  1952.         if ($aCount 0{
  1953.             $summerA $summerA $aCount;
  1954.             $summerB ($summerB $summerB);
  1955.             $returnValue ($summerA $summerB($aCount $aCount);
  1956.         }
  1957.         return $returnValue;
  1958.     }    //    function VARPA()
  1959.  
  1960.  
  1961.     /**
  1962.      *    RANK
  1963.      *
  1964.      *    Returns the rank of a number in a list of numbers.
  1965.      *
  1966.      *    @param    number                The number whose rank you want to find.
  1967.      *    @param    array of number        An array of, or a reference to, a list of numbers.
  1968.      *    @param    mixed                Order to sort the values in the value set
  1969.      *    @return    float 
  1970.      */
  1971.     public static function RANK($value,$valueSet,$order=0{
  1972.         $value self::flattenSingleValue($value);
  1973.         $valueSet self::flattenArray($valueSet);
  1974.         $order self::flattenSingleValue($order);
  1975.  
  1976.         foreach($valueSet as $key => $valueEntry{
  1977.             if (!is_numeric($valueEntry)) {
  1978.                 unset($valueSet[$key]);
  1979.             }
  1980.         }
  1981.  
  1982.         if ($order == 0{
  1983.             rsort($valueSet,SORT_NUMERIC);
  1984.         else {
  1985.             sort($valueSet,SORT_NUMERIC);
  1986.         }
  1987.         $pos array_search($value,$valueSet);
  1988.         if ($pos === False{
  1989.             return self::$_errorCodes['na'];
  1990.         }
  1991.  
  1992.         return ++$pos;
  1993.     }    //    function RANK()
  1994.  
  1995.  
  1996.     /**
  1997.      *    PERCENTRANK
  1998.      *
  1999.      *    Returns the rank of a value in a data set as a percentage of the data set.
  2000.      *
  2001.      *    @param    array of number        An array of, or a reference to, a list of numbers.
  2002.      *    @param    number                The number whose rank you want to find.
  2003.      *    @param    number                The number of significant digits for the returned percentage value.
  2004.      *    @return    float 
  2005.      */
  2006.     public static function PERCENTRANK($valueSet,$value,$significance=3{
  2007.         $valueSet self::flattenArray($valueSet);
  2008.         $value self::flattenSingleValue($value);
  2009.         $significance self::flattenSingleValue($significance);
  2010.  
  2011.         foreach($valueSet as $key => $valueEntry{
  2012.             if (!is_numeric($valueEntry)) {
  2013.                 unset($valueSet[$key]);
  2014.             }
  2015.         }
  2016.         sort($valueSet,SORT_NUMERIC);
  2017.         $valueCount count($valueSet);
  2018.         if ($valueCount == 0{
  2019.             return self::$_errorCodes['num'];
  2020.         }
  2021.  
  2022.         $valueAdjustor $valueCount 1;
  2023.         if (($value $valueSet[0]|| ($value $valueSet[$valueAdjustor])) {
  2024.             return self::$_errorCodes['na'];
  2025.         }
  2026.  
  2027.         $pos array_search($value,$valueSet);
  2028.         if ($pos === False{
  2029.             $pos 0;
  2030.             $testValue $valueSet[0];
  2031.             while ($testValue $value{
  2032.                 $testValue $valueSet[++$pos];
  2033.             }
  2034.             --$pos;
  2035.             $pos += (($value $valueSet[$pos]($testValue $valueSet[$pos]));
  2036.         }
  2037.  
  2038.         return round($pos $valueAdjustor,$significance);
  2039.     }    //    function PERCENTRANK()
  2040.  
  2041.  
  2042.     private static function _checkTrendArray($values{
  2043.         foreach($values as $key => $value{
  2044.             if ((is_bool($value)) || ((is_string($value)) && (trim($value== ''))) {
  2045.                 unset($values[$key]);
  2046.             elseif (is_string($value)) {
  2047.                 if (is_numeric($value)) {
  2048.                     $values[$key= (float) $value;
  2049.                 else {
  2050.                     unset($values[$key]);
  2051.                 }
  2052.             }
  2053.         }
  2054.         return $values;
  2055.     }    //    function _checkTrendArray()
  2056.  
  2057.  
  2058.     /**
  2059.      *    INTERCEPT
  2060.      *
  2061.      *    Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values.
  2062.      *
  2063.      *    @param    array of mixed        Data Series Y
  2064.      *    @param    array of mixed        Data Series X
  2065.      *    @return    float 
  2066.      */
  2067.     public static function INTERCEPT($yValues,$xValues{
  2068.         $yValues self::flattenArray($yValues);
  2069.         $xValues self::flattenArray($xValues);
  2070.  
  2071.         $yValues self::_checkTrendArray($yValues);
  2072.         $yValueCount count($yValues);
  2073.         $xValues self::_checkTrendArray($xValues);
  2074.         $xValueCount count($xValues);
  2075.  
  2076.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2077.             return self::$_errorCodes['na'];
  2078.         elseif ($yValueCount == 1{
  2079.             return self::$_errorCodes['divisionbyzero'];
  2080.         }
  2081.  
  2082.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2083.         return $bestFitLinear->getIntersect();
  2084.     }    //    function INTERCEPT()
  2085.  
  2086.  
  2087.     /**
  2088.      *    RSQ
  2089.      *
  2090.      *    Returns the square of the Pearson product moment correlation coefficient through data points in known_y's and known_x's.
  2091.      *
  2092.      *    @param    array of mixed        Data Series Y
  2093.      *    @param    array of mixed        Data Series X
  2094.      *    @return    float 
  2095.      */
  2096.     public static function RSQ($yValues,$xValues{
  2097.         $yValues self::flattenArray($yValues);
  2098.         $xValues self::flattenArray($xValues);
  2099.  
  2100.         $yValues self::_checkTrendArray($yValues);
  2101.         $yValueCount count($yValues);
  2102.         $xValues self::_checkTrendArray($xValues);
  2103.         $xValueCount count($xValues);
  2104.  
  2105.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2106.             return self::$_errorCodes['na'];
  2107.         elseif ($yValueCount == 1{
  2108.             return self::$_errorCodes['divisionbyzero'];
  2109.         }
  2110.  
  2111.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2112.         return $bestFitLinear->getGoodnessOfFit();
  2113.     }    //    function RSQ()
  2114.  
  2115.  
  2116.     /**
  2117.      *    SLOPE
  2118.      *
  2119.      *    Returns the slope of the linear regression line through data points in known_y's and known_x's.
  2120.      *
  2121.      *    @param    array of mixed        Data Series Y
  2122.      *    @param    array of mixed        Data Series X
  2123.      *    @return    float 
  2124.      */
  2125.     public static function SLOPE($yValues,$xValues{
  2126.         $yValues self::flattenArray($yValues);
  2127.         $xValues self::flattenArray($xValues);
  2128.  
  2129.         $yValues self::_checkTrendArray($yValues);
  2130.         $yValueCount count($yValues);
  2131.         $xValues self::_checkTrendArray($xValues);
  2132.         $xValueCount count($xValues);
  2133.  
  2134.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2135.             return self::$_errorCodes['na'];
  2136.         elseif ($yValueCount == 1{
  2137.             return self::$_errorCodes['divisionbyzero'];
  2138.         }
  2139.  
  2140.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2141.         return $bestFitLinear->getSlope();
  2142.     }    //    function SLOPE()
  2143.  
  2144.  
  2145.     /**
  2146.      *    STEYX
  2147.      *
  2148.      *    Returns the standard error of the predicted y-value for each x in the regression.
  2149.      *
  2150.      *    @param    array of mixed        Data Series Y
  2151.      *    @param    array of mixed        Data Series X
  2152.      *    @return    float 
  2153.      */
  2154.     public static function STEYX($yValues,$xValues{
  2155.         $yValues self::flattenArray($yValues);
  2156.         $xValues self::flattenArray($xValues);
  2157.  
  2158.         $yValues self::_checkTrendArray($yValues);
  2159.         $yValueCount count($yValues);
  2160.         $xValues self::_checkTrendArray($xValues);
  2161.         $xValueCount count($xValues);
  2162.  
  2163.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2164.             return self::$_errorCodes['na'];
  2165.         elseif ($yValueCount == 1{
  2166.             return self::$_errorCodes['divisionbyzero'];
  2167.         }
  2168.  
  2169.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2170.         return $bestFitLinear->getStdevOfResiduals();
  2171.     }    //    function STEYX()
  2172.  
  2173.  
  2174.     /**
  2175.      *    COVAR
  2176.      *
  2177.      *    Returns covariance, the average of the products of deviations for each data point pair.
  2178.      *
  2179.      *    @param    array of mixed        Data Series Y
  2180.      *    @param    array of mixed        Data Series X
  2181.      *    @return    float 
  2182.      */
  2183.     public static function COVAR($yValues,$xValues{
  2184.         $yValues self::flattenArray($yValues);
  2185.         $xValues self::flattenArray($xValues);
  2186.  
  2187.         $yValues self::_checkTrendArray($yValues);
  2188.         $yValueCount count($yValues);
  2189.         $xValues self::_checkTrendArray($xValues);
  2190.         $xValueCount count($xValues);
  2191.  
  2192.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2193.             return self::$_errorCodes['na'];
  2194.         elseif ($yValueCount == 1{
  2195.             return self::$_errorCodes['divisionbyzero'];
  2196.         }
  2197.  
  2198.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2199.         return $bestFitLinear->getCovariance();
  2200.     }    //    function COVAR()
  2201.  
  2202.  
  2203.     /**
  2204.      *    CORREL
  2205.      *
  2206.      *    Returns covariance, the average of the products of deviations for each data point pair.
  2207.      *
  2208.      *    @param    array of mixed        Data Series Y
  2209.      *    @param    array of mixed        Data Series X
  2210.      *    @return    float 
  2211.      */
  2212.     public static function CORREL($yValues,$xValues{
  2213.         $yValues self::flattenArray($yValues);
  2214.         $xValues self::flattenArray($xValues);
  2215.  
  2216.         $yValues self::_checkTrendArray($yValues);
  2217.         $yValueCount count($yValues);
  2218.         $xValues self::_checkTrendArray($xValues);
  2219.         $xValueCount count($xValues);
  2220.  
  2221.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2222.             return self::$_errorCodes['na'];
  2223.         elseif ($yValueCount == 1{
  2224.             return self::$_errorCodes['divisionbyzero'];
  2225.         }
  2226.  
  2227.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2228.         return $bestFitLinear->getCorrelation();
  2229.     }    //    function CORREL()
  2230.  
  2231.  
  2232.     /**
  2233.      *    LINEST
  2234.      *
  2235.      *    Calculates the statistics for a line by using the "least squares" method to calculate a straight line that best fits your data,
  2236.      *        and then returns an array that describes the line.
  2237.      *
  2238.      *    @param    array of mixed        Data Series Y
  2239.      *    @param    array of mixed        Data Series X
  2240.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2241.      *    @param    boolean                A logical value specifying whether to return additional regression statistics.
  2242.      *    @return    array 
  2243.      */
  2244.     public static function LINEST($yValues,$xValues,$const=True,$stats=False{
  2245.         $yValues self::flattenArray($yValues);
  2246.         $xValues self::flattenArray($xValues);
  2247.         $const    = (boolean) self::flattenSingleValue($const);
  2248.         $stats    = (boolean) self::flattenSingleValue($stats);
  2249.  
  2250.         $yValues self::_checkTrendArray($yValues);
  2251.         $yValueCount count($yValues);
  2252.         $xValues self::_checkTrendArray($xValues);
  2253.         $xValueCount count($xValues);
  2254.  
  2255.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2256.             return self::$_errorCodes['na'];
  2257.         elseif ($yValueCount == 1{
  2258.             return self::$_errorCodes['divisionbyzero'];
  2259.         }
  2260.  
  2261.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const);
  2262.         if ($stats{
  2263.             return arrayarray$bestFitLinear->getSlope(),
  2264.                                   $bestFitLinear->getSlopeSE(),
  2265.                                   $bestFitLinear->getGoodnessOfFit(),
  2266.                                   $bestFitLinear->getF(),
  2267.                                   $bestFitLinear->getSSRegression(),
  2268.                                ),
  2269.                           array$bestFitLinear->getIntersect(),
  2270.                                  $bestFitLinear->getIntersectSE(),
  2271.                                  $bestFitLinear->getStdevOfResiduals(),
  2272.                                  $bestFitLinear->getDFResiduals(),
  2273.                                  $bestFitLinear->getSSResiduals()
  2274.                                )
  2275.                         );
  2276.         else {
  2277.             return array$bestFitLinear->getSlope(),
  2278.                           $bestFitLinear->getIntersect()
  2279.                         );
  2280.         }
  2281.     }    //    function LINEST()
  2282.  
  2283.  
  2284.     /**
  2285.      *    LOGEST
  2286.      *
  2287.      *    Calculates an exponential curve that best fits the X and Y data series,
  2288.      *        and then returns an array that describes the line.
  2289.      *
  2290.      *    @param    array of mixed        Data Series Y
  2291.      *    @param    array of mixed        Data Series X
  2292.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2293.      *    @param    boolean                A logical value specifying whether to return additional regression statistics.
  2294.      *    @return    array 
  2295.      */
  2296.     public static function LOGEST($yValues,$xValues,$const=True,$stats=False{
  2297.         $yValues self::flattenArray($yValues);
  2298.         $xValues self::flattenArray($xValues);
  2299.         $const    = (boolean) self::flattenSingleValue($const);
  2300.         $stats    = (boolean) self::flattenSingleValue($stats);
  2301.  
  2302.         $yValues self::_checkTrendArray($yValues);
  2303.         $yValueCount count($yValues);
  2304.         $xValues self::_checkTrendArray($xValues);
  2305.         $xValueCount count($xValues);
  2306.  
  2307.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2308.             return self::$_errorCodes['na'];
  2309.         elseif ($yValueCount == 1{
  2310.             return self::$_errorCodes['divisionbyzero'];
  2311.         }
  2312.  
  2313.         $bestFitExponential trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const);
  2314.         if ($stats{
  2315.             return arrayarray$bestFitExponential->getSlope(),
  2316.                                   $bestFitExponential->getSlopeSE(),
  2317.                                   $bestFitExponential->getGoodnessOfFit(),
  2318.                                   $bestFitExponential->getF(),
  2319.                                   $bestFitExponential->getSSRegression(),
  2320.                                ),
  2321.                           array$bestFitExponential->getIntersect(),
  2322.                                  $bestFitExponential->getIntersectSE(),
  2323.                                  $bestFitExponential->getStdevOfResiduals(),
  2324.                                  $bestFitExponential->getDFResiduals(),
  2325.                                  $bestFitExponential->getSSResiduals()
  2326.                                )
  2327.                         );
  2328.         else {
  2329.             return array$bestFitExponential->getSlope(),
  2330.                           $bestFitExponential->getIntersect()
  2331.                         );
  2332.         }
  2333.     }    //    function LOGEST()
  2334.  
  2335.  
  2336.     /**
  2337.      *    FORECAST
  2338.      *
  2339.      *    Calculates, or predicts, a future value by using existing values. The predicted value is a y-value for a given x-value.
  2340.      *
  2341.      *    @param    float                Value of X for which we want to find Y
  2342.      *    @param    array of mixed        Data Series Y
  2343.      *    @param    array of mixed        Data Series X
  2344.      *    @return    float 
  2345.      */
  2346.     public static function FORECAST($xValue,$yValues,$xValues{
  2347.         $xValue    self::flattenSingleValue($xValue);
  2348.         $yValues self::flattenArray($yValues);
  2349.         $xValues self::flattenArray($xValues);
  2350.  
  2351.         if (!is_numeric($xValue)) {
  2352.             return self::$_errorCodes['value'];
  2353.         }
  2354.  
  2355.         $yValues self::_checkTrendArray($yValues);
  2356.         $yValueCount count($yValues);
  2357.         $xValues self::_checkTrendArray($xValues);
  2358.         $xValueCount count($xValues);
  2359.  
  2360.         if (($yValueCount == 0|| ($yValueCount != $xValueCount)) {
  2361.             return self::$_errorCodes['na'];
  2362.         elseif ($yValueCount == 1{
  2363.             return self::$_errorCodes['divisionbyzero'];
  2364.         }
  2365.  
  2366.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues);
  2367.         return $bestFitLinear->getValueOfYForX($xValue);
  2368.     }    //    function FORECAST()
  2369.  
  2370.  
  2371.     /**
  2372.      *    TREND
  2373.      *
  2374.      *    Returns values along a linear trend
  2375.      *
  2376.      *    @param    array of mixed        Data Series Y
  2377.      *    @param    array of mixed        Data Series X
  2378.      *    @param    array of mixed        Values of X for which we want to find Y
  2379.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2380.      *    @return    array of float
  2381.      */
  2382.     public static function TREND($yValues,$xValues=array(),$newValues=array(),$const=True{
  2383.         $yValues self::flattenArray($yValues);
  2384.         $xValues self::flattenArray($xValues);
  2385.         $newValues self::flattenArray($newValues);
  2386.         $const    = (boolean) self::flattenSingleValue($const);
  2387.  
  2388.         $bestFitLinear trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const);
  2389.         if (count($newValues== 0{
  2390.             $newValues $bestFitLinear->getXValues();
  2391.         }
  2392.  
  2393.         $returnArray array();
  2394.         foreach($newValues as $xValue{
  2395.             $returnArray[0][$bestFitLinear->getValueOfYForX($xValue);
  2396.         }
  2397.  
  2398.         return $returnArray;
  2399.     }    //    function TREND()
  2400.  
  2401.  
  2402.     /**
  2403.      *    GROWTH
  2404.      *
  2405.      *    Returns values along a predicted emponential trend
  2406.      *
  2407.      *    @param    array of mixed        Data Series Y
  2408.      *    @param    array of mixed        Data Series X
  2409.      *    @param    array of mixed        Values of X for which we want to find Y
  2410.      *    @param    boolean                A logical value specifying whether to force the intersect to equal 0.
  2411.      *    @return    array of float
  2412.      */
  2413.     public static function GROWTH($yValues,$xValues=array(),$newValues=array(),$const=True{
  2414.         $yValues self::flattenArray($yValues);
  2415.         $xValues self::flattenArray($xValues);
  2416.         $newValues self::flattenArray($newValues);
  2417.         $const    = (boolean) self::flattenSingleValue($const);
  2418.  
  2419.         $bestFitExponential trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const);
  2420.         if (count($newValues== 0{
  2421.             $newValues $bestFitExponential->getXValues();
  2422.         }
  2423.  
  2424.         $returnArray array();
  2425.         foreach($newValues as $xValue{
  2426.             $returnArray[0][$bestFitExponential->getValueOfYForX($xValue);
  2427.         }
  2428.  
  2429.         return $returnArray;
  2430.     }    //    function GROWTH()
  2431.  
  2432.  
  2433.     private static function _romanCut($num$n{
  2434.         return ($num ($num $n ) ) $n;
  2435.     }    //    function _romanCut()
  2436.  
  2437.  
  2438.     public static function ROMAN($aValue$style=0{
  2439.         $aValue    = (integer) self::flattenSingleValue($aValue);
  2440.         if ((!is_numeric($aValue)) || ($aValue 0|| ($aValue >= 4000)) {
  2441.             return self::$_errorCodes['value'];
  2442.         }
  2443.         if ($aValue == 0{
  2444.             return '';
  2445.         }
  2446.  
  2447.         $mill Array('''M''MM''MMM''MMMM''MMMMM');
  2448.         $cent Array('''C''CC''CCC''CD''D''DC''DCC''DCCC''CM');
  2449.         $tens Array('''X''XX''XXX''XL''L''LX''LXX''LXXX''XC');
  2450.         $ones Array('''I''II''III''IV''V''VI''VII''VIII''IX');
  2451.  
  2452.         $roman '';
  2453.         while ($aValue 5999{
  2454.             $roman .= 'M';
  2455.             $aValue -= 1000;
  2456.         }
  2457.         $m self::_romanCut($aValue1000);    $aValue %= 1000;
  2458.         $c self::_romanCut($aValue100);        $aValue %= 100;
  2459.         $t self::_romanCut($aValue10);        $aValue %= 10;
  2460.  
  2461.         return $roman.$mill[$m].$cent[$c].$tens[$t].$ones[$aValue];
  2462.     }    //    function ROMAN()
  2463.  
  2464.  
  2465.     /**
  2466.      * SUBTOTAL
  2467.      *
  2468.      * Returns a subtotal in a list or database.
  2469.      *
  2470.      * @param    int        the number 1 to 11 that specifies which function to
  2471.      *                     use in calculating subtotals within a list.
  2472.      * @param    array of mixed        Data Series
  2473.      * @return    float 
  2474.      */
  2475.     public static function SUBTOTAL({
  2476.         $aArgs self::flattenArray(func_get_args());
  2477.  
  2478.         // Calculate
  2479.         $subtotal array_shift($aArgs);
  2480.  
  2481.         if ((is_numeric($subtotal)) && (!is_string($subtotal))) {
  2482.             switch($subtotal{
  2483.                 case 1    :
  2484.                     return self::AVERAGE($aArgs);
  2485.                     break;
  2486.                 case 2    :
  2487.                     return self::COUNT($aArgs);
  2488.                     break;
  2489.                 case 3    :
  2490.                     return self::COUNTA($aArgs);
  2491.                     break;
  2492.                 case 4    :
  2493.                     return self::MAX($aArgs);
  2494.                     break;
  2495.                 case 5    :
  2496.                     return self::MIN($aArgs);
  2497.                     break;
  2498.                 case 6    :
  2499.                     return self::PRODUCT($aArgs);
  2500.                     break;
  2501.                 case 7    :
  2502.                     return self::STDEV($aArgs);
  2503.                     break;
  2504.                 case 8    :
  2505.                     return self::STDEVP($aArgs);
  2506.                     break;
  2507.                 case 9    :
  2508.                     return self::SUM($aArgs);
  2509.                     break;
  2510.                 case 10    :
  2511.                     return self::VARFunc($aArgs);
  2512.                     break;
  2513.                 case 11    :
  2514.                     return self::VARP($aArgs);
  2515.                     break;
  2516.             }
  2517.         }
  2518.         return self::$_errorCodes['value'];
  2519.     }    //    function SUBTOTAL()
  2520.  
  2521.  
  2522.     /**
  2523.      * SQRTPI
  2524.      *
  2525.      * Returns the square root of (number * pi).
  2526.      *
  2527.      * @param    float    $number        Number
  2528.      * @return    float    Square Root of Number * Pi
  2529.      */
  2530.     public static function SQRTPI($number{
  2531.         $number    self::flattenSingleValue($number);
  2532.  
  2533.         if (is_numeric($number)) {
  2534.             if ($number 0{
  2535.                 return self::$_errorCodes['num'];
  2536.             }
  2537.             return sqrt($number pi()) ;
  2538.         }
  2539.         return self::$_errorCodes['value'];
  2540.     }    //    function SQRTPI()
  2541.  
  2542.  
  2543.     /**
  2544.      * FACT
  2545.      *
  2546.      * Returns the factorial of a number.
  2547.      *
  2548.      * @param    float    $factVal    Factorial Value
  2549.      * @return    int        Factorial
  2550.      */
  2551.     public static function FACT($factVal{
  2552.         $factVal    self::flattenSingleValue($factVal);
  2553.  
  2554.         if (is_numeric($factVal)) {
  2555.             if ($factVal 0{
  2556.                 return self::$_errorCodes['num'];
  2557.             }
  2558.             $factLoop floor($factVal);
  2559.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  2560.                 if ($factVal $factLoop{
  2561.                     return self::$_errorCodes['num'];
  2562.                 }
  2563.             }
  2564.             $factorial 1;
  2565.             while ($factLoop 1{
  2566.                 $factorial *= $factLoop--;
  2567.             }
  2568.             return $factorial ;
  2569.         }
  2570.         return self::$_errorCodes['value'];
  2571.     }    //    function FACT()
  2572.  
  2573.  
  2574.     /**
  2575.      * FACTDOUBLE
  2576.      *
  2577.      * Returns the double factorial of a number.
  2578.      *
  2579.      * @param    float    $factVal    Factorial Value
  2580.      * @return    int        Double Factorial
  2581.      */
  2582.     public static function FACTDOUBLE($factVal{
  2583.         $factLoop    floor(self::flattenSingleValue($factVal));
  2584.  
  2585.         if (is_numeric($factLoop)) {
  2586.             if ($factVal 0{
  2587.                 return self::$_errorCodes['num'];
  2588.             }
  2589.             $factorial 1;
  2590.             while ($factLoop 1{
  2591.                 $factorial *= $factLoop--;
  2592.                 --$factLoop;
  2593.             }
  2594.             return $factorial ;
  2595.         }
  2596.         return self::$_errorCodes['value'];
  2597.     }    //    function FACTDOUBLE()
  2598.  
  2599.  
  2600.     /**
  2601.      * MULTINOMIAL
  2602.      *
  2603.      * Returns the ratio of the factorial of a sum of values to the product of factorials.
  2604.      *
  2605.      * @param    array of mixed        Data Series
  2606.      * @return    float 
  2607.      */
  2608.     public static function MULTINOMIAL({
  2609.         // Loop through arguments
  2610.         $aArgs self::flattenArray(func_get_args());
  2611.         $summer 0;
  2612.         $divisor 1;
  2613.         foreach ($aArgs as $arg{
  2614.             // Is it a numeric value?
  2615.             if (is_numeric($arg)) {
  2616.                 if ($arg 1{
  2617.                     return self::$_errorCodes['num'];
  2618.                 }
  2619.                 $summer += floor($arg);
  2620.                 $divisor *= self::FACT($arg);
  2621.             else {
  2622.                 return self::$_errorCodes['value'];
  2623.             }
  2624.         }
  2625.  
  2626.         // Return
  2627.         if ($summer 0{
  2628.             $summer self::FACT($summer);
  2629.             return $summer $divisor;
  2630.         }
  2631.         return 0;
  2632.     }    //    function MULTINOMIAL()
  2633.  
  2634.  
  2635.     /**
  2636.      * CEILING
  2637.      *
  2638.      * Returns number rounded up, away from zero, to the nearest multiple of significance.
  2639.      *
  2640.      * @param    float    $number            Number to round
  2641.      * @param    float    $significance    Significance
  2642.      * @return    float    Rounded Number
  2643.      */
  2644.     public static function CEILING($number,$significance=null{
  2645.         $number            self::flattenSingleValue($number);
  2646.         $significance    self::flattenSingleValue($significance);
  2647.  
  2648.         if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  2649.             $significance $number/abs($number);
  2650.         }
  2651.  
  2652.         if ((is_numeric($number)) && (is_numeric($significance))) {
  2653.             if (self::SIGN($number== self::SIGN($significance)) {
  2654.                 if ($significance == 0.0{
  2655.                     return 0;
  2656.                 }
  2657.                 return ceil($number $significance$significance;
  2658.             else {
  2659.                 return self::$_errorCodes['num'];
  2660.             }
  2661.         }
  2662.         return self::$_errorCodes['value'];
  2663.     }    //    function CEILING()
  2664.  
  2665.  
  2666.     /**
  2667.      * EVEN
  2668.      *
  2669.      * Returns number rounded up to the nearest even integer.
  2670.      *
  2671.      * @param    float    $number            Number to round
  2672.      * @return    int        Rounded Number
  2673.      */
  2674.     public static function EVEN($number{
  2675.         $number    self::flattenSingleValue($number);
  2676.  
  2677.         if (is_numeric($number)) {
  2678.             $significance self::SIGN($number);
  2679.             return self::CEILING($number,$significance);
  2680.         }
  2681.         return self::$_errorCodes['value'];
  2682.     }    //    function EVEN()
  2683.  
  2684.  
  2685.     /**
  2686.      * ODD
  2687.      *
  2688.      * Returns number rounded up to the nearest odd integer.
  2689.      *
  2690.      * @param    float    $number            Number to round
  2691.      * @return    int        Rounded Number
  2692.      */
  2693.     public static function ODD($number{
  2694.         $number    self::flattenSingleValue($number);
  2695.  
  2696.         if (is_numeric($number)) {
  2697.             $significance self::SIGN($number);
  2698.             if ($significance == 0{
  2699.                 return 1;
  2700.             }
  2701.             $result self::CEILING($number,$significance);
  2702.             if (self::IS_EVEN($result)) {
  2703.                 $result += $significance;
  2704.             }
  2705.             return $result;
  2706.         }
  2707.         return self::$_errorCodes['value'];
  2708.     }    //    function ODD()
  2709.  
  2710.  
  2711.     /**
  2712.      *    INTVALUE
  2713.      *
  2714.      *    Casts a floating point value to an integer
  2715.      *
  2716.      *    @param    float    $number            Number to cast to an integer
  2717.      *    @return    integer    Integer value
  2718.      */
  2719.     public static function INTVALUE($number{
  2720.         $number    self::flattenSingleValue($number);
  2721.  
  2722.         if (is_numeric($number)) {
  2723.             return (int) floor($number);
  2724.         }
  2725.         return self::$_errorCodes['value'];
  2726.     }    //    function INTVALUE()
  2727.  
  2728.  
  2729.     /**
  2730.      * ROUNDUP
  2731.      *
  2732.      * Rounds a number up to a specified number of decimal places
  2733.      *
  2734.      * @param    float    $number            Number to round
  2735.      * @param    int        $digits            Number of digits to which you want to round $number
  2736.      * @return    float    Rounded Number
  2737.      */
  2738.     public static function ROUNDUP($number,$digits{
  2739.         $number    self::flattenSingleValue($number);
  2740.         $digits    self::flattenSingleValue($digits);
  2741.  
  2742.         if ((is_numeric($number)) && (is_numeric($digits))) {
  2743.             $significance pow(10,$digits);
  2744.             if ($number 0.0{
  2745.                 return floor($number $significance$significance;
  2746.             else {
  2747.                 return ceil($number $significance$significance;
  2748.             }
  2749.         }
  2750.         return self::$_errorCodes['value'];
  2751.     }    //    function ROUNDUP()
  2752.  
  2753.  
  2754.     /**
  2755.      * ROUNDDOWN
  2756.      *
  2757.      * Rounds a number down to a specified number of decimal places
  2758.      *
  2759.      * @param    float    $number            Number to round
  2760.      * @param    int        $digits            Number of digits to which you want to round $number
  2761.      * @return    float    Rounded Number
  2762.      */
  2763.     public static function ROUNDDOWN($number,$digits{
  2764.         $number    self::flattenSingleValue($number);
  2765.         $digits    self::flattenSingleValue($digits);
  2766.  
  2767.         if ((is_numeric($number)) && (is_numeric($digits))) {
  2768.             $significance pow(10,$digits);
  2769.             if ($number 0.0{
  2770.                 return ceil($number $significance$significance;
  2771.             else {
  2772.                 return floor($number $significance$significance;
  2773.             }
  2774.         }
  2775.         return self::$_errorCodes['value'];
  2776.     }    //    function ROUNDDOWN()
  2777.  
  2778.  
  2779.     /**
  2780.      * MROUND
  2781.      *
  2782.      * Rounds a number to the nearest multiple of a specified value
  2783.      *
  2784.      * @param    float    $number            Number to round
  2785.      * @param    int        $multiple        Multiple to which you want to round $number
  2786.      * @return    float    Rounded Number
  2787.      */
  2788.     public static function MROUND($number,$multiple{
  2789.         $number        self::flattenSingleValue($number);
  2790.         $multiple    self::flattenSingleValue($multiple);
  2791.  
  2792.         if ((is_numeric($number)) && (is_numeric($multiple))) {
  2793.             if ($multiple == 0{
  2794.                 return 0;
  2795.             }
  2796.             if ((self::SIGN($number)) == (self::SIGN($multiple))) {
  2797.                 $multiplier $multiple;
  2798.                 return round($number $multiplier$multiplier;
  2799.             }
  2800.             return self::$_errorCodes['num'];
  2801.         }
  2802.         return self::$_errorCodes['value'];
  2803.     }    //    function MROUND()
  2804.  
  2805.  
  2806.     /**
  2807.      * SIGN
  2808.      *
  2809.      * Determines the sign of a number. Returns 1 if the number is positive, zero (0)
  2810.      * if the number is 0, and -1 if the number is negative.
  2811.      *
  2812.      * @param    float    $number            Number to round
  2813.      * @return    int        sign value
  2814.      */
  2815.     public static function SIGN($number{
  2816.         $number    self::flattenSingleValue($number);
  2817.  
  2818.         if (is_numeric($number)) {
  2819.             if ($number == 0.0{
  2820.                 return 0;
  2821.             }
  2822.             return $number abs($number);
  2823.         }
  2824.         return self::$_errorCodes['value'];
  2825.     }    //    function SIGN()
  2826.  
  2827.  
  2828.     /**
  2829.      * FLOOR
  2830.      *
  2831.      * Rounds number down, toward zero, to the nearest multiple of significance.
  2832.      *
  2833.      * @param    float    $number            Number to round
  2834.      * @param    float    $significance    Significance
  2835.      * @return    float    Rounded Number
  2836.      */
  2837.     public static function FLOOR($number,$significance=null{
  2838.         $number            self::flattenSingleValue($number);
  2839.         $significance    self::flattenSingleValue($significance);
  2840.  
  2841.         if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  2842.             $significance $number/abs($number);
  2843.         }
  2844.  
  2845.         if ((is_numeric($number)) && (is_numeric($significance))) {
  2846.             if ((float) $significance == 0.0{
  2847.                 return self::$_errorCodes['divisionbyzero'];
  2848.             }
  2849.             if (self::SIGN($number== self::SIGN($significance)) {
  2850.                 return floor($number $significance$significance;
  2851.             else {
  2852.                 return self::$_errorCodes['num'];
  2853.             }
  2854.         }
  2855.         return self::$_errorCodes['value'];
  2856.     }    //    function FLOOR()
  2857.  
  2858.  
  2859.     /**
  2860.      *    PERMUT
  2861.      *
  2862.      *    Returns the number of permutations for a given number of objects that can be
  2863.      *    selected from number objects. A permutation is any set or subset of objects or
  2864.      *    events where internal order is significant. Permutations are different from
  2865.      *    combinations, for which the internal order is not significant. Use this function
  2866.      *    for lottery-style probability calculations.
  2867.      *
  2868.      *    @param    int        $numObjs    Number of different objects
  2869.      *    @param    int        $numInSet    Number of objects in each permutation
  2870.      *    @return    int        Number of permutations
  2871.      */
  2872.     public static function PERMUT($numObjs,$numInSet{
  2873.         $numObjs    self::flattenSingleValue($numObjs);
  2874.         $numInSet    self::flattenSingleValue($numInSet);
  2875.  
  2876.         if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
  2877.             if ($numObjs $numInSet{
  2878.                 return self::$_errorCodes['num'];
  2879.             }
  2880.             return round(self::FACT($numObjsself::FACT($numObjs $numInSet));
  2881.         }
  2882.         return self::$_errorCodes['value'];
  2883.     }    //    function PERMUT()
  2884.  
  2885.  
  2886.     /**
  2887.      *    COMBIN
  2888.      *
  2889.      *    Returns the number of combinations for a given number of items. Use COMBIN to
  2890.      *    determine the total possible number of groups for a given number of items.
  2891.      *
  2892.      *    @param    int        $numObjs    Number of different objects
  2893.      *    @param    int        $numInSet    Number of objects in each combination
  2894.      *    @return    int        Number of combinations
  2895.      */
  2896.     public static function COMBIN($numObjs,$numInSet{
  2897.         $numObjs    self::flattenSingleValue($numObjs);
  2898.         $numInSet    self::flattenSingleValue($numInSet);
  2899.  
  2900.         if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
  2901.             if ($numObjs $numInSet{
  2902.                 return self::$_errorCodes['num'];
  2903.             elseif ($numInSet 0{
  2904.                 return self::$_errorCodes['num'];
  2905.             }
  2906.             return round(self::FACT($numObjsself::FACT($numObjs $numInSet)) self::FACT($numInSet);
  2907.         }
  2908.         return self::$_errorCodes['value'];
  2909.     }    //    function COMBIN()
  2910.  
  2911.  
  2912.     /**
  2913.      * SERIESSUM
  2914.      *
  2915.      * Returns the sum of a power series
  2916.      *
  2917.      * @param    float            $x    Input value to the power series
  2918.      * @param    float            $n    Initial power to which you want to raise $x
  2919.      * @param    float            $m    Step by which to increase $n for each term in the series
  2920.      * @param    array of mixed        Data Series
  2921.      * @return    float 
  2922.      */
  2923.     public static function SERIESSUM({
  2924.         // Return value
  2925.         $returnValue 0;
  2926.  
  2927.         // Loop trough arguments
  2928.         $aArgs self::flattenArray(func_get_args());
  2929.  
  2930.         $x array_shift($aArgs);
  2931.         $n array_shift($aArgs);
  2932.         $m array_shift($aArgs);
  2933.  
  2934.         if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) {
  2935.             // Calculate
  2936.             $i 0;
  2937.             foreach($aArgs as $arg{
  2938.                 // Is it a numeric value?
  2939.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  2940.                     $returnValue += $arg pow($x,$n ($m $i++));
  2941.                 else {
  2942.                     return self::$_errorCodes['value'];
  2943.                 }
  2944.             }
  2945.             // Return
  2946.             return $returnValue;
  2947.         }
  2948.         return self::$_errorCodes['value'];
  2949.     }    //    function SERIESSUM()
  2950.  
  2951.  
  2952.     /**
  2953.      * STANDARDIZE
  2954.      *
  2955.      * Returns a normalized value from a distribution characterized by mean and standard_dev.
  2956.      *
  2957.      * @param    float    $value        Value to normalize
  2958.      * @param    float    $mean        Mean Value
  2959.      * @param    float    $stdDev        Standard Deviation
  2960.      * @return    float    Standardized value
  2961.      */
  2962.     public static function STANDARDIZE($value,$mean,$stdDev{
  2963.         $value    self::flattenSingleValue($value);
  2964.         $mean    self::flattenSingleValue($mean);
  2965.         $stdDev    self::flattenSingleValue($stdDev);
  2966.  
  2967.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  2968.             if ($stdDev <= 0{
  2969.                 return self::$_errorCodes['num'];
  2970.             }
  2971.             return ($value $mean$stdDev ;
  2972.         }
  2973.         return self::$_errorCodes['value'];
  2974.     }    //    function STANDARDIZE()
  2975.  
  2976.  
  2977.     //
  2978.     //    Private method to return an array of the factors of the input value
  2979.     //
  2980.     private static function _factors($value{
  2981.         $startVal floor(sqrt($value));
  2982.  
  2983.         $factorArray array();
  2984.         for ($i $startVal$i 1--$i{
  2985.             if (($value $i== 0{
  2986.                 $factorArray array_merge($factorArray,self::_factors($value $i));
  2987.                 $factorArray array_merge($factorArray,self::_factors($i));
  2988.                 if ($i <= sqrt($value)) {
  2989.                     break;
  2990.                 }
  2991.             }
  2992.         }
  2993.         if (count($factorArray0{
  2994.             rsort($factorArray);
  2995.             return $factorArray;
  2996.         else {
  2997.             return array((integer) $value);
  2998.         }
  2999.     }    //    function _factors()
  3000.  
  3001.  
  3002.     /**
  3003.      * LCM
  3004.      *
  3005.      * Returns the lowest common multiplier of a series of numbers
  3006.      *
  3007.      * @param    $array    Values to calculate the Lowest Common Multiplier
  3008.      * @return    int        Lowest Common Multiplier
  3009.      */
  3010.     public static function LCM({
  3011.         $aArgs self::flattenArray(func_get_args());
  3012.  
  3013.         $returnValue 1;
  3014.         $allPoweredFactors array();
  3015.         foreach($aArgs as $value{
  3016.             if (!is_numeric($value)) {
  3017.                 return self::$_errorCodes['value'];
  3018.             }
  3019.             if ($value == 0{
  3020.                 return 0;
  3021.             elseif ($value 0{
  3022.                 return self::$_errorCodes['num'];
  3023.             }
  3024.             $myFactors self::_factors(floor($value));
  3025.             $myCountedFactors array_count_values($myFactors);
  3026.             $myPoweredFactors array();
  3027.             foreach($myCountedFactors as $myCountedFactor => $myCountedPower{
  3028.                 $myPoweredFactors[$myCountedFactorpow($myCountedFactor,$myCountedPower);
  3029.             }
  3030.             foreach($myPoweredFactors as $myPoweredValue => $myPoweredFactor{
  3031.                 if (array_key_exists($myPoweredValue,$allPoweredFactors)) {
  3032.                     if ($allPoweredFactors[$myPoweredValue$myPoweredFactor{
  3033.                         $allPoweredFactors[$myPoweredValue$myPoweredFactor;
  3034.                     }
  3035.                 else {
  3036.                     $allPoweredFactors[$myPoweredValue$myPoweredFactor;
  3037.                 }
  3038.             }
  3039.         }
  3040.         foreach($allPoweredFactors as $allPoweredFactor{
  3041.             $returnValue *= (integer) $allPoweredFactor;
  3042.         }
  3043.         return $returnValue;
  3044.     }    //    function LCM()
  3045.  
  3046.  
  3047.     /**
  3048.      * GCD
  3049.      *
  3050.      * Returns the greatest common divisor of a series of numbers
  3051.      *
  3052.      * @param    $array    Values to calculate the Greatest Common Divisor
  3053.      * @return    int        Greatest Common Divisor
  3054.      */
  3055.     public static function GCD({
  3056.         $aArgs self::flattenArray(func_get_args());
  3057.  
  3058.         $returnValue 1;
  3059.         $allPoweredFactors array();
  3060.         foreach($aArgs as $value{
  3061.             if ($value == 0{
  3062.                 break;
  3063.             }
  3064.             $myFactors self::_factors($value);
  3065.             $myCountedFactors array_count_values($myFactors);
  3066.             $allValuesFactors[$myCountedFactors;
  3067.         }
  3068.         $allValuesCount count($allValuesFactors);
  3069.         $mergedArray $allValuesFactors[0];
  3070.         for ($i=1;$i $allValuesCount++$i{
  3071.             $mergedArray array_intersect_key($mergedArray,$allValuesFactors[$i]);
  3072.         }
  3073.         $mergedArrayValues count($mergedArray);
  3074.         if ($mergedArrayValues == 0{
  3075.             return $returnValue;
  3076.         elseif ($mergedArrayValues 1{
  3077.             foreach($mergedArray as $mergedKey => $mergedValue{
  3078.                 foreach($allValuesFactors as $highestPowerTest{
  3079.                     foreach($highestPowerTest as $testKey => $testValue{
  3080.                         if (($testKey == $mergedKey&& ($testValue $mergedValue)) {
  3081.                             $mergedArray[$mergedKey$testValue;
  3082.                             $mergedValue $testValue;
  3083.                         }
  3084.                     }
  3085.                 }
  3086.             }
  3087.  
  3088.             $returnValue 1;
  3089.             foreach($mergedArray as $key => $value{
  3090.                 $returnValue *= pow($key,$value);
  3091.             }
  3092.             return $returnValue;
  3093.         else {
  3094.             $keys array_keys($mergedArray);
  3095.             $key $keys[0];
  3096.             $value $mergedArray[$key];
  3097.             foreach($allValuesFactors as $testValue{
  3098.                 foreach($testValue as $mergedKey => $mergedValue{
  3099.                     if (($mergedKey == $key&& ($mergedValue $value)) {
  3100.                         $value $mergedValue;
  3101.                     }
  3102.                 }
  3103.             }
  3104.             return pow($key,$value);
  3105.         }
  3106.     }    //    function GCD()
  3107.  
  3108.  
  3109.     /**
  3110.      * BINOMDIST
  3111.      *
  3112.      * Returns the individual term binomial distribution probability. Use BINOMDIST in problems with
  3113.      * a fixed number of tests or trials, when the outcomes of any trial are only success or failure,
  3114.      * when trials are independent, and when the probability of success is constant throughout the
  3115.      * experiment. For example, BINOMDIST can calculate the probability that two of the next three
  3116.      * babies born are male.
  3117.      *
  3118.      * @param    float        $value            Number of successes in trials
  3119.      * @param    float        $trials            Number of trials
  3120.      * @param    float        $probability    Probability of success on each trial
  3121.      * @param    boolean        $cumulative 
  3122.      * @return    float 
  3123.      *
  3124.      * @todo    Cumulative distribution function
  3125.      *
  3126.      */
  3127.     public static function BINOMDIST($value$trials$probability$cumulative{
  3128.         $value            floor(self::flattenSingleValue($value));
  3129.         $trials            floor(self::flattenSingleValue($trials));
  3130.         $probability    self::flattenSingleValue($probability);
  3131.  
  3132.         if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) {
  3133.             if (($value 0|| ($value $trials)) {
  3134.                 return self::$_errorCodes['num'];
  3135.             }
  3136.             if (($probability 0|| ($probability 1)) {
  3137.                 return self::$_errorCodes['num'];
  3138.             }
  3139.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  3140.                 if ($cumulative{
  3141.                     $summer 0;
  3142.                     for ($i 0$i <= $value++$i{
  3143.                         $summer += self::COMBIN($trials,$ipow($probability,$ipow($probability,$trials $i);
  3144.                     }
  3145.                     return $summer;
  3146.                 else {
  3147.                     return self::COMBIN($trials,$valuepow($probability,$valuepow($probability,$trials $value;
  3148.                 }
  3149.             }
  3150.         }
  3151.         return self::$_errorCodes['value'];
  3152.     }    //    function BINOMDIST()
  3153.  
  3154.  
  3155.     /**
  3156.      * NEGBINOMDIST
  3157.      *
  3158.      * Returns the negative binomial distribution. NEGBINOMDIST returns the probability that
  3159.      * there will be number_f failures before the number_s-th success, when the constant
  3160.      * probability of a success is probability_s. This function is similar to the binomial
  3161.      * distribution, except that the number of successes is fixed, and the number of trials is
  3162.      * variable. Like the binomial, trials are assumed to be independent.
  3163.      *
  3164.      * @param    float        $failures        Number of Failures
  3165.      * @param    float        $successes        Threshold number of Successes
  3166.      * @param    float        $probability    Probability of success on each trial
  3167.      * @return    float 
  3168.      *
  3169.      */
  3170.     public static function NEGBINOMDIST($failures$successes$probability{
  3171.         $failures        floor(self::flattenSingleValue($failures));
  3172.         $successes        floor(self::flattenSingleValue($successes));
  3173.         $probability    self::flattenSingleValue($probability);
  3174.  
  3175.         if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) {
  3176.             if (($failures 0|| ($successes 1)) {
  3177.                 return self::$_errorCodes['num'];
  3178.             }
  3179.             if (($probability 0|| ($probability 1)) {
  3180.                 return self::$_errorCodes['num'];
  3181.             }
  3182.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  3183.                 if (($failures $successes 1<= 0{
  3184.                     return self::$_errorCodes['num'];
  3185.                 }
  3186.             }
  3187.             return (self::COMBIN($failures $successes 1,$successes 1)) (pow($probability,$successes)) (pow($probability,$failures)) ;
  3188.         }
  3189.         return self::$_errorCodes['value'];
  3190.     }    //    function NEGBINOMDIST()
  3191.  
  3192.  
  3193.     /**
  3194.      * CRITBINOM
  3195.      *
  3196.      * Returns the smallest value for which the cumulative binomial distribution is greater
  3197.      * than or equal to a criterion value
  3198.      *
  3199.      * See http://support.microsoft.com/kb/828117/ for details of the algorithm used
  3200.      *
  3201.      * @param    float        $trials            number of Bernoulli trials
  3202.      * @param    float        $probability    probability of a success on each trial
  3203.      * @param    float        $alpha            criterion value
  3204.      * @return    int 
  3205.      *
  3206.      *    @todo    Warning. This implementation differs from the algorithm detailed on the MS
  3207.      *             web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess
  3208.      *             This eliminates a potential endless loop error, but may have an adverse affect on the
  3209.      *             accuracy of the function (although all my tests have so far returned correct results).
  3210.      *
  3211.      */
  3212.     public static function CRITBINOM($trials$probability$alpha{
  3213.         $trials            floor(self::flattenSingleValue($trials));
  3214.         $probability    self::flattenSingleValue($probability);
  3215.         $alpha            self::flattenSingleValue($alpha);
  3216.  
  3217.         if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) {
  3218.             if ($trials 0{
  3219.                 return self::$_errorCodes['num'];
  3220.             }
  3221.             if (($probability 0|| ($probability 1)) {
  3222.                 return self::$_errorCodes['num'];
  3223.             }
  3224.             if (($alpha 0|| ($alpha 1)) {
  3225.                 return self::$_errorCodes['num'];
  3226.             }
  3227.             if ($alpha <= 0.5{
  3228.                 $t sqrt(log(pow($alpha,2)));
  3229.                 $trialsApprox ($t (2.515517 0.802853 $t 0.010328 $t $t(1.432788 $t 0.189269 $t $t 0.001308 $t $t $t));
  3230.             else {
  3231.                 $t sqrt(log(pow($alpha,2)));
  3232.                 $trialsApprox $t (2.515517 0.802853 $t 0.010328 $t $t(1.432788 $t 0.189269 $t $t 0.001308 $t $t $t);
  3233.             }
  3234.             $Guess floor($trials $probability $trialsApprox sqrt($trials $probability ($probability)));
  3235.             if ($Guess 0{
  3236.                 $Guess 0;
  3237.             elseif ($Guess $trials{
  3238.                 $Guess $trials;
  3239.             }
  3240.  
  3241.             $TotalUnscaledProbability $UnscaledPGuess $UnscaledCumPGuess 0.0;
  3242.             $EssentiallyZero 10e-12;
  3243.  
  3244.             $m floor($trials $probability);
  3245.             ++$TotalUnscaledProbability;
  3246.             if ($m == $Guess++$UnscaledPGuess}
  3247.             if ($m <= $Guess++$UnscaledCumPGuess}
  3248.  
  3249.             $PreviousValue 1;
  3250.             $Done False;
  3251.             $k $m 1;
  3252.             while ((!$Done&& ($k <= $trials)) {
  3253.                 $CurrentValue $PreviousValue ($trials $k 1$probability ($k ($probability));
  3254.                 $TotalUnscaledProbability += $CurrentValue;
  3255.                 if ($k == $Guess$UnscaledPGuess += $CurrentValue}
  3256.                 if ($k <= $Guess$UnscaledCumPGuess += $CurrentValue}
  3257.                 if ($CurrentValue <= $EssentiallyZero$Done True}
  3258.                 $PreviousValue $CurrentValue;
  3259.                 ++$k;
  3260.             }
  3261.  
  3262.             $PreviousValue 1;
  3263.             $Done False;
  3264.             $k $m 1;
  3265.             while ((!$Done&& ($k >= 0)) {
  3266.                 $CurrentValue $PreviousValue $k ($probability(($trials $k$probability);
  3267.                 $TotalUnscaledProbability += $CurrentValue;
  3268.                 if ($k == $Guess$UnscaledPGuess += $CurrentValue}
  3269.                 if ($k <= $Guess$UnscaledCumPGuess += $CurrentValue}
  3270.                 if ($CurrentValue <= $EssentiallyZero$Done True}
  3271.                 $PreviousValue $CurrentValue;
  3272.                 --$k;
  3273.             }
  3274.  
  3275.             $PGuess $UnscaledPGuess $TotalUnscaledProbability;
  3276.             $CumPGuess $UnscaledCumPGuess $TotalUnscaledProbability;
  3277.  
  3278. //            $CumPGuessMinus1 = $CumPGuess - $PGuess;
  3279.             $CumPGuessMinus1 $CumPGuess 1;
  3280.  
  3281.             while (True{
  3282.                 if (($CumPGuessMinus1 $alpha&& ($CumPGuess >= $alpha)) {
  3283.                     return $Guess;
  3284.                 elseif (($CumPGuessMinus1 $alpha&& ($CumPGuess $alpha)) {
  3285.                     $PGuessPlus1 $PGuess ($trials $Guess$probability $Guess ($probability);
  3286.                     $CumPGuessMinus1 $CumPGuess;
  3287.                     $CumPGuess $CumPGuess $PGuessPlus1;
  3288.                     $PGuess $PGuessPlus1;
  3289.                     ++$Guess;
  3290.                 elseif (($CumPGuessMinus1 >= $alpha&& ($CumPGuess >= $alpha)) {
  3291.                     $PGuessMinus1 $PGuess $Guess ($probability($trials $Guess 1$probability;
  3292.                     $CumPGuess $CumPGuessMinus1;
  3293.                     $CumPGuessMinus1 $CumPGuessMinus1 $PGuess;
  3294.                     $PGuess $PGuessMinus1;
  3295.                     --$Guess;
  3296.                 }
  3297.             }
  3298.         }
  3299.         return self::$_errorCodes['value'];
  3300.     }    //    function CRITBINOM()
  3301.  
  3302.  
  3303.     /**
  3304.      * CHIDIST
  3305.      *
  3306.      * Returns the one-tailed probability of the chi-squared distribution.
  3307.      *
  3308.      * @param    float        $value            Value for the function
  3309.      * @param    float        $degrees        degrees of freedom
  3310.      * @return    float 
  3311.      */
  3312.     public static function CHIDIST($value$degrees{
  3313.         $value        self::flattenSingleValue($value);
  3314.         $degrees    floor(self::flattenSingleValue($degrees));
  3315.  
  3316.         if ((is_numeric($value)) && (is_numeric($degrees))) {
  3317.             if ($degrees 1{
  3318.                 return self::$_errorCodes['num'];
  3319.             }
  3320.             if ($value 0{
  3321.                 if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  3322.                     return 1;
  3323.                 }
  3324.                 return self::$_errorCodes['num'];
  3325.             }
  3326.             return (self::_incompleteGamma($degrees/2,$value/2self::_gamma($degrees/2));
  3327.         }
  3328.         return self::$_errorCodes['value'];
  3329.     }    //    function CHIDIST()
  3330.  
  3331.  
  3332.     /**
  3333.      * CHIINV
  3334.      *
  3335.      * Returns the one-tailed probability of the chi-squared distribution.
  3336.      *
  3337.      * @param    float        $probability    Probability for the function
  3338.      * @param    float        $degrees        degrees of freedom
  3339.      * @return    float 
  3340.      */
  3341.     public static function CHIINV($probability$degrees{
  3342.         $probability    self::flattenSingleValue($probability);
  3343.         $degrees        floor(self::flattenSingleValue($degrees));
  3344.  
  3345.         if ((is_numeric($probability)) && (is_numeric($degrees))) {
  3346.             $xLo 100;
  3347.             $xHi 0;
  3348.             $maxIteration 100;
  3349.  
  3350.             $x $xNew 1;
  3351.             $dx    1;
  3352.             $i 0;
  3353.  
  3354.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  3355.                 // Apply Newton-Raphson step
  3356.                 $result self::CHIDIST($x$degrees);
  3357.                 $error $result $probability;
  3358.                 if ($error == 0.0{
  3359.                     $dx 0;
  3360.                 elseif ($error 0.0{
  3361.                     $xLo $x;
  3362.                 else {
  3363.                     $xHi $x;
  3364.                 }
  3365.                 // Avoid division by zero
  3366.                 if ($result != 0.0{
  3367.                     $dx $error $result;
  3368.                     $xNew $x $dx;
  3369.                 }
  3370.                 // If the NR fails to converge (which for example may be the
  3371.                 // case if the initial guess is too rough) we apply a bisection
  3372.                 // step to determine a more narrow interval around the root.
  3373.                 if (($xNew $xLo|| ($xNew $xHi|| ($result == 0.0)) {
  3374.                     $xNew ($xLo $xHi2;
  3375.                     $dx $xNew $x;
  3376.                 }
  3377.                 $x $xNew;
  3378.             }
  3379.             if ($i == MAX_ITERATIONS{
  3380.                 return self::$_errorCodes['na'];
  3381.             }
  3382.             return round($x,12);
  3383.         }
  3384.         return self::$_errorCodes['value'];
  3385.     }    //    function CHIINV()
  3386.  
  3387.  
  3388.     /**
  3389.      * EXPONDIST
  3390.      *
  3391.      * Returns the exponential distribution. Use EXPONDIST to model the time between events,
  3392.      * such as how long an automated bank teller takes to deliver cash. For example, you can
  3393.      * use EXPONDIST to determine the probability that the process takes at most 1 minute.
  3394.      *
  3395.      * @param    float        $value            Value of the function
  3396.      * @param    float        $lambda            The parameter value
  3397.      * @param    boolean        $cumulative 
  3398.      * @return    float 
  3399.      */
  3400.     public static function EXPONDIST($value$lambda$cumulative{
  3401.         $value    self::flattenSingleValue($value);
  3402.         $lambda    self::flattenSingleValue($lambda);
  3403.         $cumulative    self::flattenSingleValue($cumulative);
  3404.  
  3405.         if ((is_numeric($value)) && (is_numeric($lambda))) {
  3406.             if (($value 0|| ($lambda 0)) {
  3407.                 return self::$_errorCodes['num'];
  3408.             }
  3409.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  3410.                 if ($cumulative{
  3411.                     return exp(0-$value*$lambda);
  3412.                 else {
  3413.                     return $lambda exp(0-$value*$lambda);
  3414.                 }
  3415.             }
  3416.         }
  3417.         return self::$_errorCodes['value'];
  3418.     }    //    function EXPONDIST()
  3419.  
  3420.  
  3421.     /**
  3422.      * FISHER
  3423.      *
  3424.      * Returns the Fisher transformation at x. This transformation produces a function that
  3425.      * is normally distributed rather than skewed. Use this function to perform hypothesis
  3426.      * testing on the correlation coefficient.
  3427.      *
  3428.      * @param    float        $value 
  3429.      * @return    float 
  3430.      */
  3431.     public static function FISHER($value{
  3432.         $value    self::flattenSingleValue($value);
  3433.  
  3434.         if (is_numeric($value)) {
  3435.             if (($value <= -1|| ($value >= 1)) {
  3436.                 return self::$_errorCodes['num'];
  3437.             }
  3438.             return 0.5 log((1+$value)/(1-$value));
  3439.         }
  3440.         return self::$_errorCodes['value'];
  3441.     }    //    function FISHER()
  3442.  
  3443.  
  3444.     /**
  3445.      * FISHERINV
  3446.      *
  3447.      * Returns the inverse of the Fisher transformation. Use this transformation when
  3448.      * analyzing correlations between ranges or arrays of data. If y = FISHER(x), then
  3449.      * FISHERINV(y) = x.
  3450.      *
  3451.      * @param    float        $value 
  3452.      * @return    float 
  3453.      */
  3454.     public static function FISHERINV($value{
  3455.         $value    self::flattenSingleValue($value);
  3456.  
  3457.         if (is_numeric($value)) {
  3458.             return (exp($value1(exp($value1);
  3459.         }
  3460.         return self::$_errorCodes['value'];
  3461.     }    //    function FISHERINV()
  3462.  
  3463.  
  3464.     // Function cache for _logBeta function
  3465.     private static $_logBetaCache_p            0.0;
  3466.     private static $_logBetaCache_q            0.0;
  3467.     private static $_logBetaCache_result    0.0;
  3468.  
  3469.     /**
  3470.      * The natural logarithm of the beta function.
  3471.      * @param require p>0
  3472.      * @param require q>0
  3473.      * @return if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
  3474.      * @author Jaco van Kooten
  3475.      */
  3476.     private static function _logBeta($p$q{
  3477.         if ($p != self::$_logBetaCache_p || $q != self::$_logBetaCache_q{
  3478.             self::$_logBetaCache_p $p;
  3479.             self::$_logBetaCache_q $q;
  3480.             if (($p <= 0.0|| ($q <= 0.0|| (($p $qLOG_GAMMA_X_MAX_VALUE)) {
  3481.                 self::$_logBetaCache_result 0.0;
  3482.             else {
  3483.                 self::$_logBetaCache_result self::_logGamma($pself::_logGamma($qself::_logGamma($p $q);
  3484.             }
  3485.         }
  3486.         return self::$_logBetaCache_result;
  3487.     }    //    function _logBeta()
  3488.  
  3489.  
  3490.     /**
  3491.      * Evaluates of continued fraction part of incomplete beta function.
  3492.      * Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
  3493.      * @author Jaco van Kooten
  3494.      */
  3495.     private static function _betaFraction($x$p$q{
  3496.         $c 1.0;
  3497.         $sum_pq $p $q;
  3498.         $p_plus $p 1.0;
  3499.         $p_minus $p 1.0;
  3500.         $h 1.0 $sum_pq $x $p_plus;
  3501.         if (abs($hXMININ{
  3502.             $h XMININ;
  3503.         }
  3504.         $h 1.0 $h;
  3505.         $frac $h;
  3506.         $m     1;
  3507.         $delta 0.0;
  3508.         while ($m <= MAX_ITERATIONS && abs($delta-1.0PRECISION {
  3509.             $m2 $m;
  3510.             // even index for d
  3511.             $d $m ($q $m$x ( ($p_minus $m2($p $m2));
  3512.             $h 1.0 $d $h;
  3513.             if (abs($hXMININ{
  3514.                 $h XMININ;
  3515.             }
  3516.             $h 1.0 $h;
  3517.             $c 1.0 $d $c;
  3518.             if (abs($cXMININ{
  3519.                 $c XMININ;
  3520.             }
  3521.             $frac *= $h $c;
  3522.             // odd index for d
  3523.             $d = -($p $m($sum_pq $m$x (($p $m2($p_plus $m2));
  3524.             $h 1.0 $d $h;
  3525.             if (abs($hXMININ{
  3526.                 $h XMININ;
  3527.             }
  3528.             $h 1.0 $h;
  3529.             $c 1.0 $d $c;
  3530.             if (abs($cXMININ{
  3531.                 $c XMININ;
  3532.             }
  3533.             $delta $h $c;
  3534.             $frac *= $delta;
  3535.             ++$m;
  3536.         }
  3537.         return $frac;
  3538.     }    //    function _betaFraction()
  3539.  
  3540.  
  3541.     /**
  3542.      * logGamma function
  3543.      *
  3544.      * @version 1.1
  3545.      * @author Jaco van Kooten
  3546.      *
  3547.      *  Original author was Jaco van Kooten. Ported to PHP by Paul Meagher.
  3548.      *
  3549.      *  The natural logarithm of the gamma function. <br />
  3550.      *  Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz <br />
  3551.      *  Applied Mathematics Division <br />
  3552.      *  Argonne National Laboratory <br />
  3553.      *  Argonne, IL 60439 <br />
  3554.      *  <p>
  3555.      *  References:
  3556.      *  <ol>
  3557.      *  <li>W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural
  3558.      *      Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.</li>
  3559.      *  <li>K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.</li>
  3560.      *  <li>Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.</li>
  3561.      *  </ol>
  3562.      *  </p>
  3563.      *  <p>
  3564.      *  From the original documentation:
  3565.      *  </p>
  3566.      *  <p>
  3567.      *  This routine calculates the LOG(GAMMA) function for a positive real argument X.
  3568.      *  Computation is based on an algorithm outlined in references 1 and 2.
  3569.      *  The program uses rational functions that theoretically approximate LOG(GAMMA)
  3570.      *  to at least 18 significant decimal digits. The approximation for X > 12 is from
  3571.      *  reference 3, while approximations for X < 12.0 are similar to those in reference
  3572.      *  1, but are unpublished. The accuracy achieved depends on the arithmetic system,
  3573.      *  the compiler, the intrinsic functions, and proper selection of the
  3574.      *  machine-dependent constants.
  3575.      *  </p>
  3576.      *  <p>
  3577.      *  Error returns: <br />
  3578.      *  The program returns the value XINF for X .LE. 0.0 or when overflow would occur.
  3579.      *  The computation is believed to be free of underflow and overflow.
  3580.      *  </p>
  3581.      * @return MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305
  3582.      */
  3583.  
  3584.     // Function cache for logGamma
  3585.     private static $_logGammaCache_result    0.0;
  3586.     private static $_logGammaCache_x        0.0;
  3587.  
  3588.     private static function _logGamma($x{
  3589.         // Log Gamma related constants
  3590.         static $lg_d1 = -0.5772156649015328605195174;
  3591.         static $lg_d2 0.4227843350984671393993777;
  3592.         static $lg_d4 1.791759469228055000094023;
  3593.  
  3594.         static $lg_p1 array(    4.945235359296727046734888,
  3595.                                 201.8112620856775083915565,
  3596.                                 2290.838373831346393026739,
  3597.                                 11319.67205903380828685045,
  3598.                                 28557.24635671635335736389,
  3599.                                 38484.96228443793359990269,
  3600.                                 26377.48787624195437963534,
  3601.                                 7225.813979700288197698961 );
  3602.         static $lg_p2 array(    4.974607845568932035012064,
  3603.                                 542.4138599891070494101986,
  3604.                                 15506.93864978364947665077,
  3605.                                 184793.2904445632425417223,
  3606.                                 1088204.76946882876749847,
  3607.                                 3338152.967987029735917223,
  3608.                                 5106661.678927352456275255,
  3609.                                 3074109.054850539556250927 );
  3610.         static $lg_p4 array(    14745.02166059939948905062,
  3611.                                 2426813.369486704502836312,
  3612.                                 121475557.4045093227939592,
  3613.                                 2663432449.630976949898078,
  3614.                                 29403789566.34553899906876,
  3615.                                 170266573776.5398868392998,
  3616.                                 492612579337.743088758812,
  3617.                                 560625185622.3951465078242 );
  3618.  
  3619.         static $lg_q1 array(    67.48212550303777196073036,
  3620.                                 1113.332393857199323513008,
  3621.                                 7738.757056935398733233834,
  3622.                                 27639.87074403340708898585,
  3623.                                 54993.10206226157329794414,
  3624.                                 61611.22180066002127833352,
  3625.                                 36351.27591501940507276287,
  3626.                                 8785.536302431013170870835 );
  3627.         static $lg_q2 array(    183.0328399370592604055942,
  3628.                                 7765.049321445005871323047,
  3629.                                 133190.3827966074194402448,
  3630.                                 1136705.821321969608938755,
  3631.                                 5267964.117437946917577538,
  3632.                                 13467014.54311101692290052,
  3633.                                 17827365.30353274213975932,
  3634.                                 9533095.591844353613395747 );
  3635.         static $lg_q4 array(    2690.530175870899333379843,
  3636.                                 639388.5654300092398984238,
  3637.                                 41355999.30241388052042842,
  3638.                                 1120872109.61614794137657,
  3639.                                 14886137286.78813811542398,
  3640.                                 101680358627.2438228077304,
  3641.                                 341747634550.7377132798597,
  3642.                                 446315818741.9713286462081 );
  3643.  
  3644.         static $lg_c  array(    -0.001910444077728,
  3645.                                 8.4171387781295e-4,
  3646.                                 -5.952379913043012e-4,
  3647.                                 7.93650793500350248e-4,
  3648.                                 -0.002777777777777681622553,
  3649.                                 0.08333333333333333331554247,
  3650.                                 0.0057083835261 );
  3651.  
  3652.     // Rough estimate of the fourth root of logGamma_xBig
  3653.     static $lg_frtbig 2.25e76;
  3654.     static $pnt68     0.6796875;
  3655.  
  3656.  
  3657.     if ($x == self::$_logGammaCache_x{
  3658.         return self::$_logGammaCache_result;
  3659.     }
  3660.     $y $x;
  3661.     if ($y 0.0 && $y <= LOG_GAMMA_X_MAX_VALUE{
  3662.         if ($y <= EPS{
  3663.             $res = -log(y);
  3664.         elseif ($y <= 1.5{
  3665.             // ---------------------
  3666.             //    EPS .LT. X .LE. 1.5
  3667.             // ---------------------
  3668.             if ($y $pnt68{
  3669.                 $corr = -log($y);
  3670.                 $xm1 $y;
  3671.             else {
  3672.                 $corr 0.0;
  3673.                 $xm1 $y 1.0;
  3674.             }
  3675.             if ($y <= 0.5 || $y >= $pnt68{
  3676.                 $xden 1.0;
  3677.                 $xnum 0.0;
  3678.                 for ($i 0$i 8++$i{
  3679.                     $xnum $xnum $xm1 $lg_p1[$i];
  3680.                     $xden $xden $xm1 $lg_q1[$i];
  3681.                 }
  3682.                 $res $corr $xm1 ($lg_d1 $xm1 ($xnum $xden));
  3683.             else {
  3684.                 $xm2 $y 1.0;
  3685.                 $xden 1.0;
  3686.                 $xnum 0.0;
  3687.                 for ($i 0$i 8++$i{
  3688.                     $xnum $xnum $xm2 $lg_p2[$i];
  3689.                     $xden $xden $xm2 $lg_q2[$i];
  3690.                 }
  3691.                 $res $corr $xm2 ($lg_d2 $xm2 ($xnum $xden));
  3692.             }
  3693.         elseif ($y <= 4.0{
  3694.             // ---------------------
  3695.             //    1.5 .LT. X .LE. 4.0
  3696.             // ---------------------
  3697.             $xm2 $y 2.0;
  3698.             $xden 1.0;
  3699.             $xnum 0.0;
  3700.             for ($i 0$i 8++$i{
  3701.                 $xnum $xnum $xm2 $lg_p2[$i];
  3702.                 $xden $xden $xm2 $lg_q2[$i];
  3703.             }
  3704.             $res $xm2 ($lg_d2 $xm2 ($xnum $xden));
  3705.         elseif ($y <= 12.0{
  3706.             // ----------------------
  3707.             //    4.0 .LT. X .LE. 12.0
  3708.             // ----------------------
  3709.             $xm4 $y 4.0;
  3710.             $xden = -1.0;
  3711.             $xnum 0.0;
  3712.             for ($i 0$i 8++$i{
  3713.                 $xnum $xnum $xm4 $lg_p4[$i];
  3714.                 $xden $xden $xm4 $lg_q4[$i];
  3715.             }
  3716.             $res $lg_d4 $xm4 ($xnum $xden);
  3717.         else {
  3718.             // ---------------------------------
  3719.             //    Evaluate for argument .GE. 12.0
  3720.             // ---------------------------------
  3721.             $res 0.0;
  3722.             if ($y <= $lg_frtbig{
  3723.                 $res $lg_c[6];
  3724.                 $ysq $y $y;
  3725.                 for ($i 0$i 6++$i)
  3726.                     $res $res $ysq $lg_c[$i];
  3727.                 }
  3728.                 $res /= $y;
  3729.                 $corr log($y);
  3730.                 $res $res log(SQRT2PI0.5 $corr;
  3731.                 $res += $y ($corr 1.0);
  3732.             }
  3733.         else {
  3734.             // --------------------------
  3735.             //    Return for bad arguments
  3736.             // --------------------------
  3737.             $res MAX_VALUE;
  3738.         }
  3739.         // ------------------------------
  3740.         //    Final adjustments and return
  3741.         // ------------------------------
  3742.         self::$_logGammaCache_x $x;
  3743.         self::$_logGammaCache_result $res;
  3744.         return $res;
  3745.     }    //    function _logGamma()
  3746.  
  3747.  
  3748.     /**
  3749.      * Beta function.
  3750.      *
  3751.      * @author Jaco van Kooten
  3752.      *
  3753.      * @param require p>0
  3754.      * @param require q>0
  3755.      * @return if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
  3756.      */
  3757.     private static function _beta($p$q{
  3758.         if ($p <= 0.0 || $q <= 0.0 || ($p $qLOG_GAMMA_X_MAX_VALUE{
  3759.             return 0.0;
  3760.         else {
  3761.             return exp(self::_logBeta($p$q));
  3762.         }
  3763.     }    //    function _beta()
  3764.  
  3765.  
  3766.     /**
  3767.      * Incomplete beta function
  3768.      *
  3769.      * @author Jaco van Kooten
  3770.      * @author Paul Meagher
  3771.      *
  3772.      *  The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992).
  3773.      * @param require 0<=x<=1
  3774.      * @param require p>0
  3775.      * @param require q>0
  3776.      * @return if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow
  3777.      */
  3778.     private static function _incompleteBeta($x$p$q{
  3779.         if ($x <= 0.0{
  3780.             return 0.0;
  3781.         elseif ($x >= 1.0{
  3782.             return 1.0;
  3783.         elseif (($p <= 0.0|| ($q <= 0.0|| (($p $qLOG_GAMMA_X_MAX_VALUE)) {
  3784.             return 0.0;
  3785.         }
  3786.         $beta_gam exp((self::_logBeta($p$q)) $p log($x$q log(1.0 $x));
  3787.         if ($x ($p 1.0($p $q 2.0)) {
  3788.             return $beta_gam self::_betaFraction($x$p$q$p;
  3789.         else {
  3790.             return 1.0 ($beta_gam self::_betaFraction($x$q$p$q);
  3791.         }
  3792.     }    //    function _incompleteBeta()
  3793.  
  3794.  
  3795.     /**
  3796.      * BETADIST
  3797.      *
  3798.      * Returns the beta distribution.
  3799.      *
  3800.      * @param    float        $value            Value at which you want to evaluate the distribution
  3801.      * @param    float        $alpha            Parameter to the distribution
  3802.      * @param    float        $beta            Parameter to the distribution
  3803.      * @param    boolean        $cumulative 
  3804.      * @return    float 
  3805.      *
  3806.      */
  3807.     public static function BETADIST($value,$alpha,$beta,$rMin=0,$rMax=1{
  3808.         $value    self::flattenSingleValue($value);
  3809.         $alpha    self::flattenSingleValue($alpha);
  3810.         $beta    self::flattenSingleValue($beta);
  3811.         $rMin    self::flattenSingleValue($rMin);
  3812.         $rMax    self::flattenSingleValue($rMax);
  3813.  
  3814.         if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
  3815.             if (($value $rMin|| ($value $rMax|| ($alpha <= 0|| ($beta <= 0|| ($rMin == $rMax)) {
  3816.                 return self::$_errorCodes['num'];
  3817.             }
  3818.             if ($rMin $rMax{
  3819.                 $tmp $rMin;
  3820.                 $rMin $rMax;
  3821.                 $rMax $tmp;
  3822.             }
  3823.             $value -= $rMin;
  3824.             $value /= ($rMax $rMin);
  3825.             return self::_incompleteBeta($value,$alpha,$beta);
  3826.         }
  3827.         return self::$_errorCodes['value'];
  3828.     }    //    function BETADIST()
  3829.  
  3830.  
  3831.     /**
  3832.      * BETAINV
  3833.      *
  3834.      * Returns the inverse of the beta distribution.
  3835.      *
  3836.      * @param    float        $probability    Probability at which you want to evaluate the distribution
  3837.      * @param    float        $alpha            Parameter to the distribution
  3838.      * @param    float        $beta            Parameter to the distribution
  3839.      * @param    boolean        $cumulative 
  3840.      * @return    float 
  3841.      *
  3842.      */
  3843.     public static function BETAINV($probability,$alpha,$beta,$rMin=0,$rMax=1{
  3844.         $probability    self::flattenSingleValue($probability);
  3845.         $alpha            self::flattenSingleValue($alpha);
  3846.         $beta            self::flattenSingleValue($beta);
  3847.         $rMin            self::flattenSingleValue($rMin);
  3848.         $rMax            self::flattenSingleValue($rMax);
  3849.  
  3850.         if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
  3851.             if (($alpha <= 0|| ($beta <= 0|| ($rMin == $rMax|| ($probability <= 0|| ($probability 1)) {
  3852.                 return self::$_errorCodes['num'];
  3853.             }
  3854.             if ($rMin $rMax{
  3855.                 $tmp $rMin;
  3856.                 $rMin $rMax;
  3857.                 $rMax $tmp;
  3858.             }
  3859.             $a 0;
  3860.             $b 2;
  3861.             $maxIteration 100;
  3862.  
  3863.             $i 0;
  3864.             while ((($b $aPRECISION&& ($i++ < MAX_ITERATIONS)) {
  3865.                 $guess ($a $b2;
  3866.                 $result self::BETADIST($guess$alpha$beta);
  3867.                 if (($result == $probability|| ($result == 0)) {
  3868.                     $b $a;
  3869.                 elseif ($result $probability{
  3870.                     $b $guess;
  3871.                 else {
  3872.                     $a $guess;
  3873.                 }
  3874.             }
  3875.             if ($i == MAX_ITERATIONS{
  3876.                 return self::$_errorCodes['na'];
  3877.             }
  3878.             return round($rMin $guess ($rMax $rMin),12);
  3879.         }
  3880.         return self::$_errorCodes['value'];
  3881.     }    //    function BETAINV()
  3882.  
  3883.  
  3884.     //
  3885.     //    Private implementation of the incomplete Gamma function
  3886.     //
  3887.     private static function _incompleteGamma($a,$x{
  3888.         static $max 32;
  3889.         $summer 0;
  3890.         for ($n=0$n<=$max++$n{
  3891.             $divisor $a;
  3892.             for ($i=1$i<=$n++$i{
  3893.                 $divisor *= ($a $i);
  3894.             }
  3895.             $summer += (pow($x,$n$divisor);
  3896.         }
  3897.         return pow($x,$aexp(0-$x$summer;
  3898.     }    //    function _incompleteGamma()
  3899.  
  3900.  
  3901.     //
  3902.     //    Private implementation of the Gamma function
  3903.     //
  3904.     private static function _gamma($data{
  3905.         if ($data == 0.0return 0;
  3906.  
  3907.         static $p0 1.000000000190015;
  3908.         static $p array => 76.18009172947146,
  3909.                             => -86.50532032941677,
  3910.                             => 24.01409824083091,
  3911.                             => -1.231739572450155,
  3912.                             => 1.208650973866179e-3,
  3913.                             => -5.395239384953e-6
  3914.                           );
  3915.  
  3916.         $y $x $data;
  3917.         $tmp $x 5.5;
  3918.         $tmp -= ($x 0.5log($tmp);
  3919.  
  3920.         $summer $p0;
  3921.         for ($j=1;$j<=6;++$j{
  3922.             $summer += ($p[$j/ ++$y);
  3923.         }
  3924.         return exp($tmp log(2.5066282746310005 $summer $x));
  3925.     }    //    function _gamma()
  3926.  
  3927.  
  3928.     /**
  3929.      * GAMMADIST
  3930.      *
  3931.      * Returns the gamma distribution.
  3932.      *
  3933.      * @param    float        $value            Value at which you want to evaluate the distribution
  3934.      * @param    float        $a                Parameter to the distribution
  3935.      * @param    float        $b                Parameter to the distribution
  3936.      * @param    boolean        $cumulative 
  3937.      * @return    float 
  3938.      *
  3939.      */
  3940.     public static function GAMMADIST($value,$a,$b,$cumulative{
  3941.         $value    self::flattenSingleValue($value);
  3942.         $a        self::flattenSingleValue($a);
  3943.         $b        self::flattenSingleValue($b);
  3944.  
  3945.         if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) {
  3946.             if (($value 0|| ($a <= 0|| ($b <= 0)) {
  3947.                 return self::$_errorCodes['num'];
  3948.             }
  3949.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  3950.                 if ($cumulative{
  3951.                     return self::_incompleteGamma($a,$value $bself::_gamma($a);
  3952.                 else {
  3953.                     return ((pow($b,$aself::_gamma($a))) pow($value,$a-1exp(0-($value $b));
  3954.                 }
  3955.             }
  3956.         }
  3957.         return self::$_errorCodes['value'];
  3958.     }    //    function GAMMADIST()
  3959.  
  3960.  
  3961.     /**
  3962.      * GAMMAINV
  3963.      *
  3964.      * Returns the inverse of the beta distribution.
  3965.      *
  3966.      * @param    float        $probability    Probability at which you want to evaluate the distribution
  3967.      * @param    float        $alpha            Parameter to the distribution
  3968.      * @param    float        $beta            Parameter to the distribution
  3969.      * @param    boolean        $cumulative 
  3970.      * @return    float 
  3971.      *
  3972.      */
  3973.     public static function GAMMAINV($probability,$alpha,$beta{
  3974.         $probability    self::flattenSingleValue($probability);
  3975.         $alpha            self::flattenSingleValue($alpha);
  3976.         $beta            self::flattenSingleValue($beta);
  3977. //        $rMin            = self::flattenSingleValue($rMin);
  3978. //        $rMax            = self::flattenSingleValue($rMax);
  3979.  
  3980.         if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) {
  3981.             if (($alpha <= 0|| ($beta <= 0|| ($probability <= 0|| ($probability 1)) {
  3982.                 return self::$_errorCodes['num'];
  3983.             }
  3984.             $xLo 0;
  3985.             $xHi 100;
  3986.             $maxIteration 100;
  3987.  
  3988.             $x $xNew 1;
  3989.             $dx    1;
  3990.             $i 0;
  3991.  
  3992.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  3993.                 // Apply Newton-Raphson step
  3994.                 $result self::GAMMADIST($x$alpha$betaTrue);
  3995.                 $error $result $probability;
  3996.                 if ($error == 0.0{
  3997.                     $dx 0;
  3998.                 elseif ($error 0.0{
  3999.                     $xLo $x;
  4000.                 else {
  4001.                     $xHi $x;
  4002.                 }
  4003.                 // Avoid division by zero
  4004.                 if ($result != 0.0{
  4005.                     $dx $error $result;
  4006.                     $xNew $x $dx;
  4007.                 }
  4008.                 // If the NR fails to converge (which for example may be the
  4009.                 // case if the initial guess is too rough) we apply a bisection
  4010.                 // step to determine a more narrow interval around the root.
  4011.                 if (($xNew $xLo|| ($xNew $xHi|| ($result == 0.0)) {
  4012.                     $xNew ($xLo $xHi2;
  4013.                     $dx $xNew $x;
  4014.                 }
  4015.                 $x $xNew;
  4016.             }
  4017.             if ($i == MAX_ITERATIONS{
  4018.                 return self::$_errorCodes['na'];
  4019.             }
  4020.             return round($x,12);
  4021.         }
  4022.         return self::$_errorCodes['value'];
  4023.     }    //    function GAMMAINV()
  4024.  
  4025.  
  4026.     /**
  4027.      * GAMMALN
  4028.      *
  4029.      * Returns the natural logarithm of the gamma function.
  4030.      *
  4031.      * @param    float        $value 
  4032.      * @return    float 
  4033.      */
  4034.     public static function GAMMALN($value{
  4035.         $value    self::flattenSingleValue($value);
  4036.  
  4037.         if (is_numeric($value)) {
  4038.             if ($value <= 0{
  4039.                 return self::$_errorCodes['num'];
  4040.             }
  4041.             return log(self::_gamma($value));
  4042.         }
  4043.         return self::$_errorCodes['value'];
  4044.     }    //    function GAMMALN()
  4045.  
  4046.  
  4047.     /**
  4048.      * NORMDIST
  4049.      *
  4050.      * Returns the normal distribution for the specified mean and standard deviation. This
  4051.      * function has a very wide range of applications in statistics, including hypothesis
  4052.      * testing.
  4053.      *
  4054.      * @param    float        $value 
  4055.      * @param    float        $mean        Mean Value
  4056.      * @param    float        $stdDev        Standard Deviation
  4057.      * @param    boolean        $cumulative 
  4058.      * @return    float 
  4059.      *
  4060.      */
  4061.     public static function NORMDIST($value$mean$stdDev$cumulative{
  4062.         $value    self::flattenSingleValue($value);
  4063.         $mean    self::flattenSingleValue($mean);
  4064.         $stdDev    self::flattenSingleValue($stdDev);
  4065.  
  4066.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4067.             if ($stdDev 0{
  4068.                 return self::$_errorCodes['num'];
  4069.             }
  4070.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4071.                 if ($cumulative{
  4072.                     return 0.5 (self::_erfVal(($value $mean($stdDev sqrt(2))));
  4073.                 else {
  4074.                     return ((SQRT2PI $stdDev)) exp((pow($value $mean,2(pow($stdDev,2))));
  4075.                 }
  4076.             }
  4077.         }
  4078.         return self::$_errorCodes['value'];
  4079.     }    //    function NORMDIST()
  4080.  
  4081.  
  4082.     /**
  4083.      * NORMSDIST
  4084.      *
  4085.      * Returns the standard normal cumulative distribution function. The distribution has
  4086.      * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a
  4087.      * table of standard normal curve areas.
  4088.      *
  4089.      * @param    float        $value 
  4090.      * @return    float 
  4091.      */
  4092.     public static function NORMSDIST($value{
  4093.         $value    self::flattenSingleValue($value);
  4094.  
  4095.         return self::NORMDIST($value01True);
  4096.     }    //    function NORMSDIST()
  4097.  
  4098.  
  4099.     /**
  4100.      * LOGNORMDIST
  4101.      *
  4102.      * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed
  4103.      * with parameters mean and standard_dev.
  4104.      *
  4105.      * @param    float        $value 
  4106.      * @return    float 
  4107.      */
  4108.     public static function LOGNORMDIST($value$mean$stdDev{
  4109.         $value    self::flattenSingleValue($value);
  4110.         $mean    self::flattenSingleValue($mean);
  4111.         $stdDev    self::flattenSingleValue($stdDev);
  4112.  
  4113.         if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4114.             if (($value <= 0|| ($stdDev <= 0)) {
  4115.                 return self::$_errorCodes['num'];
  4116.             }
  4117.             return self::NORMSDIST((log($value$mean$stdDev);
  4118.         }
  4119.         return self::$_errorCodes['value'];
  4120.     }    //    function LOGNORMDIST()
  4121.  
  4122.  
  4123.     /***************************************************************************
  4124.      *                                inverse_ncdf.php
  4125.      *                            -------------------
  4126.      *    begin                : Friday, January 16, 2004
  4127.      *    copyright            : (C) 2004 Michael Nickerson
  4128.      *    email                : nickersonm@yahoo.com
  4129.      *
  4130.      ***************************************************************************/
  4131.     private static function _inverse_ncdf($p{
  4132.         //    Inverse ncdf approximation by Peter J. Acklam, implementation adapted to
  4133.         //    PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
  4134.         //    a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html
  4135.         //    I have not checked the accuracy of this implementation. Be aware that PHP
  4136.         //    will truncate the coeficcients to 14 digits.
  4137.  
  4138.         //    You have permission to use and distribute this function freely for
  4139.         //    whatever purpose you want, but please show common courtesy and give credit
  4140.         //    where credit is due.
  4141.  
  4142.         //    Input paramater is $p - probability - where 0 < p < 1.
  4143.  
  4144.         //    Coefficients in rational approximations
  4145.         static $a array(    => -3.969683028665376e+01,
  4146.                             => 2.209460984245205e+02,
  4147.                             => -2.759285104469687e+02,
  4148.                             => 1.383577518672690e+02,
  4149.                             => -3.066479806614716e+01,
  4150.                             => 2.506628277459239e+00
  4151.                          );
  4152.  
  4153.         static $b array(    => -5.447609879822406e+01,
  4154.                             => 1.615858368580409e+02,
  4155.                             => -1.556989798598866e+02,
  4156.                             => 6.680131188771972e+01,
  4157.                             => -1.328068155288572e+01
  4158.                          );
  4159.  
  4160.         static $c array(    => -7.784894002430293e-03,
  4161.                             => -3.223964580411365e-01,
  4162.                             => -2.400758277161838e+00,
  4163.                             => -2.549732539343734e+00,
  4164.                             => 4.374664141464968e+00,
  4165.                             => 2.938163982698783e+00
  4166.                          );
  4167.  
  4168.         static $d array(    => 7.784695709041462e-03,
  4169.                             => 3.224671290700398e-01,
  4170.                             => 2.445134137142996e+00,
  4171.                             => 3.754408661907416e+00
  4172.                          );
  4173.  
  4174.         //    Define lower and upper region break-points.
  4175.         $p_low 0.02425;            //Use lower region approx. below this
  4176.         $p_high $p_low;        //Use upper region approx. above this
  4177.  
  4178.         if ($p && $p $p_low{
  4179.             //    Rational approximation for lower region.
  4180.             $q sqrt(-log($p));
  4181.             return ((((($c[1$q $c[2]$q $c[3]$q $c[4]$q $c[5]$q $c[6]/
  4182.                     (((($d[1$q $d[2]$q $d[3]$q $d[4]$q 1);
  4183.         elseif ($p_low <= $p && $p <= $p_high{
  4184.             //    Rational approximation for central region.
  4185.             $q $p 0.5;
  4186.             $r $q $q;
  4187.             return ((((($a[1$r $a[2]$r $a[3]$r $a[4]$r $a[5]$r $a[6]$q /
  4188.                    ((((($b[1$r $b[2]$r $b[3]$r $b[4]$r $b[5]$r 1);
  4189.         elseif ($p_high $p && $p 1{
  4190.             //    Rational approximation for upper region.
  4191.             $q sqrt(-log($p));
  4192.             return -((((($c[1$q $c[2]$q $c[3]$q $c[4]$q $c[5]$q $c[6]/
  4193.                      (((($d[1$q $d[2]$q $d[3]$q $d[4]$q 1);
  4194.         }
  4195.         //    If 0 < p < 1, return a null value
  4196.         return self::$_errorCodes['null'];
  4197.     }    //    function _inverse_ncdf()
  4198.  
  4199.  
  4200.     private static function _inverse_ncdf2($prob{
  4201.         //    Approximation of inverse standard normal CDF developed by
  4202.         //    B. Moro, "The Full Monte," Risk 8(2), Feb 1995, 57-58.
  4203.  
  4204.         $a1 2.50662823884;
  4205.         $a2 = -18.61500062529;
  4206.         $a3 41.39119773534;
  4207.         $a4 = -25.44106049637;
  4208.  
  4209.         $b1 = -8.4735109309;
  4210.         $b2 23.08336743743;
  4211.         $b3 = -21.06224101826;
  4212.         $b4 3.13082909833;
  4213.  
  4214.         $c1 0.337475482272615;
  4215.         $c2 0.976169019091719;
  4216.         $c3 0.160797971491821;
  4217.         $c4 2.76438810333863E-02;
  4218.         $c5 3.8405729373609E-03;
  4219.         $c6 3.951896511919E-04;
  4220.         $c7 3.21767881768E-05;
  4221.         $c8 2.888167364E-07;
  4222.         $c9 3.960315187E-07;
  4223.  
  4224.         $y $prob 0.5;
  4225.         if (abs($y0.42{
  4226.             $z pow($y,2);
  4227.             $z $y ((($a4 $z $a3$z $a2$z $a1(((($b4 $z $b3$z $b2$z $b1$z 1);
  4228.         else {
  4229.             if ($y 0{
  4230.                 $z log(-log($prob));
  4231.             else {
  4232.                 $z log(-log($prob));
  4233.             }
  4234.             $z $c1 $z ($c2 $z ($c3 $z ($c4 $z ($c5 $z ($c6 $z ($c7 $z ($c8 $z $c9)))))));
  4235.             if ($y 0{
  4236.                 $z = -$z;
  4237.             }
  4238.         }
  4239.         return $z;
  4240.     }    //    function _inverse_ncdf2()
  4241.  
  4242.  
  4243.     private static function _inverse_ncdf3($p{
  4244.         //    ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3.
  4245.         //    Produces the normal deviate Z corresponding to a given lower
  4246.         //    tail area of P; Z is accurate to about 1 part in 10**16.
  4247.         //
  4248.         //    This is a PHP version of the original FORTRAN code that can
  4249.         //    be found at http://lib.stat.cmu.edu/apstat/
  4250.         $split1 0.425;
  4251.         $split2 5;
  4252.         $const1 0.180625;
  4253.         $const2 1.6;
  4254.  
  4255.         //    coefficients for p close to 0.5
  4256.         $a0 3.3871328727963666080;
  4257.         $a1 1.3314166789178437745E+2;
  4258.         $a2 1.9715909503065514427E+3;
  4259.         $a3 1.3731693765509461125E+4;
  4260.         $a4 4.5921953931549871457E+4;
  4261.         $a5 6.7265770927008700853E+4;
  4262.         $a6 3.3430575583588128105E+4;
  4263.         $a7 2.5090809287301226727E+3;
  4264.  
  4265.         $b1 4.2313330701600911252E+1;
  4266.         $b2 6.8718700749205790830E+2;
  4267.         $b3 5.3941960214247511077E+3;
  4268.         $b4 2.1213794301586595867E+4;
  4269.         $b5 3.9307895800092710610E+4;
  4270.         $b6 2.8729085735721942674E+4;
  4271.         $b7 5.2264952788528545610E+3;
  4272.  
  4273.         //    coefficients for p not close to 0, 0.5 or 1.
  4274.         $c0 1.42343711074968357734;
  4275.         $c1 4.63033784615654529590;
  4276.         $c2 5.76949722146069140550;
  4277.         $c3 3.64784832476320460504;
  4278.         $c4 1.27045825245236838258;
  4279.         $c5 2.41780725177450611770E-1;
  4280.         $c6 2.27238449892691845833E-2;
  4281.         $c7 7.74545014278341407640E-4;
  4282.  
  4283.         $d1 2.05319162663775882187;
  4284.         $d2 1.67638483018380384940;
  4285.         $d3 6.89767334985100004550E-1;
  4286.         $d4 1.48103976427480074590E-1;
  4287.         $d5 1.51986665636164571966E-2;
  4288.         $d6 5.47593808499534494600E-4;
  4289.         $d7 1.05075007164441684324E-9;
  4290.  
  4291.         //    coefficients for p near 0 or 1.
  4292.         $e0 6.65790464350110377720;
  4293.         $e1 5.46378491116411436990;
  4294.         $e2 1.78482653991729133580;
  4295.         $e3 2.96560571828504891230E-1;
  4296.         $e4 2.65321895265761230930E-2;
  4297.         $e5 1.24266094738807843860E-3;
  4298.         $e6 2.71155556874348757815E-5;
  4299.         $e7 2.01033439929228813265E-7;
  4300.  
  4301.         $f1 5.99832206555887937690E-1;
  4302.         $f2 1.36929880922735805310E-1;
  4303.         $f3 1.48753612908506148525E-2;
  4304.         $f4 7.86869131145613259100E-4;
  4305.         $f5 1.84631831751005468180E-5;
  4306.         $f6 1.42151175831644588870E-7;
  4307.         $f7 2.04426310338993978564E-15;
  4308.  
  4309.         $q $p 0.5;
  4310.  
  4311.         //    computation for p close to 0.5
  4312.         if (abs($q<= split1{
  4313.             $R $const1 $q $q;
  4314.             $z $q ((((((($a7 $R $a6$R $a5$R $a4$R $a3$R $a2$R $a1$R $a0/
  4315.                       ((((((($b7 $R $b6$R $b5$R $b4$R $b3$R $b2$R $b1$R 1);
  4316.         else {
  4317.             if ($q 0{
  4318.                 $R $p;
  4319.             else {
  4320.                 $R $p;
  4321.             }
  4322.             $R pow(-log($R),2);
  4323.  
  4324.             //    computation for p not close to 0, 0.5 or 1.
  4325.             If ($R <= $split2{
  4326.                 $R $R $const2;
  4327.                 $z ((((((($c7 $R $c6$R $c5$R $c4$R $c3$R $c2$R $c1$R $c0/
  4328.                      ((((((($d7 $R $d6$R $d5$R $d4$R $d3$R $d2$R $d1$R 1);
  4329.             else {
  4330.             //    computation for p near 0 or 1.
  4331.                 $R $R $split2;
  4332.                 $z ((((((($e7 $R $e6$R $e5$R $e4$R $e3$R $e2$R $e1$R $e0/
  4333.                      ((((((($f7 $R $f6$R $f5$R $f4$R $f3$R $f2$R $f1$R 1);
  4334.             }
  4335.             if ($q 0{
  4336.                 $z = -$z;
  4337.             }
  4338.         }
  4339.         return $z;
  4340.     }    //    function _inverse_ncdf3()
  4341.  
  4342.  
  4343.     /**
  4344.      * NORMINV
  4345.      *
  4346.      * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation.
  4347.      *
  4348.      * @param    float        $value 
  4349.      * @param    float        $mean        Mean Value
  4350.      * @param    float        $stdDev        Standard Deviation
  4351.      * @return    float 
  4352.      *
  4353.      */
  4354.     public static function NORMINV($probability,$mean,$stdDev{
  4355.         $probability    self::flattenSingleValue($probability);
  4356.         $mean            self::flattenSingleValue($mean);
  4357.         $stdDev            self::flattenSingleValue($stdDev);
  4358.  
  4359.         if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4360.             if (($probability 0|| ($probability 1)) {
  4361.                 return self::$_errorCodes['num'];
  4362.             }
  4363.             if ($stdDev 0{
  4364.                 return self::$_errorCodes['num'];
  4365.             }
  4366.             return (self::_inverse_ncdf($probability$stdDev$mean;
  4367.         }
  4368.         return self::$_errorCodes['value'];
  4369.     }    //    function NORMINV()
  4370.  
  4371.  
  4372.     /**
  4373.      * NORMSINV
  4374.      *
  4375.      * Returns the inverse of the standard normal cumulative distribution
  4376.      *
  4377.      * @param    float        $value 
  4378.      * @return    float 
  4379.      */
  4380.     public static function NORMSINV($value{
  4381.         return self::NORMINV($value01);
  4382.     }    //    function NORMSINV()
  4383.  
  4384.  
  4385.     /**
  4386.      * LOGINV
  4387.      *
  4388.      * Returns the inverse of the normal cumulative distribution
  4389.      *
  4390.      * @param    float        $value 
  4391.      * @return    float 
  4392.      *
  4393.      * @todo    Try implementing P J Acklam's refinement algorithm for greater
  4394.      *             accuracy if I can get my head round the mathematics
  4395.      *             (as described at) http://home.online.no/~pjacklam/notes/invnorm/
  4396.      */
  4397.     public static function LOGINV($probability$mean$stdDev{
  4398.         $probability    self::flattenSingleValue($probability);
  4399.         $mean            self::flattenSingleValue($mean);
  4400.         $stdDev            self::flattenSingleValue($stdDev);
  4401.  
  4402.         if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
  4403.             if (($probability 0|| ($probability 1|| ($stdDev <= 0)) {
  4404.                 return self::$_errorCodes['num'];
  4405.             }
  4406.             return exp($mean $stdDev self::NORMSINV($probability));
  4407.         }
  4408.         return self::$_errorCodes['value'];
  4409.     }    //    function LOGINV()
  4410.  
  4411.  
  4412.     /**
  4413.      * HYPGEOMDIST
  4414.      *
  4415.      * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of
  4416.      * sample successes, given the sample size, population successes, and population size.
  4417.      *
  4418.      * @param    float        $sampleSuccesses        Number of successes in the sample
  4419.      * @param    float        $sampleNumber            Size of the sample
  4420.      * @param    float        $populationSuccesses    Number of successes in the population
  4421.      * @param    float        $populationNumber        Population size
  4422.      * @return    float 
  4423.      *
  4424.      */
  4425.     public static function HYPGEOMDIST($sampleSuccesses$sampleNumber$populationSuccesses$populationNumber{
  4426.         $sampleSuccesses        floor(self::flattenSingleValue($sampleSuccesses));
  4427.         $sampleNumber            floor(self::flattenSingleValue($sampleNumber));
  4428.         $populationSuccesses    floor(self::flattenSingleValue($populationSuccesses));
  4429.         $populationNumber        floor(self::flattenSingleValue($populationNumber));
  4430.  
  4431.         if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) {
  4432.             if (($sampleSuccesses 0|| ($sampleSuccesses $sampleNumber|| ($sampleSuccesses $populationSuccesses)) {
  4433.                 return self::$_errorCodes['num'];
  4434.             }
  4435.             if (($sampleNumber <= 0|| ($sampleNumber $populationNumber)) {
  4436.                 return self::$_errorCodes['num'];
  4437.             }
  4438.             if (($populationSuccesses <= 0|| ($populationSuccesses $populationNumber)) {
  4439.                 return self::$_errorCodes['num'];
  4440.             }
  4441.             return self::COMBIN($populationSuccesses,$sampleSuccesses*
  4442.                    self::COMBIN($populationNumber $populationSuccesses,$sampleNumber $sampleSuccesses/
  4443.                    self::COMBIN($populationNumber,$sampleNumber);
  4444.         }
  4445.         return self::$_errorCodes['value'];
  4446.     }    //    function HYPGEOMDIST()
  4447.  
  4448.  
  4449.     /**
  4450.      * TDIST
  4451.      *
  4452.      * Returns the probability of Student's T distribution.
  4453.      *
  4454.      * @param    float        $value            Value for the function
  4455.      * @param    float        $degrees        degrees of freedom
  4456.      * @param    float        $tails            number of tails (1 or 2)
  4457.      * @return    float 
  4458.      */
  4459.     public static function TDIST($value$degrees$tails{
  4460.         $value        self::flattenSingleValue($value);
  4461.         $degrees    floor(self::flattenSingleValue($degrees));
  4462.         $tails        floor(self::flattenSingleValue($tails));
  4463.  
  4464.         if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) {
  4465.             if (($value 0|| ($degrees 1|| ($tails 1|| ($tails 2)) {
  4466.                 return self::$_errorCodes['num'];
  4467.             }
  4468.             //    tdist, which finds the probability that corresponds to a given value
  4469.             //    of t with k degrees of freedom. This algorithm is translated from a
  4470.             //    pascal function on p81 of "Statistical Computing in Pascal" by D
  4471.             //    Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd:
  4472.             //    London). The above Pascal algorithm is itself a translation of the
  4473.             //    fortran algoritm "AS 3" by B E Cooper of the Atlas Computer
  4474.             //    Laboratory as reported in (among other places) "Applied Statistics
  4475.             //    Algorithms", editied by P Griffiths and I D Hill (1985; Ellis
  4476.             //    Horwood Ltd.; W. Sussex, England).
  4477. //            $ta = 2 / pi();
  4478.             $ta 0.636619772367581;
  4479.             $tterm $degrees;
  4480.             $ttheta atan2($value,sqrt($tterm));
  4481.             $tc cos($ttheta);
  4482.             $ts sin($ttheta);
  4483.             $tsum 0;
  4484.  
  4485.             if (($degrees 2== 1{
  4486.                 $ti 3;
  4487.                 $tterm $tc;
  4488.             else {
  4489.                 $ti 2;
  4490.                 $tterm 1;
  4491.             }
  4492.  
  4493.             $tsum $tterm;
  4494.             while ($ti $degrees{
  4495.                 $tterm *= $tc $tc ($ti 1$ti;
  4496.                 $tsum += $tterm;
  4497.                 $ti += 2;
  4498.             }
  4499.             $tsum *= $ts;
  4500.             if (($degrees 2== 1$tsum $ta ($tsum $ttheta)}
  4501.             $tValue 0.5 ($tsum);
  4502.             if ($tails == 1{
  4503.                 return abs($tValue);
  4504.             else {
  4505.                 return abs(($tValue$tValue);
  4506.             }
  4507.         }
  4508.         return self::$_errorCodes['value'];
  4509.     }    //    function TDIST()
  4510.  
  4511.  
  4512.     /**
  4513.      * TINV
  4514.      *
  4515.      * Returns the one-tailed probability of the chi-squared distribution.
  4516.      *
  4517.      * @param    float        $probability    Probability for the function
  4518.      * @param    float        $degrees        degrees of freedom
  4519.      * @return    float 
  4520.      */
  4521.     public static function TINV($probability$degrees{
  4522.         $probability    self::flattenSingleValue($probability);
  4523.         $degrees        floor(self::flattenSingleValue($degrees));
  4524.  
  4525.         if ((is_numeric($probability)) && (is_numeric($degrees))) {
  4526.             $xLo 100;
  4527.             $xHi 0;
  4528.             $maxIteration 100;
  4529.  
  4530.             $x $xNew 1;
  4531.             $dx    1;
  4532.             $i 0;
  4533.  
  4534.             while ((abs($dxPRECISION&& ($i++ < MAX_ITERATIONS)) {
  4535.                 // Apply Newton-Raphson step
  4536.                 $result self::TDIST($x$degrees2);
  4537.                 $error $result $probability;
  4538.                 if ($error == 0.0{
  4539.                     $dx 0;
  4540.                 elseif ($error 0.0{
  4541.                     $xLo $x;
  4542.                 else {
  4543.                     $xHi $x;
  4544.                 }
  4545.                 // Avoid division by zero
  4546.                 if ($result != 0.0{
  4547.                     $dx $error $result;
  4548.                     $xNew $x $dx;
  4549.                 }
  4550.                 // If the NR fails to converge (which for example may be the
  4551.                 // case if the initial guess is too rough) we apply a bisection
  4552.                 // step to determine a more narrow interval around the root.
  4553.                 if (($xNew $xLo|| ($xNew $xHi|| ($result == 0.0)) {
  4554.                     $xNew ($xLo $xHi2;
  4555.                     $dx $xNew $x;
  4556.                 }
  4557.                 $x $xNew;
  4558.             }
  4559.             if ($i == MAX_ITERATIONS{
  4560.                 return self::$_errorCodes['na'];
  4561.             }
  4562.             return round($x,12);
  4563.         }
  4564.         return self::$_errorCodes['value'];
  4565.     }    //    function TINV()
  4566.  
  4567.  
  4568.     /**
  4569.      * CONFIDENCE
  4570.      *
  4571.      * Returns the confidence interval for a population mean
  4572.      *
  4573.      * @param    float        $alpha 
  4574.      * @param    float        $stdDev        Standard Deviation
  4575.      * @param    float        $size 
  4576.      * @return    float 
  4577.      *
  4578.      */
  4579.     public static function CONFIDENCE($alpha,$stdDev,$size{
  4580.         $alpha    self::flattenSingleValue($alpha);
  4581.         $stdDev    self::flattenSingleValue($stdDev);
  4582.         $size    floor(self::flattenSingleValue($size));
  4583.  
  4584.         if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) {
  4585.             if (($alpha <= 0|| ($alpha >= 1)) {
  4586.                 return self::$_errorCodes['num'];
  4587.             }
  4588.             if (($stdDev <= 0|| ($size 1)) {
  4589.                 return self::$_errorCodes['num'];
  4590.             }
  4591.             return self::NORMSINV($alpha 2$stdDev sqrt($size);
  4592.         }
  4593.         return self::$_errorCodes['value'];
  4594.     }    //    function CONFIDENCE()
  4595.  
  4596.  
  4597.     /**
  4598.      * POISSON
  4599.      *
  4600.      * Returns the Poisson distribution. A common application of the Poisson distribution
  4601.      * is predicting the number of events over a specific time, such as the number of
  4602.      * cars arriving at a toll plaza in 1 minute.
  4603.      *
  4604.      * @param    float        $value 
  4605.      * @param    float        $mean        Mean Value
  4606.      * @param    boolean        $cumulative 
  4607.      * @return    float 
  4608.      *
  4609.      */
  4610.     public static function POISSON($value$mean$cumulative{
  4611.         $value    self::flattenSingleValue($value);
  4612.         $mean    self::flattenSingleValue($mean);
  4613.  
  4614.         if ((is_numeric($value)) && (is_numeric($mean))) {
  4615.             if (($value <= 0|| ($mean <= 0)) {
  4616.                 return self::$_errorCodes['num'];
  4617.             }
  4618.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4619.                 if ($cumulative{
  4620.                     $summer 0;
  4621.                     for ($i 0$i <= floor($value)++$i{
  4622.                         $summer += pow($mean,$iself::FACT($i);
  4623.                     }
  4624.                     return exp(0-$mean$summer;
  4625.                 else {
  4626.                     return (exp(0-$meanpow($mean,$value)) self::FACT($value);
  4627.                 }
  4628.             }
  4629.         }
  4630.         return self::$_errorCodes['value'];
  4631.     }    //    function POISSON()
  4632.  
  4633.  
  4634.     /**
  4635.      * WEIBULL
  4636.      *
  4637.      * Returns the Weibull distribution. Use this distribution in reliability
  4638.      * analysis, such as calculating a device's mean time to failure.
  4639.      *
  4640.      * @param    float        $value 
  4641.      * @param    float        $alpha        Alpha Parameter
  4642.      * @param    float        $beta        Beta Parameter
  4643.      * @param    boolean        $cumulative 
  4644.      * @return    float 
  4645.      *
  4646.      */
  4647.     public static function WEIBULL($value$alpha$beta$cumulative{
  4648.         $value    self::flattenSingleValue($value);
  4649.         $alpha    self::flattenSingleValue($alpha);
  4650.         $beta    self::flattenSingleValue($beta);
  4651.  
  4652.         if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) {
  4653.             if (($value 0|| ($alpha <= 0|| ($beta <= 0)) {
  4654.                 return self::$_errorCodes['num'];
  4655.             }
  4656.             if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
  4657.                 if ($cumulative{
  4658.                     return exp(pow($value $beta,$alpha));
  4659.                 else {
  4660.                     return ($alpha pow($beta,$alpha)) pow($value,$alpha 1exp(pow($value $beta,$alpha));
  4661.                 }
  4662.             }
  4663.         }
  4664.         return self::$_errorCodes['value'];
  4665.     }    //    function WEIBULL()
  4666.  
  4667.  
  4668.     /**
  4669.      * SKEW
  4670.      *
  4671.      * Returns the skewness of a distribution. Skewness characterizes the degree of asymmetry
  4672.      * of a distribution around its mean. Positive skewness indicates a distribution with an
  4673.      * asymmetric tail extending toward more positive values. Negative skewness indicates a
  4674.      * distribution with an asymmetric tail extending toward more negative values.
  4675.      *
  4676.      * @param    array    Data Series
  4677.      * @return    float 
  4678.      */
  4679.     public static function SKEW({
  4680.         $aArgs self::flattenArray(func_get_args());
  4681.         $mean self::AVERAGE($aArgs);
  4682.         $stdDev self::STDEV($aArgs);
  4683.  
  4684.         $count $summer 0;
  4685.         // Loop through arguments
  4686.         foreach ($aArgs as $arg{
  4687.             // Is it a numeric value?
  4688.             if ((is_numeric($arg)) && (!is_string($arg))) {
  4689.                 $summer += pow((($arg $mean$stdDev),3;
  4690.                 ++$count;
  4691.             }
  4692.         }
  4693.  
  4694.         // Return
  4695.         if ($count 2{
  4696.             return $summer ($count (($count-1($count-2)));
  4697.         }
  4698.         return self::$_errorCodes['divisionbyzero'];
  4699.     }    //    function SKEW()
  4700.  
  4701.  
  4702.     /**
  4703.      * KURT
  4704.      *
  4705.      * Returns the kurtosis of a data set. Kurtosis characterizes the relative peakedness
  4706.      * or flatness of a distribution compared with the normal distribution. Positive
  4707.      * kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a
  4708.      * relatively flat distribution.
  4709.      *
  4710.      * @param    array    Data Series
  4711.      * @return    float 
  4712.      */
  4713.     public static function KURT({
  4714.         $aArgs self::flattenArray(func_get_args());
  4715.         $mean self::AVERAGE($aArgs);
  4716.         $stdDev self::STDEV($aArgs);
  4717.  
  4718.         if ($stdDev 0{
  4719.             $count $summer 0;
  4720.             // Loop through arguments
  4721.             foreach ($aArgs as $arg{
  4722.                 // Is it a numeric value?
  4723.                 if ((is_numeric($arg)) && (!is_string($arg))) {
  4724.                     $summer += pow((($arg $mean$stdDev),4;
  4725.                     ++$count;
  4726.                 }
  4727.             }
  4728.  
  4729.             // Return
  4730.             if ($count 3{
  4731.                 return $summer ($count ($count+1(($count-1($count-2($count-3))) (pow($count-1,2(($count-2($count-3)));
  4732.             }
  4733.         }
  4734.         return self::$_errorCodes['divisionbyzero'];
  4735.     }    //    function KURT()
  4736.  
  4737.  
  4738.     /**
  4739.      * RAND
  4740.      *
  4741.      * @param    int        $min    Minimal value
  4742.      * @param    int        $max    Maximal value
  4743.      * @return    int        Random number
  4744.      */
  4745.     public static function RAND($min 0$max 0{
  4746.         $min        self::flattenSingleValue($min);
  4747.         $max        self::flattenSingleValue($max);
  4748.  
  4749.         if ($min == && $max == 0{
  4750.             return (rand(0,10000000)) 10000000;
  4751.         else {
  4752.             return rand($min$max);
  4753.         }
  4754.     }    //    function RAND()
  4755.  
  4756.  
  4757.     /**
  4758.      * MOD
  4759.      *
  4760.      * @param    int        $a        Dividend
  4761.      * @param    int        $b        Divisor
  4762.      * @return    int        Remainder
  4763.      */
  4764.     public static function MOD($a 1$b 1{
  4765.         $a        self::flattenSingleValue($a);
  4766.         $b        self::flattenSingleValue($b);
  4767.  
  4768.         return fmod($a,$b);
  4769.     }    //    function MOD()
  4770.  
  4771.  
  4772.     /**
  4773.      * CHARACTER
  4774.      *
  4775.      * @param    string    $character    Value
  4776.      * @return    int 
  4777.      */
  4778.     public static function CHARACTER($character{
  4779.         $character    self::flattenSingleValue($character);
  4780.  
  4781.         if (function_exists('mb_convert_encoding')) {
  4782.             return mb_convert_encoding('&#'.intval($character).';''UTF-8''HTML-ENTITIES');
  4783.         else {
  4784.             return chr(intval($character));
  4785.         }
  4786.     }
  4787.  
  4788.     /**
  4789.      * ASCIICODE
  4790.      *
  4791.      * @param    string    $character    Value
  4792.      * @return    int 
  4793.      */
  4794.     public static function ASCIICODE($characters{
  4795.         $characters    self::flattenSingleValue($characters);
  4796.         if (is_bool($characters)) {
  4797.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  4798.                 $characters = (int) $characters;
  4799.             else {
  4800.                 if ($characters{
  4801.                     $characters 'True';
  4802.                 else {
  4803.                     $characters 'False';
  4804.                 }
  4805.             }
  4806.         }
  4807.  
  4808.         if ((function_exists('mb_strlen')) && (function_exists('mb_substr'))) {
  4809.             if (mb_strlen($characters'UTF-8'0{
  4810.                 $character mb_substr($characters01'UTF-8');
  4811.                 $byteLength strlen($character);
  4812.                 $xValue 0;
  4813.                 for ($i 0$i $byteLength++$i{
  4814.                     $xValue ($xValue 256ord($character{$i});
  4815.                 }
  4816.                 return $xValue;
  4817.             }
  4818.         else {
  4819.             if (strlen($characters0{
  4820.                 return ord(substr($characters01));
  4821.             }
  4822.         }
  4823.         return self::$_errorCodes['value'];
  4824.     }    //    function ASCIICODE()
  4825.  
  4826.  
  4827.     /**
  4828.      * CONCATENATE
  4829.      *
  4830.      * @return    string 
  4831.      */
  4832.     public static function CONCATENATE({
  4833.         // Return value
  4834.         $returnValue '';
  4835.  
  4836.         // Loop trough arguments
  4837.         $aArgs self::flattenArray(func_get_args());
  4838.         foreach ($aArgs as $arg{
  4839.             if (is_bool($arg)) {
  4840.                 if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  4841.                     $arg = (int) $arg;
  4842.                 else {
  4843.                     if ($arg{
  4844.                         $arg 'TRUE';
  4845.                     else {
  4846.                         $arg 'FALSE';
  4847.                     }
  4848.                 }
  4849.             }
  4850.             $returnValue .= $arg;
  4851.         }
  4852.  
  4853.         // Return
  4854.         return $returnValue;
  4855.     }    //    function CONCATENATE()
  4856.  
  4857.  
  4858.     /**
  4859.      * STRINGLENGTH
  4860.      *
  4861.      * @param    string    $value    Value
  4862.      * @param    int        $chars    Number of characters
  4863.      * @return    string 
  4864.      */
  4865.     public static function STRINGLENGTH($value ''{
  4866.         $value        self::flattenSingleValue($value);
  4867.  
  4868.         if (function_exists('mb_strlen')) {
  4869.             return mb_strlen($value'UTF-8');
  4870.         else {
  4871.             return strlen($value);
  4872.         }
  4873.     }    //    function STRINGLENGTH()
  4874.  
  4875.  
  4876.     /**
  4877.      * SEARCHSENSITIVE
  4878.      *
  4879.      * @param    string    $needle        The string to look for
  4880.      * @param    string    $haystack    The string in which to look
  4881.      * @param    int        $offset        Offset within $haystack
  4882.      * @return    string 
  4883.      */
  4884.     public static function SEARCHSENSITIVE($needle,$haystack,$offset=1{
  4885.         $needle        = (string) self::flattenSingleValue($needle);
  4886.         $haystack    = (string) self::flattenSingleValue($haystack);
  4887.         $offset        self::flattenSingleValue($offset);
  4888.  
  4889.         if (($offset 0&& (strlen($haystack$offset)) {
  4890.             if (function_exists('mb_strpos')) {
  4891.                 $pos mb_strpos($haystack$needle--$offset,'UTF-8');
  4892.             else {
  4893.                 $pos strpos($haystack$needle--$offset);
  4894.             }
  4895.             if ($pos !== false{
  4896.                 return ++$pos;
  4897.             }
  4898.         }
  4899.         return self::$_errorCodes['value'];
  4900.     }    //    function SEARCHSENSITIVE()
  4901.  
  4902.  
  4903.     /**
  4904.      * SEARCHINSENSITIVE
  4905.      *
  4906.      * @param    string    $needle        The string to look for
  4907.      * @param    string    $haystack    The string in which to look
  4908.      * @param    int        $offset        Offset within $haystack
  4909.      * @return    string 
  4910.      */
  4911.     public static function SEARCHINSENSITIVE($needle,$haystack,$offset=1{
  4912.         $needle        = (string) self::flattenSingleValue($needle);
  4913.         $haystack    = (string) self::flattenSingleValue($haystack);
  4914.         $offset        self::flattenSingleValue($offset);
  4915.  
  4916.         if (($offset 0&& (strlen($haystack$offset)) {
  4917.             if (function_exists('mb_stripos')) {
  4918.                 $pos mb_stripos($haystack$needle--$offset,'UTF-8');
  4919.             else {
  4920.                 $pos stripos($haystack$needle--$offset);
  4921.             }
  4922.             if ($pos !== false{
  4923.                 return ++$pos;
  4924.             }
  4925.         }
  4926.         return self::$_errorCodes['value'];
  4927.     }    //    function SEARCHINSENSITIVE()
  4928.  
  4929.  
  4930.     /**
  4931.      * LEFT
  4932.      *
  4933.      * @param    string    $value    Value
  4934.      * @param    int        $chars    Number of characters
  4935.      * @return    string 
  4936.      */
  4937.     public static function LEFT($value ''$chars 1{
  4938.         $value        self::flattenSingleValue($value);
  4939.         $chars        self::flattenSingleValue($chars);
  4940.  
  4941.         if (function_exists('mb_substr')) {
  4942.             return mb_substr($value0$chars'UTF-8');
  4943.         else {
  4944.             return substr($value0$chars);
  4945.         }
  4946.     }    //    function LEFT()
  4947.  
  4948.  
  4949.     /**
  4950.      *    RIGHT
  4951.      *
  4952.      *    @param    string    $value    Value
  4953.      *    @param    int        $chars    Number of characters
  4954.      *    @return    string 
  4955.      */
  4956.     public static function RIGHT($value ''$chars 1{
  4957.         $value        self::flattenSingleValue($value);
  4958.         $chars        self::flattenSingleValue($chars);
  4959.  
  4960.         if ((function_exists('mb_substr')) && (function_exists('mb_strlen'))) {
  4961.             return mb_substr($valuemb_strlen($value'UTF-8'$chars$chars'UTF-8');
  4962.         else {
  4963.             return substr($valuestrlen($value$chars);
  4964.         }
  4965.     }    //    function RIGHT()
  4966.  
  4967.  
  4968.     /**
  4969.      *    MID
  4970.      *
  4971.      *    @param    string    $value    Value
  4972.      *    @param    int        $start    Start character
  4973.      *    @param    int        $chars    Number of characters
  4974.      *    @return    string 
  4975.      */
  4976.     public static function MID($value ''$start 1$chars null{
  4977.         $value        self::flattenSingleValue($value);
  4978.         $start        self::flattenSingleValue($start);
  4979.         $chars        self::flattenSingleValue($chars);
  4980.  
  4981.         if (function_exists('mb_substr')) {
  4982.             return mb_substr($value--$start$chars'UTF-8');
  4983.         else {
  4984.             return substr($value--$start$chars);
  4985.         }
  4986.     }    //    function MID()
  4987.  
  4988.  
  4989.     /**
  4990.      *    REPLACE
  4991.      *
  4992.      *    @param    string    $value    Value
  4993.      *    @param    int        $start    Start character
  4994.      *    @param    int        $chars    Number of characters
  4995.      *    @return    string 
  4996.      */
  4997.     public static function REPLACE($oldText ''$start 1$chars null$newText{
  4998.         $oldText    self::flattenSingleValue($oldText);
  4999.         $start        self::flattenSingleValue($start);
  5000.         $chars        self::flattenSingleValue($chars);
  5001.         $newText    self::flattenSingleValue($newText);
  5002.  
  5003.         $left self::LEFT($oldText,$start-1);
  5004.         $right self::RIGHT($oldText,self::STRINGLENGTH($oldText)-($start+$chars)+1);
  5005.  
  5006.         return $left.$newText.$right;
  5007.     }    //    function REPLACE()
  5008.  
  5009.  
  5010.     /**
  5011.      *    RETURNSTRING
  5012.      *
  5013.      *    @param    mixed    $value    Value to check
  5014.      *    @return    boolean 
  5015.      */
  5016.     public static function RETURNSTRING($testValue ''{
  5017.         $testValue    self::flattenSingleValue($testValue);
  5018.  
  5019.         if (is_string($testValue)) {
  5020.             return $testValue;
  5021.         }
  5022.         return Null;
  5023.     }    //    function RETURNSTRING()
  5024.  
  5025.  
  5026.     /**
  5027.      *    FIXEDFORMAT
  5028.      *
  5029.      *    @param    mixed    $value    Value to check
  5030.      *    @return    boolean 
  5031.      */
  5032.     public static function FIXEDFORMAT($value,$decimals=2,$no_commas=false{
  5033.         $value        self::flattenSingleValue($value);
  5034.         $decimals    self::flattenSingleValue($decimals);
  5035.         $no_commas        self::flattenSingleValue($no_commas);
  5036.  
  5037.         $valueResult round($value,$decimals);
  5038.         if ($decimals 0$decimals 0}
  5039.         if (!$no_commas{
  5040.             $valueResult number_format($valueResult,$decimals);
  5041.         }
  5042.  
  5043.         return (string) $valueResult;
  5044.     }    //    function FIXEDFORMAT()
  5045.  
  5046.  
  5047.     /**
  5048.      *    TEXTFORMAT
  5049.      *
  5050.      *    @param    mixed    $value    Value to check
  5051.      *    @return    boolean 
  5052.      */
  5053.     public static function TEXTFORMAT($value,$format{
  5054.         $value    self::flattenSingleValue($value);
  5055.         $format    self::flattenSingleValue($format);
  5056.  
  5057.         return (string) PHPExcel_Style_NumberFormat::toFormattedString($value,$format);
  5058.     }    //    function TEXTFORMAT()
  5059.  
  5060.  
  5061.     /**
  5062.      *    TRIMSPACES
  5063.      *
  5064.      *    @param    mixed    $value    Value to check
  5065.      *    @return    string 
  5066.      */
  5067.     public static function TRIMSPACES($stringValue ''{
  5068.         $stringValue    self::flattenSingleValue($stringValue);
  5069.  
  5070.         if (is_string($stringValue|| is_numeric($stringValue)) {
  5071.             return trim(preg_replace('/  +/',' ',$stringValue));
  5072.         }
  5073.         return Null;
  5074.     }    //    function TRIMSPACES()
  5075.  
  5076.  
  5077.     private static $_invalidChars Null;
  5078.  
  5079.     /**
  5080.      *    TRIMNONPRINTABLE
  5081.      *
  5082.      *    @param    mixed    $value    Value to check
  5083.      *    @return    string 
  5084.      */
  5085.     public static function TRIMNONPRINTABLE($stringValue ''{
  5086.         $stringValue    self::flattenSingleValue($stringValue);
  5087.  
  5088.         if (self::$_invalidChars == Null{
  5089.             self::$_invalidChars range(chr(0),chr(31));
  5090.         }
  5091.  
  5092.         if (is_string($stringValue|| is_numeric($stringValue)) {
  5093.             return str_replace(self::$_invalidChars,'',trim($stringValue,"\x00..\x1F"));
  5094.         }
  5095.         return Null;
  5096.     }    //    function TRIMNONPRINTABLE()
  5097.  
  5098.  
  5099.     /**
  5100.      *    ERROR_TYPE
  5101.      *
  5102.      *    @param    mixed    $value    Value to check
  5103.      *    @return    boolean 
  5104.      */
  5105.     public static function ERROR_TYPE($value ''{
  5106.         $value    self::flattenSingleValue($value);
  5107.  
  5108.         $i 1;
  5109.         foreach(self::$_errorCodes as $errorCode{
  5110.             if ($value == $errorCode{
  5111.                 return $i;
  5112.             }
  5113.             ++$i;
  5114.         }
  5115.         return self::$_errorCodes['na'];
  5116.     }    //    function ERROR_TYPE()
  5117.  
  5118.  
  5119.     /**
  5120.      *    IS_BLANK
  5121.      *
  5122.      *    @param    mixed    $value    Value to check
  5123.      *    @return    boolean 
  5124.      */
  5125.     public static function IS_BLANK($value null{
  5126.         if (!is_null($value)) {
  5127.             $value    self::flattenSingleValue($value);
  5128.         }
  5129.  
  5130.         return is_null($value);
  5131.     }    //    function IS_BLANK()
  5132.  
  5133.  
  5134.     /**
  5135.      *    IS_ERR
  5136.      *
  5137.      *    @param    mixed    $value    Value to check
  5138.      *    @return    boolean 
  5139.      */
  5140.     public static function IS_ERR($value ''{
  5141.         $value        self::flattenSingleValue($value);
  5142.  
  5143.         return self::IS_ERROR($value&& (!self::IS_NA($value));
  5144.     }    //    function IS_ERR()
  5145.  
  5146.  
  5147.     /**
  5148.      *    IS_ERROR
  5149.      *
  5150.      *    @param    mixed    $value    Value to check
  5151.      *    @return    boolean 
  5152.      */
  5153.     public static function IS_ERROR($value ''{
  5154.         $value        self::flattenSingleValue($value);
  5155.  
  5156.         return in_array($valuearray_values(self::$_errorCodes));
  5157.     }    //    function IS_ERROR()
  5158.  
  5159.  
  5160.     /**
  5161.      *    IS_NA
  5162.      *
  5163.      *    @param    mixed    $value    Value to check
  5164.      *    @return    boolean 
  5165.      */
  5166.     public static function IS_NA($value ''{
  5167.         $value        self::flattenSingleValue($value);
  5168.  
  5169.         return ($value === self::$_errorCodes['na']);
  5170.     }    //    function IS_NA()
  5171.  
  5172.  
  5173.     /**
  5174.      *    IS_EVEN
  5175.      *
  5176.      *    @param    mixed    $value    Value to check
  5177.      *    @return    boolean 
  5178.      */
  5179.     public static function IS_EVEN($value 0{
  5180.         $value        self::flattenSingleValue($value);
  5181.  
  5182.         if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
  5183.             return self::$_errorCodes['value'];
  5184.         }
  5185.         return ($value == 0);
  5186.     }    //    function IS_EVEN()
  5187.  
  5188.  
  5189.     /**
  5190.      *    IS_ODD
  5191.      *
  5192.      *    @param    mixed    $value    Value to check
  5193.      *    @return    boolean 
  5194.      */
  5195.     public static function IS_ODD($value null{
  5196.         $value        self::flattenSingleValue($value);
  5197.  
  5198.         if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
  5199.             return self::$_errorCodes['value'];
  5200.         }
  5201.         return (abs($value== 1);
  5202.     }    //    function IS_ODD()
  5203.  
  5204.  
  5205.     /**
  5206.      *    IS_NUMBER
  5207.      *
  5208.      *    @param    mixed    $value        Value to check
  5209.      *    @return    boolean 
  5210.      */
  5211.     public static function IS_NUMBER($value 0{
  5212.         $value        self::flattenSingleValue($value);
  5213.  
  5214.         if (is_string($value)) {
  5215.             return False;
  5216.         }
  5217.         return is_numeric($value);
  5218.     }    //    function IS_NUMBER()
  5219.  
  5220.  
  5221.     /**
  5222.      *    IS_LOGICAL
  5223.      *
  5224.      *    @param    mixed    $value        Value to check
  5225.      *    @return    boolean 
  5226.      */
  5227.     public static function IS_LOGICAL($value true{
  5228.         $value        self::flattenSingleValue($value);
  5229.  
  5230.         return is_bool($value);
  5231.     }    //    function IS_LOGICAL()
  5232.  
  5233.  
  5234.     /**
  5235.      *    IS_TEXT
  5236.      *
  5237.      *    @param    mixed    $value        Value to check
  5238.      *    @return    boolean 
  5239.      */
  5240.     public static function IS_TEXT($value ''{
  5241.         $value        self::flattenSingleValue($value);
  5242.  
  5243.         return is_string($value);
  5244.     }    //    function IS_TEXT()
  5245.  
  5246.  
  5247.     /**
  5248.      *    IS_NONTEXT
  5249.      *
  5250.      *    @param    mixed    $value        Value to check
  5251.      *    @return    boolean 
  5252.      */
  5253.     public static function IS_NONTEXT($value ''{
  5254.         return !self::IS_TEXT($value);
  5255.     }    //    function IS_NONTEXT()
  5256.  
  5257.  
  5258.     /**
  5259.      *    VERSION
  5260.      *
  5261.      *    @return    string    Version information
  5262.      */
  5263.     public static function VERSION({
  5264.         return 'PHPExcel 1.7.0, 2009-08-10';
  5265.     }    //    function VERSION()
  5266.  
  5267.  
  5268.     /**
  5269.      * DATE
  5270.      *
  5271.      * @param    long    $year 
  5272.      * @param    long    $month 
  5273.      * @param    long    $day 
  5274.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5275.      *                         depending on the value of the ReturnDateType flag
  5276.      */
  5277.     public static function DATE($year 0$month 1$day 1{
  5278.         $year    = (integer) self::flattenSingleValue($year);
  5279.         $month    = (integer) self::flattenSingleValue($month);
  5280.         $day    = (integer) self::flattenSingleValue($day);
  5281.  
  5282.         $baseYear PHPExcel_Shared_Date::getExcelCalendar();
  5283.         // Validate parameters
  5284.         if ($year ($baseYear-1900)) {
  5285.             return self::$_errorCodes['num'];
  5286.         }
  5287.         if ((($baseYear-1900!= 0&& ($year $baseYear&& ($year >= 1900)) {
  5288.             return self::$_errorCodes['num'];
  5289.         }
  5290.  
  5291.         if (($year $baseYear&& ($year >= ($baseYear-1900))) {
  5292.             $year += 1900;
  5293.         }
  5294.  
  5295.         if ($month 1{
  5296.             //    Handle year/month adjustment if month < 1
  5297.             --$month;
  5298.             $year += ceil($month 121;
  5299.             $month 13 abs($month 12);
  5300.         elseif ($month 12{
  5301.             //    Handle year/month adjustment if month > 12
  5302.             $year += floor($month 12);
  5303.             $month ($month 12);
  5304.         }
  5305.  
  5306.         // Re-validate the year parameter after adjustments
  5307.         if (($year $baseYear|| ($year >= 10000)) {
  5308.             return self::$_errorCodes['num'];
  5309.         }
  5310.  
  5311.         // Execute function
  5312.         $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel($year$month$day);
  5313.         switch (self::getReturnDateType()) {
  5314.             case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  5315.                                                   break;
  5316.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
  5317.                                                   break;
  5318.             case self::RETURNDATE_PHP_OBJECT    return PHPExcel_Shared_Date::ExcelToPHPObject($excelDateValue);
  5319.                                                   break;
  5320.         }
  5321.     }    //    function DATE()
  5322.  
  5323.  
  5324.     /**
  5325.      * TIME
  5326.      *
  5327.      * @param    long    $hour 
  5328.      * @param    long    $minute 
  5329.      * @param    long    $second 
  5330.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5331.      *                         depending on the value of the ReturnDateType flag
  5332.      */
  5333.     public static function TIME($hour 0$minute 0$second 0{
  5334.         $hour    self::flattenSingleValue($hour);
  5335.         $minute    self::flattenSingleValue($minute);
  5336.         $second    self::flattenSingleValue($second);
  5337.  
  5338.         if ($hour == ''$hour 0}
  5339.         if ($minute == ''$minute 0}
  5340.         if ($second == ''$second 0}
  5341.  
  5342.         if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) {
  5343.             return self::$_errorCodes['value'];
  5344.         }
  5345.         $hour    = (integer) $hour;
  5346.         $minute    = (integer) $minute;
  5347.         $second    = (integer) $second;
  5348.  
  5349.         if ($second 0{
  5350.             $minute += floor($second 60);
  5351.             $second 60 abs($second 60);
  5352.             if ($second == 60$second 0}
  5353.         elseif ($second >= 60{
  5354.             $minute += floor($second 60);
  5355.             $second $second 60;
  5356.         }
  5357.         if ($minute 0{
  5358.             $hour += floor($minute 60);
  5359.             $minute 60 abs($minute 60);
  5360.             if ($minute == 60$minute 0}
  5361.         elseif ($minute >= 60{
  5362.             $hour += floor($minute 60);
  5363.             $minute $minute 60;
  5364.         }
  5365.  
  5366.         if ($hour 23{
  5367.             $hour $hour 24;
  5368.         elseif ($hour 0{
  5369.             return self::$_errorCodes['num'];
  5370.         }
  5371.  
  5372.         // Execute function
  5373.         switch (self::getReturnDateType()) {
  5374.             case self::RETURNDATE_EXCEL            $date 0;
  5375.                                                   $calendar PHPExcel_Shared_Date::getExcelCalendar();
  5376.                                                   if ($calendar != PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900{
  5377.                                                      $date 1;
  5378.                                                   }
  5379.                                                   return (float) PHPExcel_Shared_Date::FormattedPHPToExcel($calendar1$date$hour$minute$second);
  5380.                                                   break;
  5381.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(197011$hour-1$minute$second));    // -2147468400; //    -2147472000 + 3600
  5382.                                                   break;
  5383.             case self::RETURNDATE_PHP_OBJECT    $dayAdjust 0;
  5384.                                                   if ($hour 0{
  5385.                                                      $dayAdjust floor($hour 24);
  5386.                                                      $hour 24 abs($hour 24);
  5387.                                                      if ($hour == 24$hour 0}
  5388.                                                   elseif ($hour >= 24{
  5389.                                                      $dayAdjust floor($hour 24);
  5390.                                                      $hour $hour 24;
  5391.                                                   }
  5392.                                                   $phpDateObject new DateTime('1900-01-01 '.$hour.':'.$minute.':'.$second);
  5393.                                                   if ($dayAdjust != 0{
  5394.                                                      $phpDateObject->modify($dayAdjust.' days');
  5395.                                                   }
  5396.                                                   return $phpDateObject;
  5397.                                                   break;
  5398.         }
  5399.     }    //    function TIME()
  5400.  
  5401.  
  5402.     /**
  5403.      * DATEVALUE
  5404.      *
  5405.      * @param    string    $dateValue 
  5406.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5407.      *                         depending on the value of the ReturnDateType flag
  5408.      */
  5409.     public static function DATEVALUE($dateValue 1{
  5410.         $dateValue    str_replace(array('/','.',' '),array('-','-','-'),self::flattenSingleValue(trim($dateValue,'"')));
  5411.  
  5412.         $yearFound false;
  5413.         $t1 explode('-',$dateValue);
  5414.         foreach($t1 as &$t{
  5415.             if ((is_numeric($t)) && (($t 31&& ($t 100))) {
  5416.                 if ($yearFound{
  5417.                     return self::$_errorCodes['value'];
  5418.                 else {
  5419.                     $t += 1900;
  5420.                     $yearFound true;
  5421.                 }
  5422.             }
  5423.         }
  5424.         unset($t);
  5425.         $dateValue implode('-',$t1);
  5426.  
  5427.         $PHPDateArray date_parse($dateValue);
  5428.         if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  5429.             $testVal1 strtok($dateValue,'- ');
  5430.             if ($testVal1 !== False{
  5431.                 $testVal2 strtok('- ');
  5432.                 if ($testVal2 !== False{
  5433.                     $testVal3 strtok('- ');
  5434.                     if ($testVal3 === False{
  5435.                         $testVal3 strftime('%Y');
  5436.                     }
  5437.                 else {
  5438.                     return self::$_errorCodes['value'];
  5439.                 }
  5440.             else {
  5441.                 return self::$_errorCodes['value'];
  5442.             }
  5443.             $PHPDateArray date_parse($testVal1.'-'.$testVal2.'-'.$testVal3);
  5444.             if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  5445.                 $PHPDateArray date_parse($testVal2.'-'.$testVal1.'-'.$testVal3);
  5446.                 if (($PHPDateArray === False|| ($PHPDateArray['error_count'0)) {
  5447.                     return self::$_errorCodes['value'];
  5448.                 }
  5449.             }
  5450.         }
  5451.  
  5452.         if (($PHPDateArray !== False&& ($PHPDateArray['error_count'== 0)) {
  5453.             // Execute function
  5454.             if ($PHPDateArray['year'== '')    $PHPDateArray['year'strftime('%Y')}
  5455.             if ($PHPDateArray['month'== '')    $PHPDateArray['month'strftime('%m')}
  5456.             if ($PHPDateArray['day'== '')        $PHPDateArray['day'strftime('%d')}
  5457.             $excelDateValue floor(PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']));
  5458.  
  5459.             switch (self::getReturnDateType()) {
  5460.                 case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  5461.                                                       break;
  5462.                 case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
  5463.                                                       break;
  5464.                 case self::RETURNDATE_PHP_OBJECT    return new DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00');
  5465.                                                       break;
  5466.             }
  5467.         }
  5468.         return self::$_errorCodes['value'];
  5469.     }    //    function DATEVALUE()
  5470.  
  5471.  
  5472.     /**
  5473.      * _getDateValue
  5474.      *
  5475.      * @param    string    $dateValue 
  5476.      * @return    mixed    Excel date/time serial value, or string if error
  5477.      */
  5478.     private static function _getDateValue($dateValue{
  5479.         if (!is_numeric($dateValue)) {
  5480.             if ((is_string($dateValue)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) {
  5481.                 return self::$_errorCodes['value'];
  5482.             }
  5483.             if ((is_object($dateValue)) && ($dateValue instanceof PHPExcel_Shared_Date::$dateTimeObjectType)) {
  5484.                 $dateValue PHPExcel_Shared_Date::PHPToExcel($dateValue);
  5485.             else {
  5486.                 $saveReturnDateType self::getReturnDateType();
  5487.                 self::setReturnDateType(self::RETURNDATE_EXCEL);
  5488.                 $dateValue self::DATEVALUE($dateValue);
  5489.                 self::setReturnDateType($saveReturnDateType);
  5490.             }
  5491.         }
  5492.         return $dateValue;
  5493.     }    //    function _getDateValue()
  5494.  
  5495.  
  5496.     /**
  5497.      * TIMEVALUE
  5498.      *
  5499.      * @param    string    $timeValue 
  5500.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5501.      *                         depending on the value of the ReturnDateType flag
  5502.      */
  5503.     public static function TIMEVALUE($timeValue{
  5504.         $timeValue    self::flattenSingleValue($timeValue);
  5505.  
  5506.         if ((($PHPDateArray date_parse($timeValue)) !== False&& ($PHPDateArray['error_count'== 0)) {
  5507.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  5508.                 $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']);
  5509.             else {
  5510.                 $excelDateValue PHPExcel_Shared_Date::FormattedPHPToExcel(1900,1,1,$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']1;
  5511.             }
  5512.  
  5513.             switch (self::getReturnDateType()) {
  5514.                 case self::RETURNDATE_EXCEL            return (float) $excelDateValue;
  5515.                                                       break;
  5516.                 case self::RETURNDATE_PHP_NUMERIC    return (integer) $phpDateValue PHPExcel_Shared_Date::ExcelToPHP($excelDateValue+255693600;;
  5517.                                                       break;
  5518.                 case self::RETURNDATE_PHP_OBJECT    return new DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']);
  5519.                                                       break;
  5520.             }
  5521.         }
  5522.         return self::$_errorCodes['value'];
  5523.     }    //    function TIMEVALUE()
  5524.  
  5525.  
  5526.     /**
  5527.      * _getTimeValue
  5528.      *
  5529.      * @param    string    $timeValue 
  5530.      * @return    mixed    Excel date/time serial value, or string if error
  5531.      */
  5532.     private static function _getTimeValue($timeValue{
  5533.         $saveReturnDateType self::getReturnDateType();
  5534.         self::setReturnDateType(self::RETURNDATE_EXCEL);
  5535.         $timeValue self::TIMEVALUE($timeValue);
  5536.         self::setReturnDateType($saveReturnDateType);
  5537.         return $timeValue;
  5538.     }    //    function _getTimeValue()
  5539.  
  5540.  
  5541.     /**
  5542.      * DATETIMENOW
  5543.      *
  5544.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5545.      *                         depending on the value of the ReturnDateType flag
  5546.      */
  5547.     public static function DATETIMENOW({
  5548.         $saveTimeZone date_default_timezone_get();
  5549.         date_default_timezone_set('UTC');
  5550.         $retValue False;
  5551.         switch (self::getReturnDateType()) {
  5552.             case self::RETURNDATE_EXCEL            $retValue = (float) PHPExcel_Shared_Date::PHPToExcel(time());
  5553.                                                   break;
  5554.             case self::RETURNDATE_PHP_NUMERIC    $retValue = (integer) time();
  5555.                                                   break;
  5556.             case self::RETURNDATE_PHP_OBJECT    $retValue new DateTime();
  5557.                                                   break;
  5558.         }
  5559.         date_default_timezone_set($saveTimeZone);
  5560.  
  5561.         return $retValue;
  5562.     }    //    function DATETIMENOW()
  5563.  
  5564.  
  5565.     /**
  5566.      * DATENOW
  5567.      *
  5568.      * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
  5569.      *                         depending on the value of the ReturnDateType flag
  5570.      */
  5571.     public static function DATENOW({
  5572.         $saveTimeZone date_default_timezone_get();
  5573.         date_default_timezone_set('UTC');
  5574.         $retValue False;
  5575.         $excelDateTime floor(PHPExcel_Shared_Date::PHPToExcel(time()));
  5576.         switch (self::getReturnDateType()) {
  5577.             case self::RETURNDATE_EXCEL            $retValue = (float) $excelDateTime;
  5578.                                                   break;
  5579.             case self::RETURNDATE_PHP_NUMERIC    $retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime3600;
  5580.                                                   break;
  5581.             case self::RETURNDATE_PHP_OBJECT    $retValue PHPExcel_Shared_Date::ExcelToPHPObject($excelDateTime);
  5582.                                                   break;
  5583.         }
  5584.         date_default_timezone_set($saveTimeZone);
  5585.  
  5586.         return $retValue;
  5587.     }    //    function DATENOW()
  5588.  
  5589.  
  5590.     private static function _isLeapYear($year{
  5591.         return ((($year 4== 0&& (($year 100!= 0|| (($year 400== 0));
  5592.     }    //    function _isLeapYear()
  5593.  
  5594.  
  5595.     private static function _dateDiff360($startDay$startMonth$startYear$endDay$endMonth$endYear$methodUS{
  5596.         if ($startDay == 31{
  5597.             --$startDay;
  5598.         elseif ($methodUS && ($startMonth == && ($startDay == 29 || ($startDay == 28 && !self::_isLeapYear($startYear))))) {
  5599.             $startDay 30;
  5600.         }
  5601.         if ($endDay == 31{
  5602.             if ($methodUS && $startDay != 30{
  5603.                 $endDay 1;
  5604.                 if ($endMonth == 12{
  5605.                     ++$endYear;
  5606.                     $endMonth 1;
  5607.                 else {
  5608.                     ++$endMonth;
  5609.                 }
  5610.             else {
  5611.                 $endDay 30;
  5612.             }
  5613.         }
  5614.  
  5615.         return $endDay $endMonth 30 $endYear 360 $startDay $startMonth 30 $startYear 360;
  5616.     }    //    function _dateDiff360()
  5617.  
  5618.  
  5619.     /**
  5620.      * DAYS360
  5621.      *
  5622.      * @param    long    $startDate        Excel date serial value or a standard date string
  5623.      * @param    long    $endDate        Excel date serial value or a standard date string
  5624.      * @param    boolean    $method            US or European Method
  5625.      * @return    long    PHP date/time serial
  5626.      */
  5627.     public static function DAYS360($startDate 0$endDate 0$method false{
  5628.         $startDate    self::flattenSingleValue($startDate);
  5629.         $endDate    self::flattenSingleValue($endDate);
  5630.  
  5631.         if (is_string($startDate self::_getDateValue($startDate))) {
  5632.             return self::$_errorCodes['value'];
  5633.         }
  5634.         if (is_string($endDate self::_getDateValue($endDate))) {
  5635.             return self::$_errorCodes['value'];
  5636.         }
  5637.  
  5638.         // Execute function
  5639.         $PHPStartDateObject PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
  5640.         $startDay $PHPStartDateObject->format('j');
  5641.         $startMonth $PHPStartDateObject->format('n');
  5642.         $startYear $PHPStartDateObject->format('Y');
  5643.  
  5644.         $PHPEndDateObject PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  5645.         $endDay $PHPEndDateObject->format('j');
  5646.         $endMonth $PHPEndDateObject->format('n');
  5647.         $endYear $PHPEndDateObject->format('Y');
  5648.  
  5649.         return self::_dateDiff360($startDay$startMonth$startYear$endDay$endMonth$endYear!$method);
  5650.     }    //    function DAYS360()
  5651.  
  5652.  
  5653.     /**
  5654.      * DATEDIF
  5655.      *
  5656.      * @param    long    $startDate        Excel date serial value or a standard date string
  5657.      * @param    long    $endDate        Excel date serial value or a standard date string
  5658.      * @param    string    $unit 
  5659.      * @return    long    Interval between the dates
  5660.      */
  5661.     public static function DATEDIF($startDate 0$endDate 0$unit 'D'{
  5662.         $startDate    self::flattenSingleValue($startDate);
  5663.         $endDate    self::flattenSingleValue($endDate);
  5664.         $unit        strtoupper(self::flattenSingleValue($unit));
  5665.  
  5666.         if (is_string($startDate self::_getDateValue($startDate))) {
  5667.             return self::$_errorCodes['value'];
  5668.         }
  5669.         if (is_string($endDate self::_getDateValue($endDate))) {
  5670.             return self::$_errorCodes['value'];
  5671.         }
  5672.  
  5673.         // Validate parameters
  5674.         if ($startDate >= $endDate{
  5675.             return self::$_errorCodes['num'];
  5676.         }
  5677.  
  5678.         // Execute function
  5679.         $difference $endDate $startDate;
  5680.  
  5681.         $PHPStartDateObject PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
  5682.         $startDays $PHPStartDateObject->format('j');
  5683.         $startMonths $PHPStartDateObject->format('n');
  5684.         $startYears $PHPStartDateObject->format('Y');
  5685.  
  5686.         $PHPEndDateObject PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  5687.         $endDays $PHPEndDateObject->format('j');
  5688.         $endMonths $PHPEndDateObject->format('n');
  5689.         $endYears $PHPEndDateObject->format('Y');
  5690.  
  5691.         $retVal self::$_errorCodes['num'];
  5692.         switch ($unit{
  5693.             case 'D':
  5694.                 $retVal intval($difference);
  5695.                 break;
  5696.             case 'M':
  5697.                 $retVal intval($endMonths $startMonths(intval($endYears $startYears12);
  5698.                 //    We're only interested in full months
  5699.                 if ($endDays $startDays{
  5700.                     --$retVal;
  5701.                 }
  5702.                 break;
  5703.             case 'Y':
  5704.                 $retVal intval($endYears $startYears);
  5705.                 //    We're only interested in full months
  5706.                 if ($endMonths $startMonths{
  5707.                     --$retVal;
  5708.                 elseif (($endMonths == $startMonths&& ($endDays $startDays)) {
  5709.                     --$retVal;
  5710.                 }
  5711.                 break;
  5712.             case 'MD':
  5713.                 if ($endDays $startDays{
  5714.                     $retVal $endDays;
  5715.                     $PHPEndDateObject->modify('-'.$endDays.' days');
  5716.                     $adjustDays $PHPEndDateObject->format('j');
  5717.                     if ($adjustDays $startDays{
  5718.                         $retVal += ($adjustDays $startDays);
  5719.                     }
  5720.                 else {
  5721.                     $retVal $endDays $startDays;
  5722.                 }
  5723.                 break;
  5724.             case 'YM':
  5725.                 $retVal abs(intval($endMonths $startMonths));
  5726.                 //    We're only interested in full months
  5727.                 if ($endDays $startDays{
  5728.                     --$retVal;
  5729.                 }
  5730.                 break;
  5731.             case 'YD':
  5732.                 $retVal intval($difference);
  5733.                 if ($endYears $startYears{
  5734.                     while ($endYears $startYears{
  5735.                         $PHPEndDateObject->modify('-1 year');
  5736.                         $endYears $PHPEndDateObject->format('Y');
  5737.                     }
  5738.                     $retVal abs($PHPEndDateObject->format('z'$PHPStartDateObject->format('z'));
  5739.                 }
  5740.                 break;
  5741.         }
  5742.         return $retVal;
  5743.     }    //    function DATEDIF()
  5744.  
  5745.  
  5746.     /**
  5747.      *    YEARFRAC
  5748.      *
  5749.      *    Calculates the fraction of the year represented by the number of whole days between two dates (the start_date and the
  5750.      *    end_date). Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or obligations
  5751.      *    to assign to a specific term.
  5752.      *
  5753.      *    @param    mixed    $startDate        Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string
  5754.      *    @param    mixed    $endDate        Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string
  5755.      *    @param    integer    $method            Method used for the calculation
  5756.      *                                         0 or omitted    US (NASD) 30/360
  5757.      *                                         1                Actual/actual
  5758.      *                                         2                Actual/360
  5759.      *                                         3                Actual/365
  5760.      *                                         4                European 30/360
  5761.      *    @return    float    fraction of the year
  5762.      */
  5763.     public static function YEARFRAC($startDate 0$endDate 0$method 0{
  5764.         $startDate    self::flattenSingleValue($startDate);
  5765.         $endDate    self::flattenSingleValue($endDate);
  5766.         $method        self::flattenSingleValue($method);
  5767.  
  5768.         if (is_string($startDate self::_getDateValue($startDate))) {
  5769.             return self::$_errorCodes['value'];
  5770.         }
  5771.         if (is_string($endDate self::_getDateValue($endDate))) {
  5772.             return self::$_errorCodes['value'];
  5773.         }
  5774.  
  5775.         if ((is_numeric($method)) && (!is_string($method))) {
  5776.             switch($method{
  5777.                 case 0    :
  5778.                     return self::DAYS360($startDate,$endDate360;
  5779.                     break;
  5780.                 case 1    :
  5781.                     $startYear self::YEAR($startDate);
  5782.                     $endYear self::YEAR($endDate);
  5783.                     $leapDay 0;
  5784.                     if (self::_isLeapYear($startYear|| self::_isLeapYear($endYear)) {
  5785.                         $leapDay 1;
  5786.                     }
  5787.                     return self::DATEDIF($startDate,$endDate(365 $leapDay);
  5788.                     break;
  5789.                 case 2    :
  5790.                     return self::DATEDIF($startDate,$endDate360;
  5791.                     break;
  5792.                 case 3    :
  5793.                     return self::DATEDIF($startDate,$endDate365;
  5794.                     break;
  5795.                 case 4    :
  5796.                     return self::DAYS360($startDate,$endDate,True360;
  5797.                     break;
  5798.             }
  5799.         }
  5800.         return self::$_errorCodes['value'];
  5801.     }    //    function YEARFRAC()
  5802.  
  5803.  
  5804.     /**
  5805.      * NETWORKDAYS
  5806.      *
  5807.      * @param    mixed                Start date
  5808.      * @param    mixed                End date
  5809.      * @param    array of mixed        Optional Date Series
  5810.      * @return    long    Interval between the dates
  5811.      */
  5812.     public static function NETWORKDAYS($startDate,$endDate{
  5813.         //    Flush the mandatory start and end date that are referenced in the function definition
  5814.         $dateArgs self::flattenArray(func_get_args());
  5815.         array_shift($dateArgs);
  5816.         array_shift($dateArgs);
  5817.  
  5818.         //    Validate the start and end dates
  5819.         if (is_string($startDate $sDate self::_getDateValue($startDate))) {
  5820.             return self::$_errorCodes['value'];
  5821.         }
  5822.         if (is_string($endDate $eDate self::_getDateValue($endDate))) {
  5823.             return self::$_errorCodes['value'];
  5824.         }
  5825.  
  5826.         if ($sDate $eDate{
  5827.             $startDate $eDate;
  5828.             $endDate $sDate;
  5829.         }
  5830.  
  5831.         // Execute function
  5832.         $startDoW self::DAYOFWEEK($startDate,2);
  5833.         if ($startDoW 0$startDoW 0}
  5834.         $endDoW self::DAYOFWEEK($endDate,2);
  5835.         if ($endDoW >= 6$endDoW 0}
  5836.  
  5837.         $wholeWeekDays floor(($endDate $startDate75;
  5838.         $partWeekDays $endDoW $startDoW;
  5839.         if ($partWeekDays 5{
  5840.             $partWeekDays -= 5;
  5841.         }
  5842.  
  5843.         //    Test any extra holiday parameters
  5844.         $holidayCountedArray array();
  5845.         foreach ($dateArgs as $holidayDate{
  5846.             if (is_string($holidayDate self::_getDateValue($holidayDate))) {
  5847.                 return self::$_errorCodes['value'];
  5848.             }
  5849.             if (($holidayDate >= $startDate&& ($holidayDate <= $endDate)) {
  5850.                 if ((self::DAYOFWEEK($holidayDate,26&& (!in_array($holidayDate,$holidayCountedArray))) {
  5851.                     --$partWeekDays;
  5852.                     $holidayCountedArray[$holidayDate;
  5853.                 }
  5854.             }
  5855.         }
  5856.  
  5857.         if ($sDate $eDate{
  5858.             return ($wholeWeekDays $partWeekDays);
  5859.         }
  5860.         return $wholeWeekDays $partWeekDays;
  5861.     }    //    function NETWORKDAYS()
  5862.  
  5863.  
  5864.     /**
  5865.      * WORKDAY
  5866.      *
  5867.      * @param    mixed                Start date
  5868.      * @param    mixed                number of days for adjustment
  5869.      * @param    array of mixed        Optional Date Series
  5870.      * @return    long    Interval between the dates
  5871.      */
  5872.     public static function WORKDAY($startDate,$endDays{
  5873.         $dateArgs self::flattenArray(func_get_args());
  5874.  
  5875.         array_shift($dateArgs);
  5876.         array_shift($dateArgs);
  5877.  
  5878.         if (is_string($startDate self::_getDateValue($startDate))) {
  5879.             return self::$_errorCodes['value'];
  5880.         }
  5881.         if (!is_numeric($endDays)) {
  5882.             return self::$_errorCodes['value'];
  5883.         }
  5884.         $endDate = (float) $startDate (floor($endDays 57($endDays 5);
  5885.         if ($endDays 0{
  5886.             $endDate += 7;
  5887.         }
  5888.  
  5889.         $endDoW self::DAYOFWEEK($endDate,3);
  5890.         if ($endDoW >= 5{
  5891.             if ($endDays >= 0{
  5892.                 $endDate += ($endDoW);
  5893.             else {
  5894.                 $endDate -= ($endDoW 5);
  5895.             }
  5896.         }
  5897.  
  5898.         //    Test any extra holiday parameters
  5899.         if (count($dateArgs0{
  5900.             $holidayCountedArray $holidayDates array();
  5901.             foreach ($dateArgs as $holidayDate{
  5902.                 if (is_string($holidayDate self::_getDateValue($holidayDate))) {
  5903.                     return self::$_errorCodes['value'];
  5904.                 }
  5905.                 $holidayDates[$holidayDate;
  5906.             }
  5907.             if ($endDays >= 0{
  5908.                 sort($holidayDatesSORT_NUMERIC);
  5909.             else {
  5910.                 rsort($holidayDatesSORT_NUMERIC);
  5911.             }
  5912.             foreach ($holidayDates as $holidayDate{
  5913.                 if ($endDays >= 0{
  5914.                     if (($holidayDate >= $startDate&& ($holidayDate <= $endDate)) {
  5915.                         if ((self::DAYOFWEEK($holidayDate,26&& (!in_array($holidayDate,$holidayCountedArray))) {
  5916.                             ++$endDate;
  5917.                             $holidayCountedArray[$holidayDate;
  5918.                         }
  5919.                     }
  5920.                 else {
  5921.                     if (($holidayDate <= $startDate&& ($holidayDate >= $endDate)) {
  5922.                         if ((self::DAYOFWEEK($holidayDate,26&& (!in_array($holidayDate,$holidayCountedArray))) {
  5923.                             --$endDate;
  5924.                             $holidayCountedArray[$holidayDate;
  5925.                         }
  5926.                     }
  5927.                 }
  5928.                 $endDoW self::DAYOFWEEK($endDate,3);
  5929.                 if ($endDoW >= 5{
  5930.                     if ($endDays >= 0{
  5931.                         $endDate += ($endDoW);
  5932.                     else {
  5933.                         $endDate -= ($endDoW 5);
  5934.                     }
  5935.                 }
  5936.             }
  5937.         }
  5938.  
  5939.         switch (self::getReturnDateType()) {
  5940.             case self::RETURNDATE_EXCEL            return (float) $endDate;
  5941.                                                   break;
  5942.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP($endDate);
  5943.                                                   break;
  5944.             case self::RETURNDATE_PHP_OBJECT    return PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
  5945.                                                   break;
  5946.         }
  5947.     }    //    function WORKDAY()
  5948.  
  5949.  
  5950.     /**
  5951.      * DAYOFMONTH
  5952.      *
  5953.      * @param    long    $dateValue        Excel date serial value or a standard date string
  5954.      * @return    int        Day
  5955.      */
  5956.     public static function DAYOFMONTH($dateValue 1{
  5957.         $dateValue    self::flattenSingleValue($dateValue);
  5958.  
  5959.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  5960.             return self::$_errorCodes['value'];
  5961.         }
  5962.  
  5963.         // Execute function
  5964.         $PHPDateObject &PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  5965.  
  5966.         return (int) $PHPDateObject->format('j');
  5967.     }    //    function DAYOFMONTH()
  5968.  
  5969.  
  5970.     /**
  5971.      * DAYOFWEEK
  5972.      *
  5973.      * @param    long    $dateValue        Excel date serial value or a standard date string
  5974.      * @return    int        Day
  5975.      */
  5976.     public static function DAYOFWEEK($dateValue 1$style 1{
  5977.         $dateValue    self::flattenSingleValue($dateValue);
  5978.         $style        floor(self::flattenSingleValue($style));
  5979.  
  5980.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  5981.             return self::$_errorCodes['value'];
  5982.         }
  5983.  
  5984.         // Execute function
  5985.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  5986.         $DoW $PHPDateObject->format('w');
  5987.  
  5988.         $firstDay 1;
  5989.         switch ($style{
  5990.             case 1: ++$DoW;
  5991.                     break;
  5992.             case 2if ($DoW == 0$DoW 7}
  5993.                     break;
  5994.             case 3if ($DoW == 0$DoW 7}
  5995.                     $firstDay 0;
  5996.                     --$DoW;
  5997.                     break;
  5998.             default:
  5999.         }
  6000.         if (self::$compatibilityMode == self::COMPATIBILITY_EXCEL{
  6001.             //    Test for Excel's 1900 leap year, and introduce the error as required
  6002.             if (($PHPDateObject->format('Y'== 1900&& ($PHPDateObject->format('n'<= 2)) {
  6003.                 --$DoW;
  6004.                 if ($DoW $firstDay{
  6005.                     $DoW += 7;
  6006.                 }
  6007.             }
  6008.         }
  6009.  
  6010.         return (int) $DoW;
  6011.     }    //    function DAYOFWEEK()
  6012.  
  6013.  
  6014.     /**
  6015.      * WEEKOFYEAR
  6016.      *
  6017.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6018.      * @param    boolean    $method            Week begins on Sunday or Monday
  6019.      * @return    int        Week Number
  6020.      */
  6021.     public static function WEEKOFYEAR($dateValue 1$method 1{
  6022.         $dateValue    self::flattenSingleValue($dateValue);
  6023.         $method        floor(self::flattenSingleValue($method));
  6024.  
  6025.         if (!is_numeric($method)) {
  6026.             return self::$_errorCodes['value'];
  6027.         elseif (($method 1|| ($method 2)) {
  6028.             return self::$_errorCodes['num'];
  6029.         }
  6030.  
  6031.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6032.             return self::$_errorCodes['value'];
  6033.         }
  6034.  
  6035.         // Execute function
  6036.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6037.         $dayOfYear $PHPDateObject->format('z');
  6038.         $dow $PHPDateObject->format('w');
  6039.         $PHPDateObject->modify('-'.$dayOfYear.' days');
  6040.         $dow $PHPDateObject->format('w');
  6041.         $daysInFirstWeek (($dow ($method)) 7);
  6042.         $dayOfYear -= $daysInFirstWeek;
  6043.         $weekOfYear ceil($dayOfYear 71;
  6044.  
  6045.         return (int) $weekOfYear;
  6046.     }    //    function WEEKOFYEAR()
  6047.  
  6048.  
  6049.     /**
  6050.      * MONTHOFYEAR
  6051.      *
  6052.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6053.      * @return    int        Month
  6054.      */
  6055.     public static function MONTHOFYEAR($dateValue 1{
  6056.         $dateValue    self::flattenSingleValue($dateValue);
  6057.  
  6058.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6059.             return self::$_errorCodes['value'];
  6060.         }
  6061.  
  6062.         // Execute function
  6063.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6064.  
  6065.         return (int) $PHPDateObject->format('n');
  6066.     }    //    function MONTHOFYEAR()
  6067.  
  6068.  
  6069.     /**
  6070.      * YEAR
  6071.      *
  6072.      * @param    long    $dateValue        Excel date serial value or a standard date string
  6073.      * @return    int        Year
  6074.      */
  6075.     public static function YEAR($dateValue 1{
  6076.         $dateValue    self::flattenSingleValue($dateValue);
  6077.  
  6078.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6079.             return self::$_errorCodes['value'];
  6080.         }
  6081.  
  6082.         // Execute function
  6083.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6084.  
  6085.         return (int) $PHPDateObject->format('Y');
  6086.     }    //    function YEAR()
  6087.  
  6088.  
  6089.     /**
  6090.      * HOUROFDAY
  6091.      *
  6092.      * @param    mixed    $timeValue        Excel time serial value or a standard time string
  6093.      * @return    int        Hour
  6094.      */
  6095.     public static function HOUROFDAY($timeValue 0{
  6096.         $timeValue    self::flattenSingleValue($timeValue);
  6097.  
  6098.         if (!is_numeric($timeValue)) {
  6099.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6100.                 $testVal strtok($timeValue,'/-: ');
  6101.                 if (strlen($testValstrlen($timeValue)) {
  6102.                     return self::$_errorCodes['value'];
  6103.                 }
  6104.             }
  6105.             $timeValue self::_getTimeValue($timeValue);
  6106.             if (is_string($timeValue)) {
  6107.                 return self::$_errorCodes['value'];
  6108.             }
  6109.         }
  6110.         // Execute function
  6111.         if (is_real($timeValue)) {
  6112.             if ($timeValue >= 1{
  6113.                 $timeValue fmod($timeValue,1);
  6114.             elseif ($timeValue 0.0{
  6115.                 return self::$_errorCodes['num'];
  6116.             }
  6117.             $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  6118.         }
  6119.         return (int) date('G',$timeValue);
  6120.     }    //    function HOUROFDAY()
  6121.  
  6122.  
  6123.     /**
  6124.      * MINUTEOFHOUR
  6125.      *
  6126.      * @param    long    $timeValue        Excel time serial value or a standard time string
  6127.      * @return    int        Minute
  6128.      */
  6129.     public static function MINUTEOFHOUR($timeValue 0{
  6130.         $timeValue $timeTester    self::flattenSingleValue($timeValue);
  6131.  
  6132.         if (!is_numeric($timeValue)) {
  6133.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6134.                 $testVal strtok($timeValue,'/-: ');
  6135.                 if (strlen($testValstrlen($timeValue)) {
  6136.                     return self::$_errorCodes['value'];
  6137.                 }
  6138.             }
  6139.             $timeValue self::_getTimeValue($timeValue);
  6140.             if (is_string($timeValue)) {
  6141.                 return self::$_errorCodes['value'];
  6142.             }
  6143.         }
  6144.         // Execute function
  6145.         if (is_real($timeValue)) {
  6146.             if ($timeValue >= 1{
  6147.                 $timeValue fmod($timeValue,1);
  6148.             elseif ($timeValue 0.0{
  6149.                 return self::$_errorCodes['num'];
  6150.             }
  6151.             $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  6152.         }
  6153.         return (int) date('i',$timeValue);
  6154.     }    //    function MINUTEOFHOUR()
  6155.  
  6156.  
  6157.     /**
  6158.      * SECONDOFMINUTE
  6159.      *
  6160.      * @param    long    $timeValue        Excel time serial value or a standard time string
  6161.      * @return    int        Second
  6162.      */
  6163.     public static function SECONDOFMINUTE($timeValue 0{
  6164.         $timeValue    self::flattenSingleValue($timeValue);
  6165.  
  6166.         if (!is_numeric($timeValue)) {
  6167.             if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6168.                 $testVal strtok($timeValue,'/-: ');
  6169.                 if (strlen($testValstrlen($timeValue)) {
  6170.                     return self::$_errorCodes['value'];
  6171.                 }
  6172.             }
  6173.             $timeValue self::_getTimeValue($timeValue);
  6174.             if (is_string($timeValue)) {
  6175.                 return self::$_errorCodes['value'];
  6176.             }
  6177.         }
  6178.         // Execute function
  6179.         if (is_real($timeValue)) {
  6180.             if ($timeValue >= 1{
  6181.                 $timeValue fmod($timeValue,1);
  6182.             elseif ($timeValue 0.0{
  6183.                 return self::$_errorCodes['num'];
  6184.             }
  6185.             $timeValue PHPExcel_Shared_Date::ExcelToPHP($timeValue);
  6186.         }
  6187.         return (int) date('s',$timeValue);
  6188.     }    //    function SECONDOFMINUTE()
  6189.  
  6190.  
  6191.     private static function _adjustDateByMonths($dateValue 0$adjustmentMonths 0{
  6192.         // Execute function
  6193.         $PHPDateObject PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
  6194.         $oMonth = (int) $PHPDateObject->format('m');
  6195.         $oYear = (int) $PHPDateObject->format('Y');
  6196.  
  6197.         $adjustmentMonthsString = (string) $adjustmentMonths;
  6198.         if ($adjustmentMonths 0{
  6199.             $adjustmentMonthsString '+'.$adjustmentMonths;
  6200.         }
  6201.         if ($adjustmentMonths != 0{
  6202.             $PHPDateObject->modify($adjustmentMonthsString.' months');
  6203.         }
  6204.         $nMonth = (int) $PHPDateObject->format('m');
  6205.         $nYear = (int) $PHPDateObject->format('Y');
  6206.  
  6207.         $monthDiff ($nMonth $oMonth(($nYear $oYear12);
  6208.         if ($monthDiff != $adjustmentMonths{
  6209.             $adjustDays = (int) $PHPDateObject->format('d');
  6210.             $adjustDaysString '-'.$adjustDays.' days';
  6211.             $PHPDateObject->modify($adjustDaysString);
  6212.         }
  6213.         return $PHPDateObject;
  6214.     }    //    function _adjustDateByMonths()
  6215.  
  6216.  
  6217.     /**
  6218.      * EDATE
  6219.      *
  6220.      * Returns the serial number that represents the date that is the indicated number of months before or after a specified date
  6221.      * (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.
  6222.      *
  6223.      * @param    long    $dateValue                Excel date serial value or a standard date string
  6224.      * @param    int        $adjustmentMonths        Number of months to adjust by
  6225.      * @return    long    Excel date serial value
  6226.      */
  6227.     public static function EDATE($dateValue 1$adjustmentMonths 0{
  6228.         $dateValue            self::flattenSingleValue($dateValue);
  6229.         $adjustmentMonths    floor(self::flattenSingleValue($adjustmentMonths));
  6230.  
  6231.         if (!is_numeric($adjustmentMonths)) {
  6232.             return self::$_errorCodes['value'];
  6233.         }
  6234.  
  6235.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6236.             return self::$_errorCodes['value'];
  6237.         }
  6238.  
  6239.         // Execute function
  6240.         $PHPDateObject self::_adjustDateByMonths($dateValue,$adjustmentMonths);
  6241.  
  6242.         switch (self::getReturnDateType()) {
  6243.             case self::RETURNDATE_EXCEL            return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
  6244.                                                   break;
  6245.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
  6246.                                                   break;
  6247.             case self::RETURNDATE_PHP_OBJECT    return $PHPDateObject;
  6248.                                                   break;
  6249.         }
  6250.     }    //    function EDATE()
  6251.  
  6252.  
  6253.     /**
  6254.      * EOMONTH
  6255.      *
  6256.      * Returns the serial number for the last day of the month that is the indicated number of months before or after start_date.
  6257.      * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
  6258.      *
  6259.      * @param    long    $dateValue            Excel date serial value or a standard date string
  6260.      * @param    int        $adjustmentMonths    Number of months to adjust by
  6261.      * @return    long    Excel date serial value
  6262.      */
  6263.     public static function EOMONTH($dateValue 1$adjustmentMonths 0{
  6264.         $dateValue            self::flattenSingleValue($dateValue);
  6265.         $adjustmentMonths    floor(self::flattenSingleValue($adjustmentMonths));
  6266.  
  6267.         if (!is_numeric($adjustmentMonths)) {
  6268.             return self::$_errorCodes['value'];
  6269.         }
  6270.  
  6271.         if (is_string($dateValue self::_getDateValue($dateValue))) {
  6272.             return self::$_errorCodes['value'];
  6273.         }
  6274.  
  6275.         // Execute function
  6276.         $PHPDateObject self::_adjustDateByMonths($dateValue,$adjustmentMonths+1);
  6277.         $adjustDays = (int) $PHPDateObject->format('d');
  6278.         $adjustDaysString '-'.$adjustDays.' days';
  6279.         $PHPDateObject->modify($adjustDaysString);
  6280.  
  6281.         switch (self::getReturnDateType()) {
  6282.             case self::RETURNDATE_EXCEL            return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
  6283.                                                   break;
  6284.             case self::RETURNDATE_PHP_NUMERIC    return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
  6285.                                                   break;
  6286.             case self::RETURNDATE_PHP_OBJECT    return $PHPDateObject;
  6287.                                                   break;
  6288.         }
  6289.     }    //    function EOMONTH()
  6290.  
  6291.  
  6292.     /**
  6293.      *    TRUNC
  6294.      *
  6295.      *    Truncates value to the number of fractional digits by number_digits.
  6296.      *
  6297.      *    @param    float        $value 
  6298.      *    @param    int            $number_digits 
  6299.      *    @return    float        Truncated value
  6300.      */
  6301.     public static function TRUNC($value 0$number_digits 0{
  6302.         $value            self::flattenSingleValue($value);
  6303.         $number_digits    self::flattenSingleValue($number_digits);
  6304.  
  6305.         // Validate parameters
  6306.         if ($number_digits 0{
  6307.             return self::$_errorCodes['value'];
  6308.         }
  6309.  
  6310.         // Truncate
  6311.         if ($number_digits 0{
  6312.             $value $value pow(10$number_digits);
  6313.         }
  6314.         $value intval($value);
  6315.         if ($number_digits 0{
  6316.             $value $value pow(10$number_digits);
  6317.         }
  6318.  
  6319.         // Return
  6320.         return $value;
  6321.     }    //    function TRUNC()
  6322.  
  6323.     /**
  6324.      *    POWER
  6325.      *
  6326.      *    Computes x raised to the power y.
  6327.      *
  6328.      *    @param    float        $x 
  6329.      *    @param    float        $y 
  6330.      *    @return    float 
  6331.      */
  6332.     public static function POWER($x 0$y 2{
  6333.         $x    self::flattenSingleValue($x);
  6334.         $y    self::flattenSingleValue($y);
  6335.  
  6336.         // Validate parameters
  6337.         if ($x == && $y <= 0{
  6338.             return self::$_errorCodes['divisionbyzero'];
  6339.         }
  6340.  
  6341.         // Return
  6342.         return pow($x$y);
  6343.     }    //    function POWER()
  6344.  
  6345.  
  6346.     private static function _nbrConversionFormat($xVal,$places{
  6347.         if (!is_null($places)) {
  6348.             if (strlen($xVal<= $places{
  6349.                 return substr(str_pad($xVal,$places,'0',STR_PAD_LEFT),-10);
  6350.             else {
  6351.                 return self::$_errorCodes['num'];
  6352.             }
  6353.         }
  6354.  
  6355.         return substr($xVal,-10);
  6356.     }    //    function _nbrConversionFormat()
  6357.  
  6358.  
  6359.     /**
  6360.      * BINTODEC
  6361.      *
  6362.      * Return a binary value as Decimal.
  6363.      *
  6364.      * @param    string        $x 
  6365.      * @return    string 
  6366.      */
  6367.     public static function BINTODEC($x{
  6368.         $x    self::flattenSingleValue($x);
  6369.  
  6370.         if (is_bool($x)) {
  6371.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6372.                 $x = (int) $x;
  6373.             else {
  6374.                 return self::$_errorCodes['value'];
  6375.             }
  6376.         }
  6377.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6378.             $x floor($x);
  6379.         }
  6380.         $x = (string) $x;
  6381.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  6382.             return self::$_errorCodes['num'];
  6383.         }
  6384.         if (strlen($x10{
  6385.             return self::$_errorCodes['num'];
  6386.         elseif (strlen($x== 10{
  6387.             //    Two's Complement
  6388.             $x substr($x,-9);
  6389.             return '-'.(512-bindec($x));
  6390.         }
  6391.         return bindec($x);
  6392.     }    //    function BINTODEC()
  6393.  
  6394.  
  6395.     /**
  6396.      * BINTOHEX
  6397.      *
  6398.      * Return a binary value as Hex.
  6399.      *
  6400.      * @param    string        $x 
  6401.      * @return    string 
  6402.      */
  6403.     public static function BINTOHEX($x$places=null{
  6404.         $x    floor(self::flattenSingleValue($x));
  6405.         $places    self::flattenSingleValue($places);
  6406.  
  6407.         if (is_bool($x)) {
  6408.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6409.                 $x = (int) $x;
  6410.             else {
  6411.                 return self::$_errorCodes['value'];
  6412.             }
  6413.         }
  6414.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6415.             $x floor($x);
  6416.         }
  6417.         $x = (string) $x;
  6418.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  6419.             return self::$_errorCodes['num'];
  6420.         }
  6421.         if (strlen($x10{
  6422.             return self::$_errorCodes['num'];
  6423.         elseif (strlen($x== 10{
  6424.             //    Two's Complement
  6425.             return str_repeat('F',8).substr(strtoupper(dechex(bindec(substr($x,-9)))),-2);
  6426.         }
  6427.         $hexVal = (string) strtoupper(dechex(bindec($x)));
  6428.  
  6429.         return self::_nbrConversionFormat($hexVal,$places);
  6430.     }    //    function BINTOHEX()
  6431.  
  6432.  
  6433.     /**
  6434.      * BINTOOCT
  6435.      *
  6436.      * Return a binary value as Octal.
  6437.      *
  6438.      * @param    string        $x 
  6439.      * @return    string 
  6440.      */
  6441.     public static function BINTOOCT($x$places=null{
  6442.         $x    floor(self::flattenSingleValue($x));
  6443.         $places    self::flattenSingleValue($places);
  6444.  
  6445.         if (is_bool($x)) {
  6446.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6447.                 $x = (int) $x;
  6448.             else {
  6449.                 return self::$_errorCodes['value'];
  6450.             }
  6451.         }
  6452.         if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC{
  6453.             $x floor($x);
  6454.         }
  6455.         $x = (string) $x;
  6456.         if (strlen($xpreg_match_all('/[01]/',$x,$out)) {
  6457.             return self::$_errorCodes['num'];
  6458.         }
  6459.         if (strlen($x10{
  6460.             return self::$_errorCodes['num'];
  6461.         elseif (strlen($x== 10{
  6462.             //    Two's Complement
  6463.             return str_repeat('7',7).substr(strtoupper(decoct(bindec(substr($x,-9)))),-3);
  6464.         }
  6465.         $octVal = (string) decoct(bindec($x));
  6466.  
  6467.         return self::_nbrConversionFormat($octVal,$places);
  6468.     }    //    function BINTOOCT()
  6469.  
  6470.  
  6471.     /**
  6472.      * DECTOBIN
  6473.      *
  6474.      * Return an octal value as binary.
  6475.      *
  6476.      * @param    string        $x 
  6477.      * @return    string 
  6478.      */
  6479.     public static function DECTOBIN($x$places=null{
  6480.         $x    self::flattenSingleValue($x);
  6481.         $places    self::flattenSingleValue($places);
  6482.  
  6483.         if (is_bool($x)) {
  6484.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6485.                 $x = (int) $x;
  6486.             else {
  6487.                 return self::$_errorCodes['value'];
  6488.             }
  6489.         }
  6490.         $x = (string) $x;
  6491.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  6492.             return self::$_errorCodes['value'];
  6493.         }
  6494.         $x = (string) floor($x);
  6495.         $r decbin($x);
  6496.         if (strlen($r== 32{
  6497.             //    Two's Complement
  6498.             $r substr($r,-10);
  6499.         elseif (strlen($r11{
  6500.             return self::$_errorCodes['num'];
  6501.         }
  6502.  
  6503.         return self::_nbrConversionFormat($r,$places);
  6504.     }    //    function DECTOBIN()
  6505.  
  6506.  
  6507.     /**
  6508.      * DECTOOCT
  6509.      *
  6510.      * Return an octal value as binary.
  6511.      *
  6512.      * @param    string        $x 
  6513.      * @return    string 
  6514.      */
  6515.     public static function DECTOOCT($x$places=null{
  6516.         $x    self::flattenSingleValue($x);
  6517.         $places    self::flattenSingleValue($places);
  6518.  
  6519.         if (is_bool($x)) {
  6520.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6521.                 $x = (int) $x;
  6522.             else {
  6523.                 return self::$_errorCodes['value'];
  6524.             }
  6525.         }
  6526.         $x = (string) $x;
  6527.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  6528.             return self::$_errorCodes['value'];
  6529.         }
  6530.         $x = (string) floor($x);
  6531.         $r decoct($x);
  6532.         if (strlen($r== 11{
  6533.             //    Two's Complement
  6534.             $r substr($r,-10);
  6535.         }
  6536.  
  6537.         return self::_nbrConversionFormat($r,$places);
  6538.     }    //    function DECTOOCT()
  6539.  
  6540.  
  6541.     /**
  6542.      * DECTOHEX
  6543.      *
  6544.      * Return an octal value as binary.
  6545.      *
  6546.      * @param    string        $x 
  6547.      * @return    string 
  6548.      */
  6549.     public static function DECTOHEX($x$places=null{
  6550.         $x    self::flattenSingleValue($x);
  6551.         $places    self::flattenSingleValue($places);
  6552.  
  6553.         if (is_bool($x)) {
  6554.             if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE{
  6555.                 $x = (int) $x;
  6556.             else {
  6557.                 return self::$_errorCodes['value'];
  6558.             }
  6559.         }
  6560.         $x = (string) $x;
  6561.         if (strlen($xpreg_match_all('/[-0123456789.]/',$x,$out)) {
  6562.             return self::$_errorCodes['value'];
  6563.         }
  6564.         $x = (string) floor($x);
  6565.         $r strtoupper(dechex($x));
  6566.         if (strlen($r== 8{
  6567.             //    Two's Complement
  6568.             $r 'FF'.$r;
  6569.         }
  6570.  
  6571.         return self::_nbrConversionFormat($r,$places);
  6572.     }    //    function DECTOHEX()
  6573.  
  6574.  
  6575.     /**
  6576.      * HEXTOBIN
  6577.      *
  6578.      * Return a hex value as binary.
  6579.      *
  6580.      * @param    string        $x 
  6581.      * @return    string 
  6582.      */
  6583.     public static function HEXTOBIN($x$places=null{
  6584.         $x    self::flattenSingleValue($x);
  6585.         $places    self::flattenSingleValue($places);
  6586.  
  6587.         if (is_bool($x)) {
  6588.             return self::$_errorCodes['value'];
  6589.         }
  6590.         $x = (string) $x;
  6591.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  6592.             return self::$_errorCodes['num'];
  6593.         }
  6594.         $binVal decbin(hexdec($x));
  6595.  
  6596.         return substr(self::_nbrConversionFormat($binVal,$places),-10);
  6597.     }    //    function HEXTOBIN()
  6598.  
  6599.  
  6600.     /**
  6601.      * HEXTOOCT
  6602.      *
  6603.      * Return a hex value as octal.
  6604.      *
  6605.      * @param    string        $x 
  6606.      * @return    string 
  6607.      */
  6608.     public static function HEXTOOCT($x$places=null{
  6609.         $x    self::flattenSingleValue($x);
  6610.         $places    self::flattenSingleValue($places);
  6611.  
  6612.         if (is_bool($x)) {
  6613.             return self::$_errorCodes['value'];
  6614.         }
  6615.         $x = (string) $x;
  6616.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  6617.             return self::$_errorCodes['num'];
  6618.         }
  6619.         $octVal decoct(hexdec($x));
  6620.  
  6621.         return self::_nbrConversionFormat($octVal,$places);
  6622.     }    //    function HEXTOOCT()
  6623.  
  6624.  
  6625.     /**
  6626.      * HEXTODEC
  6627.      *
  6628.      * Return a hex value as octal.
  6629.      *
  6630.      * @param    string        $x 
  6631.      * @return    string 
  6632.      */
  6633.     public static function HEXTODEC($x{
  6634.         $x    self::flattenSingleValue($x);
  6635.  
  6636.         if (is_bool($x)) {
  6637.             return self::$_errorCodes['value'];
  6638.         }
  6639.         $x = (string) $x;
  6640.         if (strlen($xpreg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) {
  6641.             return self::$_errorCodes['num'];
  6642.         }
  6643.         return hexdec($x);
  6644.     }    //    function HEXTODEC()
  6645.  
  6646.  
  6647.     /**
  6648.      * OCTTOBIN
  6649.      *
  6650.      * Return an octal value as binary.
  6651.      *
  6652.      * @param    string        $x 
  6653.      * @return    string 
  6654.      */
  6655.     public static function OCTTOBIN($x$places=null{
  6656.         $x    self::flattenSingleValue($x);
  6657.         $places    self::flattenSingleValue($places);
  6658.  
  6659.         if (is_bool($x)) {
  6660.             return self::$_errorCodes['value'];
  6661.         }
  6662.         $x = (string) $x;
  6663.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  6664.             return self::$_errorCodes['num'];
  6665.         }
  6666.         $binVal decbin(octdec($x));
  6667.  
  6668.         return self::_nbrConversionFormat($binVal,$places);
  6669.     }    //    function OCTTOBIN()
  6670.  
  6671.  
  6672.     /**
  6673.      * OCTTODEC
  6674.      *
  6675.      * Return an octal value as binary.
  6676.      *
  6677.      * @param    string        $x 
  6678.      * @return    string 
  6679.      */
  6680.     public static function OCTTODEC($x{
  6681.         $x    self::flattenSingleValue($x);
  6682.  
  6683.         if (is_bool($x)) {
  6684.             return self::$_errorCodes['value'];
  6685.         }
  6686.         $x = (string) $x;
  6687.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  6688.             return self::$_errorCodes['num'];
  6689.         }
  6690.         return octdec($x);
  6691.     }    //    function OCTTODEC()
  6692.  
  6693.  
  6694.     /**
  6695.      * OCTTOHEX
  6696.      *
  6697.      * Return an octal value as hex.
  6698.      *
  6699.      * @param    string        $x 
  6700.      * @return    string 
  6701.      */
  6702.     public static function OCTTOHEX($x$places=null{
  6703.         $x    self::flattenSingleValue($x);
  6704.         $places    self::flattenSingleValue($places);
  6705.  
  6706.         if (is_bool($x)) {
  6707.             return self::$_errorCodes['value'];
  6708.         }
  6709.         $x = (string) $x;
  6710.         if (preg_match_all('/[01234567]/',$x,$out!= strlen($x)) {
  6711.             return self::$_errorCodes['num'];
  6712.         }
  6713.         $hexVal strtoupper(dechex(octdec($x)));
  6714.  
  6715.         return self::_nbrConversionFormat($hexVal,$places);
  6716.     }    //    function OCTTOHEX()
  6717.  
  6718.  
  6719.     public static function _parseComplex($complexNumber{
  6720.         $workString = (string) $complexNumber;
  6721.  
  6722.         $realNumber $imaginary 0;
  6723.         //    Extract the suffix, if there is one
  6724.         $suffix substr($workString,-1);
  6725.         if (!is_numeric($suffix)) {
  6726.             $workString substr($workString,0,-1);
  6727.         else {
  6728.             $suffix '';
  6729.         }
  6730.  
  6731.         //    Split the input into its Real and Imaginary components
  6732.         $leadingSign 0;
  6733.         if (strlen($workString0{
  6734.             $leadingSign (($workString{0== '+'|| ($workString{0== '-')) 0;
  6735.         }
  6736.         $power '';
  6737.         $realNumber strtok($workString'+-');
  6738.         if (strtoupper(substr($realNumber,-1)) == 'E'{
  6739.             $power strtok('+-');
  6740.             ++$leadingSign;
  6741.         }
  6742.  
  6743.         $realNumber substr($workString,0,strlen($realNumber)+strlen($power)+$leadingSign);
  6744.  
  6745.         if ($suffix != ''{
  6746.             $imaginary substr($workString,strlen($realNumber));
  6747.  
  6748.             if (($imaginary == ''&& (($realNumber == ''|| ($realNumber == '+'|| ($realNumber == '-'))) {
  6749.                 $imaginary $realNumber.'1';
  6750.                 $realNumber '0';
  6751.             else if ($imaginary == ''{
  6752.                 $imaginary $realNumber;
  6753.                 $realNumber '0';
  6754.             elseif (($imaginary == '+'|| ($imaginary == '-')) {
  6755.                 $imaginary .= '1';
  6756.             }
  6757.         }
  6758.  
  6759.         $complexArray array'real'        => $realNumber,
  6760.                                'imaginary'    => $imaginary,
  6761.                                'suffix'        => $suffix
  6762.                              );
  6763.  
  6764.         return $complexArray;
  6765.     }    //    function _parseComplex()
  6766.  
  6767.  
  6768.     private static function _cleanComplex($complexNumber{
  6769.         if ($complexNumber{0== '+'$complexNumber substr($complexNumber,1);
  6770.         if ($complexNumber{0== '0'$complexNumber substr($complexNumber,1);
  6771.         if ($complexNumber{0== '.'$complexNumber '0'.$complexNumber;
  6772.         if ($complexNumber{0== '+'$complexNumber substr($complexNumber,1);
  6773.         return $complexNumber;
  6774.     }
  6775.  
  6776.  
  6777.     /**
  6778.      * COMPLEX
  6779.      *
  6780.      * returns a complex number of the form x + yi or x + yj.
  6781.      *
  6782.      * @param    float        $realNumber 
  6783.      * @param    float        $imaginary 
  6784.      * @param    string        $suffix 
  6785.      * @return    string 
  6786.      */
  6787.     public static function COMPLEX($realNumber=0.0$imaginary=0.0$suffix='i'{
  6788.         $realNumber    self::flattenSingleValue($realNumber);
  6789.         $imaginary    self::flattenSingleValue($imaginary);
  6790.         $suffix        self::flattenSingleValue($suffix);
  6791.  
  6792.         if (((is_numeric($realNumber)) && (is_numeric($imaginary))) &&
  6793.             (($suffix == 'i'|| ($suffix == 'j'|| ($suffix == ''))) {
  6794.             if ($realNumber == 0.0{
  6795.                 if ($imaginary == 0.0{
  6796.                     return (string) '0';
  6797.                 elseif ($imaginary == 1.0{
  6798.                     return (string) $suffix;
  6799.                 elseif ($imaginary == -1.0{
  6800.                     return (string) '-'.$suffix;
  6801.                 }
  6802.                 return (string) $imaginary.$suffix;
  6803.             elseif ($imaginary == 0.0{
  6804.                 return (string) $realNumber;
  6805.             elseif ($imaginary == 1.0{
  6806.                 return (string) $realNumber.'+'.$suffix;
  6807.             elseif ($imaginary == -1.0{
  6808.                 return (string) $realNumber.'-'.$suffix;
  6809.             }
  6810.             if ($imaginary 0$imaginary = (string) '+'.$imaginary}
  6811.             return (string) $realNumber.$imaginary.$suffix;
  6812.         }
  6813.         return self::$_errorCodes['value'];
  6814.     }    //    function COMPLEX()
  6815.  
  6816.  
  6817.     /**
  6818.      * IMAGINARY
  6819.      *
  6820.      * Returns the imaginary coefficient of a complex number in x + yi or x + yj text format.
  6821.      *
  6822.      * @param    string        $complexNumber 
  6823.      * @return    real 
  6824.      */
  6825.     public static function IMAGINARY($complexNumber{
  6826.         $complexNumber    self::flattenSingleValue($complexNumber);
  6827.  
  6828.         $parsedComplex self::_parseComplex($complexNumber);
  6829.         if (!is_array($parsedComplex)) {
  6830.             return $parsedComplex;
  6831.         }
  6832.         return $parsedComplex['imaginary'];
  6833.     }    //    function IMAGINARY()
  6834.  
  6835.  
  6836.     /**
  6837.      * IMREAL
  6838.      *
  6839.      * Returns the real coefficient of a complex number in x + yi or x + yj text format.
  6840.      *
  6841.      * @param    string        $complexNumber 
  6842.      * @return    real 
  6843.      */
  6844.     public static function IMREAL($complexNumber{
  6845.         $complexNumber    self::flattenSingleValue($complexNumber);
  6846.  
  6847.         $parsedComplex self::_parseComplex($complexNumber);
  6848.         if (!is_array($parsedComplex)) {
  6849.             return $parsedComplex;
  6850.         }
  6851.         return $parsedComplex['real'];
  6852.     }    //    function IMREAL()
  6853.  
  6854.  
  6855.     /**
  6856.      * IMABS
  6857.      *
  6858.      * Returns the absolute value (modulus) of a complex number in x + yi or x + yj text format.
  6859.      *
  6860.      * @param    string        $complexNumber 
  6861.      * @return    real 
  6862.      */
  6863.     public static function IMABS($complexNumber{
  6864.         $complexNumber    self::flattenSingleValue($complexNumber);
  6865.  
  6866.         $parsedComplex self::_parseComplex($complexNumber);
  6867.         if (!is_array($parsedComplex)) {
  6868.             return $parsedComplex;
  6869.         }
  6870.         return sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary']));
  6871.     }    //    function IMABS()
  6872.  
  6873.  
  6874.     /**
  6875.      * IMARGUMENT
  6876.      *
  6877.      * 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.
  6878.      *
  6879.      * @param    string        $complexNumber 
  6880.      * @return    string 
  6881.      */
  6882.     public static function IMARGUMENT($complexNumber{
  6883.         $complexNumber    self::flattenSingleValue($complexNumber);
  6884.  
  6885.         $parsedComplex self::_parseComplex($complexNumber);
  6886.         if (!is_array($parsedComplex)) {
  6887.             return $parsedComplex;
  6888.         }
  6889.  
  6890.         if ($parsedComplex['real'== 0.0{
  6891.             if ($parsedComplex['imaginary'== 0.0{
  6892.                 return 0.0;
  6893.             elseif($parsedComplex['imaginary'0.0{
  6894.                 return pi(/ -2;
  6895.             else {
  6896.                 return pi(2;
  6897.             }
  6898.         elseif ($parsedComplex['real'0.0{
  6899.             return atan($parsedComplex['imaginary'$parsedComplex['real']);
  6900.         elseif ($parsedComplex['imaginary'0.0{
  6901.             return (pi(atan(abs($parsedComplex['imaginary']abs($parsedComplex['real'])));
  6902.         else {
  6903.             return pi(atan($parsedComplex['imaginary'abs($parsedComplex['real']));
  6904.         }
  6905.     }    //    function IMARGUMENT()
  6906.  
  6907.  
  6908.     /**
  6909.      * IMCONJUGATE
  6910.      *
  6911.      * Returns the complex conjugate of a complex number in x + yi or x + yj text format.
  6912.      *
  6913.      * @param    string        $complexNumber 
  6914.      * @return    string 
  6915.      */
  6916.     public static function IMCONJUGATE($complexNumber{
  6917.         $complexNumber    self::flattenSingleValue($complexNumber);
  6918.  
  6919.         $parsedComplex self::_parseComplex($complexNumber);
  6920.  
  6921.         if (!is_array($parsedComplex)) {
  6922.             return $parsedComplex;
  6923.         }
  6924.  
  6925.         if ($parsedComplex['imaginary'== 0.0{
  6926.             return $parsedComplex['real'];
  6927.         else {
  6928.             return self::_cleanComplex(self::COMPLEX($parsedComplex['real']$parsedComplex['imaginary']$parsedComplex['suffix']));
  6929.         }
  6930.     }    //    function IMCONJUGATE()
  6931.  
  6932.  
  6933.     /**
  6934.      * IMCOS
  6935.      *
  6936.      * Returns the cosine of a complex number in x + yi or x + yj text format.
  6937.      *
  6938.      * @param    string        $complexNumber 
  6939.      * @return    string 
  6940.      */
  6941.     public static function IMCOS($complexNumber{
  6942.         $complexNumber    self::flattenSingleValue($complexNumber);
  6943.  
  6944.         $parsedComplex self::_parseComplex($complexNumber);
  6945.         if (!is_array($parsedComplex)) {
  6946.             return $parsedComplex;
  6947.         }
  6948.  
  6949.         if ($parsedComplex['imaginary'== 0.0{
  6950.             return cos($parsedComplex['real']);
  6951.         else {
  6952.             return self::IMCONJUGATE(self::COMPLEX(cos($parsedComplex['real']cosh($parsedComplex['imaginary']),sin($parsedComplex['real']sinh($parsedComplex['imaginary']),$parsedComplex['suffix']));
  6953.         }
  6954.     }    //    function IMCOS()
  6955.  
  6956.  
  6957.     /**
  6958.      * IMSIN
  6959.      *
  6960.      * Returns the sine of a complex number in x + yi or x + yj text format.
  6961.      *
  6962.      * @param    string        $complexNumber 
  6963.      * @return    string 
  6964.      */
  6965.     public static function IMSIN($complexNumber{
  6966.         $complexNumber    self::flattenSingleValue($complexNumber);
  6967.  
  6968.         $parsedComplex self::_parseComplex($complexNumber);
  6969.         if (!is_array($parsedComplex)) {
  6970.             return $parsedComplex;
  6971.         }
  6972.  
  6973.         if ($parsedComplex['imaginary'== 0.0{
  6974.             return sin($parsedComplex['real']);
  6975.         else {
  6976.             return self::COMPLEX(sin($parsedComplex['real']cosh($parsedComplex['imaginary']),cos($parsedComplex['real']sinh($parsedComplex['imaginary']),$parsedComplex['suffix']);
  6977.         }
  6978.     }    //    function IMSIN()
  6979.  
  6980.  
  6981.     /**
  6982.      * IMSQRT
  6983.      *
  6984.      * Returns the square root of a complex number in x + yi or x + yj text format.
  6985.      *
  6986.      * @param    string        $complexNumber 
  6987.      * @return    string 
  6988.      */
  6989.     public static function IMSQRT($complexNumber{
  6990.         $complexNumber    self::flattenSingleValue($complexNumber);
  6991.  
  6992.         $parsedComplex self::_parseComplex($complexNumber);
  6993.         if (!is_array($parsedComplex)) {
  6994.             return $parsedComplex;
  6995.         }
  6996.  
  6997.         $theta self::IMARGUMENT($complexNumber);
  6998.         $d1 cos($theta 2);
  6999.         $d2 sin($theta 2);
  7000.         $r sqrt(sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary'])));
  7001.  
  7002.         if ($parsedComplex['suffix'== ''{
  7003.             return self::COMPLEX($d1 $r,$d2 $r);
  7004.         else {
  7005.             return self::COMPLEX($d1 $r,$d2 $r,$parsedComplex['suffix']);
  7006.         }
  7007.     }    //    function IMSQRT()
  7008.  
  7009.  
  7010.     /**
  7011.      * IMLN
  7012.      *
  7013.      * Returns the natural logarithm of a complex number in x + yi or x + yj text format.
  7014.      *
  7015.      * @param    string        $complexNumber 
  7016.      * @return    string 
  7017.      */
  7018.     public static function IMLN($complexNumber{
  7019.         $complexNumber    self::flattenSingleValue($complexNumber);
  7020.  
  7021.         $parsedComplex self::_parseComplex($complexNumber);
  7022.         if (!is_array($parsedComplex)) {
  7023.             return $parsedComplex;
  7024.         }
  7025.  
  7026.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7027.             return self::$_errorCodes['num'];
  7028.         }
  7029.  
  7030.         $logR log(sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary'])));
  7031.         $t self::IMARGUMENT($complexNumber);
  7032.  
  7033.         if ($parsedComplex['suffix'== ''{
  7034.             return self::COMPLEX($logR,$t);
  7035.         else {
  7036.             return self::COMPLEX($logR,$t,$parsedComplex['suffix']);
  7037.         }
  7038.     }    //    function IMLN()
  7039.  
  7040.  
  7041.     /**
  7042.      * IMLOG10
  7043.      *
  7044.      * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
  7045.      *
  7046.      * @param    string        $complexNumber 
  7047.      * @return    string 
  7048.      */
  7049.     public static function IMLOG10($complexNumber{
  7050.         $complexNumber    self::flattenSingleValue($complexNumber);
  7051.  
  7052.         $parsedComplex self::_parseComplex($complexNumber);
  7053.         if (!is_array($parsedComplex)) {
  7054.             return $parsedComplex;
  7055.         }
  7056.  
  7057.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7058.             return self::$_errorCodes['num'];
  7059.         elseif (($parsedComplex['real'0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7060.             return log10($parsedComplex['real']);
  7061.         }
  7062.  
  7063.         return self::IMPRODUCT(log10(EULER),self::IMLN($complexNumber));
  7064.     }    //    function IMLOG10()
  7065.  
  7066.  
  7067.     /**
  7068.      * IMLOG2
  7069.      *
  7070.      * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
  7071.      *
  7072.      * @param    string        $complexNumber 
  7073.      * @return    string 
  7074.      */
  7075.     public static function IMLOG2($complexNumber{
  7076.         $complexNumber    self::flattenSingleValue($complexNumber);
  7077.  
  7078.         $parsedComplex self::_parseComplex($complexNumber);
  7079.         if (!is_array($parsedComplex)) {
  7080.             return $parsedComplex;
  7081.         }
  7082.  
  7083.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7084.             return self::$_errorCodes['num'];
  7085.         elseif (($parsedComplex['real'0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7086.             return log($parsedComplex['real'],2);
  7087.         }
  7088.  
  7089.         return self::IMPRODUCT(log(EULER,2),self::IMLN($complexNumber));
  7090.     }    //    function IMLOG2()
  7091.  
  7092.  
  7093.     /**
  7094.      * IMEXP
  7095.      *
  7096.      * Returns the exponential of a complex number in x + yi or x + yj text format.
  7097.      *
  7098.      * @param    string        $complexNumber 
  7099.      * @return    string 
  7100.      */
  7101.     public static function IMEXP($complexNumber{
  7102.         $complexNumber    self::flattenSingleValue($complexNumber);
  7103.  
  7104.         $parsedComplex self::_parseComplex($complexNumber);
  7105.         if (!is_array($parsedComplex)) {
  7106.             return $parsedComplex;
  7107.         }
  7108.  
  7109.         if (($parsedComplex['real'== 0.0&& ($parsedComplex['imaginary'== 0.0)) {
  7110.             return '1';
  7111.         }
  7112.  
  7113.         $e exp($parsedComplex['real']);
  7114.         $eX $e cos($parsedComplex['imaginary']);
  7115.         $eY $e sin($parsedComplex['imaginary']);
  7116.  
  7117.         if ($parsedComplex['suffix'== ''{
  7118.             return self::COMPLEX($eX,$eY);
  7119.         else {
  7120.             return self::COMPLEX($eX,$eY,$parsedComplex['suffix']);
  7121.         }
  7122.     }    //    function IMEXP()
  7123.  
  7124.  
  7125.     /**
  7126.      * IMPOWER
  7127.      *
  7128.      * Returns a complex number in x + yi or x + yj text format raised to a power.
  7129.      *
  7130.      * @param    string        $complexNumber 
  7131.      * @return    string 
  7132.      */
  7133.     public static function IMPOWER($complexNumber,$realNumber{
  7134.         $complexNumber    self::flattenSingleValue($complexNumber);
  7135.         $realNumber        self::flattenSingleValue($realNumber);
  7136.  
  7137.         if (!is_numeric($realNumber)) {
  7138.             return self::$_errorCodes['value'];
  7139.         }
  7140.  
  7141.         $parsedComplex self::_parseComplex($complexNumber);
  7142.         if (!is_array($parsedComplex)) {
  7143.             return $parsedComplex;
  7144.         }
  7145.  
  7146.         $r sqrt(($parsedComplex['real'$parsedComplex['real']($parsedComplex['imaginary'$parsedComplex['imaginary']));
  7147.         $rPower pow($r,$realNumber);
  7148.         $theta self::IMARGUMENT($complexNumber$realNumber;
  7149.         if ($theta == 0{
  7150.             return 1;
  7151.         elseif ($parsedComplex['imaginary'== 0.0{
  7152.             return self::COMPLEX($rPower cos($theta),$rPower sin($theta),$parsedComplex['suffix']);
  7153.         else {
  7154.             return self::COMPLEX($rPower cos($theta),$rPower sin($theta),$parsedComplex['suffix']);
  7155.         }
  7156.     }    //    function IMPOWER()
  7157.  
  7158.  
  7159.     /**
  7160.      * IMDIV
  7161.      *
  7162.      * Returns the quotient of two complex numbers in x + yi or x + yj text format.
  7163.      *
  7164.      * @param    string        $complexDividend 
  7165.      * @param    string        $complexDivisor 
  7166.      * @return    real 
  7167.      */
  7168.     public static function IMDIV($complexDividend,$complexDivisor{
  7169.         $complexDividend    self::flattenSingleValue($complexDividend);
  7170.         $complexDivisor    self::flattenSingleValue($complexDivisor);
  7171.  
  7172.         $parsedComplexDividend self::_parseComplex($complexDividend);
  7173.         if (!is_array($parsedComplexDividend)) {
  7174.             return $parsedComplexDividend;
  7175.         }
  7176.  
  7177.         $parsedComplexDivisor self::_parseComplex($complexDivisor);
  7178.         if (!is_array($parsedComplexDivisor)) {
  7179.             return $parsedComplexDividend;
  7180.         }
  7181.  
  7182.         if (($parsedComplexDividend['suffix'!= ''&& ($parsedComplexDivisor['suffix'!= ''&&
  7183.             ($parsedComplexDividend['suffix'!= $parsedComplexDivisor['suffix'])) {
  7184.             return self::$_errorCodes['num'];
  7185.         }
  7186.         if (($parsedComplexDividend['suffix'!= ''&& ($parsedComplexDivisor['suffix'== '')) {
  7187.             $parsedComplexDivisor['suffix'$parsedComplexDividend['suffix'];
  7188.         }
  7189.  
  7190.         $d1 ($parsedComplexDividend['real'$parsedComplexDivisor['real']($parsedComplexDividend['imaginary'$parsedComplexDivisor['imaginary']);
  7191.         $d2 ($parsedComplexDividend['imaginary'$parsedComplexDivisor['real']($parsedComplexDividend['real'$parsedComplexDivisor['imaginary']);
  7192.         $d3 ($parsedComplexDivisor['real'$parsedComplexDivisor['real']($parsedComplexDivisor['imaginary'$parsedComplexDivisor['imaginary']);
  7193.  
  7194.         $r $d1/$d3;
  7195.         $i $d2/$d3;
  7196.  
  7197.         if ($i 0.0{
  7198.             return self::_cleanComplex($r.'+'.$i.$parsedComplexDivisor['suffix']);
  7199.         elseif ($i 0.0{
  7200.             return self::_cleanComplex($r.$i.$parsedComplexDivisor['suffix']);
  7201.         else {
  7202.             return $r;
  7203.         }
  7204.     }    //    function IMDIV()
  7205.  
  7206.  
  7207.     /**
  7208.      * IMSUB
  7209.      *
  7210.      * Returns the difference of two complex numbers in x + yi or x + yj text format.
  7211.      *
  7212.      * @param    string        $complexNumber1 
  7213.      * @param    string        $complexNumber2 
  7214.      * @return    real 
  7215.      */
  7216.     public static function IMSUB($complexNumber1,$complexNumber2{
  7217.         $complexNumber1    self::flattenSingleValue($complexNumber1);
  7218.         $complexNumber2    self::flattenSingleValue($complexNumber2);
  7219.  
  7220.         $parsedComplex1 self::_parseComplex($complexNumber1);
  7221.         if (!is_array($parsedComplex1)) {
  7222.             return $parsedComplex1;
  7223.         }
  7224.  
  7225.         $parsedComplex2 self::_parseComplex($complexNumber2);
  7226.         if (!is_array($parsedComplex2)) {
  7227.             return $parsedComplex2;
  7228.         }
  7229.  
  7230.         if ((($parsedComplex1['suffix'!= ''&& ($parsedComplex2['suffix'!= '')) &&
  7231.             ($parsedComplex1['suffix'!= $parsedComplex2['suffix'])) {
  7232.             return self::$_errorCodes['num'];
  7233.         elseif (($parsedComplex1['suffix'== ''&& ($parsedComplex2['suffix'!= '')) {
  7234.             $parsedComplex1['suffix'$parsedComplex2['suffix'];
  7235.         }
  7236.  
  7237.         $d1 $parsedComplex1['real'$parsedComplex2['real'];
  7238.         $d2 $parsedComplex1['imaginary'$parsedComplex2['imaginary'];
  7239.  
  7240.         return self::COMPLEX($d1,$d2,$parsedComplex1['suffix']);
  7241.     }    //    function IMSUB()
  7242.  
  7243.  
  7244.     /**
  7245.      * IMSUM
  7246.      *
  7247.      * Returns the sum of two or more complex numbers in x + yi or x + yj text format.
  7248.      *
  7249.      * @param    array of mixed        Data Series
  7250.      * @return    real 
  7251.      */
  7252.     public static function IMSUM({
  7253.         // Return value
  7254.         $returnValue self::_parseComplex('0');
  7255.         $activeSuffix '';
  7256.  
  7257.         // Loop through the arguments
  7258.         $aArgs self::flattenArray(func_get_args());
  7259.         foreach ($aArgs as $arg{
  7260.             $parsedComplex self::_parseComplex($arg);
  7261.             if (!is_array($parsedComplex)) {
  7262.                 return $parsedComplex;
  7263.             }
  7264.  
  7265.             if ($activeSuffix == ''{
  7266.                 $activeSuffix $parsedComplex['suffix'];
  7267.             elseif (($parsedComplex['suffix'!= ''&& ($activeSuffix != $parsedComplex['suffix'])) {
  7268.                 return self::$_errorCodes['value'];
  7269.             }
  7270.  
  7271.             $returnValue['real'+= $parsedComplex['real'];
  7272.             $returnValue['imaginary'+= $parsedComplex['imaginary'];
  7273.         }
  7274.  
  7275.         if ($returnValue['imaginary'== 0.0$activeSuffix ''}
  7276.         return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix);
  7277.     }    //    function IMSUM()
  7278.  
  7279.  
  7280.     /**
  7281.      * IMPRODUCT
  7282.      *
  7283.      * Returns the product of two or more complex numbers in x + yi or x + yj text format.
  7284.      *
  7285.      * @param    array of mixed        Data Series
  7286.      * @return    real 
  7287.      */
  7288.     public static function IMPRODUCT({
  7289.         // Return value
  7290.         $returnValue self::_parseComplex('1');
  7291.         $activeSuffix '';
  7292.  
  7293.         // Loop through the arguments
  7294.         $aArgs self::flattenArray(func_get_args());
  7295.         foreach ($aArgs as $arg{
  7296.             $parsedComplex self::_parseComplex($arg);
  7297.             if (!is_array($parsedComplex)) {
  7298.                 return $parsedComplex;
  7299.             }
  7300.             $workValue $returnValue;
  7301.             if (($parsedComplex['suffix'!= ''&& ($activeSuffix == '')) {
  7302.                 $activeSuffix $parsedComplex['suffix'];
  7303.             elseif (($parsedComplex['suffix'!= ''&& ($activeSuffix != $parsedComplex['suffix'])) {
  7304.                 return self::$_errorCodes['num'];
  7305.             }
  7306.             $returnValue['real'($workValue['real'$parsedComplex['real']($workValue['imaginary'$parsedComplex['imaginary']);
  7307.             $returnValue['imaginary'($workValue['real'$parsedComplex['imaginary']($workValue['imaginary'$parsedComplex['real']);
  7308.         }
  7309.  
  7310.         if ($returnValue['imaginary'== 0.0$activeSuffix ''}
  7311.         return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix);
  7312.     }    //    function IMPRODUCT()
  7313.  
  7314.  
  7315.     private static $_conversionUnits array'g'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Gram',                        'AllowPrefix'    => True        ),
  7316.                                               'sg'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Slug',                        'AllowPrefix'    => False    ),
  7317.                                               'lbm'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Pound mass (avoirdupois)',    'AllowPrefix'    => False    ),
  7318.                                               'u'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'U (atomic mass unit)',        'AllowPrefix'    => True        ),
  7319.                                               'ozm'        => array(    'Group'    => 'Mass',            'Unit Name'    => 'Ounce mass (avoirdupois)',    'AllowPrefix'    => False    ),
  7320.                                               'm'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Meter',                        'AllowPrefix'    => True        ),
  7321.                                               'mi'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Statute mile',                'AllowPrefix'    => False    ),
  7322.                                               'Nmi'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Nautical mile',                'AllowPrefix'    => False    ),
  7323.                                               'in'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Inch',                        'AllowPrefix'    => False    ),
  7324.                                               'ft'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Foot',                        'AllowPrefix'    => False    ),
  7325.                                               'yd'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Yard',                        'AllowPrefix'    => False    ),
  7326.                                               'ang'        => array(    'Group'    => 'Distance',        'Unit Name'    => 'Angstrom',                    'AllowPrefix'    => True        ),
  7327.                                               'Pica'    => array(    'Group'    => 'Distance',        'Unit Name'    => 'Pica (1/72 in)',            'AllowPrefix'    => False    ),
  7328.                                               'yr'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Year',                        'AllowPrefix'    => False    ),
  7329.                                               'day'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Day',                        'AllowPrefix'    => False    ),
  7330.                                               'hr'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Hour',                        'AllowPrefix'    => False    ),
  7331.                                               'mn'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Minute',                    'AllowPrefix'    => False    ),
  7332.                                               'sec'        => array(    'Group'    => 'Time',            'Unit Name'    => 'Second',                    'AllowPrefix'    => True        ),
  7333.                                               'Pa'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Pascal',                    'AllowPrefix'    => True        ),
  7334.                                               'p'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Pascal',                    'AllowPrefix'    => True        ),
  7335.                                               'atm'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Atmosphere',                'AllowPrefix'    => True        ),
  7336.                                               'at'        => array(    'Group'    => 'Pressure',        'Unit Name'    => 'Atmosphere',                'AllowPrefix'    => True        ),
  7337.                                               'mmHg'    => array(    'Group'    => 'Pressure',        'Unit Name'    => 'mm of Mercury',                'AllowPrefix'    => True        ),
  7338.                                               'N'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Newton',                    'AllowPrefix'    => True        ),
  7339.                                               'dyn'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Dyne',                        'AllowPrefix'    => True        ),
  7340.                                               'dy'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Dyne',                        'AllowPrefix'    => True        ),
  7341.                                               'lbf'        => array(    'Group'    => 'Force',            'Unit Name'    => 'Pound force',                'AllowPrefix'    => False    ),
  7342.                                               'J'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Joule',                        'AllowPrefix'    => True        ),
  7343.                                               'e'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Erg',                        'AllowPrefix'    => True        ),
  7344.                                               'c'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Thermodynamic calorie',        'AllowPrefix'    => True        ),
  7345.                                               'cal'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'IT calorie',                'AllowPrefix'    => True        ),
  7346.                                               'eV'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Electron volt',                'AllowPrefix'    => True        ),
  7347.                                               'ev'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Electron volt',                'AllowPrefix'    => True        ),
  7348.                                               'HPh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Horsepower-hour',            'AllowPrefix'    => False    ),
  7349.                                               'hh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Horsepower-hour',            'AllowPrefix'    => False    ),
  7350.                                               'Wh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Watt-hour',                    'AllowPrefix'    => True        ),
  7351.                                               'wh'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Watt-hour',                    'AllowPrefix'    => True        ),
  7352.                                               'flb'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'Foot-pound',                'AllowPrefix'    => False    ),
  7353.                                               'BTU'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'BTU',                        'AllowPrefix'    => False    ),
  7354.                                               'btu'        => array(    'Group'    => 'Energy',        'Unit Name'    => 'BTU',                        'AllowPrefix'    => False    ),
  7355.                                               'HP'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Horsepower',                'AllowPrefix'    => False    ),
  7356.                                               'h'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Horsepower',                'AllowPrefix'    => False    ),
  7357.                                               'W'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Watt',                        'AllowPrefix'    => True        ),
  7358.                                               'w'        => array(    'Group'    => 'Power',            'Unit Name'    => 'Watt',                        'AllowPrefix'    => True        ),
  7359.                                               'T'        => array(    'Group'    => 'Magnetism',        'Unit Name'    => 'Tesla',                        'AllowPrefix'    => True        ),
  7360.                                               'ga'        => array(    'Group'    => 'Magnetism',        'Unit Name'    => 'Gauss',                        'AllowPrefix'    => True        ),
  7361.                                               'C'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Celsius',                    'AllowPrefix'    => False    ),
  7362.                                               'cel'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Celsius',                    'AllowPrefix'    => False    ),
  7363.                                               'F'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Fahrenheit',                'AllowPrefix'    => False    ),
  7364.                                               'fah'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Fahrenheit',                'AllowPrefix'    => False    ),
  7365.                                               'K'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Kelvin',                    'AllowPrefix'    => False    ),
  7366.                                               'kel'        => array(    'Group'    => 'Temperature',    'Unit Name'    => 'Kelvin',                    'AllowPrefix'    => False    ),
  7367.                                               'tsp'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Teaspoon',                    'AllowPrefix'    => False    ),
  7368.                                               'tbs'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Tablespoon',                'AllowPrefix'    => False    ),
  7369.                                               'oz'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Fluid Ounce',                'AllowPrefix'    => False    ),
  7370.                                               'cup'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Cup',                        'AllowPrefix'    => False    ),
  7371.                                               'pt'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'U.S. Pint',                    'AllowPrefix'    => False    ),
  7372.                                               'us_pt'    => array(    'Group'    => 'Liquid',        'Unit Name'    => 'U.S. Pint',                    'AllowPrefix'    => False    ),
  7373.                                               'uk_pt'    => array(    'Group'    => 'Liquid',        'Unit Name'    => 'U.K. Pint',                    'AllowPrefix'    => False    ),
  7374.                                               'qt'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Quart',                        'AllowPrefix'    => False    ),
  7375.                                               'gal'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Gallon',                    'AllowPrefix'    => False    ),
  7376.                                               'l'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Litre',                        'AllowPrefix'    => True        ),
  7377.                                               'lt'        => array(    'Group'    => 'Liquid',        'Unit Name'    => 'Litre',                        'AllowPrefix'    => True        )
  7378.                                             );
  7379.  
  7380.     private static $_conversionMultipliers array(    'Y'    => array(    'multiplier'    => 1E24,    'name'    => 'yotta'    ),
  7381.                                                     'Z'    => array(    'multiplier'    => 1E21,    'name'    => 'zetta'    ),
  7382.                                                     'E'    => array(    'multiplier'    => 1E18,    'name'    => 'exa'    ),
  7383.                                                     'P'    => array(    'multiplier'    => 1E15,    'name'    => 'peta'    ),
  7384.                                                     'T'    => array(    'multiplier'    => 1E12,    'name'    => 'tera'    ),
  7385.                                                     'G'    => array(    'multiplier'    => 1E9,        'name'    => 'giga'    ),
  7386.                                                     'M'    => array(    'multiplier'    => 1E6,        'name'    => 'mega'    ),
  7387.                                                     'k'    => array(    'multiplier'    => 1E3,        'name'    => 'kilo'    ),
  7388.                                                     'h'    => array(    'multiplier'    => 1E2,        'name'    => 'hecto'    ),
  7389.                                                     'e'    => array(    'multiplier'    => 1E1,        'name'    => 'deka'    ),
  7390.                                                     'd'    => array(    'multiplier'    => 1E-1,    'name'    => 'deci'    ),
  7391.                                                     'c'    => array(    'multiplier'    => 1E-2,    'name'    => 'centi'    ),
  7392.                                                     'm'    => array(    'multiplier'    => 1E-3,    'name'    => 'milli'    ),
  7393.                                                     'u'    => array(    'multiplier'    => 1E-6,    'name'    => 'micro'    ),
  7394.                                                     'n'    => array(    'multiplier'    => 1E-9,    'name'    => 'nano'    ),
  7395.                                                     'p'    => array(    'multiplier'    => 1E-12,    'name'    => 'pico'    ),
  7396.                                                     'f'    => array(    'multiplier'    => 1E-15,    'name'    => 'femto'    ),
  7397.                                                     'a'    => array(    'multiplier'    => 1E-18,    'name'    => 'atto'    ),
  7398.                                                     'z'    => array(    'multiplier'    => 1E-21,    'name'    => 'zepto'    ),
  7399.                                                     'y'    => array(    'multiplier'    => 1E-24,    'name'    => 'yocto'    )
  7400.                                                  );
  7401.  
  7402.     private static $_unitConversions array(    'Mass'        => array(    'g'        => array(    'g'        => 1.0,
  7403.                                                                                             'sg'    => 6.85220500053478E-05,
  7404.                                                                                             'lbm'    => 2.20462291469134E-03,
  7405.                                                                                             'u'        => 6.02217000000000E+23,
  7406.                                                                                             'ozm'    => 3.52739718003627E-02
  7407.                                                                                         ),
  7408.                                                                         'sg'    => array(    'g'        => 1.45938424189287E+04,
  7409.                                                                                             'sg'    => 1.0,
  7410.                                                                                             'lbm'    => 3.21739194101647E+01,
  7411.                                                                                             'u'        => 8.78866000000000E+27,
  7412.                                                                                             'ozm'    => 5.14782785944229E+02
  7413.                                                                                         ),
  7414.                                                                         'lbm'    => array(    'g'        => 4.5359230974881148E+02,
  7415.                                                                                             'sg'    => 3.10810749306493E-02,
  7416.                                                                                             'lbm'    => 1.0,
  7417.                                                                                             'u'        => 2.73161000000000E+26,
  7418.                                                                                             'ozm'    => 1.60000023429410E+01
  7419.                                                                                         ),
  7420.                                                                         'u'        => array(    'g'        => 1.66053100460465E-24,
  7421.                                                                                             'sg'    => 1.13782988532950E-28,
  7422.                                                                                             'lbm'    => 3.66084470330684E-27,
  7423.                                                                                             'u'        => 1.0,
  7424.                                                                                             'ozm'    => 5.85735238300524E-26
  7425.                                                                                         ),
  7426.                                                                         'ozm'    => array(    'g'        => 2.83495152079732E+01,
  7427.                                                                                             'sg'    => 1.94256689870811E-03,
  7428.                                                                                             'lbm'    => 6.24999908478882E-02,
  7429.                                                                                             'u'        => 1.70725600000000E+25,
  7430.                                                                                             'ozm'    => 1.0
  7431.                                                                                         )
  7432.                                                                     ),
  7433.                                                 'Distance'    => array(    'm'        => array(    'm'        => 1.0,
  7434.                                                                                             'mi'    => 6.21371192237334E-04,
  7435.                                                                                             'Nmi'    => 5.39956803455724E-04,
  7436.                                                                                             'in'    => 3.93700787401575E+01,
  7437.                                                                                             'ft'    => 3.28083989501312E+00,
  7438.                                                                                             'yd'    => 1.09361329797891E+00,
  7439.                                                                                             'ang'    => 1.00000000000000E+10,
  7440.                                                                                             'Pica'    => 2.83464566929116E+03
  7441.                                                                                         ),
  7442.                                                                         'mi'    => array(    'm'        => 1.60934400000000E+03,
  7443.                                                                                             'mi'    => 1.0,
  7444.                                                                                             'Nmi'    => 8.68976241900648E-01,
  7445.                                                                                             'in'    => 6.33600000000000E+04,
  7446.                                                                                             'ft'    => 5.28000000000000E+03,
  7447.                                                                                             'yd'    => 1.76000000000000E+03,
  7448.                                                                                             'ang'    => 1.60934400000000E+13,
  7449.                                                                                             'Pica'    => 4.56191999999971E+06
  7450.                                                                                         ),
  7451.                                                                         'Nmi'    => array(    'm'        => 1.85200000000000E+03,
  7452.                                                                                             'mi'    => 1.15077944802354E+00,
  7453.                                                                                             'Nmi'    => 1.0,
  7454.                                                                                             'in'    => 7.29133858267717E+04,
  7455.                                                                                             'ft'    => 6.07611548556430E+03,
  7456.                                                                                             'yd'    => 2.02537182785694E+03,
  7457.                                                                                             'ang'    => 1.85200000000000E+13,
  7458.                                                                                             'Pica'    => 5.24976377952723E+06
  7459.                                                                                         ),
  7460.                                                                         'in'    => array(    'm'        => 2.54000000000000E-02,
  7461.                                                                                             'mi'    => 1.57828282828283E-05,
  7462.                                                                                             'Nmi'    => 1.37149028077754E-05,
  7463.                                                                                             'in'    => 1.0,
  7464.                                                                                             'ft'    => 8.33333333333333E-02,
  7465.                                                                                             'yd'    => 2.77777777686643E-02,
  7466.                                                                                             'ang'    => 2.54000000000000E+08,
  7467.                                                                                             'Pica'    => 7.19999999999955E+01
  7468.                                                                                         ),
  7469.                                                                         'ft'    => array(    'm'        => 3.04800000000000E-01,
  7470.                                                                                             'mi'    => 1.89393939393939E-04,
  7471.                                                                                             'Nmi'    => 1.64578833693305E-04,
  7472.                                                                                             'in'    => 1.20000000000000E+01,
  7473.                                                                                             'ft'    => 1.0,
  7474.                                                                                             'yd'    => 3.33333333223972E-01,
  7475.                                                                                             'ang'    => 3.04800000000000E+09,
  7476.                                                                                             'Pica'    => 8.63999999999946E+02
  7477.                                                                                         ),
  7478.                                                                         'yd'    => array(    'm'        => 9.14400000300000E-01,
  7479.                                                                                             'mi'    => 5.68181818368230E-04,
  7480.                                                                                             'Nmi'    => 4.93736501241901E-04,
  7481.                                                                                             'in'    => 3.60000000118110E+01,
  7482.                                                                                             'ft'    => 3.00000000000000E+00,
  7483.                                                                                             'yd'    => 1.0,
  7484.                                                                                             'ang'    => 9.14400000300000E+09,
  7485.                                                                                             'Pica'    => 2.59200000085023E+03
  7486.                                                                                         ),
  7487.                                                                         'ang'    => array(    'm'        => 1.00000000000000E-10,
  7488.                                                                                             'mi'    => 6.21371192237334E-14,
  7489.                                                                                             'Nmi'    => 5.39956803455724E-14,
  7490.                                                                                             'in'    => 3.93700787401575E-09,
  7491.                                                                                             'ft'    => 3.28083989501312E-10,
  7492.                                                                                             'yd'    => 1.09361329797891E-10,
  7493.                                                                                             'ang'    => 1.0,
  7494.                                                                                             'Pica'    => 2.83464566929116E-07
  7495.                                                                                         ),
  7496.                                                                         'Pica'    => array(    'm'        => 3.52777777777800E-04,
  7497.                                                                                             'mi'    => 2.19205948372629E-07,
  7498.                                                                                             'Nmi'    => 1.90484761219114E-07,
  7499.                                                                                             'in'    => 1.38888888888898E-02,
  7500.                                                                                             'ft'    => 1.15740740740748E-03,
  7501.                                                                                             'yd'    => 3.85802469009251E-04,
  7502.                                                                                             'ang'    => 3.52777777777800E+06,
  7503.                                                                                             'Pica'    => 1.0
  7504.                                                                                         )
  7505.                                                                     ),
  7506.                                                 'Time'        => array(    'yr'    => array(    'yr'        => 1.0,
  7507.                                                                                             'day'        => 365.25,
  7508.                                                                                             'hr'        => 8766.0,
  7509.                                                                                             'mn'        => 525960.0,
  7510.                                                                                             'sec'        => 31557600.0
  7511.                                                                                         ),
  7512.                                                                         'day'    => array(    'yr'        => 2.73785078713210E-03,
  7513.                                                                                             'day'        => 1.0,
  7514.                                                                                             'hr'        => 24.0,
  7515.                                                                                             'mn'        => 1440.0,
  7516.                                                                                             'sec'        => 86400.0
  7517.                                                                                         ),
  7518.                                                                         'hr'    => array(    'yr'        => 1.14077116130504E-04,
  7519.                                                                                             'day'        => 4.16666666666667E-02,
  7520.                                                                                             'hr'        => 1.0,
  7521.                                                                                             'mn'        => 60.0,
  7522.                                                                                             'sec'        => 3600.0
  7523.                                                                                         ),
  7524.                                                                         'mn'    => array(    'yr'        => 1.90128526884174E-06,
  7525.                                                                                             'day'        => 6.94444444444444E-04,
  7526.                                                                                             'hr'        => 1.66666666666667E-02,
  7527.                                                                                             'mn'        => 1.0,
  7528.                                                                                             'sec'        => 60.0
  7529.                                                                                         ),
  7530.                                                                         'sec'    => array(    'yr'        => 3.16880878140289E-08,
  7531.                                                                                             'day'        => 1.15740740740741E-05,
  7532.                                                                                             'hr'        => 2.77777777777778E-04,
  7533.                                                                                             'mn'        => 1.66666666666667E-02,
  7534.                                                                                             'sec'        => 1.0
  7535.                                                                                         )
  7536.                                                                     ),
  7537.                                                 'Pressure'    => array(    'Pa'    => array(    'Pa'        => 1.0,
  7538.                                                                                             'p'            => 1.0,
  7539.                                                                                             'atm'        => 9.86923299998193E-06,
  7540.                                                                                             'at'        => 9.86923299998193E-06,
  7541.                                                                                             'mmHg'        => 7.50061707998627E-03
  7542.                                                                                         ),
  7543.                                                                         'p'        => array(    'Pa'        => 1.0,
  7544.                                                                                             'p'            => 1.0,
  7545.                                                                                             'atm'        => 9.86923299998193E-06,
  7546.                                                                                             'at'        => 9.86923299998193E-06,
  7547.                                                                                             'mmHg'        => 7.50061707998627E-03
  7548.                                                                                         ),
  7549.                                                                         'atm'    => array(    'Pa'        => 1.01324996583000E+05,
  7550.                                                                                             'p'            => 1.01324996583000E+05,
  7551.                                                                                             'atm'        => 1.0,
  7552.                                                                                             'at'        => 1.0,
  7553.                                                                                             'mmHg'        => 760.0
  7554.                                                                                         ),
  7555.                                                                         'at'    => array(    'Pa'        => 1.01324996583000E+05,
  7556.                                                                                             'p'            => 1.01324996583000E+05,
  7557.                                                                                             'atm'        => 1.0,
  7558.                                                                                             'at'        => 1.0,
  7559.                                                                                             'mmHg'        => 760.0
  7560.                                                                                         ),
  7561.                                                                         'mmHg'    => array(    'Pa'        => 1.33322363925000E+02,
  7562.                                                                                             'p'            => 1.33322363925000E+02,
  7563.                                                                                             'atm'        => 1.31578947368421E-03,
  7564.                                                                                             'at'        => 1.31578947368421E-03,
  7565.                                                                                             'mmHg'        => 1.0
  7566.                                                                                         )
  7567.                                                                     ),
  7568.                                                 'Force'        => array(    'N'        => array(    'N'            => 1.0,
  7569.                                                                                             'dyn'        => 1.0E+5,
  7570.                                                                                             'dy'        => 1.0E+5,
  7571.                                                                                             'lbf'        => 2.24808923655339E-01
  7572.                                                                                         ),
  7573.                                                                         'dyn'    => array(    'N'            => 1.0E-5,
  7574.                                                                                             'dyn'        => 1.0,
  7575.                                                                                             'dy'        => 1.0,
  7576.                                                                                             'lbf'        => 2.24808923655339E-06
  7577.                                                                                         ),
  7578.                                                                         'dy'    => array(    'N'            => 1.0E-5,
  7579.                                                                                             'dyn'        => 1.0,
  7580.                                                                                             'dy'        => 1.0,
  7581.                                                                                             'lbf'        => 2.24808923655339E-06
  7582.                                                                                         ),
  7583.                                                                         'lbf'    => array(    'N'            => 4.448222,
  7584.                                                                                             'dyn'        => 4.448222E+5,
  7585.                                                                                             'dy'        => 4.448222E+5,
  7586.                                                                                             'lbf'        => 1.0
  7587.                                                                                         )
  7588.                                                                     ),
  7589.                                                 'Energy'    => array(    'J'        => array(    'J'            => 1.0,
  7590.                                                                                             'e'            => 9.99999519343231E+06,
  7591.                                                                                             'c'            => 2.39006249473467E-01,
  7592.                                                                                             'cal'        => 2.38846190642017E-01,
  7593.                                                                                             'eV'        => 6.24145700000000E+18,
  7594.                                                                                             'ev'        => 6.24145700000000E+18,
  7595.                                                                                             'HPh'        => 3.72506430801000E-07,
  7596.                                                                                             'hh'        => 3.72506430801000E-07,
  7597.                                                                                             'Wh'        => 2.77777916238711E-04,
  7598.                                                                                             'wh'        => 2.77777916238711E-04,
  7599.                                                                                             'flb'        => 2.37304222192651E+01,
  7600.                                                                                             'BTU'        => 9.47815067349015E-04,
  7601.                                                                                             'btu'        => 9.47815067349015E-04
  7602.                                                                                         ),
  7603.                                                                         'e'        => array(    'J'            => 1.00000048065700E-07,
  7604.                                                                                             'e'            => 1.0,
  7605.                                                                                             'c'            => 2.39006364353494E-08,
  7606.                                                                                             'cal'        => 2.38846305445111E-08,
  7607.                                                                                             'eV'        => 6.24146000000000E+11,
  7608.                                                                                             'ev'        => 6.24146000000000E+11,
  7609.                                                                                             'HPh'        => 3.72506609848824E-14,
  7610.                                                                                             'hh'        => 3.72506609848824E-14,
  7611.                                                                                             'Wh'        => 2.77778049754611E-11,
  7612.                                                                                             'wh'        => 2.77778049754611E-11,
  7613.                                                                                             'flb'        => 2.37304336254586E-06,
  7614.                                                                                             'BTU'        => 9.47815522922962E-11,
  7615.                                                                                             'btu'        => 9.47815522922962E-11
  7616.                                                                                         ),
  7617.                                                                         'c'        => array(    'J'            => 4.18399101363672E+00,
  7618.                                                                                             'e'            => 4.18398900257312E+07,
  7619.                                                                                             'c'            => 1.0,
  7620.                                                                                             'cal'        => 9.99330315287563E-01,
  7621.                                                                                             'eV'        => 2.61142000000000E+19,
  7622.                                                                                             'ev'        => 2.61142000000000E+19,
  7623.                                                                                             'HPh'        => 1.55856355899327E-06,
  7624.                                                                                             'hh'        => 1.55856355899327E-06,
  7625.                                                                                             'Wh'        => 1.16222030532950E-03,
  7626.                                                                                             'wh'        => 1.16222030532950E-03,
  7627.                                                                                             'flb'        => 9.92878733152102E+01,
  7628.                                                                                             'BTU'        => 3.96564972437776E-03,
  7629.                                                                                             'btu'        => 3.96564972437776E-03
  7630.                                                                                         ),
  7631.                                                                         'cal'    => array(    'J'            => 4.18679484613929E+00,
  7632.                                                                                             'e'            => 4.18679283372801E+07,
  7633.                                                                                             'c'            => 1.00067013349059E+00,
  7634.                                                                                             'cal'        => 1.0,
  7635.                                                                                             'eV'        => 2.61317000000000E+19,
  7636.                                                                                             'ev'        => 2.61317000000000E+19,
  7637.                                                                                             'HPh'        => 1.55960800463137E-06,
  7638.                                                                                             'hh'        => 1.55960800463137E-06,
  7639.                                                                                             'Wh'        => 1.16299914807955E-03,
  7640.                                                                                             'wh'        => 1.16299914807955E-03,
  7641.                                                                                             'flb'        => 9.93544094443283E+01,
  7642.                                                                                             'BTU'        => 3.96830723907002E-03,
  7643.                                                                                             'btu'        => 3.96830723907002E-03
  7644.                                                                                         ),
  7645.                                                                         'eV'    => array(    'J'            => 1.60219000146921E-19,
  7646.                                                                                             'e'            => 1.60218923136574E-12,
  7647.                                                                                             'c'            => 3.82933423195043E-20,
  7648.                                                                                             'cal'        => 3.82676978535648E-20,
  7649.                                                                                             'eV'        => 1.0,
  7650.                                                                                             'ev'        => 1.0,
  7651.                                                                                             'HPh'        => 5.96826078912344E-26,
  7652.                                                                                             'hh'        => 5.96826078912344E-26,
  7653.                                                                                             'Wh'        => 4.45053000026614E-23,
  7654.                                                                                             'wh'        => 4.45053000026614E-23,
  7655.                                                                                             'flb'        => 3.80206452103492E-18,
  7656.                                                                                             'BTU'        => 1.51857982414846E-22,
  7657.                                                                                             'btu'        => 1.51857982414846E-22
  7658.                                                                                         ),
  7659.                                                                         'ev'    => array(    'J'            => 1.60219000146921E-19,
  7660.                                                                                             'e'            => 1.60218923136574E-12,
  7661.                                                                                             'c'            => 3.82933423195043E-20,
  7662.                                                                                             'cal'        => 3.82676978535648E-20,
  7663.                                                                                             'eV'        => 1.0,
  7664.                                                                                             'ev'        => 1.0,
  7665.                                                                                             'HPh'        => 5.96826078912344E-26,
  7666.                                                                                             'hh'        => 5.96826078912344E-26,
  7667.                                                                                             'Wh'        => 4.45053000026614E-23,
  7668.                                                                                             'wh'        => 4.45053000026614E-23,
  7669.                                                                                             'flb'        => 3.80206452103492E-18,
  7670.                                                                                             'BTU'        => 1.51857982414846E-22,
  7671.                                                                                             'btu'        => 1.51857982414846E-22
  7672.                                                                                         ),
  7673.                                                                         'HPh'    => array(    'J'            => 2.68451741316170E+06,
  7674.                                                                                             'e'            => 2.68451612283024E+13,
  7675.                                                                                             'c'            => 6.41616438565991E+05,
  7676.                                                                                             'cal'        => 6.41186757845835E+05,
  7677.                                                                                             'eV'        => 1.67553000000000E+25,
  7678.                                                                                             'ev'        => 1.67553000000000E+25,
  7679.                                                                                             'HPh'        => 1.0,
  7680.                                                                                             'hh'        => 1.0,
  7681.                                                                                             'Wh'        => 7.45699653134593E+02,
  7682.                                                                                             'wh'        => 7.45699653134593E+02,
  7683.                                                                                             'flb'        => 6.37047316692964E+07,
  7684.                                                                                             'BTU'        => 2.54442605275546E+03,
  7685.                                                                                             'btu'        => 2.54442605275546E+03
  7686.                                                                                         ),
  7687.                                                                         'hh'    => array(    'J'            => 2.68451741316170E+06,
  7688.                                                                                             'e'            => 2.68451612283024E+13,
  7689.                                                                                             'c'            => 6.41616438565991E+05,
  7690.                                                                                             'cal'        => 6.41186757845835E+05,
  7691.                                                                                             'eV'        => 1.67553000000000E+25,
  7692.                                                                                             'ev'        => 1.67553000000000E+25,
  7693.                                                                                             'HPh'        => 1.0,
  7694.                                                                                             'hh'        => 1.0,
  7695.                                                                                             'Wh'        => 7.45699653134593E+02,
  7696.                                                                                             'wh'        => 7.45699653134593E+02,
  7697.                                                                                             'flb'        => 6.37047316692964E+07,
  7698.                                                                                             'BTU'        => 2.54442605275546E+03,
  7699.                                                                                             'btu'        => 2.54442605275546E+03
  7700.                                                                                         ),
  7701.                                                                         'Wh'    => array(    'J'            => 3.59999820554720E+03,
  7702.                                                                                             'e'            => 3.59999647518369E+10,
  7703.                                                                                             'c'            => 8.60422069219046E+02,
  7704.                                                                                             'cal'        => 8.59845857713046E+02,
  7705.                                                                                             'eV'        => 2.24692340000000E+22,
  7706.                                                                                             'ev'        => 2.24692340000000E+22,
  7707.                                                                                             'HPh'        => 1.34102248243839E-03,
  7708.                                                                                             'hh'        => 1.34102248243839E-03,
  7709.                                                                                             'Wh'        => 1.0,
  7710.                                                                                             'wh'        => 1.0,
  7711.                                                                                             'flb'        => 8.54294774062316E+04,
  7712.                                                                                             'BTU'        => 3.41213254164705E+00,
  7713.                                                                                             'btu'        => 3.41213254164705E+00
  7714.                                                                                         ),
  7715.                                                                         'wh'    => array(    'J'            => 3.59999820554720E+03,
  7716.                                                                                             'e'            => 3.59999647518369E+10,
  7717.                                                                                             'c'            => 8.60422069219046E+02,
  7718.                                                                                             'cal'        => 8.59845857713046E+02,
  7719.                                                                                             'eV'        => 2.24692340000000E+22,
  7720.                                                                                             'ev'        => 2.24692340000000E+22,
  7721.                                                                                             'HPh'        => 1.34102248243839E-03,
  7722.                                                                                             'hh'        => 1.34102248243839E-03,
  7723.                                                                                             'Wh'        => 1.0,
  7724.                                                                                             'wh'        => 1.0,
  7725.                                                                                             'flb'        => 8.54294774062316E+04,
  7726.                                                                                             'BTU'        => 3.41213254164705E+00,
  7727.                                                                                             'btu'        => 3.41213254164705E+00
  7728.                                                                                         ),
  7729.                                                                         'flb'    => array(    'J'            => 4.21400003236424E-02,
  7730.                                                                                             'e'            => 4.21399800687660E+05,
  7731.                                                                                             'c'            => 1.00717234301644E-02,
  7732.                                                                                             'cal'        => 1.00649785509554E-02,
  7733.                                                                                             'eV'        => 2.63015000000000E+17,
  7734.                                                                                             'ev'        => 2.63015000000000E+17,
  7735.                                                                                             'HPh'        => 1.56974211145130E-08,
  7736.                                                                                             'hh'        => 1.56974211145130E-08,
  7737.                                                                                             'Wh'        => 1.17055614802000E-05,
  7738.                                                                                             'wh'        => 1.17055614802000E-05,
  7739.                                                                                             'flb'        => 1.0,
  7740.                                                                                             'BTU'        => 3.99409272448406E-05,
  7741.                                                                                             'btu'        => 3.99409272448406E-05
  7742.                                                                                         ),
  7743.                                                                         'BTU'    => array(    'J'            => 1.05505813786749E+03,
  7744.                                                                                             'e'            => 1.05505763074665E+10,
  7745.                                                                                             'c'            => 2.52165488508168E+02,
  7746.                                                                                             'cal'        => 2.51996617135510E+02,
  7747.                                                                                             'eV'        => 6.58510000000000E+21,
  7748.                                                                                             'ev'        => 6.58510000000000E+21,
  7749.                                                                                             'HPh'        => 3.93015941224568E-04,
  7750.                                                                                             'hh'        => 3.93015941224568E-04,
  7751.                                                                                             'Wh'        => 2.93071851047526E-01,
  7752.                                                                                             'wh'        => 2.93071851047526E-01,
  7753.                                                                                             'flb'        => 2.50369750774671E+04,
  7754.                                                                                             'BTU'        => 1.0,
  7755.                                                                                             'btu'        => 1.0,
  7756.                                                                                         ),
  7757.                                                                         'btu'    => array(    'J'            => 1.05505813786749E+03,
  7758.                                                                                             'e'            => 1.05505763074665E+10,
  7759.                                                                                             'c'            => 2.52165488508168E+02,
  7760.                                                                                             'cal'        => 2.51996617135510E+02,
  7761.                                                                                             'eV'        => 6.58510000000000E+21,
  7762.                                                                                             'ev'        => 6.58510000000000E+21,
  7763.                                                                                             'HPh'        => 3.93015941224568E-04,
  7764.                                                                                             'hh'        => 3.93015941224568E-04,
  7765.                                                                                             'Wh'        => 2.93071851047526E-01,
  7766.                                                                                             'wh'        => 2.93071851047526E-01,
  7767.                                                                                             'flb'        => 2.50369750774671E+04,
  7768.                                                                                             'BTU'        => 1.0,
  7769.                                                                                             'btu'        => 1.0,
  7770.                                                                                         )
  7771.                                                                     ),
  7772.                                                 'Power'        => array(    'HP'    => array(    'HP'        => 1.0,
  7773.                                                                                             'h'            => 1.0,
  7774.                                                                                             'W'            => 7.45701000000000E+02,
  7775.                                                                                             'w'            => 7.45701000000000E+02
  7776.                                                                                         ),
  7777.                                                                         'h'        => array(    'HP'        => 1.0,
  7778.                                                                                             'h'            => 1.0,
  7779.                                                                                             'W'            => 7.45701000000000E+02,
  7780.                                                                                             'w'            => 7.45701000000000E+02
  7781.                                                                                         ),
  7782.                                                                         'W'        => array(    'HP'        => 1.34102006031908E-03,
  7783.                                                                                             'h'            => 1.34102006031908E-03,
  7784.                                                                                             'W'            => 1.0,
  7785.                                                                                             'w'            => 1.0
  7786.                                                                                         ),
  7787.                                                                         'w'        => array(    'HP'        => 1.34102006031908E-03,
  7788.                                                                                             'h'            => 1.34102006031908E-03,
  7789.                                                                                             'W'            => 1.0,
  7790.                                                                                             'w'            => 1.0
  7791.                                                                                         )
  7792.                                                                     ),
  7793.                                                 'Magnetism'    => array(    'T'        => array(    'T'            => 1.0,
  7794.                                                                                             'ga'        => 10000.0
  7795.                                                                                         ),
  7796.                                                                         'ga'    => array(    'T'            => 0.0001,
  7797.                                                                                             'ga'        => 1.0
  7798.                                                                                         )
  7799.                                                                     ),
  7800.                                                 'Liquid'    => array(    'tsp'    => array(    'tsp'        => 1.0,
  7801.                                                                                             'tbs'        => 3.33333333333333E-01,
  7802.                                                                                             'oz'        => 1.66666666666667E-01,
  7803.                                                                                             'cup'        => 2.08333333333333E-02,
  7804.                                                                                             'pt'        => 1.04166666666667E-02,
  7805.                                                                                             'us_pt'        => 1.04166666666667E-02,
  7806.                                                                                             'uk_pt'        => 8.67558516821960E-03,
  7807.                                                                                             'qt'        => 5.20833333333333E-03,
  7808.                                                                                             'gal'        => 1.30208333333333E-03,
  7809.                                                                                             'l'            => 4.92999408400710E-03,
  7810.                                                                                             'lt'        => 4.92999408400710E-03
  7811.                                                                                         ),
  7812.                                                                         'tbs'    => array(    'tsp'        => 3.00000000000000E+00,
  7813.                                                                                             'tbs'        => 1.0,
  7814.                                                                                             'oz'        => 5.00000000000000E-01,
  7815.                                                                                             'cup'        => 6.25000000000000E-02,
  7816.                                                                                             'pt'        => 3.12500000000000E-02,
  7817.                                                                                             'us_pt'        => 3.12500000000000E-02,
  7818.                                                                                             'uk_pt'        => 2.60267555046588E-02,
  7819.                                                                                             'qt'        => 1.56250000000000E-02,
  7820.                                                                                             'gal'        => 3.90625000000000E-03,
  7821.                                                                                             'l'            => 1.47899822520213E-02,
  7822.                                                                                             'lt'        => 1.47899822520213E-02
  7823.                                                                                         ),
  7824.                                                                         'oz'    => array(    'tsp'        => 6.00000000000000E+00,
  7825.                                                                                             'tbs'        => 2.00000000000000E+00,
  7826.                                                                                             'oz'        => 1.0,
  7827.                                                                                             'cup'        => 1.25000000000000E-01,
  7828.                                                                                             'pt'        => 6.25000000000000E-02,
  7829.                                                                                             'us_pt'        => 6.25000000000000E-02,
  7830.                                                                                             'uk_pt'        => 5.20535110093176E-02,
  7831.                                                                                             'qt'        => 3.12500000000000E-02,
  7832.                                                                                             'gal'        => 7.81250000000000E-03,
  7833.                                                                                             'l'            => 2.95799645040426E-02,
  7834.                                                                                             'lt'        => 2.95799645040426E-02
  7835.                                                                                         ),
  7836.                                                                         'cup'    => array(    'tsp'        => 4.80000000000000E+01,
  7837.                                                                                             'tbs'        => 1.60000000000000E+01,
  7838.                                                                                             'oz'        => 8.00000000000000E+00,
  7839.                                                                                             'cup'        => 1.0,
  7840.                                                                                             'pt'        => 5.00000000000000E-01,
  7841.                                                                                             'us_pt'        => 5.00000000000000E-01,
  7842.                                                                                             'uk_pt'        => 4.16428088074541E-01,
  7843.                                                                                             'qt'        => 2.50000000000000E-01,
  7844.                                                                                             'gal'        => 6.25000000000000E-02,
  7845.                                                                                             'l'            => 2.36639716032341E-01,
  7846.                                                                                             'lt'        => 2.36639716032341E-01
  7847.                                                                                         ),
  7848.                                                                         'pt'    => array(    'tsp'        => 9.60000000000000E+01,
  7849.                                                                                             'tbs'        => 3.20000000000000E+01,
  7850.                                                                                             'oz'        => 1.60000000000000E+01,
  7851.                                                                                             'cup'        => 2.00000000000000E+00,
  7852.                                                                                             'pt'        => 1.0,
  7853.                                                                                             'us_pt'        => 1.0,
  7854.                                                                                             'uk_pt'        => 8.32856176149081E-01,
  7855.                                                                                             'qt'        => 5.00000000000000E-01,
  7856.                                                                                             'gal'        => 1.25000000000000E-01,
  7857.                                                                                             'l'            => 4.73279432064682E-01,
  7858.                                                                                             'lt'        => 4.73279432064682E-01
  7859.                                                                                         ),
  7860.                                                                         'us_pt'    => array(    'tsp'        => 9.60000000000000E+01,
  7861.                                                                                             'tbs'        => 3.20000000000000E+01,
  7862.                                                                                             'oz'        => 1.60000000000000E+01,
  7863.                                                                                             'cup'        => 2.00000000000000E+00,
  7864.                                                                                             'pt'        => 1.0,
  7865.                                                                                             'us_pt'        => 1.0,
  7866.                                                                                             'uk_pt'        => 8.32856176149081E-01,
  7867.                                                                                             'qt'        => 5.00000000000000E-01,
  7868.                                                                                             'gal'        => 1.25000000000000E-01,
  7869.                                                                                             'l'            => 4.73279432064682E-01,
  7870.                                                                                             'lt'        => 4.73279432064682E-01
  7871.                                                                                         ),
  7872.                                                                         'uk_pt'    => array(    'tsp'        => 1.15266000000000E+02,
  7873.                                                                                             'tbs'        => 3.84220000000000E+01,
  7874.                                                                                             'oz'        => 1.92110000000000E+01,
  7875.                                                                                             'cup'        => 2.40137500000000E+00,
  7876.                                                                                             'pt'        => 1.20068750000000E+00,
  7877.                                                                                             'us_pt'        => 1.20068750000000E+00,
  7878.                                                                                             'uk_pt'        => 1.0,
  7879.                                                                                             'qt'        => 6.00343750000000E-01,
  7880.                                                                                             'gal'        => 1.50085937500000E-01,
  7881.                                                                                             'l'            => 5.68260698087162E-01,
  7882.                                                                                             'lt'        => 5.68260698087162E-01
  7883.                                                                                         ),
  7884.                                                                         'qt'    => array(    'tsp'        => 1.92000000000000E+02,
  7885.                                                                                             'tbs'        => 6.40000000000000E+01,
  7886.                                                                                             'oz'        => 3.20000000000000E+01,
  7887.                                                                                             'cup'        => 4.00000000000000E+00,
  7888.                                                                                             'pt'        => 2.00000000000000E+00,
  7889.                                                                                             'us_pt'        => 2.00000000000000E+00,
  7890.                                                                                             'uk_pt'        => 1.66571235229816E+00,
  7891.                                                                                             'qt'        => 1.0,
  7892.                                                                                             'gal'        => 2.50000000000000E-01,
  7893.                                                                                             'l'            => 9.46558864129363E-01,
  7894.                                                                                             'lt'        => 9.46558864129363E-01
  7895.                                                                                         ),
  7896.                                                                         'gal'    => array(    'tsp'        => 7.68000000000000E+02,
  7897.                                                                                             'tbs'        => 2.56000000000000E+02,
  7898.                                                                                             'oz'        => 1.28000000000000E+02,
  7899.                                                                                             'cup'        => 1.60000000000000E+01,
  7900.                                                                                             'pt'        => 8.00000000000000E+00,
  7901.                                                                                             'us_pt'        => 8.00000000000000E+00,
  7902.                                                                                             'uk_pt'        => 6.66284940919265E+00,
  7903.                                                                                             'qt'        => 4.00000000000000E+00,
  7904.                                                                                             'gal'        => 1.0,
  7905.                                                                                             'l'            => 3.78623545651745E+00,
  7906.                                                                                             'lt'        => 3.78623545651745E+00
  7907.                                                                                         ),
  7908.                                                                         'l'        => array(    'tsp'        => 2.02840000000000E+02,
  7909.                                                                                             'tbs'        => 6.76133333333333E+01,
  7910.                                                                                             'oz'        => 3.38066666666667E+01,
  7911.                                                                                             'cup'        => 4.22583333333333E+00,
  7912.                                                                                             'pt'        => 2.11291666666667E+00,
  7913.                                                                                             'us_pt'        => 2.11291666666667E+00,
  7914.                                                                                             'uk_pt'        => 1.75975569552166E+00,
  7915.                                                                                             'qt'        => 1.05645833333333E+00,
  7916.                                                                                             'gal'        => 2.64114583333333E-01,
  7917.                                                                                             'l'            => 1.0,
  7918.                                                                                             'lt'        => 1.0
  7919.                                                                                         ),
  7920.                                                                         'lt'    => array(    'tsp'        => 2.02840000000000E+02,
  7921.                                                                                             'tbs'        => 6.76133333333333E+01,
  7922.                                                                                             'oz'        => 3.38066666666667E+01,
  7923.                                                                                             'cup'        => 4.22583333333333E+00,
  7924.                                                                                             'pt'        => 2.11291666666667E+00,
  7925.                                                                                             'us_pt'        => 2.11291666666667E+00,
  7926.                                                                                             'uk_pt'        => 1.75975569552166E+00,
  7927.                                                                                             'qt'        => 1.05645833333333E+00,
  7928.                                                                                             'gal'        => 2.64114583333333E-01,
  7929.                                                                                             'l'            => 1.0,
  7930.                                                                                             'lt'        => 1.0
  7931.                                                                                         )
  7932.                                                                     )
  7933.                                             );
  7934.  
  7935.  
  7936.     /**
  7937.      * getConversionGroups
  7938.      *
  7939.      * @return    array 
  7940.      */
  7941.     public static function getConversionGroups({
  7942.         $conversionGroups array();
  7943.         foreach(self::$_conversionUnits as $conversionUnit{
  7944.             $conversionGroups[$conversionUnit['Group'];
  7945.         }
  7946.         return array_merge(array_unique($conversionGroups));
  7947.     }    //    function getConversionGroups()
  7948.  
  7949.  
  7950.     /**
  7951.      * getConversionGroupUnits
  7952.      *
  7953.      * @return    array 
  7954.      */
  7955.     public static function getConversionGroupUnits($group NULL{
  7956.         $conversionGroups array();
  7957.         foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup{
  7958.             if ((is_null($group)) || ($conversionGroup['Group'== $group)) {
  7959.                 $conversionGroups[$conversionGroup['Group']][$conversionUnit;
  7960.             }
  7961.         }
  7962.         return $conversionGroups;
  7963.     }    //    function getConversionGroupUnits()
  7964.  
  7965.  
  7966.     /**
  7967.      * getConversionGroupUnitDetails
  7968.      *
  7969.      * @return    array 
  7970.      */
  7971.     public static function getConversionGroupUnitDetails($group NULL{
  7972.         $conversionGroups array();
  7973.         foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup{
  7974.             if ((is_null($group)) || ($conversionGroup['Group'== $group)) {
  7975.                 $conversionGroups[$conversionGroup['Group']][array(    'unit'            => $conversionUnit,
  7976.                                                                         'description'    => $conversionGroup['Unit Name']
  7977.                                                                       );
  7978.             }
  7979.         }
  7980.         return $conversionGroups;
  7981.     }    //    function getConversionGroupUnitDetails()
  7982.  
  7983.  
  7984.     /**
  7985.      * getConversionGroups
  7986.      *
  7987.      * @return    array 
  7988.      */
  7989.     public static function getConversionMultipliers({
  7990.         return self::$_conversionMultipliers;
  7991.     }    //    function getConversionGroups()
  7992.  
  7993.  
  7994.     /**
  7995.      * CONVERTUOM
  7996.      *
  7997.      * @param    float        $value 
  7998.      * @param    string        $fromUOM 
  7999.      * @param    string        $toUOM 
  8000.      * @return    float 
  8001.      */
  8002.     public static function CONVERTUOM($value$fromUOM$toUOM{
  8003.         $value        self::flattenSingleValue($value);
  8004.         $fromUOM    self::flattenSingleValue($fromUOM);
  8005.         $toUOM        self::flattenSingleValue($toUOM);
  8006.  
  8007.         if (!is_numeric($value)) {
  8008.             return self::$_errorCodes['value'];
  8009.         }
  8010.         $fromMultiplier 1;
  8011.         if (isset(self::$_conversionUnits[$fromUOM])) {
  8012.             $unitGroup1 self::$_conversionUnits[$fromUOM]['Group'];
  8013.         else {
  8014.             $fromMultiplier substr($fromUOM,0,1);
  8015.             $fromUOM substr($fromUOM,1);
  8016.             if (isset(self::$_conversionMultipliers[$fromMultiplier])) {
  8017.                 $fromMultiplier self::$_conversionMultipliers[$fromMultiplier]['multiplier'];
  8018.             else {
  8019.                 return self::$_errorCodes['na'];
  8020.             }
  8021.             if ((isset(self::$_conversionUnits[$fromUOM])) && (self::$_conversionUnits[$fromUOM]['AllowPrefix'])) {
  8022.                 $unitGroup1 self::$_conversionUnits[$fromUOM]['Group'];
  8023.             else {
  8024.                 return self::$_errorCodes['na'];
  8025.             }
  8026.         }
  8027.         $value *= $fromMultiplier;
  8028.  
  8029.         $toMultiplier 1;
  8030.         if (isset(self::$_conversionUnits[$toUOM])) {
  8031.             $unitGroup2 self::$_conversionUnits[$toUOM]['Group'];
  8032.         else {
  8033.             $toMultiplier substr($toUOM,0,1);
  8034.             $toUOM substr($toUOM,1);
  8035.             if (isset(self::$_conversionMultipliers[$toMultiplier])) {
  8036.                 $toMultiplier self::$_conversionMultipliers[$toMultiplier]['multiplier'];
  8037.             else {
  8038.                 return self::$_errorCodes['na'];
  8039.             }
  8040.             if ((isset(self::$_conversionUnits[$toUOM])) && (self::$_conversionUnits[$toUOM]['AllowPrefix'])) {
  8041.                 $unitGroup2 self::$_conversionUnits[$toUOM]['Group'];
  8042.             else {
  8043.                 return self::$_errorCodes['na'];
  8044.             }
  8045.         }
  8046.         if ($unitGroup1 != $unitGroup2{
  8047.             return self::$_errorCodes['na'];
  8048.         }
  8049.  
  8050.         if ($fromUOM == $toUOM{
  8051.             return 1.0;
  8052.         elseif ($unitGroup1 == 'Temperature'{
  8053.             if (($fromUOM == 'F'|| ($fromUOM == 'fah')) {
  8054.                 if (($toUOM == 'F'|| ($toUOM == 'fah')) {
  8055.                     return 1.0;
  8056.                 else {
  8057.                     $value (($value 321.8);
  8058.                     if (($toUOM == 'K'|| ($toUOM == 'kel')) {
  8059.                         $value += 273.15;
  8060.                     }
  8061.                     return $value;
  8062.                 }
  8063.             elseif ((($fromUOM == 'K'|| ($fromUOM == 'kel')) &&
  8064.                       (($toUOM == 'K'|| ($toUOM == 'kel'))) {
  8065.                         return 1.0;
  8066.             elseif ((($fromUOM == 'C'|| ($fromUOM == 'cel')) &&
  8067.                       (($toUOM == 'C'|| ($toUOM == 'cel'))) {
  8068.                     return 1.0;
  8069.             }
  8070.             if (($toUOM == 'F'|| ($toUOM == 'fah')) {
  8071.                 if (($fromUOM == 'K'|| ($fromUOM == 'kel')) {
  8072.                     $value -= 273.15;
  8073.                 }
  8074.                 return ($value 1.832;
  8075.             }
  8076.             if (($toUOM == 'C'|| ($toUOM == 'cel')) {
  8077.                 return $value 273.15;
  8078.             }
  8079.             return $value 273.15;
  8080.         }
  8081.         return ($value self::$_unitConversions[$unitGroup1][$fromUOM][$toUOM]$toMultiplier;
  8082.     }    //    function CONVERTUOM()
  8083.  
  8084.  
  8085.     /**
  8086.      * BESSELI
  8087.      *
  8088.      * Returns the modified Bessel function, which is equivalent to the Bessel function evaluated for purely imaginary arguments
  8089.      *
  8090.      * @param    float        $x 
  8091.      * @param    float        $n 
  8092.      * @return    int 
  8093.      */
  8094.     public static function BESSELI($x$n{
  8095.         $x    self::flattenSingleValue($x);
  8096.         $n    floor(self::flattenSingleValue($n));
  8097.  
  8098.         if ((is_numeric($x)) && (is_numeric($n))) {
  8099.             if ($n 0{
  8100.                 return self::$_errorCodes['num'];
  8101.             }
  8102.             $f_2_PI pi();
  8103.  
  8104.             if (abs($x<= 30{
  8105.                 $fTerm pow($x 2$nself::FACT($n);
  8106.                 $nK 1;
  8107.                 $fResult $fTerm;
  8108.                 $fSqrX pow($x,24;
  8109.                 do {
  8110.                     $fTerm *= $fSqrX;
  8111.                     $fTerm /= ($nK ($nK $n));
  8112.                     $fResult += $fTerm;
  8113.                 while ((abs($fTerm1e-10&& (++$nK 100));
  8114.             else {
  8115.                 $fXAbs abs($x);
  8116.                 $fResult exp($fXAbssqrt($f_2_PI $fXAbs);
  8117.                 if (($n && 1&& ($x 0)) {
  8118.                     $fResult = -$fResult;
  8119.                 }
  8120.             }
  8121.             return $fResult;
  8122.         }
  8123.         return self::$_errorCodes['value'];
  8124.     }    //    function BESSELI()
  8125.  
  8126.  
  8127.     /**
  8128.      * BESSELJ
  8129.      *
  8130.      * Returns the Bessel function
  8131.      *
  8132.      * @param    float        $x 
  8133.      * @param    float        $n 
  8134.      * @return    int 
  8135.      */
  8136.     public static function BESSELJ($x$n{
  8137.         $x    self::flattenSingleValue($x);
  8138.         $n    floor(self::flattenSingleValue($n));
  8139.  
  8140.         if ((is_numeric($x)) && (is_numeric($n))) {
  8141.             if ($n 0{
  8142.                 return self::$_errorCodes['num'];
  8143.             }
  8144.             $f_2_DIV_PI pi();
  8145.             $f_PI_DIV_2 pi(2;
  8146.             $f_PI_DIV_4 pi(4;
  8147.  
  8148.             $fResult 0;
  8149.             if (abs($x<= 30{
  8150.                 $fTerm pow($x 2$nself::FACT($n);
  8151.                 $nK 1;
  8152.                 $fResult $fTerm;
  8153.                 $fSqrX pow($x,2/ -4;
  8154.                 do {
  8155.                     $fTerm *= $fSqrX;
  8156.                     $fTerm /= ($nK ($nK $n));
  8157.                     $fResult += $fTerm;
  8158.                 while ((abs($fTerm1e-10&& (++$nK 100));
  8159.             else {
  8160.                 $fXAbs abs($x);
  8161.                 $fResult sqrt($f_2_DIV_PI $fXAbscos($fXAbs $n $f_PI_DIV_2 $f_PI_DIV_4);
  8162.                 if (($n && 1&& ($x 0)) {
  8163.                     $fResult = -$fResult;
  8164.                 }
  8165.             }
  8166.             return $fResult;
  8167.         }
  8168.         return self::$_errorCodes['value'];
  8169.     }    //    function BESSELJ()
  8170.  
  8171.  
  8172.     private static function _Besselk0($fNum{
  8173.         if ($fNum <= 2{
  8174.             $fNum2 $fNum 0.5;
  8175.             $y pow($fNum2,2);
  8176.             $fRet = -log($fNum2self::BESSELI($fNum0+
  8177.                     (-0.57721566 $y (0.42278420 $y (0.23069756 $y (0.3488590e-1 $y (0.262698e-2 $y *
  8178.                     (0.10750e-3 $y 0.74e-5))))));
  8179.         else {
  8180.             $y $fNum;
  8181.             $fRet exp(-$fNumsqrt($fNum*
  8182.                     (1.25331414 $y (-0.7832358e-1 $y (0.2189568e-1 $y (-0.1062446e-1 $y *
  8183.                     (0.587872e-2 $y (-0.251540e-2 $y 0.53208e-3))))));
  8184.         }
  8185.         return $fRet;
  8186.     }    //    function _Besselk0()
  8187.  
  8188.  
  8189.     private static function _Besselk1($fNum{
  8190.         if ($fNum <= 2{
  8191.             $fNum2 $fNum 0.5;
  8192.             $y pow($fNum2,2);
  8193.             $fRet log($fNum2self::BESSELI($fNum1+
  8194.                     ($y (0.15443144 $y (-0.67278579 $y (-0.18156897 $y (-0.1919402e-1 $y *
  8195.                     (-0.110404e-2 $y (-0.4686e-4))))))) $fNum;
  8196.         else {
  8197.             $y $fNum;
  8198.             $fRet exp(-$fNumsqrt($fNum*
  8199.                     (1.25331414 $y (0.23498619 $y (-0.3655620e-1 $y (0.1504268e-1 $y (-0.780353e-2 $y *
  8200.                     (0.325614e-2 $y (-0.68245e-3)))))));
  8201.         }
  8202.         return $fRet;
  8203.     }    //    function _Besselk1()
  8204.  
  8205.  
  8206.     /**
  8207.      * BESSELK
  8208.      *
  8209.      * Returns the modified Bessel function, which is equivalent to the Bessel functions evaluated for purely imaginary arguments.
  8210.      *
  8211.      * @param    float        $x 
  8212.      * @param    float        $ord 
  8213.      * @return    float 
  8214.      */
  8215.     public static function BESSELK($x$ord{
  8216.         $x        self::flattenSingleValue($x);
  8217.         $ord    floor(self::flattenSingleValue($ord));
  8218.  
  8219.         if ((is_numeric($x)) && (is_numeric($ord))) {
  8220.             if ($ord 0{
  8221.                 return self::$_errorCodes['num'];
  8222.             }
  8223.  
  8224.             switch($ord{
  8225.                 case :    return self::_Besselk0($x);
  8226.                             break;
  8227.                 case :    return self::_Besselk1($x);
  8228.                             break;
  8229.                 default :    $fTox    $x;
  8230.                             $fBkm    self::_Besselk0($x);
  8231.                             $fBk    self::_Besselk1($x);
  8232.                             for ($n 1$n $ord++$n{
  8233.                                 $fBkp    $fBkm $n $fTox $fBk;
  8234.                                 $fBkm    $fBk;
  8235.                                 $fBk    $fBkp;
  8236.                             }
  8237.             }
  8238.             return $fBk;
  8239.         }
  8240.         return self::$_errorCodes['value'];
  8241.     }    //    function BESSELK()
  8242.  
  8243.  
  8244.     private static function _Bessely0($fNum{
  8245.         if ($fNum 8.0{
  8246.             $y pow($fNum,2);
  8247.             $f1 = -2957821389.0 $y (7062834065.0 $y (-512359803.6 $y (10879881.29 $y (-86327.92757 $y 228.4622733))));
  8248.             $f2 40076544269.0 $y (745249964.8 $y (7189466.438 $y (47447.26470 $y (226.1030244 $y))));
  8249.             $fRet $f1 $f2 0.636619772 self::BESSELJ($fNum0log($fNum);
  8250.         else {
  8251.             $z 8.0 $fNum;
  8252.             $y pow($z,2);
  8253.             $xx $fNum 0.785398164;
  8254.             $f1 $y (-0.1098628627e-2 $y (0.2734510407e-4 $y (-0.2073370639e-5 $y 0.2093887211e-6)));
  8255.             $f2 = -0.1562499995e-1 $y (0.1430488765e-3 $y (-0.6911147651e-5 $y (0.7621095161e-6 $y (-0.934945152e-7))));
  8256.             $fRet sqrt(0.636619772 $fNum(sin($xx$f1 $z cos($xx$f2);
  8257.         }
  8258.         return $fRet;
  8259.     }    //    function _Bessely0()
  8260.  
  8261.  
  8262.     private static function _Bessely1($fNum{
  8263.         if ($fNum 8.0{
  8264.             $y pow($fNum,2);
  8265.             $f1 $fNum (-0.4900604943e13 $y (0.1275274390e13 $y (-0.5153438139e11 $y (0.7349264551e9 $y *
  8266.                 (-0.4237922726e7 $y 0.8511937935e4)))));
  8267.             $f2 0.2499580570e14 $y (0.4244419664e12 $y (0.3733650367e10 $y (0.2245904002e8 $y *
  8268.                 (0.1020426050e6 $y (0.3549632885e3 $y)))));
  8269.             $fRet $f1 $f2 0.636619772 self::BESSELJ($fNum1log($fNum$fNum);
  8270.         else {
  8271.             $z 8.0 $fNum;
  8272.             $y pow($z,2);
  8273.             $xx $fNum 2.356194491;
  8274.             $f1 $y (0.183105e-2 $y (-0.3516396496e-4 $y (0.2457520174e-5 $y (-0.240337019e6))));
  8275.             $f2 0.04687499995 $y (-0.2002690873e-3 $y (0.8449199096e-5 $y (-0.88228987e-6 $y 0.105787412e-6)));
  8276.             $fRet sqrt(0.636619772 $fNum(sin($xx$f1 $z cos($xx$f2);
  8277.             #i12430# ...but this seems to work much better.
  8278. //            $fRet = sqrt(0.636619772 / $fNum) * sin($fNum - 2.356194491);
  8279.         }
  8280.         return $fRet;
  8281.     }    //    function _Bessely1()
  8282.  
  8283.  
  8284.     /**
  8285.      * BESSELY
  8286.      *
  8287.      * Returns the Bessel function, which is also called the Weber function or the Neumann function.
  8288.      *
  8289.      * @param    float        $x 
  8290.      * @param    float        $n 
  8291.      * @return    int 
  8292.      */
  8293.     public static function BESSELY($x$ord{
  8294.         $x        self::flattenSingleValue($x);
  8295.         $ord    floor(self::flattenSingleValue($ord));
  8296.  
  8297.         if ((is_numeric($x)) && (is_numeric($ord))) {
  8298.             if ($ord 0{
  8299.                 return self::$_errorCodes['num'];
  8300.             }
  8301.  
  8302.             switch($ord{
  8303.                 case :    return self::_Bessely0($x);
  8304.                             break;
  8305.                 case :    return self::_Bessely1($x);
  8306.                             break;
  8307.                 default:    $fTox    $x;
  8308.                             $fBym    self::_Bessely0($x);
  8309.                             $fBy    self::_Bessely1($x);
  8310.                             for ($n 1$n $ord++$n{
  8311.                                 $fByp    $n $fTox $fBy $fBym;
  8312.                                 $fBym    $fBy;
  8313.                                 $fBy    $fByp;
  8314.                             }
  8315.             }
  8316.             return $fBy;
  8317.         }
  8318.         return self::$_errorCodes['value'];
  8319.     }    //    function BESSELY()
  8320.  
  8321.  
  8322.     /**
  8323.      * DELTA
  8324.      *
  8325.      * Tests whether two values are equal. Returns 1 if number1 = number2; returns 0 otherwise.
  8326.      *
  8327.      * @param    float        $a 
  8328.      * @param    float        $b 
  8329.      * @return    int 
  8330.      */
  8331.     public static function DELTA($a$b=0{
  8332.         $a    self::flattenSingleValue($a);
  8333.         $b    self::flattenSingleValue($b);
  8334.  
  8335.         return (int) ($a == $b);
  8336.     }    //    function DELTA()
  8337.  
  8338.  
  8339.     /**
  8340.      * GESTEP
  8341.      *
  8342.      * Returns 1 if number = step; returns 0 (zero) otherwise
  8343.      *
  8344.      * @param    float        $number 
  8345.      * @param    float        $step 
  8346.      * @return    int 
  8347.      */
  8348.     public static function GESTEP($number$step=0{
  8349.         $number    self::flattenSingleValue($number);
  8350.         $step    self::flattenSingleValue($step);
  8351.  
  8352.         return (int) ($number >= $step);
  8353.     }    //    function GESTEP()
  8354.  
  8355.  
  8356.     //
  8357.     //    Private method to calculate the erf value
  8358.     //
  8359.     private static $_two_sqrtpi 1.128379167095512574;
  8360.     private static $_rel_error 1E-15;
  8361.  
  8362.     private static function _erfVal($x{
  8363.         if (abs($x2.2{
  8364.             return self::_erfcVal($x);
  8365.         }
  8366.         $sum $term $x;
  8367.         $xsqr pow($x,2);
  8368.         $j 1;
  8369.         do {
  8370.             $term *= $xsqr $j;
  8371.             $sum -= $term ($j 1);
  8372.             ++$j;
  8373.             $term *= $xsqr $j;
  8374.             $sum += $term ($j 1);
  8375.             ++$j;
  8376.             if ($sum == 0{
  8377.                 break;
  8378.             }
  8379.         while (abs($term $sumself::$_rel_error);
  8380.         return self::$_two_sqrtpi $sum;
  8381.     }    //    function _erfVal()
  8382.  
  8383.  
  8384.     /**
  8385.      * ERF
  8386.      *
  8387.      * Returns the error function integrated between lower_limit and upper_limit
  8388.      *
  8389.      * @param    float        $lower    lower bound for integrating ERF
  8390.      * @param    float        $upper    upper bound for integrating ERF.
  8391.      *                                 If omitted, ERF integrates between zero and lower_limit
  8392.      * @return    int 
  8393.      */
  8394.     public static function ERF($lower$upper null{
  8395.         $lower    self::flattenSingleValue($lower);
  8396.         $upper    self::flattenSingleValue($upper);
  8397.  
  8398.         if (is_numeric($lower)) {
  8399.             if ($lower 0{
  8400.                 return self::$_errorCodes['num'];
  8401.             }
  8402.             if (is_null($upper)) {
  8403.                 return self::_erfVal($lower);
  8404.             }
  8405.             if (is_numeric($upper)) {
  8406.                 if ($upper 0{
  8407.                     return self::$_errorCodes['num'];
  8408.                 }
  8409.                 return self::_erfVal($upperself::_erfVal($lower);
  8410.             }
  8411.         }
  8412.         return self::$_errorCodes['value'];
  8413.     }    //    function ERF()
  8414.  
  8415.  
  8416.     //
  8417.     //    Private method to calculate the erfc value
  8418.     //
  8419.     private static $_one_sqrtpi 0.564189583547756287;
  8420.  
  8421.     private static function _erfcVal($x{
  8422.         if (abs($x2.2{
  8423.             return self::_erfVal($x);
  8424.         }
  8425.         if ($x 0{
  8426.             return self::erfc(-$x);
  8427.         }
  8428.         $a $n 1;
  8429.         $b $c $x;
  8430.         $d pow($x,20.5;
  8431.         $q1 $q2 $b $d;
  8432.         $t 0;
  8433.         do {
  8434.             $t $a $n $b $x;
  8435.             $a $b;
  8436.             $b $t;
  8437.             $t $c $n $d $x;
  8438.             $c $d;
  8439.             $d $t;
  8440.             $n += 0.5;
  8441.             $q1 $q2;
  8442.             $q2 $b $d;
  8443.         while ((abs($q1 $q2$q2self::$_rel_error);
  8444.         return self::$_one_sqrtpi exp(-$x $x$q2;
  8445.     }    //    function _erfcVal()
  8446.  
  8447.  
  8448.     /**
  8449.      * ERFC
  8450.      *
  8451.      * Returns the complementary ERF function integrated between x and infinity
  8452.      *
  8453.      * @param    float        $x        The lower bound for integrating ERF
  8454.      * @return    int 
  8455.      */
  8456.     public static function ERFC($x{
  8457.         $x    self::flattenSingleValue($x);
  8458.  
  8459.         if (is_numeric($x)) {
  8460.             if ($x 0{
  8461.                 return self::$_errorCodes['num'];
  8462.             }
  8463.             return self::_erfcVal($x);
  8464.         }
  8465.         return self::$_errorCodes['value'];
  8466.     }    //    function ERFC()
  8467.  
  8468.  
  8469.     /**
  8470.      *    LOWERCASE
  8471.      *
  8472.      *    Converts a string value to upper case.
  8473.      *
  8474.      *    @param    string        $mixedCaseString 
  8475.      *    @return    string 
  8476.      */
  8477.     public static function LOWERCASE($mixedCaseString{
  8478.         $mixedCaseString    self::flattenSingleValue($mixedCaseString);
  8479.  
  8480.         if (function_exists('mb_convert_case')) {
  8481.             return mb_convert_case($mixedCaseStringMB_CASE_LOWER'UTF-8');
  8482.         else {
  8483.             return strtoupper($mixedCaseString);
  8484.         }
  8485.     }    //    function LOWERCASE()
  8486.  
  8487.  
  8488.     /**
  8489.      *    UPPERCASE
  8490.      *
  8491.      *    Converts a string value to upper case.
  8492.      *
  8493.      *    @param    string        $mixedCaseString 
  8494.      *    @return    string 
  8495.      */
  8496.     public static function UPPERCASE($mixedCaseString{
  8497.         $mixedCaseString    self::flattenSingleValue($mixedCaseString);
  8498.  
  8499.         if (function_exists('mb_convert_case')) {
  8500.             return mb_convert_case($mixedCaseStringMB_CASE_UPPER'UTF-8');
  8501.         else {
  8502.             return strtoupper($mixedCaseString);
  8503.         }
  8504.     }    //    function UPPERCASE()
  8505.  
  8506.  
  8507.     /**
  8508.      *    PROPERCASE
  8509.      *
  8510.      *    Converts a string value to upper case.
  8511.      *
  8512.      *    @param    string        $mixedCaseString 
  8513.      *    @return    string 
  8514.      */
  8515.     public static function PROPERCASE($mixedCaseString{
  8516.         $mixedCaseString    self::flattenSingleValue($mixedCaseString);
  8517.  
  8518.         if (function_exists('mb_convert_case')) {
  8519.             return mb_convert_case($mixedCaseStringMB_CASE_TITLE'UTF-8');
  8520.         else {
  8521.             return ucwords($mixedCaseString);
  8522.         }
  8523.     }    //    function PROPERCASE()
  8524.  
  8525.  
  8526.     /**
  8527.      *    DOLLAR
  8528.      *
  8529.      *    This function converts a number to text using currency format, with the decimals rounded to the specified place.
  8530.      *    The format used is $#,##0.00_);($#,##0.00)..
  8531.      *
  8532.      *    @param    float    $value            The value to format
  8533.      *    @param    int        $decimals        The number of digits to display to the right of the decimal point.
  8534.      *                                     If decimals is negative, number is rounded to the left of the decimal point.
  8535.      *                                     If you omit decimals, it is assumed to be 2
  8536.      *    @return    string 
  8537.      */
  8538.     public static function DOLLAR($value 0$decimals 2{
  8539.         $value        self::flattenSingleValue($value);
  8540.         $decimals    self::flattenSingleValue($decimals);
  8541.  
  8542.         // Validate parameters
  8543.         if (!is_numeric($value|| !is_numeric($decimals)) {
  8544.             return self::$_errorCodes['num'];
  8545.         }
  8546.         $decimals floor($decimals);
  8547.  
  8548.         if ($decimals 0{
  8549.             return money_format('%.'.$decimals.'n',$value);
  8550.         else {
  8551.             $round pow(10,abs($decimals));
  8552.             if ($value 0$round 0-$round}
  8553.             $value self::MROUND($value,$round);
  8554.             //    The implementation of money_format used if the standard PHP function is not available can't handle decimal places of 0,
  8555.             //        so we display to 1 dp and chop off that character and the decimal separator using substr
  8556.             return substr(money_format('%.1n',$value),0,-2);
  8557.         }
  8558.     }    //    function DOLLAR()
  8559.  
  8560.  
  8561.     /**
  8562.      * DOLLARDE
  8563.      *
  8564.      * Converts a dollar price expressed as an integer part and a fraction part into a dollar price expressed as a decimal number.
  8565.      * Fractional dollar numbers are sometimes used for security prices.
  8566.      *
  8567.      * @param    float    $fractional_dollar    Fractional Dollar
  8568.      * @param    int        $fraction            Fraction
  8569.      * @return    float 
  8570.      */
  8571.     public static function DOLLARDE($fractional_dollar Null$fraction 0{
  8572.         $fractional_dollar    self::flattenSingleValue($fractional_dollar);
  8573.         $fraction            = (int)self::flattenSingleValue($fraction);
  8574.  
  8575.         // Validate parameters
  8576.         if (is_null($fractional_dollar|| $fraction 0{
  8577.             return self::$_errorCodes['num'];
  8578.         }
  8579.         if ($fraction == 0{
  8580.             return self::$_errorCodes['divisionbyzero'];
  8581.         }
  8582.  
  8583.         $dollars floor($fractional_dollar);
  8584.         $cents fmod($fractional_dollar,1);
  8585.         $cents /= $fraction;
  8586.         $cents *= pow(10,ceil(log10($fraction)));
  8587.         return $dollars $cents;
  8588.     }    //    function DOLLARDE()
  8589.  
  8590.  
  8591.     /**
  8592.      * DOLLARFR
  8593.      *
  8594.      * Converts a dollar price expressed as a decimal number into a dollar price expressed as a fraction.
  8595.      * Fractional dollar numbers are sometimes used for security prices.
  8596.      *
  8597.      * @param    float    $decimal_dollar        Decimal Dollar
  8598.      * @param    int        $fraction            Fraction
  8599.      * @return    float 
  8600.      */
  8601.     public static function DOLLARFR($decimal_dollar Null$fraction 0{
  8602.         $decimal_dollar    self::flattenSingleValue($decimal_dollar);
  8603.         $fraction        = (int)self::flattenSingleValue($fraction);
  8604.  
  8605.         // Validate parameters
  8606.         if (is_null($decimal_dollar|| $fraction 0{
  8607.             return self::$_errorCodes['num'];
  8608.         }
  8609.         if ($fraction == 0{
  8610.             return self::$_errorCodes['divisionbyzero'];
  8611.         }
  8612.  
  8613.         $dollars floor($decimal_dollar);
  8614.         $cents fmod($decimal_dollar,1);
  8615.         $cents *= $fraction;
  8616.         $cents *= pow(10,-ceil(log10($fraction)));
  8617.         return $dollars $cents;
  8618.     }    //    function DOLLARFR()
  8619.  
  8620.  
  8621.     /**
  8622.      * EFFECT
  8623.      *
  8624.      * Returns the effective interest rate given the nominal rate and the number of compounding payments per year.
  8625.      *
  8626.      * @param    float    $nominal_rate        Nominal interest rate
  8627.      * @param    int        $npery                Number of compounding payments per year
  8628.      * @return    float 
  8629.      */
  8630.     public static function EFFECT($nominal_rate 0$npery 0{
  8631.         $nominal_rate    self::flattenSingleValue($nominal_rate);
  8632.         $npery            = (int)self::flattenSingleValue($npery);
  8633.  
  8634.         // Validate parameters
  8635.         if ($nominal_rate <= || $npery 1{
  8636.             return self::$_errorCodes['num'];
  8637.         }
  8638.  
  8639.         return pow(($nominal_rate $npery)$npery1;
  8640.     }    //    function EFFECT()
  8641.  
  8642.  
  8643.     /**
  8644.      * NOMINAL
  8645.      *
  8646.      * Returns the nominal interest rate given the effective rate and the number of compounding payments per year.
  8647.      *
  8648.      * @param    float    $effect_rate    Effective interest rate
  8649.      * @param    int        $npery            Number of compounding payments per year
  8650.      * @return    float 
  8651.      */
  8652.     public static function NOMINAL($effect_rate 0$npery 0{
  8653.         $effect_rate    self::flattenSingleValue($effect_rate);
  8654.         $npery            = (int)self::flattenSingleValue($npery);
  8655.  
  8656.         // Validate parameters
  8657.         if ($effect_rate <= || $npery 1{
  8658.             return self::$_errorCodes['num'];
  8659.         }
  8660.  
  8661.         // Calculate
  8662.         return $npery (pow($effect_rate 1$npery1);
  8663.     }    //    function NOMINAL()
  8664.  
  8665.  
  8666.     /**
  8667.      * PV
  8668.      *
  8669.      * Returns the Present Value of a cash flow with constant payments and interest rate (annuities).
  8670.      *
  8671.      * @param    float    $rate    Interest rate per period
  8672.      * @param    int        $nper    Number of periods
  8673.      * @param    float    $pmt    Periodic payment (annuity)
  8674.      * @param    float    $fv        Future Value
  8675.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  8676.      * @return    float 
  8677.      */
  8678.     public static function PV($rate 0$nper 0$pmt 0$fv 0$type 0{
  8679.         $rate    self::flattenSingleValue($rate);
  8680.         $nper    self::flattenSingleValue($nper);
  8681.         $pmt    self::flattenSingleValue($pmt);
  8682.         $fv        self::flattenSingleValue($fv);
  8683.         $type    self::flattenSingleValue($type);
  8684.  
  8685.         // Validate parameters
  8686.         if ($type != && $type != 1{
  8687.             return self::$_errorCodes['num'];
  8688.         }
  8689.  
  8690.         // Calculate
  8691.         if (!is_null($rate&& $rate != 0{
  8692.             return (-$pmt ($rate $type((pow($rate$nper1$rate$fvpow($rate$nper);
  8693.         else {
  8694.             return -$fv $pmt $nper;
  8695.         }
  8696.     }    //    function PV()
  8697.  
  8698.  
  8699.     /**
  8700.      * FV
  8701.      *
  8702.      * Returns the Future Value of a cash flow with constant payments and interest rate (annuities).
  8703.      *
  8704.      * @param    float    $rate    Interest rate per period
  8705.      * @param    int        $nper    Number of periods
  8706.      * @param    float    $pmt    Periodic payment (annuity)
  8707.      * @param    float    $pv        Present Value
  8708.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  8709.      * @return    float 
  8710.      */
  8711.     public static function FV($rate 0$nper 0$pmt 0$pv 0$type 0{
  8712.         $rate    self::flattenSingleValue($rate);
  8713.         $nper    self::flattenSingleValue($nper);
  8714.         $pmt    self::flattenSingleValue($pmt);
  8715.         $pv        self::flattenSingleValue($pv);
  8716.         $type    self::flattenSingleValue($type);
  8717.  
  8718.         // Validate parameters
  8719.         if ($type != && $type != 1{
  8720.             return self::$_errorCodes['num'];
  8721.         }
  8722.  
  8723.         // Calculate
  8724.         if (!is_null($rate&& $rate != 0{
  8725.             return -$pv pow($rate$nper$pmt ($rate $type(pow($rate$nper1$rate;
  8726.         else {
  8727.             return -$pv $pmt $nper;
  8728.         }
  8729.     }    //    function FV()
  8730.  
  8731.  
  8732.     /**
  8733.      * PMT
  8734.      *
  8735.      * Returns the constant payment (annuity) for a cash flow with a constant interest rate.
  8736.      *
  8737.      * @param    float    $rate    Interest rate per period
  8738.      * @param    int        $nper    Number of periods
  8739.      * @param    float    $pv        Present Value
  8740.      * @param    float    $fv        Future Value
  8741.      * @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  8742.      * @return    float 
  8743.      */
  8744.     public static function PMT($rate 0$nper 0$pv 0$fv 0$type 0{
  8745.         $rate    self::flattenSingleValue($rate);
  8746.         $nper    self::flattenSingleValue($nper);
  8747.         $pv        self::flattenSingleValue($pv);
  8748.         $fv        self::flattenSingleValue($fv);
  8749.         $type    self::flattenSingleValue($type);
  8750.  
  8751.         // Validate parameters
  8752.         if ($type != && $type != 1{
  8753.             return self::$_errorCodes['num'];
  8754.         }
  8755.  
  8756.         // Calculate
  8757.         if (!is_null($rate&& $rate != 0{
  8758.             return (-$fv $pv pow($rate$nper)) ($rate $type((pow($rate$nper1$rate);
  8759.         else {
  8760.             return (-$pv $fv$nper;
  8761.         }
  8762.     }    //    function PMT()
  8763.  
  8764.  
  8765.     /**
  8766.      * NPER
  8767.      *
  8768.      * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate.
  8769.      *
  8770.      *    @param    float    $rate    Interest rate per period
  8771.      *    @param    int        $pmt    Periodic payment (annuity)
  8772.      *    @param    float    $pv        Present Value
  8773.      *    @param    float    $fv        Future Value
  8774.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  8775.      *    @return    float 
  8776.      */
  8777.     public static function NPER($rate 0$pmt 0$pv 0$fv 0$type 0{
  8778.         $rate    self::flattenSingleValue($rate);
  8779.         $pmt    self::flattenSingleValue($pmt);
  8780.         $pv        self::flattenSingleValue($pv);
  8781.         $fv        self::flattenSingleValue($fv);
  8782.         $type    self::flattenSingleValue($type);
  8783.  
  8784.         // Validate parameters
  8785.         if ($type != && $type != 1{
  8786.             return self::$_errorCodes['num'];
  8787.         }
  8788.  
  8789.         // Calculate
  8790.         if (!is_null($rate&& $rate != 0{
  8791.             if ($pmt == && $pv == 0{
  8792.                 return self::$_errorCodes['num'];
  8793.             }
  8794.             return log(($pmt ($rate $type$rate $fv($pv $pmt ($rate $type$rate)) log($rate);
  8795.         else {
  8796.             if ($pmt == 0{
  8797.                 return self::$_errorCodes['num'];
  8798.             }
  8799.             return (-$pv -$fv$pmt;
  8800.         }
  8801.     }    //    function NPER()
  8802.  
  8803.  
  8804.     private static function _interestAndPrincipal($rate=0$per=0$nper=0$pv=0$fv=0$type=0{
  8805.         $pmt self::PMT($rate$nper$pv$fv$type);
  8806.         $capital $pv;
  8807.         for ($i 1$i<= $per++$i{
  8808.             $interest ($type && $i == 1): -$capital $rate;
  8809.             $principal $pmt $interest;
  8810.             $capital += $principal;
  8811.         }
  8812.         return array($interest$principal);
  8813.     }    //    function _interestAndPrincipal()
  8814.  
  8815.  
  8816.     /**
  8817.      *    IPMT
  8818.      *
  8819.      *    Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
  8820.      *
  8821.      *    @param    float    $rate    Interest rate per period
  8822.      *    @param    int        $per    Period for which we want to find the interest
  8823.      *    @param    int        $nper    Number of periods
  8824.      *    @param    float    $pv        Present Value
  8825.      *    @param    float    $fv        Future Value
  8826.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  8827.      *    @return    float 
  8828.      */
  8829.     public static function IPMT($rate$per$nper$pv$fv 0$type 0{
  8830.         $rate    self::flattenSingleValue($rate);
  8831.         $per    = (int) self::flattenSingleValue($per);
  8832.         $nper    = (int) self::flattenSingleValue($nper);
  8833.         $pv        self::flattenSingleValue($pv);
  8834.         $fv        self::flattenSingleValue($fv);
  8835.         $type    = (int) self::flattenSingleValue($type);
  8836.  
  8837.         // Validate parameters
  8838.         if ($type != && $type != 1{
  8839.             return self::$_errorCodes['num'];
  8840.         }
  8841.         if ($per <= || $per $nper{
  8842.             return self::$_errorCodes['value'];
  8843.         }
  8844.  
  8845.         // Calculate
  8846.         $interestAndPrincipal self::_interestAndPrincipal($rate$per$nper$pv$fv$type);
  8847.         return $interestAndPrincipal[0];
  8848.     }    //    function IPMT()
  8849.  
  8850.  
  8851.     /**
  8852.      *    CUMIPMT
  8853.      *
  8854.      *    Returns the cumulative interest paid on a loan between start_period and end_period.
  8855.      *
  8856.      *    @param    float    $rate    Interest rate per period
  8857.      *    @param    int        $nper    Number of periods
  8858.      *    @param    float    $pv        Present Value
  8859.      *    @param    int        start    The first period in the calculation.
  8860.      *                                 Payment periods are numbered beginning with 1.
  8861.      *    @param    int        end        The last period in the calculation.
  8862.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  8863.      *    @return    float 
  8864.      */
  8865.     public static function CUMIPMT($rate$nper$pv$start$end$type 0{
  8866.         $rate    self::flattenSingleValue($rate);
  8867.         $nper    = (int) self::flattenSingleValue($nper);
  8868.         $pv        self::flattenSingleValue($pv);
  8869.         $start    = (int) self::flattenSingleValue($start);
  8870.         $end    = (int) self::flattenSingleValue($end);
  8871.         $type    = (int) self::flattenSingleValue($type);
  8872.  
  8873.         // Validate parameters
  8874.         if ($type != && $type != 1{
  8875.             return self::$_errorCodes['num'];
  8876.         }
  8877.         if ($start || $start $end{
  8878.             return self::$_errorCodes['value'];
  8879.         }
  8880.  
  8881.         // Calculate
  8882.         $interest 0;
  8883.         for ($per $start$per <= $end++$per{
  8884.             $interest += self::IPMT($rate$per$nper$pv0$type);
  8885.         }
  8886.  
  8887.         return $interest;
  8888.     }    //    function CUMIPMT()
  8889.  
  8890.  
  8891.     /**
  8892.      *    PPMT
  8893.      *
  8894.      *    Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
  8895.      *
  8896.      *    @param    float    $rate    Interest rate per period
  8897.      *    @param    int        $per    Period for which we want to find the interest
  8898.      *    @param    int        $nper    Number of periods
  8899.      *    @param    float    $pv        Present Value
  8900.      *    @param    float    $fv        Future Value
  8901.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  8902.      *    @return    float 
  8903.      */
  8904.     public static function PPMT($rate$per$nper$pv$fv 0$type 0{
  8905.         $rate    self::flattenSingleValue($rate);
  8906.         $per    = (int) self::flattenSingleValue($per);
  8907.         $nper    = (int) self::flattenSingleValue($nper);
  8908.         $pv        self::flattenSingleValue($pv);
  8909.         $fv        self::flattenSingleValue($fv);
  8910.         $type    = (int) self::flattenSingleValue($type);
  8911.  
  8912.         // Validate parameters
  8913.         if ($type != && $type != 1{
  8914.             return self::$_errorCodes['num'];
  8915.         }
  8916.         if ($per <= || $per $nper{
  8917.             return self::$_errorCodes['value'];
  8918.         }
  8919.  
  8920.         // Calculate
  8921.         $interestAndPrincipal self::_interestAndPrincipal($rate$per$nper$pv$fv$type);
  8922.         return $interestAndPrincipal[1];
  8923.     }    //    function PPMT()
  8924.  
  8925.  
  8926.     /**
  8927.      *    CUMPRINC
  8928.      *
  8929.      *    Returns the cumulative principal paid on a loan between start_period and end_period.
  8930.      *
  8931.      *    @param    float    $rate    Interest rate per period
  8932.      *    @param    int        $nper    Number of periods
  8933.      *    @param    float    $pv        Present Value
  8934.      *    @param    int        start    The first period in the calculation.
  8935.      *                                 Payment periods are numbered beginning with 1.
  8936.      *    @param    int        end        The last period in the calculation.
  8937.      *    @param    int        $type    Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  8938.      *    @return    float 
  8939.      */
  8940.     public static function CUMPRINC($rate$nper$pv$start$end$type 0{
  8941.         $rate    self::flattenSingleValue($rate);
  8942.         $nper    = (int) self::flattenSingleValue($nper);
  8943.         $pv        self::flattenSingleValue($pv);
  8944.         $start    = (int) self::flattenSingleValue($start);
  8945.         $end    = (int) self::flattenSingleValue($end);
  8946.         $type    = (int) self::flattenSingleValue($type);
  8947.  
  8948.         // Validate parameters
  8949.         if ($type != && $type != 1{
  8950.             return self::$_errorCodes['num'];
  8951.         }
  8952.         if ($start || $start $end{
  8953.             return self::$_errorCodes['value'];
  8954.         }
  8955.  
  8956.         // Calculate
  8957.         $principal 0;
  8958.         for ($per $start$per <= $end++$per{
  8959.             $principal += self::PPMT($rate$per$nper$pv0$type);
  8960.         }
  8961.  
  8962.         return $principal;
  8963.     }    //    function CUMPRINC()
  8964.  
  8965.  
  8966.     /**
  8967.      * NPV
  8968.      *
  8969.      * Returns the Net Present Value of a cash flow series given a discount rate.
  8970.      *
  8971.      * @param    float    Discount interest rate
  8972.      * @param    array    Cash flow series
  8973.      * @return    float 
  8974.      */
  8975.     public static function NPV({
  8976.         // Return value
  8977.         $returnValue 0;
  8978.  
  8979.         // Loop trough arguments
  8980.         $aArgs self::flattenArray(func_get_args());
  8981.  
  8982.         // Calculate
  8983.         $rate array_shift($aArgs);
  8984.         for ($i 1$i <= count($aArgs)++$i{
  8985.             // Is it a numeric value?
  8986.             if (is_numeric($aArgs[$i 1])) {
  8987.                 $returnValue += $aArgs[$i 1pow($rate$i);
  8988.             }
  8989.         }
  8990.  
  8991.         // Return
  8992.         return $returnValue;
  8993.     }    //    function NPV()
  8994.  
  8995.  
  8996.     /**
  8997.      *    DB
  8998.      *
  8999.      *    Returns the depreciation of an asset for a specified period using the fixed-declining balance method.
  9000.      *    This form of depreciation is used if you want to get a higher depreciation value at the beginning of the depreciation
  9001.      *        (as opposed to linear depreciation). The depreciation value is reduced with every depreciation period by the
  9002.      *        depreciation already deducted from the initial cost.
  9003.      *
  9004.      *    @param    float    cost        Initial cost of the asset.
  9005.      *    @param    float    salvage        Value at the end of the depreciation. (Sometimes called the salvage value of the asset)
  9006.      *    @param    int        life        Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset)
  9007.      *    @param    int        period        The period for which you want to calculate the depreciation. Period must use the same units as life.
  9008.      *    @param    float    month        Number of months in the first year. If month is omitted, it defaults to 12.
  9009.      *    @return    float 
  9010.      */
  9011.     public static function DB($cost$salvage$life$period$month=12{
  9012.         $cost        = (float) self::flattenSingleValue($cost);
  9013.         $salvage    = (float) self::flattenSingleValue($salvage);
  9014.         $life        = (int) self::flattenSingleValue($life);
  9015.         $period        = (int) self::flattenSingleValue($period);
  9016.         $month        = (int) self::flattenSingleValue($month);
  9017.  
  9018.         //    Validate
  9019.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($month))) {
  9020.             if ($cost == 0{
  9021.                 return 0.0;
  9022.             elseif (($cost 0|| (($salvage $cost0|| ($life <= 0|| ($period 1|| ($month 1)) {
  9023.                 return self::$_errorCodes['num'];
  9024.             }
  9025.             //    Set Fixed Depreciation Rate
  9026.             $fixedDepreciationRate pow(($salvage $cost)($life));
  9027.             $fixedDepreciationRate round($fixedDepreciationRate3);
  9028.  
  9029.             //    Loop through each period calculating the depreciation
  9030.             $previousDepreciation 0;
  9031.             for ($per 1$per <= $period++$per{
  9032.                 if ($per == 1{
  9033.                     $depreciation $cost $fixedDepreciationRate $month 12;
  9034.                 elseif ($per == ($life 1)) {
  9035.                     $depreciation ($cost $previousDepreciation$fixedDepreciationRate (12 $month12;
  9036.                 else {
  9037.                     $depreciation ($cost $previousDepreciation$fixedDepreciationRate;
  9038.                 }
  9039.                 $previousDepreciation += $depreciation;
  9040.             }
  9041.             return $depreciation;
  9042.         }
  9043.         return self::$_errorCodes['value'];
  9044.     }    //    function DB()
  9045.  
  9046.  
  9047.     /**
  9048.      *    DDB
  9049.      *
  9050.      *    Returns the depreciation of an asset for a specified period using the double-declining balance method or some other method you specify.
  9051.      *
  9052.      *    @param    float    cost        Initial cost of the asset.
  9053.      *    @param    float    salvage        Value at the end of the depreciation. (Sometimes called the salvage value of the asset)
  9054.      *    @param    int        life        Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset)
  9055.      *    @param    int        period        The period for which you want to calculate the depreciation. Period must use the same units as life.
  9056.      *    @param    float    factor        The rate at which the balance declines.
  9057.      *                                 If factor is omitted, it is assumed to be 2 (the double-declining balance method).
  9058.      *    @return    float 
  9059.      */
  9060.     public static function DDB($cost$salvage$life$period$factor=2.0{
  9061.         $cost        = (float) self::flattenSingleValue($cost);
  9062.         $salvage    = (float) self::flattenSingleValue($salvage);
  9063.         $life        = (int) self::flattenSingleValue($life);
  9064.         $period        = (int) self::flattenSingleValue($period);
  9065.         $factor        = (float) self::flattenSingleValue($factor);
  9066.  
  9067.         //    Validate
  9068.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($factor))) {
  9069.             if (($cost <= 0|| (($salvage $cost0|| ($life <= 0|| ($period 1|| ($factor <= 0.0|| ($period $life)) {
  9070.                 return self::$_errorCodes['num'];
  9071.             }
  9072.             //    Set Fixed Depreciation Rate
  9073.             $fixedDepreciationRate pow(($salvage $cost)($life));
  9074.             $fixedDepreciationRate round($fixedDepreciationRate3);
  9075.  
  9076.             //    Loop through each period calculating the depreciation
  9077.             $previousDepreciation 0;
  9078.             for ($per 1$per <= $period++$per{
  9079.                 $depreciation min( ($cost $previousDepreciation($factor $life)($cost $salvage $previousDepreciation) );
  9080.                 $previousDepreciation += $depreciation;
  9081.             }
  9082.             return $depreciation;
  9083.         }
  9084.         return self::$_errorCodes['value'];
  9085.     }    //    function DDB()
  9086.  
  9087.  
  9088.     private static function _daysPerYear($year,$basis{
  9089.         switch ($basis{
  9090.             case :
  9091.             case :
  9092.             case :
  9093.                 $daysPerYear 360;
  9094.                 break;
  9095.             case :
  9096.                 $daysPerYear 365;
  9097.                 break;
  9098.             case :
  9099.                 if (self::_isLeapYear(self::YEAR($year))) {
  9100.                     $daysPerYear 366;
  9101.                 else {
  9102.                     $daysPerYear 365;
  9103.                 }
  9104.                 break;
  9105.             default    :
  9106.                 return self::$_errorCodes['num'];
  9107.         }
  9108.         return $daysPerYear;
  9109.     }    //    function _daysPerYear()
  9110.  
  9111.  
  9112.     /**
  9113.      *    ACCRINT
  9114.      *
  9115.      *    Returns the discount rate for a security.
  9116.      *
  9117.      *    @param    mixed    issue        The security's issue date.
  9118.      *    @param    mixed    firstinter    The security's first interest date.
  9119.      *    @param    mixed    settlement    The security's settlement date.
  9120.      *    @param    float    rate        The security's annual coupon rate.
  9121.      *    @param    float    par            The security's par value.
  9122.      *    @param    int        basis        The type of day count to use.
  9123.      *                                         0 or omitted    US (NASD) 30/360
  9124.      *                                         1                Actual/actual
  9125.      *                                         2                Actual/360
  9126.      *                                         3                Actual/365
  9127.      *                                         4                European 30/360
  9128.      *    @return    float 
  9129.      */
  9130.     public static function ACCRINT($issue$firstinter$settlement$rate$par=1000$frequency=1$basis=0{
  9131.         $issue        self::flattenSingleValue($issue);
  9132.         $firstinter    self::flattenSingleValue($firstinter);
  9133.         $settlement    self::flattenSingleValue($settlement);
  9134.         $rate        = (float) self::flattenSingleValue($rate);
  9135.         $par        (is_null($par))    1000    : (float) self::flattenSingleValue($par);
  9136.         $frequency    (is_null($frequency))    1    : (int) self::flattenSingleValue($frequency);
  9137.         $basis        (is_null($basis))    0        : (int) self::flattenSingleValue($basis);
  9138.  
  9139.         //    Validate
  9140.         if ((is_numeric($rate)) && (is_numeric($par))) {
  9141.             if (($rate <= 0|| ($par <= 0)) {
  9142.                 return self::$_errorCodes['num'];
  9143.             }
  9144.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  9145.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  9146.                 return $daysBetweenIssueAndSettlement;
  9147.             }
  9148.             $daysPerYear self::_daysPerYear(self::YEAR($issue),$basis);
  9149.             if (!is_numeric($daysPerYear)) {
  9150.                 return $daysPerYear;
  9151.             }
  9152.             $daysBetweenIssueAndSettlement *= $daysPerYear;
  9153.  
  9154.             return $par $rate ($daysBetweenIssueAndSettlement $daysPerYear);
  9155.         }
  9156.         return self::$_errorCodes['value'];
  9157.     }    //    function ACCRINT()
  9158.  
  9159.  
  9160.     /**
  9161.      *    ACCRINTM
  9162.      *
  9163.      *    Returns the discount rate for a security.
  9164.      *
  9165.      *    @param    mixed    issue        The security's issue date.
  9166.      *    @param    mixed    settlement    The security's settlement date.
  9167.      *    @param    float    rate        The security's annual coupon rate.
  9168.      *    @param    float    par            The security's par value.
  9169.      *    @param    int        basis        The type of day count to use.
  9170.      *                                         0 or omitted    US (NASD) 30/360
  9171.      *                                         1                Actual/actual
  9172.      *                                         2                Actual/360
  9173.      *                                         3                Actual/365
  9174.      *                                         4                European 30/360
  9175.      *    @return    float 
  9176.      */
  9177.     public static function ACCRINTM($issue$settlement$rate$par=1000$basis=0{
  9178.         $issue        self::flattenSingleValue($issue);
  9179.         $settlement    self::flattenSingleValue($settlement);
  9180.         $rate        = (float) self::flattenSingleValue($rate);
  9181.         $par        (is_null($par))    1000    : (float) self::flattenSingleValue($par);
  9182.         $basis        (is_null($basis))    0        : (int) self::flattenSingleValue($basis);
  9183.  
  9184.         //    Validate
  9185.         if ((is_numeric($rate)) && (is_numeric($par))) {
  9186.             if (($rate <= 0|| ($par <= 0)) {
  9187.                 return self::$_errorCodes['num'];
  9188.             }
  9189.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  9190.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  9191.                 return $daysBetweenIssueAndSettlement;
  9192.             }
  9193.             $daysPerYear self::_daysPerYear(self::YEAR($issue),$basis);
  9194.             if (!is_numeric($daysPerYear)) {
  9195.                 return $daysPerYear;
  9196.             }
  9197.             $daysBetweenIssueAndSettlement *= $daysPerYear;
  9198.  
  9199.             return $par $rate ($daysBetweenIssueAndSettlement $daysPerYear);
  9200.         }
  9201.         return self::$_errorCodes['value'];
  9202.     }    //    function ACCRINTM()
  9203.  
  9204.  
  9205.     public static function AMORDEGRC($cost$purchased$firstPeriod$salvage$period$rate$basis=0{
  9206.     }    //    function AMORDEGRC()
  9207.  
  9208.  
  9209.     public static function AMORLINC($cost$purchased$firstPeriod$salvage$period$rate$basis=0{
  9210.     }    //    function AMORLINC()
  9211.  
  9212.  
  9213.     /**
  9214.      *    DISC
  9215.      *
  9216.      *    Returns the discount rate for a security.
  9217.      *
  9218.      *    @param    mixed    settlement    The security's settlement date.
  9219.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  9220.      *    @param    mixed    maturity    The security's maturity date.
  9221.      *                                 The maturity date is the date when the security expires.
  9222.      *    @param    int        price        The security's price per $100 face value.
  9223.      *    @param    int        redemption    the security's redemption value per $100 face value.
  9224.      *    @param    int        basis        The type of day count to use.
  9225.      *                                         0 or omitted    US (NASD) 30/360
  9226.      *                                         1                Actual/actual
  9227.      *                                         2                Actual/360
  9228.      *                                         3                Actual/365
  9229.      *                                         4                European 30/360
  9230.      *    @return    float 
  9231.      */
  9232.     public static function DISC($settlement$maturity$price$redemption$basis=0{
  9233.         $settlement    self::flattenSingleValue($settlement);
  9234.         $maturity    self::flattenSingleValue($maturity);
  9235.         $price        = (float) self::flattenSingleValue($price);
  9236.         $redemption    = (float) self::flattenSingleValue($redemption);
  9237.         $basis        = (int) self::flattenSingleValue($basis);
  9238.  
  9239.         //    Validate
  9240.         if ((is_numeric($price)) && (is_numeric($redemption)) && (is_numeric($basis))) {
  9241.             if (($price <= 0|| ($redemption <= 0)) {
  9242.                 return self::$_errorCodes['num'];
  9243.             }
  9244.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  9245.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9246.                 return $daysBetweenSettlementAndMaturity;
  9247.             }
  9248.  
  9249.             return (($price $redemption$daysBetweenSettlementAndMaturity);
  9250.         }
  9251.         return self::$_errorCodes['value'];
  9252.     }    //    function DISC()
  9253.  
  9254.  
  9255.     /**
  9256.      *    PRICEDISC
  9257.      *
  9258.      *    Returns the price per $100 face value of a discounted security.
  9259.      *
  9260.      *    @param    mixed    settlement    The security's settlement date.
  9261.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  9262.      *    @param    mixed    maturity    The security's maturity date.
  9263.      *                                 The maturity date is the date when the security expires.
  9264.      *    @param    int        discount    The security's discount rate.
  9265.      *    @param    int        redemption    The security's redemption value per $100 face value.
  9266.      *    @param    int        basis        The type of day count to use.
  9267.      *                                         0 or omitted    US (NASD) 30/360
  9268.      *                                         1                Actual/actual
  9269.      *                                         2                Actual/360
  9270.      *                                         3                Actual/365
  9271.      *                                         4                European 30/360
  9272.      *    @return    float 
  9273.      */
  9274.     public static function PRICEDISC($settlement$maturity$discount$redemption$basis=0{
  9275.         $settlement    self::flattenSingleValue($settlement);
  9276.         $maturity    self::flattenSingleValue($maturity);
  9277.         $discount    = (float) self::flattenSingleValue($discount);
  9278.         $redemption    = (float) self::flattenSingleValue($redemption);
  9279.         $basis        = (int) self::flattenSingleValue($basis);
  9280.  
  9281.         //    Validate
  9282.         if ((is_numeric($discount)) && (is_numeric($redemption)) && (is_numeric($basis))) {
  9283.             if (($discount <= 0|| ($redemption <= 0)) {
  9284.                 return self::$_errorCodes['num'];
  9285.             }
  9286.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  9287.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9288.                 return $daysBetweenSettlementAndMaturity;
  9289.             }
  9290.  
  9291.             return $redemption ($discount $daysBetweenSettlementAndMaturity);
  9292.         }
  9293.         return self::$_errorCodes['value'];
  9294.     }    //    function PRICEDISC()
  9295.  
  9296.  
  9297.     /**
  9298.      *    PRICEMAT
  9299.      *
  9300.      *    Returns the price per $100 face value of a security that pays interest at maturity.
  9301.      *
  9302.      *    @param    mixed    settlement    The security's settlement date.
  9303.      *                                 The security's settlement date is the date after the issue date when the security is traded to the buyer.
  9304.      *    @param    mixed    maturity    The security's maturity date.
  9305.      *                                 The maturity date is the date when the security expires.
  9306.      *    @param    mixed    issue        The security's issue date.
  9307.      *    @param    int        rate        The security's interest rate at date of issue.
  9308.      *    @param    int        yield        The security's annual yield.
  9309.      *    @param    int        basis        The type of day count to use.
  9310.      *                                         0 or omitted    US (NASD) 30/360
  9311.      *                                         1                Actual/actual
  9312.      *                                         2                Actual/360
  9313.      *                                         3                Actual/365
  9314.      *                                         4                European 30/360
  9315.      *    @return    float 
  9316.      */
  9317.     public static function PRICEMAT($settlement$maturity$issue$rate$yield$basis=0{
  9318.         $settlement    self::flattenSingleValue($settlement);
  9319.         $maturity    self::flattenSingleValue($maturity);
  9320.         $issue        self::flattenSingleValue($issue);
  9321.         $rate        self::flattenSingleValue($rate);
  9322.         $yield        self::flattenSingleValue($yield);
  9323.         $basis        = (int) self::flattenSingleValue($basis);
  9324.  
  9325.         //    Validate
  9326.         if (is_numeric($rate&& is_numeric($yield)) {
  9327.             if (($rate <= 0|| ($yield <= 0)) {
  9328.                 return self::$_errorCodes['num'];
  9329.             }
  9330.             $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  9331.             if (!is_numeric($daysPerYear)) {
  9332.                 return $daysPerYear;
  9333.             }
  9334.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  9335.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  9336.                 return $daysBetweenIssueAndSettlement;
  9337.             }
  9338.             $daysBetweenIssueAndSettlement *= $daysPerYear;
  9339.             $daysBetweenIssueAndMaturity self::YEARFRAC($issue$maturity$basis);
  9340.             if (!is_numeric($daysBetweenIssueAndMaturity)) {
  9341.                 return $daysBetweenIssueAndMaturity;
  9342.             }
  9343.             $daysBetweenIssueAndMaturity *= $daysPerYear;
  9344.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  9345.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9346.                 return $daysBetweenSettlementAndMaturity;
  9347.             }
  9348.             $daysBetweenSettlementAndMaturity *= $daysPerYear;
  9349.  
  9350.             return ((100 (($daysBetweenIssueAndMaturity $daysPerYear$rate 100)) /
  9351.                    ((($daysBetweenSettlementAndMaturity $daysPerYear$yield)) -
  9352.                    (($daysBetweenIssueAndSettlement $daysPerYear$rate 100));
  9353.         }
  9354.         return self::$_errorCodes['value'];
  9355.     }    //    function PRICEMAT()
  9356.  
  9357.  
  9358.     /**
  9359.      *    RECEIVED
  9360.      *
  9361.      *    Returns the price per $100 face value of a discounted security.
  9362.      *
  9363.      *    @param    mixed    settlement    The security's settlement date.
  9364.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  9365.      *    @param    mixed    maturity    The security's maturity date.
  9366.      *                                 The maturity date is the date when the security expires.
  9367.      *    @param    int        investment    The amount invested in the security.
  9368.      *    @param    int        discount    The security's discount rate.
  9369.      *    @param    int        basis        The type of day count to use.
  9370.      *                                         0 or omitted    US (NASD) 30/360
  9371.      *                                         1                Actual/actual
  9372.      *                                         2                Actual/360
  9373.      *                                         3                Actual/365
  9374.      *                                         4                European 30/360
  9375.      *    @return    float 
  9376.      */
  9377.     public static function RECEIVED($settlement$maturity$investment$discount$basis=0{
  9378.         $settlement    self::flattenSingleValue($settlement);
  9379.         $maturity    self::flattenSingleValue($maturity);
  9380.         $investment    = (float) self::flattenSingleValue($investment);
  9381.         $discount    = (float) self::flattenSingleValue($discount);
  9382.         $basis        = (int) self::flattenSingleValue($basis);
  9383.  
  9384.         //    Validate
  9385.         if ((is_numeric($investment)) && (is_numeric($discount)) && (is_numeric($basis))) {
  9386.             if (($investment <= 0|| ($discount <= 0)) {
  9387.                 return self::$_errorCodes['num'];
  9388.             }
  9389.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  9390.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9391.                 return $daysBetweenSettlementAndMaturity;
  9392.             }
  9393.  
  9394.             return $investment ($discount $daysBetweenSettlementAndMaturity));
  9395.         }
  9396.         return self::$_errorCodes['value'];
  9397.     }    //    function RECEIVED()
  9398.  
  9399.  
  9400.     /**
  9401.      *    INTRATE
  9402.      *
  9403.      *    Returns the interest rate for a fully invested security.
  9404.      *
  9405.      *    @param    mixed    settlement    The security's settlement date.
  9406.      *                                 The security settlement date is the date after the issue date when the security is traded to the buyer.
  9407.      *    @param    mixed    maturity    The security's maturity date.
  9408.      *                                 The maturity date is the date when the security expires.
  9409.      *    @param    int        investment    The amount invested in the security.
  9410.      *    @param    int        redemption    The amount to be received at maturity.
  9411.      *    @param    int        basis        The type of day count to use.
  9412.      *                                         0 or omitted    US (NASD) 30/360
  9413.      *                                         1                Actual/actual
  9414.      *                                         2                Actual/360
  9415.      *                                         3                Actual/365
  9416.      *                                         4                European 30/360
  9417.      *    @return    float 
  9418.      */
  9419.     public static function INTRATE($settlement$maturity$investment$redemption$basis=0{
  9420.         $settlement    self::flattenSingleValue($settlement);
  9421.         $maturity    self::flattenSingleValue($maturity);
  9422.         $investment    = (float) self::flattenSingleValue($investment);
  9423.         $redemption    = (float) self::flattenSingleValue($redemption);
  9424.         $basis        = (int) self::flattenSingleValue($basis);
  9425.  
  9426.         //    Validate
  9427.         if ((is_numeric($investment)) && (is_numeric($redemption)) && (is_numeric($basis))) {
  9428.             if (($investment <= 0|| ($redemption <= 0)) {
  9429.                 return self::$_errorCodes['num'];
  9430.             }
  9431.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  9432.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9433.                 return $daysBetweenSettlementAndMaturity;
  9434.             }
  9435.  
  9436.             return (($redemption $investment1($daysBetweenSettlementAndMaturity);
  9437.         }
  9438.         return self::$_errorCodes['value'];
  9439.     }    //    function INTRATE()
  9440.  
  9441.  
  9442.     /**
  9443.      *    TBILLEQ
  9444.      *
  9445.      *    Returns the bond-equivalent yield for a Treasury bill.
  9446.      *
  9447.      *    @param    mixed    settlement    The Treasury bill's settlement date.
  9448.      *                                 The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  9449.      *    @param    mixed    maturity    The Treasury bill's maturity date.
  9450.      *                                 The maturity date is the date when the Treasury bill expires.
  9451.      *    @param    int        discount    The Treasury bill's discount rate.
  9452.      *    @return    float 
  9453.      */
  9454.     public static function TBILLEQ($settlement$maturity$discount{
  9455.         $settlement    self::flattenSingleValue($settlement);
  9456.         $maturity    self::flattenSingleValue($maturity);
  9457.         $discount    self::flattenSingleValue($discount);
  9458.  
  9459.         //    Use TBILLPRICE for validation
  9460.         $testValue self::TBILLPRICE($settlement$maturity$discount);
  9461.         if (is_string($testValue)) {
  9462.             return $testValue;
  9463.         }
  9464.  
  9465.         if (is_string($maturity self::_getDateValue($maturity))) {
  9466.             return self::$_errorCodes['value'];
  9467.         }
  9468.         ++$maturity;
  9469.  
  9470.         $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity);
  9471.         $daysBetweenSettlementAndMaturity *= 360;
  9472.  
  9473.         return (365 $discount(360 ($discount ($daysBetweenSettlementAndMaturity)));
  9474.     }    //    function TBILLEQ()
  9475.  
  9476.  
  9477.     /**
  9478.      *    TBILLPRICE
  9479.      *
  9480.      *    Returns the yield for a Treasury bill.
  9481.      *
  9482.      *    @param    mixed    settlement    The Treasury bill's settlement date.
  9483.      *                                 The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  9484.      *    @param    mixed    maturity    The Treasury bill's maturity date.
  9485.      *                                 The maturity date is the date when the Treasury bill expires.
  9486.      *    @param    int        discount    The Treasury bill's discount rate.
  9487.      *    @return    float 
  9488.      */
  9489.     public static function TBILLPRICE($settlement$maturity$discount{
  9490.         $settlement    self::flattenSingleValue($settlement);
  9491.         $maturity    self::flattenSingleValue($maturity);
  9492.         $discount    self::flattenSingleValue($discount);
  9493.  
  9494.         if (is_string($maturity self::_getDateValue($maturity))) {
  9495.             return self::$_errorCodes['value'];
  9496.         }
  9497.         ++$maturity;
  9498.  
  9499.         //    Validate
  9500.         if (is_numeric($discount)) {
  9501.             if ($discount <= 0{
  9502.                 return self::$_errorCodes['num'];
  9503.             }
  9504.  
  9505.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity);
  9506.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9507.                 return $daysBetweenSettlementAndMaturity;
  9508.             }
  9509.             $daysBetweenSettlementAndMaturity *= 360;
  9510.             if ($daysBetweenSettlementAndMaturity 360{
  9511.                 return self::$_errorCodes['num'];
  9512.             }
  9513.  
  9514.             $price 100 ((($discount $daysBetweenSettlementAndMaturity360));
  9515.             if ($price <= 0{
  9516.                 return self::$_errorCodes['num'];
  9517.             }
  9518.             return $price;
  9519.         }
  9520.         return self::$_errorCodes['value'];
  9521.     }    //    function TBILLPRICE()
  9522.  
  9523.  
  9524.     /**
  9525.      *    TBILLYIELD
  9526.      *
  9527.      *    Returns the yield for a Treasury bill.
  9528.      *
  9529.      *    @param    mixed    settlement    The Treasury bill's settlement date.
  9530.      *                                 The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  9531.      *    @param    mixed    maturity    The Treasury bill's maturity date.
  9532.      *                                 The maturity date is the date when the Treasury bill expires.
  9533.      *    @param    int        price        The Treasury bill's price per $100 face value.
  9534.      *    @return    float 
  9535.      */
  9536.     public static function TBILLYIELD($settlement$maturity$price{
  9537.         $settlement    self::flattenSingleValue($settlement);
  9538.         $maturity    self::flattenSingleValue($maturity);
  9539.         $price        self::flattenSingleValue($price);
  9540.  
  9541.         //    Validate
  9542.         if (is_numeric($price)) {
  9543.             if ($price <= 0{
  9544.                 return self::$_errorCodes['num'];
  9545.             }
  9546.  
  9547.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity);
  9548.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9549.                 return $daysBetweenSettlementAndMaturity;
  9550.             }
  9551.  
  9552.             $daysBetweenSettlementAndMaturity *= 360;
  9553. //            Sometimes we need to add 1, sometimes not. I haven't yet worked out the rule which determines this.
  9554.             ++$daysBetweenSettlementAndMaturity;
  9555.             if ($daysBetweenSettlementAndMaturity 360{
  9556.                 return self::$_errorCodes['num'];
  9557.             }
  9558.  
  9559.             return ((100 $price$price(360 $daysBetweenSettlementAndMaturity);
  9560.         }
  9561.         return self::$_errorCodes['value'];
  9562.     }    //    function TBILLYIELD()
  9563.  
  9564.  
  9565.     /**
  9566.      * SLN
  9567.      *
  9568.      * Returns the straight-line depreciation of an asset for one period
  9569.      *
  9570.      * @param    cost        Initial cost of the asset
  9571.      * @param    salvage        Value at the end of the depreciation
  9572.      * @param    life        Number of periods over which the asset is depreciated
  9573.      * @return    float 
  9574.      */
  9575.     public static function SLN($cost$salvage$life{
  9576.         $cost        self::flattenSingleValue($cost);
  9577.         $salvage    self::flattenSingleValue($salvage);
  9578.         $life        self::flattenSingleValue($life);
  9579.  
  9580.         // Calculate
  9581.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life))) {
  9582.             if ($life 0{
  9583.                 return self::$_errorCodes['num'];
  9584.             }
  9585.             return ($cost $salvage$life;
  9586.         }
  9587.         return self::$_errorCodes['value'];
  9588.     }    //    function SLN()
  9589.  
  9590.  
  9591.     /**
  9592.      *    YIELDMAT
  9593.      *
  9594.      *    Returns the annual yield of a security that pays interest at maturity.
  9595.      *
  9596.      *    @param    mixed    settlement    The security's settlement date.
  9597.      *                                 The security's settlement date is the date after the issue date when the security is traded to the buyer.
  9598.      *    @param    mixed    maturity    The security's maturity date.
  9599.      *                                 The maturity date is the date when the security expires.
  9600.      *    @param    mixed    issue        The security's issue date.
  9601.      *    @param    int        rate        The security's interest rate at date of issue.
  9602.      *    @param    int        price        The security's price per $100 face value.
  9603.      *    @param    int        basis        The type of day count to use.
  9604.      *                                         0 or omitted    US (NASD) 30/360
  9605.      *                                         1                Actual/actual
  9606.      *                                         2                Actual/360
  9607.      *                                         3                Actual/365
  9608.      *                                         4                European 30/360
  9609.      *    @return    float 
  9610.      */
  9611.     public static function YIELDMAT($settlement$maturity$issue$rate$price$basis=0{
  9612.         $settlement    self::flattenSingleValue($settlement);
  9613.         $maturity    self::flattenSingleValue($maturity);
  9614.         $issue        self::flattenSingleValue($issue);
  9615.         $rate        self::flattenSingleValue($rate);
  9616.         $price        self::flattenSingleValue($price);
  9617.         $basis        = (int) self::flattenSingleValue($basis);
  9618.  
  9619.         //    Validate
  9620.         if (is_numeric($rate&& is_numeric($price)) {
  9621.             if (($rate <= 0|| ($price <= 0)) {
  9622.                 return self::$_errorCodes['num'];
  9623.             }
  9624.             $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  9625.             if (!is_numeric($daysPerYear)) {
  9626.                 return $daysPerYear;
  9627.             }
  9628.             $daysBetweenIssueAndSettlement self::YEARFRAC($issue$settlement$basis);
  9629.             if (!is_numeric($daysBetweenIssueAndSettlement)) {
  9630.                 return $daysBetweenIssueAndSettlement;
  9631.             }
  9632.             $daysBetweenIssueAndSettlement *= $daysPerYear;
  9633.             $daysBetweenIssueAndMaturity self::YEARFRAC($issue$maturity$basis);
  9634.             if (!is_numeric($daysBetweenIssueAndMaturity)) {
  9635.                 return $daysBetweenIssueAndMaturity;
  9636.             }
  9637.             $daysBetweenIssueAndMaturity *= $daysPerYear;
  9638.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity$basis);
  9639.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9640.                 return $daysBetweenSettlementAndMaturity;
  9641.             }
  9642.             $daysBetweenSettlementAndMaturity *= $daysPerYear;
  9643.  
  9644.             return (((($daysBetweenIssueAndMaturity $daysPerYear$rate(($price 100(($daysBetweenIssueAndSettlement $daysPerYear$rate))) /
  9645.                    (($price 100(($daysBetweenIssueAndSettlement $daysPerYear$rate))) *
  9646.                    ($daysPerYear $daysBetweenSettlementAndMaturity);
  9647.         }
  9648.         return self::$_errorCodes['value'];
  9649.     }    //    function YIELDMAT()
  9650.  
  9651.  
  9652.     /**
  9653.      *    YIELDDISC
  9654.      *
  9655.      *    Returns the annual yield of a security that pays interest at maturity.
  9656.      *
  9657.      *    @param    mixed    settlement    The security's settlement date.
  9658.      *                                 The security's settlement date is the date after the issue date when the security is traded to the buyer.
  9659.      *    @param    mixed    maturity    The security's maturity date.
  9660.      *                                 The maturity date is the date when the security expires.
  9661.      *    @param    int        price        The security's price per $100 face value.
  9662.      *    @param    int        redemption    The security's redemption value per $100 face value.
  9663.      *    @param    int        basis        The type of day count to use.
  9664.      *                                         0 or omitted    US (NASD) 30/360
  9665.      *                                         1                Actual/actual
  9666.      *                                         2                Actual/360
  9667.      *                                         3                Actual/365
  9668.      *                                         4                European 30/360
  9669.      *    @return    float 
  9670.      */
  9671.     public static function YIELDDISC($settlement$maturity$price$redemption$basis=0{
  9672.         $settlement    self::flattenSingleValue($settlement);
  9673.         $maturity    self::flattenSingleValue($maturity);
  9674.         $price        self::flattenSingleValue($price);
  9675.         $redemption    self::flattenSingleValue($redemption);
  9676.         $basis        = (int) self::flattenSingleValue($basis);
  9677.  
  9678.         //    Validate
  9679.         if (is_numeric($price&& is_numeric($redemption)) {
  9680.             if (($price <= 0|| ($redemption <= 0)) {
  9681.                 return self::$_errorCodes['num'];
  9682.             }
  9683.             $daysPerYear self::_daysPerYear(self::YEAR($settlement),$basis);
  9684.             if (!is_numeric($daysPerYear)) {
  9685.                 return $daysPerYear;
  9686.             }
  9687.             $daysBetweenSettlementAndMaturity self::YEARFRAC($settlement$maturity,$basis);
  9688.             if (!is_numeric($daysBetweenSettlementAndMaturity)) {
  9689.                 return $daysBetweenSettlementAndMaturity;
  9690.             }
  9691.             $daysBetweenSettlementAndMaturity *= $daysPerYear;
  9692.  
  9693.             return (($redemption $price$price($daysPerYear $daysBetweenSettlementAndMaturity);
  9694.         }
  9695.         return self::$_errorCodes['value'];
  9696.     }    //    function YIELDDISC()
  9697.  
  9698.  
  9699.     /**
  9700.      * CELL_ADDRESS
  9701.      *
  9702.      * Returns the straight-line depreciation of an asset for one period
  9703.      *
  9704.      * @param    row            Row number to use in the cell reference
  9705.      * @param    column        Column number to use in the cell reference
  9706.      * @param    relativity    Flag indicating the type of reference to return
  9707.      * @param    sheetText    Name of worksheet to use
  9708.      * @return    string 
  9709.      */
  9710.     public static function CELL_ADDRESS($row$column$relativity=1$referenceStyle=True$sheetText=''{
  9711.         $row        self::flattenSingleValue($row);
  9712.         $column        self::flattenSingleValue($column);
  9713.         $relativity    self::flattenSingleValue($relativity);
  9714.         $sheetText    self::flattenSingleValue($sheetText);
  9715.  
  9716.         if ($sheetText ''{
  9717.             if (strpos($sheetText,' '!== False$sheetText "'".$sheetText."'"}
  9718.             $sheetText .='!';
  9719.         }
  9720.         if ((!is_bool($referenceStyle)) || $referenceStyle{
  9721.             $rowRelative $columnRelative '$';
  9722.             $column PHPExcel_Cell::stringFromColumnIndex($column-1);
  9723.             if (($relativity == 2|| ($relativity == 4)) $columnRelative ''}
  9724.             if (($relativity == 3|| ($relativity == 4)) $rowRelative ''}
  9725.             return $sheetText.$columnRelative.$column.$rowRelative.$row;
  9726.         else {
  9727.             if (($relativity == 2|| ($relativity == 4)) $column '['.$column.']'}
  9728.             if (($relativity == 3|| ($relativity == 4)) $row '['.$row.']'}
  9729.             return $sheetText.'R'.$row.'C'.$column;
  9730.         }
  9731.     }    //    function CELL_ADDRESS()
  9732.  
  9733.  
  9734.     public static function COLUMN($cellAddress=Null{
  9735.         if (is_null($cellAddress|| $cellAddress === ''{
  9736.             return 0;
  9737.         }
  9738.  
  9739.         foreach($cellAddress as $columnKey => $value{
  9740.             return PHPExcel_Cell::columnIndexFromString($columnKey);
  9741.         }
  9742.     }    //    function COLUMN()
  9743.  
  9744.  
  9745.     public static function ROW($cellAddress=Null{
  9746.         if ($cellAddress === Null{
  9747.             return 0;
  9748.         }
  9749.  
  9750.         foreach($cellAddress as $columnKey => $rowValue{
  9751.             foreach($rowValue as $rowKey => $cellValue{
  9752.                 return $rowKey;
  9753.             }
  9754.         }
  9755.     }    //    function ROW()
  9756.  
  9757.  
  9758.     public static function OFFSET($cellAddress=Null,$rows=0,$columns=0,$height=null,$width=null{
  9759.         if ($cellAddress == Null{
  9760.             return 0;
  9761.         }
  9762.  
  9763.         foreach($cellAddress as $startColumnKey => $rowValue{
  9764.             $startColumnIndex PHPExcel_Cell::columnIndexFromString($startColumnKey);
  9765.             foreach($rowValue as $startRowKey => $cellValue{
  9766.                 break 2;
  9767.             }
  9768.         }
  9769.  
  9770.         foreach($cellAddress as $endColumnKey => $rowValue{
  9771.             foreach($rowValue as $endRowKey => $cellValue{
  9772.             }
  9773.         }
  9774.         $endColumnIndex PHPExcel_Cell::columnIndexFromString($endColumnKey);
  9775.  
  9776.         $startColumnIndex += --$columns;
  9777.         $startRowKey += $rows;
  9778.  
  9779.         if ($width == null{
  9780.             $endColumnIndex += $columns -1;
  9781.         else {
  9782.             $endColumnIndex $startColumnIndex $width;
  9783.         }
  9784.         if ($height == null{
  9785.             $endRowKey += $rows;
  9786.         else {
  9787.             $endRowKey $startRowKey $height -1;
  9788.         }
  9789.  
  9790.         if (($startColumnIndex 0|| ($startRowKey <= 0)) {
  9791.             return self::$_errorCodes['reference'];
  9792.         }
  9793.  
  9794.         $startColumnKey PHPExcel_Cell::stringFromColumnIndex($startColumnIndex);
  9795.         $endColumnKey PHPExcel_Cell::stringFromColumnIndex($endColumnIndex);
  9796.  
  9797.         $startCell $startColumnKey.$startRowKey;
  9798.         $endCell $endColumnKey.$endRowKey;
  9799.  
  9800.         if ($startCell == $endCell{
  9801.             return $startColumnKey.$startRowKey;
  9802.         else {
  9803.             return $startColumnKey.$startRowKey.':'.$endColumnKey.$endRowKey;
  9804.         }
  9805.     }    //    function OFFSET()
  9806.  
  9807.  
  9808.     public static function CHOOSE({
  9809.         $chooseArgs func_get_args();
  9810.         $chosenEntry self::flattenSingleValue(array_shift($chooseArgs));
  9811.         $entryCount count($chooseArgs1;
  9812.  
  9813.         if ((is_numeric($chosenEntry)) && (!is_bool($chosenEntry))) {
  9814.             --$chosenEntry;
  9815.         else {
  9816.             return self::$_errorCodes['value'];
  9817.         }
  9818.         $chosenEntry floor($chosenEntry);
  9819.         if (($chosenEntry <= 0|| ($chosenEntry $entryCount)) {
  9820.             return self::$_errorCodes['value'];
  9821.         }
  9822.  
  9823.         if (is_array($chooseArgs[$chosenEntry])) {
  9824.             return self::flattenArray($chooseArgs[$chosenEntry]);
  9825.         else {
  9826.             return $chooseArgs[$chosenEntry];
  9827.         }
  9828.     }    //    function CHOOSE()
  9829.  
  9830.  
  9831.     /**
  9832.      * MATCH
  9833.      * The MATCH function searches for a specified item in a range of cells
  9834.      * @param    lookup_value    The value that you want to match in lookup_array
  9835.      * @param    lookup_array    The range of cells being searched
  9836.      * @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.
  9837.      * @return    integer        the relative position of the found item
  9838.      */
  9839.     public static function MATCH($lookup_value$lookup_array$match_type=1{
  9840.  
  9841.         // flatten the lookup_array
  9842.         $lookup_array self::flattenArray($lookup_array);
  9843.  
  9844.         // flatten lookup_value since it may be a cell reference to a value or the value itself
  9845.         $lookup_value self::flattenSingleValue($lookup_value);
  9846.  
  9847.         // MATCH is not case sensitive
  9848.         $lookup_value strtolower($lookup_value);
  9849.  
  9850.         /*
  9851.         echo "--------------------<br>looking for $lookup_value in <br>";
  9852.         print_r($lookup_array);
  9853.         echo "<br>";
  9854.         //return 1;
  9855.         /**/
  9856.  
  9857.         // **
  9858.         // check inputs
  9859.         // **
  9860.         // lookup_value type has to be number, text, or logical values
  9861.         if (!is_numeric($lookup_value&& !is_string($lookup_value&& !is_bool($lookup_value)){
  9862.             // error: lookup_array should contain only number, text, or logical values
  9863.             //echo "error: lookup_array should contain only number, text, or logical values<br>";
  9864.             return self::$_errorCodes['na'];
  9865.         }
  9866.  
  9867.         // match_type is 0, 1 or -1
  9868.         if ($match_type!==&& $match_type!==-&& $match_type!==1){
  9869.             // error: wrong value for match_type
  9870.             //echo "error: wrong value for match_type<br>";
  9871.             return self::$_errorCodes['na'];
  9872.         }
  9873.  
  9874.         // lookup_array should not be empty
  9875.         if (sizeof($lookup_array)<=0){
  9876.             // error: empty range
  9877.             //echo "error: empty range ".sizeof($lookup_array)."<br>";
  9878.             return self::$_errorCodes['na'];
  9879.         }
  9880.  
  9881.         // lookup_array should contain only number, text, or logical values
  9882.         for ($i=0;$i<sizeof($lookup_array);++$i){
  9883.             // check the type of the value
  9884.             if (!is_numeric($lookup_array[$i]&& !is_string($lookup_array[$i]&& !is_bool($lookup_array[$i])){
  9885.                 // error: lookup_array should contain only number, text, or logical values
  9886.                 //echo "error: lookup_array should contain only number, text, or logical values<br>";
  9887.                 return self::$_errorCodes['na'];
  9888.             }
  9889.             // convert tpo lowercase
  9890.             if (is_string($lookup_array[$i]))
  9891.                 $lookup_array[$istrtolower($lookup_array[$i]);
  9892.         }
  9893.  
  9894.         // if match_type is 1 or -1, the list has to be ordered
  9895.         if($match_type==|| $match_type==-1){
  9896.             // **
  9897.             // iniitialization
  9898.             // store the last value
  9899.             $iLastValue=$lookup_array[0];
  9900.             // **
  9901.             // loop on the cells
  9902.             for ($i=0;$i<sizeof($lookup_array);++$i){
  9903.                 // check ascending order
  9904.                 if(($match_type==&& $lookup_array[$i]<$iLastValue)
  9905.                     // OR check descending order
  9906.                     || ($match_type==-&& $lookup_array[$i]>$iLastValue)){
  9907.                     // error: list is not ordered correctly
  9908.                     //echo "error: list is not ordered correctly<br>";
  9909.                     return self::$_errorCodes['na'];
  9910.                 }
  9911.             }
  9912.         }
  9913.         // **
  9914.         // find the match
  9915.         // **
  9916.         // loop on the cells
  9917.         for ($i=0$i sizeof($lookup_array)++$i){
  9918.             // if match_type is 0 <=> find the first value that is exactly equal to lookup_value
  9919.             if ($match_type==&& $lookup_array[$i]==$lookup_value){
  9920.                 // this is the exact match
  9921.                 return $i+1;
  9922.             }
  9923.             // if match_type is -1 <=> find the smallest value that is greater than or equal to lookup_value
  9924.             if ($match_type==-&& $lookup_array[$i$lookup_value){
  9925.                 if ($i<1){
  9926.                     // 1st cell was allready smaller than the lookup_value
  9927.                     break;
  9928.                 }
  9929.                 else
  9930.                     // the previous cell was the match
  9931.                     return $i;
  9932.             }
  9933.             // if match_type is 1 <=> find the largest value that is less than or equal to lookup_value
  9934.             if ($match_type==&& $lookup_array[$i$lookup_value){
  9935.                 if ($i<1){
  9936.                     // 1st cell was allready bigger than the lookup_value
  9937.                     break;
  9938.                 }
  9939.                 else
  9940.                     // the previous cell was the match
  9941.                     return $i;
  9942.             }
  9943.         }
  9944.         // unsuccessful in finding a match, return #N/A error value
  9945.         //echo "unsuccessful in finding a match<br>";
  9946.         return self::$_errorCodes['na'];
  9947.     }    //    function MATCH()
  9948.  
  9949.  
  9950.     /**
  9951.      * Uses an index to choose a value from a reference or array
  9952.      * implemented: Return the value of a specified cell or array of cells    Array form
  9953.      * not implemented: Return a reference to specified cells    Reference form
  9954.      *
  9955.      * @param    range_array    a range of cells or an array constant
  9956.      * @param    row_num        selects the row in array from which to return a value. If row_num is omitted, column_num is required.
  9957.      * @param    column_num    selects the column in array from which to return a value. If column_num is omitted, row_num is required.
  9958.      */
  9959.     public static function INDEX($arrayValues,$rowNum 0,$columnNum 0{
  9960.  
  9961.         if (($rowNum 0|| ($columnNum 0)) {
  9962.             return self::$_errorCodes['value'];
  9963.         }
  9964.  
  9965.         $rowKeys array_keys($arrayValues);
  9966.         $columnKeys array_keys($arrayValues[$rowKeys[0]]);
  9967.         if ($columnNum count($columnKeys)) {
  9968.             return self::$_errorCodes['value'];
  9969.         elseif ($columnNum == 0{
  9970.             if ($rowNum == 0{
  9971.                 return $arrayValues;
  9972.             }
  9973.             $rowNum $rowKeys[--$rowNum];
  9974.             $returnArray array();
  9975.             foreach($arrayValues as $arrayColumn{
  9976.                 $returnArray[$arrayColumn[$rowNum];
  9977.             }
  9978.             return $returnArray;
  9979.         }
  9980.         $columnNum $columnKeys[--$columnNum];
  9981.         if ($rowNum count($rowKeys)) {
  9982.             return self::$_errorCodes['value'];
  9983.         elseif ($rowNum == 0{
  9984.             return $arrayValues[$columnNum];
  9985.         }
  9986.         $rowNum $rowKeys[--$rowNum];
  9987.  
  9988.         return $arrayValues[$rowNum][$columnNum];
  9989.     }    //    function INDEX()
  9990.  
  9991.  
  9992.     /**
  9993.      * SYD
  9994.      *
  9995.      * Returns the sum-of-years' digits depreciation of an asset for a specified period.
  9996.      *
  9997.      * @param    cost        Initial cost of the asset
  9998.      * @param    salvage        Value at the end of the depreciation
  9999.      * @param    life        Number of periods over which the asset is depreciated
  10000.      * @param    period        Period
  10001.      * @return    float 
  10002.      */
  10003.     public static function SYD($cost$salvage$life$period{
  10004.         $cost        self::flattenSingleValue($cost);
  10005.         $salvage    self::flattenSingleValue($salvage);
  10006.         $life        self::flattenSingleValue($life);
  10007.         $period        self::flattenSingleValue($period);
  10008.  
  10009.         // Calculate
  10010.         if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period))) {
  10011.             if (($life 1|| ($salvage $life|| ($period $life)) {
  10012.                 return self::$_errorCodes['num'];
  10013.             }
  10014.             return (($cost $salvage($life $period 12($life ($life 1));
  10015.         }
  10016.         return self::$_errorCodes['value'];
  10017.     }    //    function SYD()
  10018.  
  10019.  
  10020.     /**
  10021.      * TRANSPOSE
  10022.      *
  10023.      * @param    array    $matrixData    A matrix of values
  10024.      * @return    array 
  10025.      *
  10026.      *  Unlike the Excel TRANSPOSE function, which will only work on a single row or column, this function will transpose a full matrix.
  10027.      */
  10028.     public static function TRANSPOSE($matrixData{
  10029.         $returnMatrix array();
  10030.         if (!is_array($matrixData)) $matrixData array(array($matrixData))}
  10031.  
  10032.         $column 0;
  10033.         foreach($matrixData as $matrixRow{
  10034.             $row 0;
  10035.             foreach($matrixRow as $matrixCell{
  10036.                 $returnMatrix[$column][$row$matrixCell;
  10037.                 ++$row;
  10038.             }
  10039.             ++$column;
  10040.         }
  10041.         return $returnMatrix;
  10042.     }    //    function TRANSPOSE()
  10043.  
  10044.  
  10045.     /**
  10046.      * MMULT
  10047.      *
  10048.      * @param    array    $matrixData1    A matrix of values
  10049.      * @param    array    $matrixData2    A matrix of values
  10050.      * @return    array 
  10051.      */
  10052.     public static function MMULT($matrixData1,$matrixData2{
  10053.         $matrixAData $matrixBData array();
  10054.         if (!is_array($matrixData1)) $matrixData1 array(array($matrixData1))}
  10055.         if (!is_array($matrixData2)) $matrixData2 array(array($matrixData2))}
  10056.  
  10057.         $rowA 0;
  10058.         foreach($matrixData1 as $matrixRow{
  10059.             $columnA 0;
  10060.             foreach($matrixRow as $matrixCell{
  10061.                 if ((is_string($matrixCell)) || ($matrixCell === null)) {
  10062.                     return self::$_errorCodes['value'];
  10063.                 }
  10064.                 $matrixAData[$rowA][$columnA$matrixCell;
  10065.                 ++$columnA;
  10066.             }
  10067.             ++$rowA;
  10068.         }
  10069.         try {
  10070.             $matrixA new Matrix($matrixAData);
  10071.             $rowB 0;
  10072.             foreach($matrixData2 as $matrixRow{
  10073.                 $columnB 0;
  10074.                 foreach($matrixRow as $matrixCell{
  10075.                     if ((is_string($matrixCell)) || ($matrixCell === null)) {
  10076.                         return self::$_errorCodes['value'];
  10077.                     }
  10078.                     $matrixBData[$rowB][$columnB$matrixCell;
  10079.                     ++$columnB;
  10080.                 }
  10081.                 ++$rowB;
  10082.             }
  10083.             $matrixB new Matrix($matrixBData);
  10084.  
  10085.             if (($rowA != $columnB|| ($rowB != $columnA)) {
  10086.                 return self::$_errorCodes['value'];
  10087.             }
  10088.  
  10089.             return $matrixA->times($matrixB)->getArray();
  10090.         catch (Exception $ex{
  10091.             return self::$_errorCodes['value'];
  10092.         }
  10093.     }    //    function MMULT()
  10094.  
  10095.  
  10096.     /**
  10097.      * MINVERSE
  10098.      *
  10099.      * @param    array    $matrixValues    A matrix of values
  10100.      * @return    array 
  10101.      */
  10102.     public static function MINVERSE($matrixValues{
  10103.         $matrixData array();
  10104.         if (!is_array($matrixValues)) $matrixValues array(array($matrixValues))}
  10105.  
  10106.         $row $maxColumn 0;
  10107.         foreach($matrixValues as $matrixRow{
  10108.             $column 0;
  10109.             foreach($matrixRow as $matrixCell{
  10110.                 if ((is_string($matrixCell)) || ($matrixCell === null)) {
  10111.                     return self::$_errorCodes['value'];
  10112.                 }
  10113.                 $matrixData[$column][$row$matrixCell;
  10114.                 ++$column;
  10115.             }
  10116.             if ($column $maxColumn$maxColumn $column}
  10117.             ++$row;
  10118.         }
  10119.         if ($row != $maxColumnreturn self::$_errorCodes['value']}
  10120.  
  10121.         try {
  10122.             $matrix new Matrix($matrixData);
  10123.             return $matrix->inverse()->getArray();
  10124.         catch (Exception $ex{
  10125.             return self::$_errorCodes['value'];
  10126.         }
  10127.     }    //    function MINVERSE()
  10128.  
  10129.  
  10130.     /**
  10131.      * MDETERM
  10132.      *
  10133.      * @param    array    $matrixValues    A matrix of values
  10134.      * @return    float 
  10135.      */
  10136.     public static function MDETERM($matrixValues{
  10137.         $matrixData array();
  10138.         if (!is_array($matrixValues)) $matrixValues array(array($matrixValues))}
  10139.  
  10140.         $row $maxColumn 0;
  10141.         foreach($matrixValues as $matrixRow{
  10142.             $column 0;
  10143.             foreach($matrixRow as $matrixCell{
  10144.                 if ((is_string($matrixCell)) || ($matrixCell === null)) {
  10145.                     return self::$_errorCodes['value'];
  10146.                 }
  10147.                 $matrixData[$column][$row$matrixCell;
  10148.                 ++$column;
  10149.             }
  10150.             if ($column $maxColumn$maxColumn $column}
  10151.             ++$row;
  10152.         }
  10153.         if ($row != $maxColumnreturn self::$_errorCodes['value']}
  10154.  
  10155.         try {
  10156.             $matrix new Matrix($matrixData);
  10157.             return $matrix->det();
  10158.         catch (Exception $ex{
  10159.             return self::$_errorCodes['value'];
  10160.         }
  10161.     }    //    function MDETERM()
  10162.  
  10163.  
  10164.     /**
  10165.      * SUMX2MY2
  10166.      *
  10167.      * @param    mixed    $value    Value to check
  10168.      * @return    float 
  10169.      */
  10170.     public static function SUMX2MY2($matrixData1,$matrixData2{
  10171.         $array1 self::flattenArray($matrixData1);
  10172.         $array2 self::flattenArray($matrixData2);
  10173.         $count1 count($array1);
  10174.         $count2 count($array2);
  10175.         if ($count1 $count2{
  10176.             $count $count1;
  10177.         else {
  10178.             $count $count2;
  10179.         }
  10180.  
  10181.         $result 0;
  10182.         for ($i 0$i $count++$i{
  10183.             if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
  10184.                 ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
  10185.                 $result += ($array1[$i$array1[$i]($array2[$i$array2[$i]);
  10186.             }
  10187.         }
  10188.  
  10189.         return $result;
  10190.     }    //    function SUMX2MY2()
  10191.  
  10192.  
  10193.     /**
  10194.      * SUMX2PY2
  10195.      *
  10196.      * @param    mixed    $value    Value to check
  10197.      * @return    float 
  10198.      */
  10199.     public static function SUMX2PY2($matrixData1,$matrixData2{
  10200.         $array1 self::flattenArray($matrixData1);
  10201.         $array2 self::flattenArray($matrixData2);
  10202.         $count1 count($array1);
  10203.         $count2 count($array2);
  10204.         if ($count1 $count2{
  10205.             $count $count1;
  10206.         else {
  10207.             $count $count2;
  10208.         }
  10209.  
  10210.         $result 0;
  10211.         for ($i 0$i $count++$i{
  10212.             if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
  10213.                 ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
  10214.                 $result += ($array1[$i$array1[$i]($array2[$i$array2[$i]);
  10215.             }
  10216.         }
  10217.  
  10218.         return $result;
  10219.     }    //    function SUMX2PY2()
  10220.  
  10221.  
  10222.     /**
  10223.      * SUMXMY2
  10224.      *
  10225.      * @param    mixed    $value    Value to check
  10226.      * @return    float 
  10227.      */
  10228.     public static function SUMXMY2($matrixData1,$matrixData2{
  10229.         $array1 self::flattenArray($matrixData1);
  10230.         $array2 self::flattenArray($matrixData2);
  10231.         $count1 count($array1);
  10232.         $count2 count($array2);
  10233.         if ($count1 $count2{
  10234.             $count $count1;
  10235.         else {
  10236.             $count $count2;
  10237.         }
  10238.  
  10239.         $result 0;
  10240.         for ($i 0$i $count++$i{
  10241.             if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
  10242.                 ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
  10243.                 $result += ($array1[$i$array2[$i]($array1[$i$array2[$i]);
  10244.             }
  10245.         }
  10246.  
  10247.         return $result;
  10248.     }    //    function SUMXMY2()
  10249.  
  10250.  
  10251.     /**
  10252.     * VLOOKUP
  10253.     * 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.
  10254.     * @param    lookup_value    The value that you want to match in lookup_array
  10255.     * @param    lookup_array    The range of cells being searched
  10256.     * @param    index_number    The column number in table_array from which the matching value must be returned. The first column is 1.
  10257.     * @param    not_exact_match    Determines if you are looking for an exact match based on lookup_value.
  10258.     * @return    mixed            The value of the found cell
  10259.     */
  10260.     public static function VLOOKUP($lookup_value$lookup_array$index_number$not_exact_match=true{
  10261.         // index_number must be greater than or equal to 1
  10262.         if ($index_number 1{
  10263.             return self::$_errorCodes['value'];
  10264.         }
  10265.  
  10266.         // index_number must be less than or equal to the number of columns in lookup_array
  10267.         if ($index_number count($lookup_array)) {
  10268.             return self::$_errorCodes['reference'];
  10269.         }
  10270.  
  10271.         // re-index lookup_array with numeric keys starting at 1
  10272.         array_unshift($lookup_arrayarray());
  10273.         $lookup_array array_slice(array_values($lookup_array)1count($lookup_array)true);
  10274.  
  10275.         // look for an exact match
  10276.         $row_number array_search($lookup_value$lookup_array[1]);
  10277.  
  10278.         // if an exact match is required, we have what we need to return an appropriate response
  10279.         if ($not_exact_match == false{
  10280.             if ($row_number === false{
  10281.                 return self::$_errorCodes['na'];
  10282.             else {
  10283.                 return $lookup_array[$index_number][$row_number];
  10284.             }
  10285.         }
  10286.  
  10287.         // TODO: The VLOOKUP spec in Excel states that, at this point, we should search for
  10288.         // the highest value that is less than lookup_value. However, documentation on how string
  10289.         // values should be treated here is sparse.
  10290.         return self::$_errorCodes['na'];
  10291.     }    //    function VLOOKUP()
  10292.  
  10293.     /**
  10294.     * LOOKUP
  10295.     * The LOOKUP function searches for value either from a one-row or one-column range or from an array.
  10296.     * @param    lookup_value    The value that you want to match in lookup_array
  10297.     * @param    lookup_vector    The range of cells being searched
  10298.     * @param    result_vector    The column from which the matching value must be returned
  10299.     * @return    mixed            The value of the found cell
  10300.     */
  10301.     public static function LOOKUP($lookup_value$lookup_vector$result_vector=null{
  10302.  
  10303.         // check for LOOKUP Syntax (view Excel documentation)
  10304.         ifis_null($result_vector) )
  10305.         {
  10306.         // TODO: Syntax 2 (array)
  10307.         else {
  10308.         // Syntax 1 (vector)
  10309.             // get key (column or row) of lookup_vector
  10310.             $kl key($lookup_vector);
  10311.             // check if lookup_value exists in lookup_vector
  10312.             ifin_array($lookup_value$lookup_vector[$kl]) )
  10313.             {
  10314.             // FOUND IT! Get key of lookup_vector
  10315.                 $k_res array_search($lookup_value$lookup_vector[$kl]);
  10316.             else {
  10317.             // value NOT FOUND
  10318.                 // Get the smallest value in lookup_vector
  10319.                 // The LOOKUP spec in Excel states --> IMPORTANT - The values in lookup_vector must be placed in ascending order!
  10320.                 $ksv key($lookup_vector[$kl]);
  10321.                 $smallest_value $lookup_vector[$kl][$ksv];
  10322.                 // If lookup_value is smaller than the smallest value in lookup_vector, LOOKUP gives the #N/A error value.
  10323.                 if$lookup_value $smallest_value )
  10324.                 {
  10325.                     return self::$_errorCodes['na'];
  10326.                 else {
  10327.                     // If LOOKUP can't find the lookup_value, it matches the largest value in lookup_vector that is less than or equal to lookup_value.
  10328.                     // IMPORTANT : In Excel Documentation is not clear what happen if lookup_value is text!
  10329.                     foreach$lookup_vector[$klAS $kk => $value )
  10330.                     {
  10331.                         if$lookup_value >= $value )
  10332.                         {
  10333.                             $k_res $kk;
  10334.                         }
  10335.                     }
  10336.                 }
  10337.             }
  10338.  
  10339.             // Returns a value from the same position in result_vector
  10340.             // get key (column or row) of result_vector
  10341.             $kr key($result_vector);
  10342.             ifisset($result_vector[$kr][$k_res]) )
  10343.             {
  10344.                 return $result_vector[$kr][$k_res];
  10345.             else {
  10346.                 // TODO: In Excel Documentation is not clear what happen here...
  10347.             }
  10348.         }
  10349.      }    //    function LOOKUP()
  10350.  
  10351.  
  10352.     /**
  10353.      * Flatten multidemensional array
  10354.      *
  10355.      * @param    array    $array    Array to be flattened
  10356.      * @return    array    Flattened array
  10357.      */
  10358.     public static function flattenArray($array{
  10359.         if(!is_array $array ) ){
  10360.             $array array $array );
  10361.         }
  10362.  
  10363.         $arrayValues array();
  10364.  
  10365.         foreach ($array as $value{
  10366.             if (is_scalar($value)) {
  10367.                 $arrayValues[self::flattenSingleValue($value);
  10368.             elseif (is_array($value)) {
  10369.                 $arrayValues array_merge($arrayValuesself::flattenArray($value));
  10370.             else {
  10371.                 $arrayValues[$value;
  10372.             }
  10373.         }
  10374.  
  10375.         return $arrayValues;
  10376.     }    //    function flattenArray()
  10377.  
  10378.  
  10379.     /**
  10380.      * Convert an array with one element to a flat value
  10381.      *
  10382.      * @param    mixed        $value        Array or flat value
  10383.      * @return    mixed 
  10384.      */
  10385.     public static function flattenSingleValue($value ''{
  10386.         if (is_array($value)) {
  10387.             $value self::flattenSingleValue(array_pop($value));
  10388.         }
  10389.         return $value;
  10390.     }    //    function flattenSingleValue()
  10391.  
  10392. }    //    class PHPExcel_Calculation_Functions
  10393.  
  10394.  
  10395. //
  10396. //    There are a few mathematical functions that aren't available on all versions of PHP for all platforms
  10397. //    These functions aren't available in Windows implementations of PHP prior to version 5.3.0
  10398. //    So we test if they do exist for this version of PHP/operating platform; and if not we create them
  10399. //
  10400. if (!function_exists('acosh')) {
  10401.     function acosh($x{
  10402.         return log(sqrt(($x 12sqrt(($x 12));
  10403.     }    //    function acosh()
  10404. }
  10405.  
  10406. if (!function_exists('asinh')) {
  10407.     function asinh($x{
  10408.         return log($x sqrt($x $x));
  10409.     }    //    function asinh()
  10410. }
  10411.  
  10412. if (!function_exists('atanh')) {
  10413.     function atanh($x{
  10414.         return (log($xlog($x)) 2;
  10415.     }    //    function atanh()
  10416. }
  10417.  
  10418. if (!function_exists('money_format')) {
  10419.     function money_format($format$number{
  10420.         $regex array'/%((?:[\^!\-]|\+|\(|\=.)*)([0-9]+)?(?:#([0-9]+))?',
  10421.                          '(?:\.([0-9]+))?([in%])/'
  10422.                       );
  10423.         $regex implode(''$regex);
  10424.         if (setlocale(LC_MONETARYnull== ''{
  10425.             setlocale(LC_MONETARY'');
  10426.         }
  10427.         $locale localeconv();
  10428.         $number floatval($number);
  10429.         if (!preg_match($regex$format$fmatch)) {
  10430.             trigger_error("No format specified or invalid format"E_USER_WARNING);
  10431.             return $number;
  10432.         }
  10433.         $flags array'fillchar'    => preg_match('/\=(.)/'$fmatch[1]$match$match[1' ',
  10434.                         'nogroup'    => preg_match('/\^/'$fmatch[1]0,
  10435.                         'usesignal'    => preg_match('/\+|\(/'$fmatch[1]$match$match[0'+',
  10436.                         'nosimbol'    => preg_match('/\!/'$fmatch[1]0,
  10437.                         'isleft'    => preg_match('/\-/'$fmatch[1]0
  10438.                       );
  10439.         $width    trim($fmatch[2]? (int)$fmatch[20;
  10440.         $left    trim($fmatch[3]? (int)$fmatch[30;
  10441.         $right    trim($fmatch[4]? (int)$fmatch[4$locale['int_frac_digits'];
  10442.         $conversion $fmatch[5];
  10443.         $positive true;
  10444.         if ($number 0{
  10445.             $positive false;
  10446.             $number *= -1;
  10447.         }
  10448.         $letter $positive 'p' 'n';
  10449.         $prefix $suffix $cprefix $csuffix $signal '';
  10450.         if (!$positive{
  10451.             $signal $locale['negative_sign'];
  10452.             switch (true{
  10453.                 case $locale['n_sign_posn'== || $flags['usesignal'== '(':
  10454.                     $prefix '(';
  10455.                     $suffix ')';
  10456.                     break;
  10457.                 case $locale['n_sign_posn'== 1:
  10458.                     $prefix $signal;
  10459.                     break;
  10460.                 case $locale['n_sign_posn'== 2:
  10461.                     $suffix $signal;
  10462.                     break;
  10463.                 case $locale['n_sign_posn'== 3:
  10464.                     $cprefix $signal;
  10465.                     break;
  10466.                 case $locale['n_sign_posn'== 4:
  10467.                     $csuffix $signal;
  10468.                     break;
  10469.             }
  10470.         }
  10471.         if (!$flags['nosimbol']{
  10472.             $currency $cprefix;
  10473.             $currency .= ($conversion == 'i' $locale['int_curr_symbol'$locale['currency_symbol']);
  10474.             $currency .= $csuffix;
  10475.             $currency iconv('ISO-8859-1','UTF-8',$currency);
  10476.         else {
  10477.             $currency '';
  10478.         }
  10479.         $space $locale["{$letter}_sep_by_space"' ' '';
  10480.  
  10481.         $number number_format($number$right$locale['mon_decimal_point']$flags['nogroup''' $locale['mon_thousands_sep');
  10482.         $number explode($locale['mon_decimal_point']$number);
  10483.  
  10484.         $n strlen($prefixstrlen($currency);
  10485.         if ($left && $left $n{
  10486.             if ($flags['isleft']{
  10487.                 $number[0.= str_repeat($flags['fillchar']$left $n);
  10488.             else {
  10489.                 $number[0str_repeat($flags['fillchar']$left $n$number[0];
  10490.             }
  10491.         }
  10492.         $number implode($locale['mon_decimal_point']$number);
  10493.         if ($locale["{$letter}_cs_precedes"]{
  10494.             $number $prefix $currency $space $number $suffix;
  10495.         else {
  10496.             $number $prefix $number $space $currency $suffix;
  10497.         }
  10498.         if ($width 0{
  10499.             $number str_pad($number$width$flags['fillchar']$flags['isleft'STR_PAD_RIGHT STR_PAD_LEFT);
  10500.         }
  10501.         $format str_replace($fmatch[0]$number$format);
  10502.         return $format;
  10503.     }    //    function money_format()
  10504. }

Documentation generated on Mon, 10 Aug 2009 08:05:33 +0200 by phpDocumentor 1.4.1