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

Source for file Functions.php

Documentation is available at Functions.php

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

Documentation generated on Wed, 22 Apr 2009 08:59:33 +0200 by phpDocumentor 1.4.1