diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php
index c5dbaa53..80a6fbcc 100644
--- a/src/PhpSpreadsheet/Calculation/Calculation.php
+++ b/src/PhpSpreadsheet/Calculation/Calculation.php
@@ -328,17 +328,17 @@ class Calculation
],
'AVEDEV' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical\Averages::class, 'AVEDEV'],
+ 'functionCall' => [Statistical\Averages::class, 'averageDeviations'],
'argumentCount' => '1+',
],
'AVERAGE' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical\Averages::class, 'AVERAGE'],
+ 'functionCall' => [Statistical\Averages::class, 'average'],
'argumentCount' => '1+',
],
'AVERAGEA' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical\Averages::class, 'AVERAGEA'],
+ 'functionCall' => [Statistical\Averages::class, 'averageA'],
'argumentCount' => '1+',
],
'AVERAGEIF' => [
@@ -383,7 +383,7 @@ class Calculation
],
'BETADIST' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'BETADIST'],
+ 'functionCall' => [Statistical\Distributions\Beta::class, 'distribution'],
'argumentCount' => '3-5',
],
'BETA.DIST' => [
@@ -393,12 +393,12 @@ class Calculation
],
'BETAINV' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'BETAINV'],
+ 'functionCall' => [Statistical\Distributions\Beta::class, 'inverse'],
'argumentCount' => '3-5',
],
'BETA.INV' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'BETAINV'],
+ 'functionCall' => [Statistical\Distributions\Beta::class, 'inverse'],
'argumentCount' => '3-5',
],
'BIN2DEC' => [
@@ -488,7 +488,7 @@ class Calculation
],
'CHIDIST' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'CHIDIST'],
+ 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distribution'],
'argumentCount' => '2',
],
'CHISQ.DIST' => [
@@ -498,12 +498,12 @@ class Calculation
],
'CHISQ.DIST.RT' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'CHIDIST'],
+ 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distribution'],
'argumentCount' => '2',
],
'CHIINV' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'CHIINV'],
+ 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverse'],
'argumentCount' => '2',
],
'CHISQ.INV' => [
@@ -513,7 +513,7 @@ class Calculation
],
'CHISQ.INV.RT' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'CHIINV'],
+ 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverse'],
'argumentCount' => '2',
],
'CHITEST' => [
@@ -1055,12 +1055,12 @@ class Calculation
],
'FISHER' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'FISHER'],
+ 'functionCall' => [Statistical\Distributions\Fisher::class, 'distribution'],
'argumentCount' => '1',
],
'FISHERINV' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'FISHERINV'],
+ 'functionCall' => [Statistical\Distributions\Fisher::class, 'inverse'],
'argumentCount' => '1',
],
'FIXED' => [
@@ -1147,37 +1147,37 @@ class Calculation
],
'GAMMA' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'GAMMAFunction'],
+ 'functionCall' => [Statistical\Distributions\Gamma::class, 'gamma'],
'argumentCount' => '1',
],
'GAMMADIST' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'GAMMADIST'],
+ 'functionCall' => [Statistical\Distributions\Gamma::class, 'distribution'],
'argumentCount' => '4',
],
'GAMMA.DIST' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'GAMMADIST'],
+ 'functionCall' => [Statistical\Distributions\Gamma::class, 'distribution'],
'argumentCount' => '4',
],
'GAMMAINV' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'GAMMAINV'],
+ 'functionCall' => [Statistical\Distributions\Gamma::class, 'inverse'],
'argumentCount' => '3',
],
'GAMMA.INV' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'GAMMAINV'],
+ 'functionCall' => [Statistical\Distributions\Gamma::class, 'inverse'],
'argumentCount' => '3',
],
'GAMMALN' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'GAMMALN'],
+ 'functionCall' => [Statistical\Distributions\Gamma::class, 'ln'],
'argumentCount' => '1',
],
'GAMMALN.PRECISE' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'GAMMALN'],
+ 'functionCall' => [Statistical\Distributions\Gamma::class, 'ln'],
'argumentCount' => '1',
],
'GAUSS' => [
@@ -1646,7 +1646,7 @@ class Calculation
],
'MEDIAN' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'MEDIAN'],
+ 'functionCall' => [Statistical\Averages::class, 'median'],
'argumentCount' => '1+',
],
'MEDIANIF' => [
@@ -1706,7 +1706,7 @@ class Calculation
],
'MODE' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'MODE'],
+ 'functionCall' => [Statistical\Averages::class, 'mode'],
'argumentCount' => '1+',
],
'MODE.MULT' => [
@@ -1716,7 +1716,7 @@ class Calculation
],
'MODE.SNGL' => [
'category' => Category::CATEGORY_STATISTICAL,
- 'functionCall' => [Statistical::class, 'MODE'],
+ 'functionCall' => [Statistical\Averages::class, 'mode'],
'argumentCount' => '1+',
],
'MONTH' => [
diff --git a/src/PhpSpreadsheet/Calculation/Database/DAverage.php b/src/PhpSpreadsheet/Calculation/Database/DAverage.php
index 738cb78e..e30842dc 100644
--- a/src/PhpSpreadsheet/Calculation/Database/DAverage.php
+++ b/src/PhpSpreadsheet/Calculation/Database/DAverage.php
@@ -38,7 +38,7 @@ class DAverage extends DatabaseAbstract
return null;
}
- return Averages::AVERAGE(
+ return Averages::average(
self::getFilteredColumn($database, $field, $criteria)
);
}
diff --git a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php
index 76be7e12..7bb7fb40 100644
--- a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php
+++ b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php
@@ -22,13 +22,13 @@ class Amortization
* Excel Function:
* AMORDEGRC(cost,purchased,firstPeriod,salvage,period,rate[,basis])
*
- * @param float $cost The cost of the asset
+ * @param mixed (float) $cost The cost of the asset
* @param mixed $purchased Date of the purchase of the asset
* @param mixed $firstPeriod Date of the end of the first period
* @param mixed $salvage The salvage value at the end of the life of the asset
- * @param float $period The period
- * @param float $rate Rate of depreciation
- * @param int $basis The type of day count to use.
+ * @param mixed (float) $period The period
+ * @param mixed (float) $rate Rate of depreciation
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
@@ -88,13 +88,13 @@ class Amortization
* Excel Function:
* AMORLINC(cost,purchased,firstPeriod,salvage,period,rate[,basis])
*
- * @param float $cost The cost of the asset
+ * @param mixed (float) $cost The cost of the asset
* @param mixed $purchased Date of the purchase of the asset
* @param mixed $firstPeriod Date of the end of the first period
* @param mixed $salvage The salvage value at the end of the life of the asset
- * @param float $period The period
- * @param float $rate Rate of depreciation
- * @param int $basis The type of day count to use.
+ * @param mixed (float) $period The period
+ * @param mixed (float) $rate Rate of depreciation
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
diff --git a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php
index 835ef633..d0efd689 100644
--- a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php
+++ b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php
@@ -29,12 +29,12 @@ class Coupons
* date when the security is traded to the buyer.
* @param mixed $maturity The security's maturity date.
* The maturity date is the date when the security expires.
- * @param int $frequency the number of coupon payments per year.
+ * @param mixed (int) $frequency the number of coupon payments per year.
* Valid frequency values are:
* 1 Annual
* 2 Semi-Annual
* 4 Quarterly
- * @param int $basis The type of day count to use.
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
@@ -88,7 +88,7 @@ class Coupons
* 1 Annual
* 2 Semi-Annual
* 4 Quarterly
- * @param int $basis The type of day count to use.
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
@@ -153,7 +153,7 @@ class Coupons
* 1 Annual
* 2 Semi-Annual
* 4 Quarterly
- * @param int $basis The type of day count to use.
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
@@ -211,7 +211,7 @@ class Coupons
* 1 Annual
* 2 Semi-Annual
* 4 Quarterly
- * @param int $basis The type of day count to use.
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
@@ -260,7 +260,7 @@ class Coupons
* 1 Annual
* 2 Semi-Annual
* 4 Quarterly
- * @param int $basis The type of day count to use.
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
@@ -309,7 +309,7 @@ class Coupons
* 1 Annual
* 2 Semi-Annual
* 4 Quarterly
- * @param int $basis The type of day count to use.
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
diff --git a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php
index 9236b4d4..173e29bb 100644
--- a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php
+++ b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php
@@ -20,14 +20,14 @@ class Depreciation
* Excel Function:
* DB(cost,salvage,life,period[,month])
*
- * @param float $cost Initial cost of the asset
- * @param float $salvage Value at the end of the depreciation.
+ * @param mixed (float) $cost Initial cost of the asset
+ * @param mixed (float) $salvage Value at the end of the depreciation.
* (Sometimes called the salvage value of the asset)
- * @param int $life Number of periods over which the asset is depreciated.
+ * @param mixed (int) $life Number of periods over which the asset is depreciated.
* (Sometimes called the useful life of the asset)
- * @param int $period The period for which you want to calculate the
+ * @param mixed (int) $period The period for which you want to calculate the
* depreciation. Period must use the same units as life.
- * @param int $month Number of months in the first year. If month is omitted,
+ * @param mixed (int) $month Number of months in the first year. If month is omitted,
* it defaults to 12.
*
* @return float|string
@@ -85,14 +85,14 @@ class Depreciation
* Excel Function:
* DDB(cost,salvage,life,period[,factor])
*
- * @param float $cost Initial cost of the asset
- * @param float $salvage Value at the end of the depreciation.
+ * @param mixed (float) $cost Initial cost of the asset
+ * @param mixed (float) $salvage Value at the end of the depreciation.
* (Sometimes called the salvage value of the asset)
- * @param int $life Number of periods over which the asset is depreciated.
+ * @param mixed (int) $life Number of periods over which the asset is depreciated.
* (Sometimes called the useful life of the asset)
- * @param int $period The period for which you want to calculate the
+ * @param mixed (int) $period The period for which you want to calculate the
* depreciation. Period must use the same units as life.
- * @param float $factor The rate at which the balance declines.
+ * @param mixed (float) $factor The rate at which the balance declines.
* If factor is omitted, it is assumed to be 2 (the
* double-declining balance method).
*
diff --git a/src/PhpSpreadsheet/Calculation/Financial/Dollar.php b/src/PhpSpreadsheet/Calculation/Financial/Dollar.php
index e85b00c6..36326a60 100644
--- a/src/PhpSpreadsheet/Calculation/Financial/Dollar.php
+++ b/src/PhpSpreadsheet/Calculation/Financial/Dollar.php
@@ -16,8 +16,8 @@ class Dollar
* Excel Function:
* DOLLARDE(fractional_dollar,fraction)
*
- * @param float $fractionalDollar Fractional Dollar
- * @param int $fraction Fraction
+ * @param mixed (float) $fractionalDollar Fractional Dollar
+ * @param mixed (int) $fraction Fraction
*
* @return float|string
*/
@@ -52,8 +52,8 @@ class Dollar
* Excel Function:
* DOLLARFR(decimal_dollar,fraction)
*
- * @param float $decimalDollar Decimal Dollar
- * @param int $fraction Fraction
+ * @param mixed (float) $decimalDollar Decimal Dollar
+ * @param mixed (int) $fraction Fraction
*
* @return float|string
*/
diff --git a/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php b/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php
index be7e6fd7..04b43e32 100644
--- a/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php
+++ b/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php
@@ -15,8 +15,8 @@ class InterestRate
* Excel Function:
* EFFECT(nominal_rate,npery)
*
- * @param float $nominalRate Nominal interest rate
- * @param int $periodsPerYear Number of compounding payments per year
+ * @param mixed (float) $nominalRate Nominal interest rate
+ * @param mixed (int) $periodsPerYear Number of compounding payments per year
*
* @return float|string
*/
@@ -43,8 +43,8 @@ class InterestRate
*
* Returns the nominal interest rate given the effective rate and the number of compounding payments per year.
*
- * @param float $effectiveRate Effective interest rate
- * @param int $periodsPerYear Number of compounding payments per year
+ * @param mixed (float) $effectiveRate Effective interest rate
+ * @param mixed (int) $periodsPerYear Number of compounding payments per year
*
* @return float|string Result, or a string containing an error
*/
diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php
index a5f0fb46..14be7f84 100644
--- a/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php
+++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php
@@ -20,14 +20,14 @@ class Price extends BaseValidations
* is traded to the buyer.
* @param mixed $maturity The security's maturity date.
* The maturity date is the date when the security expires.
- * @param float $rate the security's annual coupon rate
- * @param float $yield the security's annual yield
- * @param float $redemption The number of coupon payments per year.
+ * @param mixed (float) $rate the security's annual coupon rate
+ * @param mixed (float) $yield the security's annual yield
+ * @param mixed (float) $redemption The number of coupon payments per year.
* For annual payments, frequency = 1;
* for semiannual, frequency = 2;
* for quarterly, frequency = 4.
- * @param int $frequency
- * @param int $basis The type of day count to use.
+ * @param mixed (int) $frequency
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
@@ -87,9 +87,9 @@ class Price extends BaseValidations
* is traded to the buyer.
* @param mixed $maturity The security's maturity date.
* The maturity date is the date when the security expires.
- * @param float $discount The security's discount rate
- * @param float $redemption The security's redemption value per $100 face value
- * @param int $basis The type of day count to use.
+ * @param mixed (float) $discount The security's discount rate
+ * @param mixed (float) $redemption The security's redemption value per $100 face value
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
@@ -137,9 +137,9 @@ class Price extends BaseValidations
* @param mixed $maturity The security's maturity date.
* The maturity date is the date when the security expires.
* @param mixed $issue The security's issue date
- * @param float $rate The security's interest rate at date of issue
- * @param float $yield The security's annual yield
- * @param int $basis The type of day count to use.
+ * @param mixed (float) $rate The security's interest rate at date of issue
+ * @param mixed (float) $yield The security's annual yield
+ * @param mixed (int) $basis The type of day count to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
diff --git a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php
index 8f8fa530..3177124a 100644
--- a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php
+++ b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php
@@ -17,7 +17,7 @@ class TreasuryBill
* when the Treasury bill is traded to the buyer.
* @param mixed $maturity The Treasury bill's maturity date.
* The maturity date is the date when the Treasury bill expires.
- * @param int $discount The Treasury bill's discount rate
+ * @param mixed (int) $discount The Treasury bill's discount rate
*
* @return float|string Result, or a string containing an error
*/
@@ -65,7 +65,7 @@ class TreasuryBill
* when the Treasury bill is traded to the buyer.
* @param mixed $maturity The Treasury bill's maturity date.
* The maturity date is the date when the Treasury bill expires.
- * @param int $discount The Treasury bill's discount rate
+ * @param mixed (int) $discount The Treasury bill's discount rate
*
* @return float|string Result, or a string containing an error
*/
@@ -117,7 +117,7 @@ class TreasuryBill
* the Treasury bill is traded to the buyer.
* @param mixed $maturity The Treasury bill's maturity date.
* The maturity date is the date when the Treasury bill expires.
- * @param int $price The Treasury bill's price per $100 face value
+ * @param mixed (int) $price The Treasury bill's price per $100 face value
*
* @return float|string
*/
diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Address.php b/src/PhpSpreadsheet/Calculation/LookupRef/Address.php
index 53c9c9d8..daaebea2 100644
--- a/src/PhpSpreadsheet/Calculation/LookupRef/Address.php
+++ b/src/PhpSpreadsheet/Calculation/LookupRef/Address.php
@@ -25,15 +25,15 @@ class Address
*
* @param mixed $row Row number to use in the cell reference
* @param mixed $column Column number to use in the cell reference
- * @param int $relativity Flag indicating the type of reference to return
+ * @param mixed (int) $relativity Flag indicating the type of reference to return
* 1 or omitted Absolute
* 2 Absolute row; relative column
* 3 Relative row; absolute column
* 4 Relative
- * @param bool $referenceStyle A logical value that specifies the A1 or R1C1 reference style.
+ * @param mixed (bool) $referenceStyle A logical value that specifies the A1 or R1C1 reference style.
* TRUE or omitted ADDRESS returns an A1-style reference
* FALSE ADDRESS returns an R1C1-style reference
- * @param string $sheetName Optional Name of worksheet to use
+ * @param mixed (string) $sheetName Optional Name of worksheet to use
*
* @return string
*/
diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php b/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php
index 690b32e4..c34dd965 100644
--- a/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php
+++ b/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php
@@ -21,7 +21,7 @@ class Indirect
* NOTE - INDIRECT() does not yet support the optional a1 parameter introduced in Excel 2010
*
* @param null|array|string $cellAddress $cellAddress The cell address of the current cell (containing this formula)
- * @param Cell $pCell The current cell (containing this formula)
+ * @param null|Cell $pCell The current cell (containing this formula)
*
* @return array|string An array containing a cell or range of cells, or a string on error
*
diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php
index f3d8351d..94850906 100644
--- a/src/PhpSpreadsheet/Calculation/MathTrig.php
+++ b/src/PhpSpreadsheet/Calculation/MathTrig.php
@@ -1156,7 +1156,7 @@ class MathTrig
$aArgs = self::filterFormulaArgs($cellReference, $aArgs);
switch ($subtotal) {
case 1:
- return Statistical\Averages::AVERAGE($aArgs);
+ return Statistical\Averages::average($aArgs);
case 2:
return Statistical\Counts::COUNT($aArgs);
case 3:
diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php
index 8a9e3fea..c8e084b5 100644
--- a/src/PhpSpreadsheet/Calculation/Statistical.php
+++ b/src/PhpSpreadsheet/Calculation/Statistical.php
@@ -12,411 +12,15 @@ use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Permutations;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical\StandardDeviations;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Trends;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Variances;
-use PhpOffice\PhpSpreadsheet\Shared\Trend\Trend;
class Statistical
{
const LOG_GAMMA_X_MAX_VALUE = 2.55e305;
- const XMININ = 2.23e-308;
const EPS = 2.22e-16;
const MAX_VALUE = 1.2e308;
const MAX_ITERATIONS = 256;
const SQRT2PI = 2.5066282746310005024157652848110452530069867406099;
- /**
- * Incomplete beta function.
- *
- * @author Jaco van Kooten
- * @author Paul Meagher
- *
- * The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992).
- *
- * @param mixed $x require 0<=x<=1
- * @param mixed $p require p>0
- * @param mixed $q require q>0
- *
- * @return float 0 if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow
- */
- private static function incompleteBeta($x, $p, $q)
- {
- if ($x <= 0.0) {
- return 0.0;
- } elseif ($x >= 1.0) {
- return 1.0;
- } elseif (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > self::LOG_GAMMA_X_MAX_VALUE)) {
- return 0.0;
- }
- $beta_gam = exp((0 - self::logBeta($p, $q)) + $p * log($x) + $q * log(1.0 - $x));
- if ($x < ($p + 1.0) / ($p + $q + 2.0)) {
- return $beta_gam * self::betaFraction($x, $p, $q) / $p;
- }
-
- return 1.0 - ($beta_gam * self::betaFraction(1 - $x, $q, $p) / $q);
- }
-
- // Function cache for logBeta function
- private static $logBetaCacheP = 0.0;
-
- private static $logBetaCacheQ = 0.0;
-
- private static $logBetaCacheResult = 0.0;
-
- /**
- * The natural logarithm of the beta function.
- *
- * @param mixed $p require p>0
- * @param mixed $q require q>0
- *
- * @return float 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
- *
- * @author Jaco van Kooten
- */
- private static function logBeta($p, $q)
- {
- if ($p != self::$logBetaCacheP || $q != self::$logBetaCacheQ) {
- self::$logBetaCacheP = $p;
- self::$logBetaCacheQ = $q;
- if (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > self::LOG_GAMMA_X_MAX_VALUE)) {
- self::$logBetaCacheResult = 0.0;
- } else {
- self::$logBetaCacheResult = self::logGamma($p) + self::logGamma($q) - self::logGamma($p + $q);
- }
- }
-
- return self::$logBetaCacheResult;
- }
-
- /**
- * Evaluates of continued fraction part of incomplete beta function.
- * Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
- *
- * @author Jaco van Kooten
- *
- * @param mixed $x
- * @param mixed $p
- * @param mixed $q
- *
- * @return float
- */
- private static function betaFraction($x, $p, $q)
- {
- $c = 1.0;
- $sum_pq = $p + $q;
- $p_plus = $p + 1.0;
- $p_minus = $p - 1.0;
- $h = 1.0 - $sum_pq * $x / $p_plus;
- if (abs($h) < self::XMININ) {
- $h = self::XMININ;
- }
- $h = 1.0 / $h;
- $frac = $h;
- $m = 1;
- $delta = 0.0;
- while ($m <= self::MAX_ITERATIONS && abs($delta - 1.0) > Functions::PRECISION) {
- $m2 = 2 * $m;
- // even index for d
- $d = $m * ($q - $m) * $x / (($p_minus + $m2) * ($p + $m2));
- $h = 1.0 + $d * $h;
- if (abs($h) < self::XMININ) {
- $h = self::XMININ;
- }
- $h = 1.0 / $h;
- $c = 1.0 + $d / $c;
- if (abs($c) < self::XMININ) {
- $c = self::XMININ;
- }
- $frac *= $h * $c;
- // odd index for d
- $d = -($p + $m) * ($sum_pq + $m) * $x / (($p + $m2) * ($p_plus + $m2));
- $h = 1.0 + $d * $h;
- if (abs($h) < self::XMININ) {
- $h = self::XMININ;
- }
- $h = 1.0 / $h;
- $c = 1.0 + $d / $c;
- if (abs($c) < self::XMININ) {
- $c = self::XMININ;
- }
- $delta = $h * $c;
- $frac *= $delta;
- ++$m;
- }
-
- return $frac;
- }
-
- /**
- * logGamma function.
- *
- * @version 1.1
- *
- * @author Jaco van Kooten
- *
- * Original author was Jaco van Kooten. Ported to PHP by Paul Meagher.
- *
- * The natural logarithm of the gamma function.
- * Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz
- * Applied Mathematics Division
- * Argonne National Laboratory
- * Argonne, IL 60439
- *
- * References:
- *
- * - W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural
- * Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.
- * - K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.
- * - Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.
- *
- *
- *
- * From the original documentation:
- *
- *
- * This routine calculates the LOG(GAMMA) function for a positive real argument X.
- * Computation is based on an algorithm outlined in references 1 and 2.
- * The program uses rational functions that theoretically approximate LOG(GAMMA)
- * to at least 18 significant decimal digits. The approximation for X > 12 is from
- * reference 3, while approximations for X < 12.0 are similar to those in reference
- * 1, but are unpublished. The accuracy achieved depends on the arithmetic system,
- * the compiler, the intrinsic functions, and proper selection of the
- * machine-dependent constants.
- *
- *
- * Error returns:
- * The program returns the value XINF for X .LE. 0.0 or when overflow would occur.
- * The computation is believed to be free of underflow and overflow.
- *
- *
- * @return float MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305
- */
-
- // Function cache for logGamma
- private static $logGammaCacheResult = 0.0;
-
- private static $logGammaCacheX = 0.0;
-
- private static function logGamma($x)
- {
- // Log Gamma related constants
- static $lg_d1 = -0.5772156649015328605195174;
- static $lg_d2 = 0.4227843350984671393993777;
- static $lg_d4 = 1.791759469228055000094023;
-
- static $lg_p1 = [
- 4.945235359296727046734888,
- 201.8112620856775083915565,
- 2290.838373831346393026739,
- 11319.67205903380828685045,
- 28557.24635671635335736389,
- 38484.96228443793359990269,
- 26377.48787624195437963534,
- 7225.813979700288197698961,
- ];
- static $lg_p2 = [
- 4.974607845568932035012064,
- 542.4138599891070494101986,
- 15506.93864978364947665077,
- 184793.2904445632425417223,
- 1088204.76946882876749847,
- 3338152.967987029735917223,
- 5106661.678927352456275255,
- 3074109.054850539556250927,
- ];
- static $lg_p4 = [
- 14745.02166059939948905062,
- 2426813.369486704502836312,
- 121475557.4045093227939592,
- 2663432449.630976949898078,
- 29403789566.34553899906876,
- 170266573776.5398868392998,
- 492612579337.743088758812,
- 560625185622.3951465078242,
- ];
- static $lg_q1 = [
- 67.48212550303777196073036,
- 1113.332393857199323513008,
- 7738.757056935398733233834,
- 27639.87074403340708898585,
- 54993.10206226157329794414,
- 61611.22180066002127833352,
- 36351.27591501940507276287,
- 8785.536302431013170870835,
- ];
- static $lg_q2 = [
- 183.0328399370592604055942,
- 7765.049321445005871323047,
- 133190.3827966074194402448,
- 1136705.821321969608938755,
- 5267964.117437946917577538,
- 13467014.54311101692290052,
- 17827365.30353274213975932,
- 9533095.591844353613395747,
- ];
- static $lg_q4 = [
- 2690.530175870899333379843,
- 639388.5654300092398984238,
- 41355999.30241388052042842,
- 1120872109.61614794137657,
- 14886137286.78813811542398,
- 101680358627.2438228077304,
- 341747634550.7377132798597,
- 446315818741.9713286462081,
- ];
- static $lg_c = [
- -0.001910444077728,
- 8.4171387781295e-4,
- -5.952379913043012e-4,
- 7.93650793500350248e-4,
- -0.002777777777777681622553,
- 0.08333333333333333331554247,
- 0.0057083835261,
- ];
-
- // Rough estimate of the fourth root of logGamma_xBig
- static $lg_frtbig = 2.25e76;
- static $pnt68 = 0.6796875;
-
- if ($x == self::$logGammaCacheX) {
- return self::$logGammaCacheResult;
- }
- $y = $x;
- if ($y > 0.0 && $y <= self::LOG_GAMMA_X_MAX_VALUE) {
- if ($y <= self::EPS) {
- $res = -log($y);
- } elseif ($y <= 1.5) {
- // ---------------------
- // EPS .LT. X .LE. 1.5
- // ---------------------
- if ($y < $pnt68) {
- $corr = -log($y);
- $xm1 = $y;
- } else {
- $corr = 0.0;
- $xm1 = $y - 1.0;
- }
- if ($y <= 0.5 || $y >= $pnt68) {
- $xden = 1.0;
- $xnum = 0.0;
- for ($i = 0; $i < 8; ++$i) {
- $xnum = $xnum * $xm1 + $lg_p1[$i];
- $xden = $xden * $xm1 + $lg_q1[$i];
- }
- $res = $corr + $xm1 * ($lg_d1 + $xm1 * ($xnum / $xden));
- } else {
- $xm2 = $y - 1.0;
- $xden = 1.0;
- $xnum = 0.0;
- for ($i = 0; $i < 8; ++$i) {
- $xnum = $xnum * $xm2 + $lg_p2[$i];
- $xden = $xden * $xm2 + $lg_q2[$i];
- }
- $res = $corr + $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden));
- }
- } elseif ($y <= 4.0) {
- // ---------------------
- // 1.5 .LT. X .LE. 4.0
- // ---------------------
- $xm2 = $y - 2.0;
- $xden = 1.0;
- $xnum = 0.0;
- for ($i = 0; $i < 8; ++$i) {
- $xnum = $xnum * $xm2 + $lg_p2[$i];
- $xden = $xden * $xm2 + $lg_q2[$i];
- }
- $res = $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden));
- } elseif ($y <= 12.0) {
- // ----------------------
- // 4.0 .LT. X .LE. 12.0
- // ----------------------
- $xm4 = $y - 4.0;
- $xden = -1.0;
- $xnum = 0.0;
- for ($i = 0; $i < 8; ++$i) {
- $xnum = $xnum * $xm4 + $lg_p4[$i];
- $xden = $xden * $xm4 + $lg_q4[$i];
- }
- $res = $lg_d4 + $xm4 * ($xnum / $xden);
- } else {
- // ---------------------------------
- // Evaluate for argument .GE. 12.0
- // ---------------------------------
- $res = 0.0;
- if ($y <= $lg_frtbig) {
- $res = $lg_c[6];
- $ysq = $y * $y;
- for ($i = 0; $i < 6; ++$i) {
- $res = $res / $ysq + $lg_c[$i];
- }
- $res /= $y;
- $corr = log($y);
- $res = $res + log(self::SQRT2PI) - 0.5 * $corr;
- $res += $y * ($corr - 1.0);
- }
- }
- } else {
- // --------------------------
- // Return for bad arguments
- // --------------------------
- $res = self::MAX_VALUE;
- }
- // ------------------------------
- // Final adjustments and return
- // ------------------------------
- self::$logGammaCacheX = $x;
- self::$logGammaCacheResult = $res;
-
- return $res;
- }
-
- //
- // Private implementation of the incomplete Gamma function
- //
- private static function incompleteGamma($a, $x)
- {
- static $max = 32;
- $summer = 0;
- for ($n = 0; $n <= $max; ++$n) {
- $divisor = $a;
- for ($i = 1; $i <= $n; ++$i) {
- $divisor *= ($a + $i);
- }
- $summer += ($x ** $n / $divisor);
- }
-
- return $x ** $a * exp(0 - $x) * $summer;
- }
-
- //
- // Private implementation of the Gamma function
- //
- private static function gamma($data)
- {
- if ($data == 0.0) {
- return 0;
- }
-
- static $p0 = 1.000000000190015;
- static $p = [
- 1 => 76.18009172947146,
- 2 => -86.50532032941677,
- 3 => 24.01409824083091,
- 4 => -1.231739572450155,
- 5 => 1.208650973866179e-3,
- 6 => -5.395239384953e-6,
- ];
-
- $y = $x = $data;
- $tmp = $x + 5.5;
- $tmp -= ($x + 0.5) * log($tmp);
-
- $summer = $p0;
- for ($j = 1; $j <= 6; ++$j) {
- $summer += ($p[$j] / ++$y);
- }
-
- return exp(0 - $tmp + log(self::SQRT2PI * $summer / $x));
- }
-
/*
* inverse_ncdf.php
* -------------------
@@ -512,16 +116,16 @@ class Statistical
*
* @Deprecated 1.17.0
*
- * @see Statistical\Averages::AVEDEV()
- * Use the AVEDEV() method in the Statistical\Averages class instead
- *
* @param mixed ...$args Data values
*
* @return float|string
+ *
+ *@see Statistical\Averages::averageDeviations()
+ * Use the averageDeviations() method in the Statistical\Averages class instead
*/
public static function AVEDEV(...$args)
{
- return Averages::AVEDEV(...$args);
+ return Averages::averageDeviations(...$args);
}
/**
@@ -534,8 +138,8 @@ class Statistical
*
* @Deprecated 1.17.0
*
- * @see Statistical\Averages::AVERAGE()
- * Use the AVERAGE() method in the Statistical\Averages class instead
+ * @see Statistical\Averages::average()
+ * Use the average() method in the Statistical\Averages class instead
*
* @param mixed ...$args Data values
*
@@ -543,7 +147,7 @@ class Statistical
*/
public static function AVERAGE(...$args)
{
- return Averages::AVERAGE(...$args);
+ return Averages::average(...$args);
}
/**
@@ -556,16 +160,16 @@ class Statistical
*
* @Deprecated 1.17.0
*
- * @see Statistical\Averages::AVERAGEA()
- * Use the AVERAGEA() method in the Statistical\Averages class instead
- *
* @param mixed ...$args Data values
*
* @return float|string
+ *
+ *@see Statistical\Averages::averageA()
+ * Use the averageA() method in the Statistical\Averages class instead
*/
public static function AVERAGEA(...$args)
{
- return Averages::AVERAGEA(...$args);
+ return Averages::averageA(...$args);
}
/**
@@ -597,6 +201,11 @@ class Statistical
*
* Returns the beta distribution.
*
+ * @Deprecated 1.18.0
+ *
+ *@see Statistical\Distributions\Beta::distribution()
+ * Use the distribution() method in the Statistical\Distributions\Beta class instead
+ *
* @param float $value Value at which you want to evaluate the distribution
* @param float $alpha Parameter to the distribution
* @param float $beta Parameter to the distribution
@@ -607,28 +216,7 @@ class Statistical
*/
public static function BETADIST($value, $alpha, $beta, $rMin = 0, $rMax = 1)
{
- $value = Functions::flattenSingleValue($value);
- $alpha = Functions::flattenSingleValue($alpha);
- $beta = Functions::flattenSingleValue($beta);
- $rMin = Functions::flattenSingleValue($rMin);
- $rMax = Functions::flattenSingleValue($rMax);
-
- if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
- if ($rMin > $rMax) {
- $tmp = $rMin;
- $rMin = $rMax;
- $rMax = $tmp;
- }
- if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) {
- return Functions::NAN();
- }
- $value -= $rMin;
- $value /= ($rMax - $rMin);
-
- return self::incompleteBeta($value, $alpha, $beta);
- }
-
- return Functions::VALUE();
+ return Statistical\Distributions\Beta::distribution($value, $alpha, $beta, $rMin, $rMax);
}
/**
@@ -636,6 +224,11 @@ class Statistical
*
* Returns the inverse of the Beta distribution.
*
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Distributions\Beta::inverse()
+ * Use the inverse() method in the Statistical\Distributions\Beta class instead
+ *
* @param float $probability Probability at which you want to evaluate the distribution
* @param float $alpha Parameter to the distribution
* @param float $beta Parameter to the distribution
@@ -646,44 +239,7 @@ class Statistical
*/
public static function BETAINV($probability, $alpha, $beta, $rMin = 0, $rMax = 1)
{
- $probability = Functions::flattenSingleValue($probability);
- $alpha = Functions::flattenSingleValue($alpha);
- $beta = Functions::flattenSingleValue($beta);
- $rMin = Functions::flattenSingleValue($rMin);
- $rMax = Functions::flattenSingleValue($rMax);
-
- if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
- if ($rMin > $rMax) {
- $tmp = $rMin;
- $rMin = $rMax;
- $rMax = $tmp;
- }
- if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) {
- return Functions::NAN();
- }
- $a = 0;
- $b = 2;
-
- $i = 0;
- while ((($b - $a) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) {
- $guess = ($a + $b) / 2;
- $result = self::BETADIST($guess, $alpha, $beta);
- if (($result == $probability) || ($result == 0)) {
- $b = $a;
- } elseif ($result > $probability) {
- $b = $guess;
- } else {
- $a = $guess;
- }
- }
- if ($i == self::MAX_ITERATIONS) {
- return Functions::NA();
- }
-
- return round($rMin + $guess * ($rMax - $rMin), 12);
- }
-
- return Functions::VALUE();
+ return Statistical\Distributions\Beta::inverse($probability, $alpha, $beta, $rMin, $rMax);
}
/**
@@ -739,6 +295,11 @@ class Statistical
*
* Returns the one-tailed probability of the chi-squared distribution.
*
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Distributions\ChiSquared::distribution()
+ * Use the distribution() method in the Statistical\Distributions\ChiSquared class instead
+ *
* @param float $value Value for the function
* @param float $degrees degrees of freedom
*
@@ -746,26 +307,7 @@ class Statistical
*/
public static function CHIDIST($value, $degrees)
{
- $value = Functions::flattenSingleValue($value);
- $degrees = Functions::flattenSingleValue($degrees);
-
- if ((is_numeric($value)) && (is_numeric($degrees))) {
- $degrees = floor($degrees);
- if ($degrees < 1) {
- return Functions::NAN();
- }
- if ($value < 0) {
- if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
- return 1;
- }
-
- return Functions::NAN();
- }
-
- return 1 - (self::incompleteGamma($degrees / 2, $value / 2) / self::gamma($degrees / 2));
- }
-
- return Functions::VALUE();
+ return Statistical\Distributions\ChiSquared::distribution($value, $degrees);
}
/**
@@ -773,6 +315,11 @@ class Statistical
*
* Returns the one-tailed probability of the chi-squared distribution.
*
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Distributions\ChiSquared::inverse()
+ * Use the inverse() method in the Statistical\Distributions\ChiSquared class instead
+ *
* @param float $probability Probability for the function
* @param float $degrees degrees of freedom
*
@@ -780,52 +327,7 @@ class Statistical
*/
public static function CHIINV($probability, $degrees)
{
- $probability = Functions::flattenSingleValue($probability);
- $degrees = Functions::flattenSingleValue($degrees);
-
- if ((is_numeric($probability)) && (is_numeric($degrees))) {
- $degrees = floor($degrees);
-
- $xLo = 100;
- $xHi = 0;
-
- $x = $xNew = 1;
- $dx = 1;
- $i = 0;
-
- while ((abs($dx) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) {
- // Apply Newton-Raphson step
- $result = 1 - (self::incompleteGamma($degrees / 2, $x / 2) / self::gamma($degrees / 2));
- $error = $result - $probability;
- if ($error == 0.0) {
- $dx = 0;
- } elseif ($error < 0.0) {
- $xLo = $x;
- } else {
- $xHi = $x;
- }
- // Avoid division by zero
- if ($result != 0.0) {
- $dx = $error / $result;
- $xNew = $x - $dx;
- }
- // If the NR fails to converge (which for example may be the
- // case if the initial guess is too rough) we apply a bisection
- // step to determine a more narrow interval around the root.
- if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
- $xNew = ($xLo + $xHi) / 2;
- $dx = $xNew - $x;
- }
- $x = $xNew;
- }
- if ($i == self::MAX_ITERATIONS) {
- return Functions::NA();
- }
-
- return round($x, 12);
- }
-
- return Functions::VALUE();
+ return Statistical\Distributions\ChiSquared::inverse($probability, $degrees);
}
/**
@@ -1146,7 +648,7 @@ class Statistical
// Return value
$returnValue = null;
- $aMean = Averages::AVERAGE($aArgs);
+ $aMean = Averages::average($aArgs);
if ($aMean != Functions::DIV0()) {
$aCount = -1;
foreach ($aArgs as $k => $arg) {
@@ -1214,16 +716,6 @@ class Statistical
return Functions::VALUE();
}
- private static function betaFunction($a, $b)
- {
- return (self::gamma($a) * self::gamma($b)) / self::gamma($a + $b);
- }
-
- private static function regularizedIncompleteBeta($value, $a, $b)
- {
- return self::incompleteBeta($value, $a, $b) / self::betaFunction($a, $b);
- }
-
/**
* F.DIST.
*
@@ -1259,10 +751,12 @@ class Statistical
if ($cumulative) {
$adjustedValue = ($u * $value) / ($u * $value + $v);
- return self::incompleteBeta($adjustedValue, $u / 2, $v / 2);
+ return Statistical\Distributions\Beta::incompleteBeta($adjustedValue, $u / 2, $v / 2);
}
- return (self::gamma(($v + $u) / 2) / (self::gamma($u / 2) * self::gamma($v / 2))) *
+ return (Statistical\Distributions\Gamma::gammaValue(($v + $u) / 2) /
+ (Statistical\Distributions\Gamma::gammaValue($u / 2) *
+ Statistical\Distributions\Gamma::gammaValue($v / 2))) *
(($u / $v) ** ($u / 2)) *
(($value ** (($u - 2) / 2)) / ((1 + ($u / $v) * $value) ** (($u + $v) / 2)));
}
@@ -1277,23 +771,18 @@ class Statistical
* is normally distributed rather than skewed. Use this function to perform hypothesis
* testing on the correlation coefficient.
*
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Distributions\Fisher::distribution()
+ * Use the distribution() method in the Statistical\Distributions\Fisher class instead
+ *
* @param float $value
*
* @return float|string
*/
public static function FISHER($value)
{
- $value = Functions::flattenSingleValue($value);
-
- if (is_numeric($value)) {
- if (($value <= -1) || ($value >= 1)) {
- return Functions::NAN();
- }
-
- return 0.5 * log((1 + $value) / (1 - $value));
- }
-
- return Functions::VALUE();
+ return Statistical\Distributions\Fisher::distribution($value);
}
/**
@@ -1303,19 +792,18 @@ class Statistical
* analyzing correlations between ranges or arrays of data. If y = FISHER(x), then
* FISHERINV(y) = x.
*
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Distributions\Fisher::inverse()
+ * Use the inverse() method in the Statistical\Distributions\Fisher class instead
+ *
* @param float $value
*
* @return float|string
*/
public static function FISHERINV($value)
{
- $value = Functions::flattenSingleValue($value);
-
- if (is_numeric($value)) {
- return (exp(2 * $value) - 1) / (exp(2 * $value) + 1);
- }
-
- return Functions::VALUE();
+ return Statistical\Distributions\Fisher::inverse($value);
}
/**
@@ -1342,7 +830,12 @@ class Statistical
/**
* GAMMA.
*
- * Return the gamma function value.
+ * Returns the gamma function value.
+ *
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Distributions\Gamma::gamma()
+ * Use the gamma() method in the Statistical\Distributions\Gamma class instead
*
* @param float $value
*
@@ -1350,14 +843,7 @@ class Statistical
*/
public static function GAMMAFunction($value)
{
- $value = Functions::flattenSingleValue($value);
- if (!is_numeric($value)) {
- return Functions::VALUE();
- } elseif ((((int) $value) == ((float) $value)) && $value <= 0.0) {
- return Functions::NAN();
- }
-
- return self::gamma($value);
+ return Statistical\Distributions\Gamma::gamma($value);
}
/**
@@ -1365,6 +851,11 @@ class Statistical
*
* Returns the gamma distribution.
*
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Distributions\Gamma::distribution()
+ * Use the distribution() method in the Statistical\Distributions\Gamma class instead
+ *
* @param float $value Value at which you want to evaluate the distribution
* @param float $a Parameter to the distribution
* @param float $b Parameter to the distribution
@@ -1374,24 +865,7 @@ class Statistical
*/
public static function GAMMADIST($value, $a, $b, $cumulative)
{
- $value = Functions::flattenSingleValue($value);
- $a = Functions::flattenSingleValue($a);
- $b = Functions::flattenSingleValue($b);
-
- if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) {
- if (($value < 0) || ($a <= 0) || ($b <= 0)) {
- return Functions::NAN();
- }
- if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
- if ($cumulative) {
- return self::incompleteGamma($a, $value / $b) / self::gamma($a);
- }
-
- return (1 / ($b ** $a * self::gamma($a))) * $value ** ($a - 1) * exp(0 - ($value / $b));
- }
- }
-
- return Functions::VALUE();
+ return Statistical\Distributions\Gamma::distribution($value, $a, $b, $cumulative);
}
/**
@@ -1399,6 +873,11 @@ class Statistical
*
* Returns the inverse of the Gamma distribution.
*
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Distributions\Gamma::inverse()
+ * Use the inverse() method in the Statistical\Distributions\Gamma class instead
+ *
* @param float $probability Probability at which you want to evaluate the distribution
* @param float $alpha Parameter to the distribution
* @param float $beta Parameter to the distribution
@@ -1407,53 +886,7 @@ class Statistical
*/
public static function GAMMAINV($probability, $alpha, $beta)
{
- $probability = Functions::flattenSingleValue($probability);
- $alpha = Functions::flattenSingleValue($alpha);
- $beta = Functions::flattenSingleValue($beta);
-
- if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) {
- if (($alpha <= 0) || ($beta <= 0) || ($probability < 0) || ($probability > 1)) {
- return Functions::NAN();
- }
-
- $xLo = 0;
- $xHi = $alpha * $beta * 5;
-
- $x = $xNew = 1;
- $dx = 1024;
- $i = 0;
-
- while ((abs($dx) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) {
- // Apply Newton-Raphson step
- $error = self::GAMMADIST($x, $alpha, $beta, true) - $probability;
- if ($error < 0.0) {
- $xLo = $x;
- } else {
- $xHi = $x;
- }
- $pdf = self::GAMMADIST($x, $alpha, $beta, false);
- // Avoid division by zero
- if ($pdf != 0.0) {
- $dx = $error / $pdf;
- $xNew = $x - $dx;
- }
- // If the NR fails to converge (which for example may be the
- // case if the initial guess is too rough) we apply a bisection
- // step to determine a more narrow interval around the root.
- if (($xNew < $xLo) || ($xNew > $xHi) || ($pdf == 0.0)) {
- $xNew = ($xLo + $xHi) / 2;
- $dx = $xNew - $x;
- }
- $x = $xNew;
- }
- if ($i == self::MAX_ITERATIONS) {
- return Functions::NA();
- }
-
- return $x;
- }
-
- return Functions::VALUE();
+ return Statistical\Distributions\Gamma::inverse($probability, $alpha, $beta);
}
/**
@@ -1461,23 +894,18 @@ class Statistical
*
* Returns the natural logarithm of the gamma function.
*
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Distributions\Gamma::ln()
+ * Use the ln() method in the Statistical\Distributions\Gamma class instead
+ *
* @param float $value
*
* @return float|string
*/
public static function GAMMALN($value)
{
- $value = Functions::flattenSingleValue($value);
-
- if (is_numeric($value)) {
- if ($value <= 0) {
- return Functions::NAN();
- }
-
- return log(self::gamma($value));
- }
-
- return Functions::VALUE();
+ return Statistical\Distributions\Gamma::ln($value);
}
/**
@@ -1673,7 +1101,7 @@ class Statistical
public static function KURT(...$args)
{
$aArgs = Functions::flattenArrayIndexed($args);
- $mean = Averages::AVERAGE($aArgs);
+ $mean = Averages::average($aArgs);
$stdDev = StandardDeviations::STDEV($aArgs);
if ($stdDev > 0) {
@@ -1962,37 +1390,18 @@ class Statistical
* Excel Function:
* MEDIAN(value1[,value2[, ...]])
*
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Averages::median()
+ * Use the median() method in the Statistical\Averages class instead
+ *
* @param mixed ...$args Data values
*
* @return float|string The result, or a string containing an error
*/
public static function MEDIAN(...$args)
{
- $returnValue = Functions::NAN();
-
- $mArgs = [];
- // Loop through arguments
- $aArgs = Functions::flattenArray($args);
- foreach ($aArgs as $arg) {
- // Is it a numeric value?
- if ((is_numeric($arg)) && (!is_string($arg))) {
- $mArgs[] = $arg;
- }
- }
-
- $mValueCount = count($mArgs);
- if ($mValueCount > 0) {
- sort($mArgs, SORT_NUMERIC);
- $mValueCount = $mValueCount / 2;
- if ($mValueCount == floor($mValueCount)) {
- $returnValue = ($mArgs[$mValueCount--] + $mArgs[$mValueCount]) / 2;
- } else {
- $mValueCount = floor($mValueCount);
- $returnValue = $mArgs[$mValueCount];
- }
- }
-
- return $returnValue;
+ return Statistical\Averages::median(...$args);
}
/**
@@ -2062,55 +1471,6 @@ class Statistical
return Conditional::MINIFS(...$args);
}
- //
- // Special variant of array_count_values that isn't limited to strings and integers,
- // but can work with floating point numbers as values
- //
- private static function modeCalc($data)
- {
- $frequencyArray = [];
- $index = 0;
- $maxfreq = 0;
- $maxfreqkey = '';
- $maxfreqdatum = '';
- foreach ($data as $datum) {
- $found = false;
- ++$index;
- foreach ($frequencyArray as $key => $value) {
- if ((string) $value['value'] == (string) $datum) {
- ++$frequencyArray[$key]['frequency'];
- $freq = $frequencyArray[$key]['frequency'];
- if ($freq > $maxfreq) {
- $maxfreq = $freq;
- $maxfreqkey = $key;
- $maxfreqdatum = $datum;
- } elseif ($freq == $maxfreq) {
- if ($frequencyArray[$key]['index'] < $frequencyArray[$maxfreqkey]['index']) {
- $maxfreqkey = $key;
- $maxfreqdatum = $datum;
- }
- }
- $found = true;
-
- break;
- }
- }
- if (!$found) {
- $frequencyArray[] = [
- 'value' => $datum,
- 'frequency' => 1,
- 'index' => $index,
- ];
- }
- }
-
- if ($maxfreq <= 1) {
- return Functions::NA();
- }
-
- return $maxfreqdatum;
- }
-
/**
* MODE.
*
@@ -2119,30 +1479,18 @@ class Statistical
* Excel Function:
* MODE(value1[,value2[, ...]])
*
+ * @Deprecated 1.18.0
+ *
+ * @see Statistical\Averages::mode()
+ * Use the mode() method in the Statistical\Averages class instead
+ *
* @param mixed ...$args Data values
*
* @return float|string The result, or a string containing an error
*/
public static function MODE(...$args)
{
- $returnValue = Functions::NA();
-
- // Loop through arguments
- $aArgs = Functions::flattenArray($args);
-
- $mArgs = [];
- foreach ($aArgs as $arg) {
- // Is it a numeric value?
- if ((is_numeric($arg)) && (!is_string($arg))) {
- $mArgs[] = $arg;
- }
- }
-
- if (!empty($mArgs)) {
- return self::modeCalc($mArgs);
- }
-
- return $returnValue;
+ return Statistical\Averages::mode(...$args);
}
/**
@@ -2575,7 +1923,7 @@ class Statistical
public static function SKEW(...$args)
{
$aArgs = Functions::flattenArrayIndexed($args);
- $mean = Averages::AVERAGE($aArgs);
+ $mean = Averages::average($aArgs);
$stdDev = StandardDeviations::STDEV($aArgs);
if ($stdDev === 0.0 || is_string($stdDev)) {
@@ -2990,7 +2338,7 @@ class Statistical
array_shift($mArgs);
}
- return Averages::AVERAGE($mArgs);
+ return Averages::average($mArgs);
}
return Functions::VALUE();
@@ -3142,6 +2490,6 @@ class Statistical
}
$n = count($dataSet);
- return 1 - self::NORMSDIST((Averages::AVERAGE($dataSet) - $m0) / ($sigma / sqrt($n)));
+ return 1 - self::NORMSDIST((Averages::average($dataSet) - $m0) / ($sigma / sqrt($n)));
}
}
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Averages.php b/src/PhpSpreadsheet/Calculation/Statistical/Averages.php
index 14c9fef2..1a627e99 100644
--- a/src/PhpSpreadsheet/Calculation/Statistical/Averages.php
+++ b/src/PhpSpreadsheet/Calculation/Statistical/Averages.php
@@ -19,14 +19,14 @@ class Averages extends AggregateBase
*
* @return float|string (string if result is an error)
*/
- public static function AVEDEV(...$args)
+ public static function averageDeviations(...$args)
{
$aArgs = Functions::flattenArrayIndexed($args);
// Return value
$returnValue = 0;
- $aMean = self::AVERAGE(...$args);
+ $aMean = self::average(...$args);
if ($aMean === Functions::DIV0()) {
return Functions::NAN();
} elseif ($aMean === Functions::VALUE()) {
@@ -68,7 +68,7 @@ class Averages extends AggregateBase
*
* @return float|string (string if result is an error)
*/
- public static function AVERAGE(...$args)
+ public static function average(...$args)
{
$returnValue = $aCount = 0;
@@ -107,7 +107,7 @@ class Averages extends AggregateBase
*
* @return float|string (string if result is an error)
*/
- public static function AVERAGEA(...$args)
+ public static function averageA(...$args)
{
$returnValue = null;
@@ -134,4 +134,126 @@ class Averages extends AggregateBase
return Functions::DIV0();
}
+
+ /**
+ * MEDIAN.
+ *
+ * Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
+ *
+ * Excel Function:
+ * MEDIAN(value1[,value2[, ...]])
+ *
+ * @param mixed ...$args Data values
+ *
+ * @return float|string The result, or a string containing an error
+ */
+ public static function median(...$args)
+ {
+ $aArgs = Functions::flattenArray($args);
+
+ $returnValue = Functions::NAN();
+
+ $aArgs = self::filterArguments($aArgs);
+ $valueCount = count($aArgs);
+ if ($valueCount > 0) {
+ sort($aArgs, SORT_NUMERIC);
+ $valueCount = $valueCount / 2;
+ if ($valueCount == floor($valueCount)) {
+ $returnValue = ($aArgs[$valueCount--] + $aArgs[$valueCount]) / 2;
+ } else {
+ $valueCount = floor($valueCount);
+ $returnValue = $aArgs[$valueCount];
+ }
+ }
+
+ return $returnValue;
+ }
+
+ /**
+ * MODE.
+ *
+ * Returns the most frequently occurring, or repetitive, value in an array or range of data
+ *
+ * Excel Function:
+ * MODE(value1[,value2[, ...]])
+ *
+ * @param mixed ...$args Data values
+ *
+ * @return float|string The result, or a string containing an error
+ */
+ public static function mode(...$args)
+ {
+ $returnValue = Functions::NA();
+
+ // Loop through arguments
+ $aArgs = Functions::flattenArray($args);
+ $aArgs = self::filterArguments($aArgs);
+
+ if (!empty($aArgs)) {
+ return self::modeCalc($aArgs);
+ }
+
+ return $returnValue;
+ }
+
+ protected static function filterArguments($args)
+ {
+ return array_filter(
+ $args,
+ function ($value) {
+ // Is it a numeric value?
+ return (is_numeric($value)) && (!is_string($value));
+ }
+ );
+ }
+
+ //
+ // Special variant of array_count_values that isn't limited to strings and integers,
+ // but can work with floating point numbers as values
+ //
+ private static function modeCalc($data)
+ {
+ $frequencyArray = [];
+ $index = 0;
+ $maxfreq = 0;
+ $maxfreqkey = '';
+ $maxfreqdatum = '';
+ foreach ($data as $datum) {
+ $found = false;
+ ++$index;
+ foreach ($frequencyArray as $key => $value) {
+ if ((string) $value['value'] == (string) $datum) {
+ ++$frequencyArray[$key]['frequency'];
+ $freq = $frequencyArray[$key]['frequency'];
+ if ($freq > $maxfreq) {
+ $maxfreq = $freq;
+ $maxfreqkey = $key;
+ $maxfreqdatum = $datum;
+ } elseif ($freq == $maxfreq) {
+ if ($frequencyArray[$key]['index'] < $frequencyArray[$maxfreqkey]['index']) {
+ $maxfreqkey = $key;
+ $maxfreqdatum = $datum;
+ }
+ }
+ $found = true;
+
+ break;
+ }
+ }
+
+ if ($found === false) {
+ $frequencyArray[] = [
+ 'value' => $datum,
+ 'frequency' => 1,
+ 'index' => $index,
+ ];
+ }
+ }
+
+ if ($maxfreq <= 1) {
+ return Functions::NA();
+ }
+
+ return $maxfreqdatum;
+ }
}
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php b/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php
index c4c2a7dd..3147859b 100644
--- a/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php
+++ b/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php
@@ -12,9 +12,9 @@ class Confidence
*
* Returns the confidence interval for a population mean
*
- * @param float $alpha
- * @param float $stdDev Standard Deviation
- * @param float $size
+ * @param mixed (float) $alpha
+ * @param mixed (float) $stdDev Standard Deviation
+ * @param mixed (float) $size
*
* @return float|string
*/
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php
new file mode 100644
index 00000000..a8ab3e89
--- /dev/null
+++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php
@@ -0,0 +1,36 @@
+getMessage();
+ }
+
+ if ($rMin > $rMax) {
+ $tmp = $rMin;
+ $rMin = $rMax;
+ $rMax = $tmp;
+ }
+ if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) {
+ return Functions::NAN();
+ }
+
+ $value -= $rMin;
+ $value /= ($rMax - $rMin);
+
+ return self::incompleteBeta($value, $alpha, $beta);
+ }
+
+ /**
+ * BETAINV.
+ *
+ * Returns the inverse of the Beta distribution.
+ *
+ * @param mixed (float) $probability Probability at which you want to evaluate the distribution
+ * @param mixed (float) $alpha Parameter to the distribution
+ * @param mixed (float) $beta Parameter to the distribution
+ * @param mixed (float) $rMin Minimum value
+ * @param mixed (float) $rMax Maximum value
+ *
+ * @return float|string
+ */
+ public static function inverse($probability, $alpha, $beta, $rMin = 0, $rMax = 1)
+ {
+ $probability = Functions::flattenSingleValue($probability);
+ $alpha = Functions::flattenSingleValue($alpha);
+ $beta = Functions::flattenSingleValue($beta);
+ $rMin = Functions::flattenSingleValue($rMin);
+ $rMax = Functions::flattenSingleValue($rMax);
+
+ try {
+ $probability = self::validateFloat($probability);
+ $alpha = self::validateFloat($alpha);
+ $beta = self::validateFloat($beta);
+ $rMax = self::validateFloat($rMax);
+ $rMin = self::validateFloat($rMin);
+ } catch (Exception $e) {
+ return $e->getMessage();
+ }
+
+ if ($rMin > $rMax) {
+ $tmp = $rMin;
+ $rMin = $rMax;
+ $rMax = $tmp;
+ }
+ if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) {
+ return Functions::NAN();
+ }
+
+ return self::calculateInverse($probability, $alpha, $beta, $rMin, $rMax);
+ }
+
+ private static function calculateInverse(float $probability, float $alpha, float $beta, float $rMin, float $rMax)
+ {
+ $a = 0;
+ $b = 2;
+
+ $i = 0;
+ while ((($b - $a) > Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) {
+ $guess = ($a + $b) / 2;
+ $result = self::distribution($guess, $alpha, $beta);
+ if (($result === $probability) || ($result === 0.0)) {
+ $b = $a;
+ } elseif ($result > $probability) {
+ $b = $guess;
+ } else {
+ $a = $guess;
+ }
+ }
+
+ if ($i === self::MAX_ITERATIONS) {
+ return Functions::NA();
+ }
+
+ return round($rMin + $guess * ($rMax - $rMin), 12);
+ }
+
+ /**
+ * Incomplete beta function.
+ *
+ * @author Jaco van Kooten
+ * @author Paul Meagher
+ *
+ * The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992).
+ *
+ * @param mixed $x require 0<=x<=1
+ * @param mixed $p require p>0
+ * @param mixed $q require q>0
+ *
+ * @return float 0 if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow
+ */
+ public static function incompleteBeta(float $x, float $p, float $q): float
+ {
+ if ($x <= 0.0) {
+ return 0.0;
+ } elseif ($x >= 1.0) {
+ return 1.0;
+ } elseif (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > self::LOG_GAMMA_X_MAX_VALUE)) {
+ return 0.0;
+ }
+
+ $beta_gam = exp((0 - self::logBeta($p, $q)) + $p * log($x) + $q * log(1.0 - $x));
+ if ($x < ($p + 1.0) / ($p + $q + 2.0)) {
+ return $beta_gam * self::betaFraction($x, $p, $q) / $p;
+ }
+
+ return 1.0 - ($beta_gam * self::betaFraction(1 - $x, $q, $p) / $q);
+ }
+
+ // Function cache for logBeta function
+ private static $logBetaCacheP = 0.0;
+
+ private static $logBetaCacheQ = 0.0;
+
+ private static $logBetaCacheResult = 0.0;
+
+ /**
+ * The natural logarithm of the beta function.
+ *
+ * @param mixed $p require p>0
+ * @param mixed $q require q>0
+ *
+ * @return float 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
+ *
+ * @author Jaco van Kooten
+ */
+ private static function logBeta(float $p, float $q): float
+ {
+ if ($p != self::$logBetaCacheP || $q != self::$logBetaCacheQ) {
+ self::$logBetaCacheP = $p;
+ self::$logBetaCacheQ = $q;
+ if (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > self::LOG_GAMMA_X_MAX_VALUE)) {
+ self::$logBetaCacheResult = 0.0;
+ } else {
+ self::$logBetaCacheResult = Gamma::logGamma($p) + Gamma::logGamma($q) - Gamma::logGamma($p + $q);
+ }
+ }
+
+ return self::$logBetaCacheResult;
+ }
+
+ /**
+ * Evaluates of continued fraction part of incomplete beta function.
+ * Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
+ *
+ * @author Jaco van Kooten
+ *
+ * @param mixed $x
+ * @param mixed $p
+ * @param mixed $q
+ */
+ private static function betaFraction(float $x, float $p, float $q): float
+ {
+ $c = 1.0;
+ $sum_pq = $p + $q;
+ $p_plus = $p + 1.0;
+ $p_minus = $p - 1.0;
+ $h = 1.0 - $sum_pq * $x / $p_plus;
+ if (abs($h) < self::XMININ) {
+ $h = self::XMININ;
+ }
+ $h = 1.0 / $h;
+ $frac = $h;
+ $m = 1;
+ $delta = 0.0;
+ while ($m <= self::MAX_ITERATIONS && abs($delta - 1.0) > Functions::PRECISION) {
+ $m2 = 2 * $m;
+ // even index for d
+ $d = $m * ($q - $m) * $x / (($p_minus + $m2) * ($p + $m2));
+ $h = 1.0 + $d * $h;
+ if (abs($h) < self::XMININ) {
+ $h = self::XMININ;
+ }
+ $h = 1.0 / $h;
+ $c = 1.0 + $d / $c;
+ if (abs($c) < self::XMININ) {
+ $c = self::XMININ;
+ }
+ $frac *= $h * $c;
+ // odd index for d
+ $d = -($p + $m) * ($sum_pq + $m) * $x / (($p + $m2) * ($p_plus + $m2));
+ $h = 1.0 + $d * $h;
+ if (abs($h) < self::XMININ) {
+ $h = self::XMININ;
+ }
+ $h = 1.0 / $h;
+ $c = 1.0 + $d / $c;
+ if (abs($c) < self::XMININ) {
+ $c = self::XMININ;
+ }
+ $delta = $h * $c;
+ $frac *= $delta;
+ ++$m;
+ }
+
+ return $frac;
+ }
+
+ private static function betaValue(float $a, float $b): float
+ {
+ return (Gamma::gammaValue($a) * Gamma::gammaValue($b)) /
+ Gamma::gammaValue($a + $b);
+ }
+
+ private static function regularizedIncompleteBeta(float $value, float $a, float $b): float
+ {
+ return self::incompleteBeta($value, $a, $b) / self::betaValue($a, $b);
+ }
+}
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
new file mode 100644
index 00000000..2d5e4496
--- /dev/null
+++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
@@ -0,0 +1,127 @@
+getMessage();
+ }
+
+ if ($degrees < 1) {
+ return Functions::NAN();
+ }
+ if ($value < 0) {
+ if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
+ return 1;
+ }
+
+ return Functions::NAN();
+ }
+
+ return 1 - (Gamma::incompleteGamma($degrees / 2, $value / 2) / Gamma::gammaValue($degrees / 2));
+ }
+
+ /**
+ * CHIINV.
+ *
+ * Returns the one-tailed probability of the chi-squared distribution.
+ *
+ * @param mixed (float) $probability Probability for the function
+ * @param mixed (int) $degrees degrees of freedom
+ *
+ * @return float|string
+ */
+ public static function inverse($probability, $degrees)
+ {
+ $probability = Functions::flattenSingleValue($probability);
+ $degrees = Functions::flattenSingleValue($degrees);
+
+ try {
+ $probability = self::validateFloat($probability);
+ $degrees = self::validateInt($degrees);
+ } catch (Exception $e) {
+ return $e->getMessage();
+ }
+
+ if ($probability < 0.0 || $probability > 1.0 || $degrees < 1) {
+ return Functions::NAN();
+ }
+
+ return self::calculateInverse($degrees, $probability);
+ }
+
+ /**
+ * @return float|string
+ */
+ protected static function calculateInverse(int $degrees, float $probability)
+ {
+ $xLo = 100;
+ $xHi = 0;
+
+ $x = $xNew = 1;
+ $dx = 1;
+ $i = 0;
+
+ while ((abs($dx) > Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) {
+ // Apply Newton-Raphson step
+ $result = 1 - (Gamma::incompleteGamma($degrees / 2, $x / 2)
+ / Gamma::gammaValue($degrees / 2));
+ $error = $result - $probability;
+
+ if ($error == 0.0) {
+ $dx = 0;
+ } elseif ($error < 0.0) {
+ $xLo = $x;
+ } else {
+ $xHi = $x;
+ }
+
+ // Avoid division by zero
+ if ($result != 0.0) {
+ $dx = $error / $result;
+ $xNew = $x - $dx;
+ }
+
+ // If the NR fails to converge (which for example may be the
+ // case if the initial guess is too rough) we apply a bisection
+ // step to determine a more narrow interval around the root.
+ if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
+ $xNew = ($xLo + $xHi) / 2;
+ $dx = $xNew - $x;
+ }
+ $x = $xNew;
+ }
+
+ if ($i === self::MAX_ITERATIONS) {
+ return Functions::NA();
+ }
+
+ return $x;
+ }
+}
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php
new file mode 100644
index 00000000..1d3a7be4
--- /dev/null
+++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php
@@ -0,0 +1,63 @@
+getMessage();
+ }
+
+ if (($value <= -1) || ($value >= 1)) {
+ return Functions::NAN();
+ }
+
+ return 0.5 * log((1 + $value) / (1 - $value));
+ }
+
+ /**
+ * FISHERINV.
+ *
+ * Returns the inverse of the Fisher transformation. Use this transformation when
+ * analyzing correlations between ranges or arrays of data. If y = FISHER(x), then
+ * FISHERINV(y) = x.
+ *
+ * @param mixed (float) $value
+ *
+ * @return float|string
+ */
+ public static function inverse($value)
+ {
+ $value = Functions::flattenSingleValue($value);
+
+ try {
+ self::validateFloat($value);
+ } catch (Exception $e) {
+ return $e->getMessage();
+ }
+
+ return (exp(2 * $value) - 1) / (exp(2 * $value) + 1);
+ }
+}
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php
new file mode 100644
index 00000000..aa487329
--- /dev/null
+++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php
@@ -0,0 +1,129 @@
+getMessage();
+ }
+
+ if ((((int) $value) == ((float) $value)) && $value <= 0.0) {
+ return Functions::NAN();
+ }
+
+ return self::gammaValue($value);
+ }
+
+ /**
+ * GAMMADIST.
+ *
+ * Returns the gamma distribution.
+ *
+ * @param mixed (float) $value Value at which you want to evaluate the distribution
+ * @param mixed (float) $a Parameter to the distribution
+ * @param mixed (float) $b Parameter to the distribution
+ * @param mixed (bool) $cumulative
+ *
+ * @return float|string
+ */
+ public static function distribution($value, $a, $b, $cumulative)
+ {
+ $value = Functions::flattenSingleValue($value);
+ $a = Functions::flattenSingleValue($a);
+ $b = Functions::flattenSingleValue($b);
+
+ try {
+ $value = self::validateFloat($value);
+ $a = self::validateFloat($a);
+ $b = self::validateFloat($b);
+ $cumulative = self::validateBool($cumulative);
+ } catch (Exception $e) {
+ return $e->getMessage();
+ }
+
+ if (($value < 0) || ($a <= 0) || ($b <= 0)) {
+ return Functions::NAN();
+ }
+
+ return self::calculateDistribution($value, $a, $b, $cumulative);
+ }
+
+ /**
+ * GAMMAINV.
+ *
+ * Returns the inverse of the Gamma distribution.
+ *
+ * @param mixed (float) $probability Probability at which you want to evaluate the distribution
+ * @param mixed (float) $alpha Parameter to the distribution
+ * @param mixed (float) $beta Parameter to the distribution
+ *
+ * @return float|string
+ */
+ public static function inverse($probability, $alpha, $beta)
+ {
+ $probability = Functions::flattenSingleValue($probability);
+ $alpha = Functions::flattenSingleValue($alpha);
+ $beta = Functions::flattenSingleValue($beta);
+
+ try {
+ $probability = self::validateFloat($probability);
+ $alpha = self::validateFloat($alpha);
+ $beta = self::validateFloat($beta);
+ } catch (Exception $e) {
+ return $e->getMessage();
+ }
+
+ if (($alpha <= 0.0) || ($beta <= 0.0) || ($probability < 0.0) || ($probability > 1.0)) {
+ return Functions::NAN();
+ }
+
+ return self::calculateInverse($probability, $alpha, $beta);
+ }
+
+ /**
+ * GAMMALN.
+ *
+ * Returns the natural logarithm of the gamma function.
+ *
+ * @param mixed (float) $value
+ *
+ * @return float|string
+ */
+ public static function ln($value)
+ {
+ $value = Functions::flattenSingleValue($value);
+
+ try {
+ $value = self::validateFloat($value);
+ } catch (Exception $e) {
+ return $e->getMessage();
+ }
+
+ if ($value <= 0) {
+ return Functions::NAN();
+ }
+
+ return log(self::gammaValue($value));
+ }
+}
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
new file mode 100644
index 00000000..ae951af3
--- /dev/null
+++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
@@ -0,0 +1,377 @@
+ Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) {
+ // Apply Newton-Raphson step
+ $error = self::calculateDistribution($x, $alpha, $beta, true) - $probability;
+ if ($error < 0.0) {
+ $xLo = $x;
+ } else {
+ $xHi = $x;
+ }
+
+ $pdf = self::calculateDistribution($x, $alpha, $beta, false);
+ // Avoid division by zero
+ if ($pdf !== 0.0) {
+ $dx = $error / $pdf;
+ $xNew = $x - $dx;
+ }
+
+ // If the NR fails to converge (which for example may be the
+ // case if the initial guess is too rough) we apply a bisection
+ // step to determine a more narrow interval around the root.
+ if (($xNew < $xLo) || ($xNew > $xHi) || ($pdf == 0.0)) {
+ $xNew = ($xLo + $xHi) / 2;
+ $dx = $xNew - $x;
+ }
+ $x = $xNew;
+ }
+
+ if ($i === self::MAX_ITERATIONS) {
+ return Functions::NA();
+ }
+
+ return $x;
+ }
+
+ //
+ // Implementation of the incomplete Gamma function
+ //
+ public static function incompleteGamma(float $a, float $x): float
+ {
+ static $max = 32;
+ $summer = 0;
+ for ($n = 0; $n <= $max; ++$n) {
+ $divisor = $a;
+ for ($i = 1; $i <= $n; ++$i) {
+ $divisor *= ($a + $i);
+ }
+ $summer += ($x ** $n / $divisor);
+ }
+
+ return $x ** $a * exp(0 - $x) * $summer;
+ }
+
+ //
+ // Implementation of the Gamma function
+ //
+ public static function gammaValue(float $value): float
+ {
+ if ($value == 0.0) {
+ return 0;
+ }
+
+ static $p0 = 1.000000000190015;
+ static $p = [
+ 1 => 76.18009172947146,
+ 2 => -86.50532032941677,
+ 3 => 24.01409824083091,
+ 4 => -1.231739572450155,
+ 5 => 1.208650973866179e-3,
+ 6 => -5.395239384953e-6,
+ ];
+
+ $y = $x = $value;
+ $tmp = $x + 5.5;
+ $tmp -= ($x + 0.5) * log($tmp);
+
+ $summer = $p0;
+ for ($j = 1; $j <= 6; ++$j) {
+ $summer += ($p[$j] / ++$y);
+ }
+
+ return exp(0 - $tmp + log(self::SQRT2PI * $summer / $x));
+ }
+
+ /**
+ * logGamma function.
+ *
+ * @version 1.1
+ *
+ * @author Jaco van Kooten
+ *
+ * Original author was Jaco van Kooten. Ported to PHP by Paul Meagher.
+ *
+ * The natural logarithm of the gamma function.
+ * Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz
+ * Applied Mathematics Division
+ * Argonne National Laboratory
+ * Argonne, IL 60439
+ *
+ * References:
+ *
+ * - W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural
+ * Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.
+ * - K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.
+ * - Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.
+ *
+ *
+ *
+ * From the original documentation:
+ *
+ *
+ * This routine calculates the LOG(GAMMA) function for a positive real argument X.
+ * Computation is based on an algorithm outlined in references 1 and 2.
+ * The program uses rational functions that theoretically approximate LOG(GAMMA)
+ * to at least 18 significant decimal digits. The approximation for X > 12 is from
+ * reference 3, while approximations for X < 12.0 are similar to those in reference
+ * 1, but are unpublished. The accuracy achieved depends on the arithmetic system,
+ * the compiler, the intrinsic functions, and proper selection of the
+ * machine-dependent constants.
+ *
+ *
+ * Error returns:
+ * The program returns the value XINF for X .LE. 0.0 or when overflow would occur.
+ * The computation is believed to be free of underflow and overflow.
+ *
+ *
+ * @return float MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305
+ */
+
+ // Log Gamma related constants
+ private const LG_D1 = -0.5772156649015328605195174;
+
+ private const LG_D2 = 0.4227843350984671393993777;
+
+ private const LG_D4 = 1.791759469228055000094023;
+
+ private const LG_P1 = [
+ 4.945235359296727046734888,
+ 201.8112620856775083915565,
+ 2290.838373831346393026739,
+ 11319.67205903380828685045,
+ 28557.24635671635335736389,
+ 38484.96228443793359990269,
+ 26377.48787624195437963534,
+ 7225.813979700288197698961,
+ ];
+
+ private const LG_P2 = [
+ 4.974607845568932035012064,
+ 542.4138599891070494101986,
+ 15506.93864978364947665077,
+ 184793.2904445632425417223,
+ 1088204.76946882876749847,
+ 3338152.967987029735917223,
+ 5106661.678927352456275255,
+ 3074109.054850539556250927,
+ ];
+
+ private const LG_P4 = [
+ 14745.02166059939948905062,
+ 2426813.369486704502836312,
+ 121475557.4045093227939592,
+ 2663432449.630976949898078,
+ 29403789566.34553899906876,
+ 170266573776.5398868392998,
+ 492612579337.743088758812,
+ 560625185622.3951465078242,
+ ];
+
+ private const LG_Q1 = [
+ 67.48212550303777196073036,
+ 1113.332393857199323513008,
+ 7738.757056935398733233834,
+ 27639.87074403340708898585,
+ 54993.10206226157329794414,
+ 61611.22180066002127833352,
+ 36351.27591501940507276287,
+ 8785.536302431013170870835,
+ ];
+
+ private const LG_Q2 = [
+ 183.0328399370592604055942,
+ 7765.049321445005871323047,
+ 133190.3827966074194402448,
+ 1136705.821321969608938755,
+ 5267964.117437946917577538,
+ 13467014.54311101692290052,
+ 17827365.30353274213975932,
+ 9533095.591844353613395747,
+ ];
+
+ private const LG_Q4 = [
+ 2690.530175870899333379843,
+ 639388.5654300092398984238,
+ 41355999.30241388052042842,
+ 1120872109.61614794137657,
+ 14886137286.78813811542398,
+ 101680358627.2438228077304,
+ 341747634550.7377132798597,
+ 446315818741.9713286462081,
+ ];
+
+ private const LG_C = [
+ -0.001910444077728,
+ 8.4171387781295e-4,
+ -5.952379913043012e-4,
+ 7.93650793500350248e-4,
+ -0.002777777777777681622553,
+ 0.08333333333333333331554247,
+ 0.0057083835261,
+ ];
+
+ // Rough estimate of the fourth root of logGamma_xBig
+ private const LG_FRTBIG = 2.25e76;
+
+ private const PNT68 = 0.6796875;
+
+ // Function cache for logGamma
+ private static $logGammaCacheResult = 0.0;
+
+ private static $logGammaCacheX = 0.0;
+
+ public static function logGamma(float $x): float
+ {
+ if ($x == self::$logGammaCacheX) {
+ return self::$logGammaCacheResult;
+ }
+
+ $y = $x;
+ if ($y > 0.0 && $y <= self::LOG_GAMMA_X_MAX_VALUE) {
+ if ($y <= self::EPS) {
+ $res = -log($y);
+ } elseif ($y <= 1.5) {
+ $res = self::logGamma1($y);
+ } elseif ($y <= 4.0) {
+ $res = self::logGamma2($y);
+ } elseif ($y <= 12.0) {
+ $res = self::logGamma3($y);
+ } else {
+ $res = self::logGamma4($y);
+ }
+ } else {
+ // --------------------------
+ // Return for bad arguments
+ // --------------------------
+ $res = self::MAX_VALUE;
+ }
+
+ // ------------------------------
+ // Final adjustments and return
+ // ------------------------------
+ self::$logGammaCacheX = $x;
+ self::$logGammaCacheResult = $res;
+
+ return $res;
+ }
+
+ private static function logGamma1(float $y)
+ {
+ // ---------------------
+ // EPS .LT. X .LE. 1.5
+ // ---------------------
+ if ($y < self::PNT68) {
+ $corr = -log($y);
+ $xm1 = $y;
+ } else {
+ $corr = 0.0;
+ $xm1 = $y - 1.0;
+ }
+
+ $xden = 1.0;
+ $xnum = 0.0;
+ if ($y <= 0.5 || $y >= self::PNT68) {
+ for ($i = 0; $i < 8; ++$i) {
+ $xnum = $xnum * $xm1 + self::LG_P1[$i];
+ $xden = $xden * $xm1 + self::LG_Q1[$i];
+ }
+
+ return $corr + $xm1 * (self::LG_D1 + $xm1 * ($xnum / $xden));
+ }
+
+ $xm2 = $y - 1.0;
+ for ($i = 0; $i < 8; ++$i) {
+ $xnum = $xnum * $xm2 + self::LG_P2[$i];
+ $xden = $xden * $xm2 + self::LG_Q2[$i];
+ }
+
+ return $corr + $xm2 * (self::LG_D2 + $xm2 * ($xnum / $xden));
+ }
+
+ private static function logGamma2(float $y)
+ {
+ // ---------------------
+ // 1.5 .LT. X .LE. 4.0
+ // ---------------------
+ $xm2 = $y - 2.0;
+ $xden = 1.0;
+ $xnum = 0.0;
+ for ($i = 0; $i < 8; ++$i) {
+ $xnum = $xnum * $xm2 + self::LG_P2[$i];
+ $xden = $xden * $xm2 + self::LG_Q2[$i];
+ }
+
+ return $xm2 * (self::LG_D2 + $xm2 * ($xnum / $xden));
+ }
+
+ protected static function logGamma3(float $y)
+ {
+ // ----------------------
+ // 4.0 .LT. X .LE. 12.0
+ // ----------------------
+ $xm4 = $y - 4.0;
+ $xden = -1.0;
+ $xnum = 0.0;
+ for ($i = 0; $i < 8; ++$i) {
+ $xnum = $xnum * $xm4 + self::LG_P4[$i];
+ $xden = $xden * $xm4 + self::LG_Q4[$i];
+ }
+
+ return self::LG_D4 + $xm4 * ($xnum / $xden);
+ }
+
+ protected static function logGamma4(float $y)
+ {
+ // ---------------------------------
+ // Evaluate for argument .GE. 12.0
+ // ---------------------------------
+ $res = 0.0;
+ if ($y <= self::LG_FRTBIG) {
+ $res = self::LG_C[6];
+ $ysq = $y * $y;
+ for ($i = 0; $i < 6; ++$i) {
+ $res = $res / $ysq + self::LG_C[$i];
+ }
+ $res /= $y;
+ $corr = log($y);
+ $res = $res + log(self::SQRT2PI) - 0.5 * $corr;
+ $res += $y * ($corr - 1.0);
+ }
+
+ return $res;
+ }
+}
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php
index 84c10719..5d03e5d5 100644
--- a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php
+++ b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php
@@ -16,8 +16,8 @@ class Permutations
* combinations, for which the internal order is not significant. Use this function
* for lottery-style probability calculations.
*
- * @param int $numObjs Number of different objects
- * @param int $numInSet Number of objects in each permutation
+ * @param mixed (int) $numObjs Number of different objects
+ * @param mixed (int) $numInSet Number of objects in each permutation
*
* @return int|string Number of permutations, or a string containing an error
*/
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php b/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php
index 28a25a75..4f15615c 100644
--- a/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php
+++ b/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php
@@ -23,7 +23,7 @@ class StandardDeviations extends VarianceBase
{
$aArgs = Functions::flattenArrayIndexed($args);
- $aMean = Averages::AVERAGE($aArgs);
+ $aMean = Averages::average($aArgs);
if (!is_string($aMean)) {
$returnValue = 0.0;
@@ -67,7 +67,7 @@ class StandardDeviations extends VarianceBase
{
$aArgs = Functions::flattenArrayIndexed($args);
- $aMean = Averages::AVERAGEA($aArgs);
+ $aMean = Averages::averageA($aArgs);
if (!is_string($aMean)) {
$returnValue = 0.0;
@@ -109,7 +109,7 @@ class StandardDeviations extends VarianceBase
{
$aArgs = Functions::flattenArrayIndexed($args);
- $aMean = Averages::AVERAGE($aArgs);
+ $aMean = Averages::average($aArgs);
if (!is_string($aMean)) {
$returnValue = 0.0;
@@ -153,7 +153,7 @@ class StandardDeviations extends VarianceBase
{
$aArgs = Functions::flattenArrayIndexed($args);
- $aMean = Averages::AVERAGEA($aArgs);
+ $aMean = Averages::averageA($aArgs);
if (!is_string($aMean)) {
$returnValue = 0.0;
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php
index a1137cef..b1dfbaef 100644
--- a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php
+++ b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php
@@ -107,7 +107,7 @@ class Trends
* Calculates, or predicts, a future value by using existing values.
* The predicted value is a y-value for a given x-value.
*
- * @param float $xValue Value of X for which we want to find Y
+ * @param mixed (float) $xValue Value of X for which we want to find Y
* @param mixed $yValues array of mixed Data Series Y
* @param mixed $xValues of mixed Data Series X
*
@@ -140,7 +140,7 @@ class Trends
* @param mixed[] $yValues Data Series Y
* @param mixed[] $xValues Data Series X
* @param mixed[] $newValues Values of X for which we want to find Y
- * @param bool $const a logical value specifying whether to force the intersect to equal 0
+ * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0
*
* @return array of float
*/
@@ -196,8 +196,8 @@ class Trends
*
* @param mixed[] $yValues Data Series Y
* @param null|mixed[] $xValues Data Series X
- * @param bool $const a logical value specifying whether to force the intersect to equal 0
- * @param bool $stats a logical value specifying whether to return additional regression statistics
+ * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0
+ * @param mixed (bool) $stats a logical value specifying whether to return additional regression statistics
*
* @return array|int|string The result, or a string containing an error
*/
@@ -257,8 +257,8 @@ class Trends
*
* @param mixed[] $yValues Data Series Y
* @param null|mixed[] $xValues Data Series X
- * @param bool $const a logical value specifying whether to force the intersect to equal 0
- * @param bool $stats a logical value specifying whether to return additional regression statistics
+ * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0
+ * @param mixed (bool) $stats a logical value specifying whether to return additional regression statistics
*
* @return array|int|string The result, or a string containing an error
*/
@@ -397,7 +397,7 @@ class Trends
* @param mixed[] $yValues Data Series Y
* @param mixed[] $xValues Data Series X
* @param mixed[] $newValues Values of X for which we want to find Y
- * @param bool $const a logical value specifying whether to force the intersect to equal 0
+ * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0
*
* @return array of float
*/
diff --git a/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php b/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php
index 2a275133..846a3124 100644
--- a/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php
+++ b/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php
@@ -13,7 +13,7 @@ class CaseConvert
*
* Converts a string value to upper case.
*
- * @param string $mixedCaseValue
+ * @param mixed (string) $mixedCaseValue
*/
public static function lower($mixedCaseValue): string
{
@@ -31,7 +31,7 @@ class CaseConvert
*
* Converts a string value to upper case.
*
- * @param string $mixedCaseValue
+ * @param mixed (string) $mixedCaseValue
*/
public static function upper($mixedCaseValue): string
{
@@ -49,7 +49,7 @@ class CaseConvert
*
* Converts a string value to upper case.
*
- * @param string $mixedCaseValue
+ * @param mixed (string) $mixedCaseValue
*/
public static function proper($mixedCaseValue): string
{
diff --git a/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php b/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php
index 2263b1a7..0003e0cd 100644
--- a/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php
+++ b/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php
@@ -10,7 +10,7 @@ class CharacterConvert
/**
* CHARACTER.
*
- * @param string $character Value
+ * @param mixed (int) $character Value
*/
public static function character($character): string
{
@@ -31,7 +31,7 @@ class CharacterConvert
/**
* ASCIICODE.
*
- * @param string $characters Value
+ * @param mixed (string) $characters Value
*
* @return int|string A string if arguments are invalid
*/
diff --git a/src/PhpSpreadsheet/Calculation/TextData/Extract.php b/src/PhpSpreadsheet/Calculation/TextData/Extract.php
index 126d9f49..7ef76546 100644
--- a/src/PhpSpreadsheet/Calculation/TextData/Extract.php
+++ b/src/PhpSpreadsheet/Calculation/TextData/Extract.php
@@ -10,8 +10,8 @@ class Extract
/**
* LEFT.
*
- * @param string $value Value
- * @param int $chars Number of characters
+ * @param mixed (string) $value Value
+ * @param mixed (int) $chars Number of characters
*/
public static function left($value = '', $chars = 1): string
{
@@ -32,9 +32,9 @@ class Extract
/**
* MID.
*
- * @param string $value Value
- * @param int $start Start character
- * @param int $chars Number of characters
+ * @param mixed (string) $value Value
+ * @param mixed (int) $start Start character
+ * @param mixed (int) $chars Number of characters
*/
public static function mid($value = '', $start = 1, $chars = null): string
{
@@ -56,8 +56,8 @@ class Extract
/**
* RIGHT.
*
- * @param string $value Value
- * @param int $chars Number of characters
+ * @param mixed (string) $value Value
+ * @param mixed (int) $chars Number of characters
*/
public static function right($value = '', $chars = 1): string
{
diff --git a/src/PhpSpreadsheet/Calculation/TextData/Format.php b/src/PhpSpreadsheet/Calculation/TextData/Format.php
index 2cea474d..f24ed7ae 100644
--- a/src/PhpSpreadsheet/Calculation/TextData/Format.php
+++ b/src/PhpSpreadsheet/Calculation/TextData/Format.php
@@ -18,8 +18,8 @@ class Format
* This function converts a number to text using currency format, with the decimals rounded to the specified place.
* The format used is $#,##0.00_);($#,##0.00)..
*
- * @param float $value The value to format
- * @param int $decimals The number of digits to display to the right of the decimal point.
+ * @param mixed (float) $value The value to format
+ * @param mixed (int) $decimals The number of digits to display to the right of the decimal point.
* If decimals is negative, number is rounded to the left of the decimal point.
* If you omit decimals, it is assumed to be 2
*/
@@ -54,7 +54,7 @@ class Format
*
* @param mixed $value Value to check
* @param mixed $decimals
- * @param bool $noCommas
+ * @param mixed (bool) $noCommas
*/
public static function FIXEDFORMAT($value, $decimals = 2, $noCommas = false): string
{
@@ -72,7 +72,7 @@ class Format
if ($decimals < 0) {
$decimals = 0;
}
- if (!$noCommas) {
+ if ($noCommas === false) {
$valueResult = number_format(
$valueResult,
$decimals,
@@ -88,7 +88,7 @@ class Format
* TEXTFORMAT.
*
* @param mixed $value Value to check
- * @param string $format Format mask to use
+ * @param mixed (string) $format Format mask to use
*/
public static function TEXTFORMAT($value, $format): string
{
@@ -152,8 +152,8 @@ class Format
* NUMBERVALUE.
*
* @param mixed $value Value to check
- * @param string $decimalSeparator decimal separator, defaults to locale defined value
- * @param string $groupSeparator group/thosands separator, defaults to locale defined value
+ * @param mixed (string) $decimalSeparator decimal separator, defaults to locale defined value
+ * @param mixed (string) $groupSeparator group/thosands separator, defaults to locale defined value
*
* @return float|string
*/
diff --git a/src/PhpSpreadsheet/Calculation/TextData/Replace.php b/src/PhpSpreadsheet/Calculation/TextData/Replace.php
index 9a849ba0..a06d4364 100644
--- a/src/PhpSpreadsheet/Calculation/TextData/Replace.php
+++ b/src/PhpSpreadsheet/Calculation/TextData/Replace.php
@@ -10,10 +10,10 @@ class Replace
/**
* REPLACE.
*
- * @param string $oldText String to modify
- * @param int $start Start character
- * @param int $chars Number of characters
- * @param string $newText String to replace in defined position
+ * @param mixed (string) $oldText String to modify
+ * @param mixed (int) $start Start character
+ * @param mixed (int) $chars Number of characters
+ * @param mixed (string) $newText String to replace in defined position
*/
public static function replace($oldText, $start, $chars, $newText): string
{
@@ -31,10 +31,10 @@ class Replace
/**
* SUBSTITUTE.
*
- * @param string $text Value
- * @param string $fromText From Value
- * @param string $toText To Value
- * @param int $instance Instance Number
+ * @param mixed (string) $text Value
+ * @param mixed (string) $fromText From Value
+ * @param mixed (string) $toText To Value
+ * @param mixed (int) $instance Instance Number
*/
public static function substitute($text = '', $fromText = '', $toText = '', $instance = 0): string
{
diff --git a/src/PhpSpreadsheet/Calculation/TextData/Search.php b/src/PhpSpreadsheet/Calculation/TextData/Search.php
index acbe6a24..cf1bf241 100644
--- a/src/PhpSpreadsheet/Calculation/TextData/Search.php
+++ b/src/PhpSpreadsheet/Calculation/TextData/Search.php
@@ -11,9 +11,9 @@ class Search
/**
* SEARCHSENSITIVE.
*
- * @param string $needle The string to look for
- * @param string $haystack The string in which to look
- * @param int $offset Offset within $haystack
+ * @param mixed (string) $needle The string to look for
+ * @param mixed (string) $haystack The string in which to look
+ * @param mixed (int) $offset Offset within $haystack
*
* @return int|string
*/
@@ -46,9 +46,9 @@ class Search
/**
* SEARCHINSENSITIVE.
*
- * @param string $needle The string to look for
- * @param string $haystack The string in which to look
- * @param int $offset Offset within $haystack
+ * @param mixed (string) $needle The string to look for
+ * @param mixed (string) $haystack The string in which to look
+ * @param mixed (int) $offset Offset within $haystack
*
* @return int|string
*/
diff --git a/src/PhpSpreadsheet/Calculation/TextData/Text.php b/src/PhpSpreadsheet/Calculation/TextData/Text.php
index a47d373b..338cdd20 100644
--- a/src/PhpSpreadsheet/Calculation/TextData/Text.php
+++ b/src/PhpSpreadsheet/Calculation/TextData/Text.php
@@ -10,7 +10,7 @@ class Text
/**
* STRINGLENGTH.
*
- * @param string $value Value
+ * @param mixed (string) $value Value
*/
public static function length($value = ''): int
{
@@ -28,8 +28,8 @@ class Text
* EXACT is case-sensitive but ignores formatting differences.
* Use EXACT to test text being entered into a document.
*
- * @param $value1
- * @param $value2
+ * @param mixed (string) $value1
+ * @param mixed (string) $value2
*/
public static function exact($value1, $value2): bool
{
diff --git a/src/PhpSpreadsheet/Calculation/TextData/Trim.php b/src/PhpSpreadsheet/Calculation/TextData/Trim.php
index 0d5688b0..01fff1a8 100644
--- a/src/PhpSpreadsheet/Calculation/TextData/Trim.php
+++ b/src/PhpSpreadsheet/Calculation/TextData/Trim.php
@@ -12,7 +12,7 @@ class Trim
/**
* TRIMNONPRINTABLE.
*
- * @param mixed $stringValue Value to check
+ * @param mixed (string) $stringValue Value to check
*
* @return null|string
*/
@@ -38,7 +38,7 @@ class Trim
/**
* TRIMSPACES.
*
- * @param mixed $stringValue Value to check
+ * @param mixed (string) $stringValue Value to check
*
* @return null|string
*/
diff --git a/tests/data/Calculation/Statistical/BETADIST.php b/tests/data/Calculation/Statistical/BETADIST.php
index 9fbecaaa..2046e189 100644
--- a/tests/data/Calculation/Statistical/BETADIST.php
+++ b/tests/data/Calculation/Statistical/BETADIST.php
@@ -25,12 +25,56 @@ return [
0.685470581054,
2, 8, 10, 1, 3,
],
+ [
+ 0.4059136,
+ 0.4, 4, 5,
+ ],
+ [
+ '#VALUE!',
+ 'NAN', 8, 10, 1, 3,
+ ],
[
'#VALUE!',
2, 'NAN', 10, 1, 3,
],
[
+ '#VALUE!',
+ 2, 8, 'NAN', 1, 3,
+ ],
+ [
+ '#VALUE!',
+ 2, 8, 10, 'NAN', 3,
+ ],
+ [
+ '#VALUE!',
+ 2, 8, 10, 1, 'NAN',
+ ],
+ 'alpha < 0' => [
'#NUM!',
2, -8, 10, 1, 3,
],
+ 'alpha = 0' => [
+ '#NUM!',
+ 2, 0, 10, 1, 3,
+ ],
+ 'beta < 0' => [
+ '#NUM!',
+ 2, 8, -10, 1, 3,
+ ],
+ 'beta = 0' => [
+ '#NUM!',
+ 2, 8, 0, 1, 3,
+ ],
+ 'value < Min' => [
+ '#NUM!',
+ 0.5, 8, 10, 1, 3,
+ ],
+ 'value > Max' => [
+ '#NUM!',
+ 3.5, 8, 10, 1, 3,
+ ],
+ 'Min = Max' => [
+ '#NUM!',
+ 2, 8, 10, 2, 2,
+ ],
];
diff --git a/tests/data/Calculation/Statistical/BETAINV.php b/tests/data/Calculation/Statistical/BETAINV.php
index 5afe14cb..4d8cb5bd 100644
--- a/tests/data/Calculation/Statistical/BETAINV.php
+++ b/tests/data/Calculation/Statistical/BETAINV.php
@@ -25,12 +25,56 @@ return [
0.303225844664,
0.2, 4, 5, 0, 1,
],
+ [
+ '#VALUE!',
+ 'NAN', 4, 5, 0, 1,
+ ],
[
'#VALUE!',
0.2, 'NAN', 5, 0, 1,
],
[
+ '#VALUE!',
+ 0.2, 4, 'NAN', 0, 1,
+ ],
+ [
+ '#VALUE!',
+ 0.2, 4, 5, 'NAN', 1,
+ ],
+ [
+ '#VALUE!',
+ 0.2, 4, 5, 0, 'NAN',
+ ],
+ 'alpha < 0' => [
'#NUM!',
0.2, -4, 5, 0, 1,
],
+ 'alpha = 0' => [
+ '#NUM!',
+ 0.2, 0, 5, 0, 1,
+ ],
+ 'beta < 0' => [
+ '#NUM!',
+ 0.2, 4, -5, 0, 1,
+ ],
+ 'beta = 0' => [
+ '#NUM!',
+ 0.2, 4, 0, 0, 1,
+ ],
+ 'Probability < 0' => [
+ '#NUM!',
+ -0.5, 4, 5, 1, 3,
+ ],
+ 'Probability = 0' => [
+ '#NUM!',
+ 0.0, 4, 5, 1, 3,
+ ],
+ 'Probability > 1' => [
+ '#NUM!',
+ 1.5, 4, 5, 1, 3,
+ ],
+ 'Min = Max' => [
+ '#NUM!',
+ 1, 4, 5, 1, 1,
+ ],
];
diff --git a/tests/data/Calculation/Statistical/CHIDIST.php b/tests/data/Calculation/Statistical/CHIDIST.php
index 5cfdc664..24ddab9f 100644
--- a/tests/data/Calculation/Statistical/CHIDIST.php
+++ b/tests/data/Calculation/Statistical/CHIDIST.php
@@ -35,14 +35,18 @@ return [
],
[
'#VALUE!',
- 'NAN', 3,
+ 'NaN', 3,
],
[
- '#NUM!',
- 8, 0,
+ '#VALUE!',
+ 8, 'NaN',
],
- [
+ 'Value < 0' => [
'#NUM!',
-8, 3,
],
+ 'Degrees < 1' => [
+ '#NUM!',
+ 8, 0,
+ ],
];
diff --git a/tests/data/Calculation/Statistical/CHIINV.php b/tests/data/Calculation/Statistical/CHIINV.php
index 2384cda6..f931a780 100644
--- a/tests/data/Calculation/Statistical/CHIINV.php
+++ b/tests/data/Calculation/Statistical/CHIINV.php
@@ -35,6 +35,22 @@ return [
],
[
'#VALUE!',
- 0.25, 'NAN',
+ 'NaN', 3,
+ ],
+ [
+ '#VALUE!',
+ 0.25, 'NaN',
+ ],
+ 'Probability < 0' => [
+ '#NUM!',
+ -0.1, 3,
+ ],
+ 'Probability > 1' => [
+ '#NUM!',
+ 1.1, 3,
+ ],
+ 'Freedom > 1' => [
+ '#NUM!',
+ 0.1, 0.5,
],
];
diff --git a/tests/data/Calculation/Statistical/FISHER.php b/tests/data/Calculation/Statistical/FISHER.php
index 12909012..faf6442e 100644
--- a/tests/data/Calculation/Statistical/FISHER.php
+++ b/tests/data/Calculation/Statistical/FISHER.php
@@ -13,12 +13,20 @@ return [
1.098612288668,
0.8,
],
+ [
+ 0.972955074528,
+ 0.75,
+ ],
[
'#VALUE!',
'NAN',
],
[
'#NUM!',
- -2,
+ -1.5,
+ ],
+ [
+ '#NUM!',
+ 1.5,
],
];
diff --git a/tests/data/Calculation/Statistical/FISHERINV.php b/tests/data/Calculation/Statistical/FISHERINV.php
index b79fd4f8..d23472b2 100644
--- a/tests/data/Calculation/Statistical/FISHERINV.php
+++ b/tests/data/Calculation/Statistical/FISHERINV.php
@@ -17,6 +17,10 @@ return [
0.992631520201,
2.8,
],
+ [
+ 0.7499999990254,
+ 0.9729550723,
+ ],
[
'#VALUE!',
'NAN',
diff --git a/tests/data/Calculation/Statistical/GAMMA.php b/tests/data/Calculation/Statistical/GAMMA.php
index 760b429d..24b83f04 100644
--- a/tests/data/Calculation/Statistical/GAMMA.php
+++ b/tests/data/Calculation/Statistical/GAMMA.php
@@ -6,8 +6,10 @@ return [
[9.513507698669, 0.1],
[1.0, 1.0],
[0.886226925453, 1.5],
+ [1.3293403881791, 2.5],
[17.837861981813, 4.8],
[52.342777784553, 5.5],
- ['#NUM!', -1],
+ 'Zero value' => ['#NUM!', 0.0],
+ 'Negative integer value' => ['#NUM!', -1],
['#VALUE!', 'NAN'],
];
diff --git a/tests/data/Calculation/Statistical/GAMMADIST.php b/tests/data/Calculation/Statistical/GAMMADIST.php
index e79b3869..2a1bfa14 100644
--- a/tests/data/Calculation/Statistical/GAMMADIST.php
+++ b/tests/data/Calculation/Statistical/GAMMADIST.php
@@ -17,12 +17,44 @@ return [
0.576809918873,
6, 3, 2, true,
],
+ 'Boolean as numeric' => [
+ 0.576809918873,
+ 6, 3, 2, 1,
+ ],
+ [
+ '#VALUE!',
+ 'NAN', 3, 2, true,
+ ],
[
'#VALUE!',
6, 'NAN', 2, true,
],
[
+ '#VALUE!',
+ 6, 3, 'NAN', true,
+ ],
+ [
+ '#VALUE!',
+ 6, 3, 2, 'NAN',
+ ],
+ 'Value < 0' => [
'#NUM!',
-6, 3, 2, true,
],
+ 'A < 0' => [
+ '#NUM!',
+ 6, -3, 2, true,
+ ],
+ 'A = 0' => [
+ '#NUM!',
+ 6, 0, 2, true,
+ ],
+ 'B < 0' => [
+ '#NUM!',
+ 6, 3, -2, true,
+ ],
+ 'B = 0' => [
+ '#NUM!',
+ 6, 3, 0, true,
+ ],
];
diff --git a/tests/data/Calculation/Statistical/GAMMAINV.php b/tests/data/Calculation/Statistical/GAMMAINV.php
index 3b3604b4..c35c4219 100644
--- a/tests/data/Calculation/Statistical/GAMMAINV.php
+++ b/tests/data/Calculation/Statistical/GAMMAINV.php
@@ -11,10 +11,38 @@ return [
],
[
'#VALUE!',
- 'NAN', 3, 2,
+ 'NaN', 3, 2,
],
[
+ '#VALUE!',
+ 0.5, 'NaN', 2,
+ ],
+ [
+ '#VALUE!',
+ 0.5, 3, 'NaN',
+ ],
+ 'Probability < 0' => [
'#NUM!',
-0.5, 3, 2,
],
+ 'Probability > 1' => [
+ '#NUM!',
+ 1.5, 3, 2,
+ ],
+ 'Alpha < 0' => [
+ '#NUM!',
+ 0.5, -3, 2,
+ ],
+ 'Alpha = 0' => [
+ '#NUM!',
+ 0.5, 0, 2,
+ ],
+ 'Beta < 0' => [
+ '#NUM!',
+ 0.5, 3, -2,
+ ],
+ 'Beta = 0' => [
+ '#NUM!',
+ 0.5, 3, 0,
+ ],
];
diff --git a/tests/data/Calculation/Statistical/GAMMALN.php b/tests/data/Calculation/Statistical/GAMMALN.php
index a415f559..7b43eea8 100644
--- a/tests/data/Calculation/Statistical/GAMMALN.php
+++ b/tests/data/Calculation/Statistical/GAMMALN.php
@@ -13,8 +13,12 @@ return [
'#VALUE!',
'NAN',
],
- [
+ 'Value < 0' => [
'#NUM!',
-4.5,
],
+ 'Value = 0' => [
+ '#NUM!',
+ 0.0,
+ ],
];
diff --git a/tests/data/Calculation/TextData/FIND.php b/tests/data/Calculation/TextData/FIND.php
index 0a583456..04d3276d 100644
--- a/tests/data/Calculation/TextData/FIND.php
+++ b/tests/data/Calculation/TextData/FIND.php
@@ -101,4 +101,9 @@ return [
'Mark Baker',
8,
],
+ 'Boolean Needle' => [
+ '#VALUE!',
+ true,
+ 'Mark Baker',
+ ],
];
diff --git a/tests/data/Calculation/TextData/SEARCH.php b/tests/data/Calculation/TextData/SEARCH.php
index 579830f6..fa970bec 100644
--- a/tests/data/Calculation/TextData/SEARCH.php
+++ b/tests/data/Calculation/TextData/SEARCH.php
@@ -94,4 +94,9 @@ return [
'BITE',
'BIT',
],
+ 'Boolean Needle' => [
+ '#VALUE!',
+ true,
+ 'Mark Baker',
+ ],
];