First steps toward refactoring Excel's Statistical Distributions (#1949)
* First steps toward refactoring Statistical Distributions into smaller classes: BETA() and GAMMA() (and related functions) to start with... they all need a lot of tidying up, and more testing; but it's a start * Add basic datatype validations to Beta and Gamma Excel function implementations * Switch to using a trait with the validation methods to provide easier sharing between distribution classes * Additional unit tests for Beta and Gamma functions, including unhappy path for validations * Extract ChiSquared functions * Additional argument validation checks with unit tests for Chi Squared functions * Extract Fisher * Move MEDIAN() and MODE() to the Averages class * Extract filters for Median and Mode for common usage
This commit is contained in:
parent
b7f93754d6
commit
f51c19c125
|
|
@ -328,17 +328,17 @@ class Calculation
|
||||||
],
|
],
|
||||||
'AVEDEV' => [
|
'AVEDEV' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical\Averages::class, 'AVEDEV'],
|
'functionCall' => [Statistical\Averages::class, 'averageDeviations'],
|
||||||
'argumentCount' => '1+',
|
'argumentCount' => '1+',
|
||||||
],
|
],
|
||||||
'AVERAGE' => [
|
'AVERAGE' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical\Averages::class, 'AVERAGE'],
|
'functionCall' => [Statistical\Averages::class, 'average'],
|
||||||
'argumentCount' => '1+',
|
'argumentCount' => '1+',
|
||||||
],
|
],
|
||||||
'AVERAGEA' => [
|
'AVERAGEA' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical\Averages::class, 'AVERAGEA'],
|
'functionCall' => [Statistical\Averages::class, 'averageA'],
|
||||||
'argumentCount' => '1+',
|
'argumentCount' => '1+',
|
||||||
],
|
],
|
||||||
'AVERAGEIF' => [
|
'AVERAGEIF' => [
|
||||||
|
|
@ -383,7 +383,7 @@ class Calculation
|
||||||
],
|
],
|
||||||
'BETADIST' => [
|
'BETADIST' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'BETADIST'],
|
'functionCall' => [Statistical\Distributions\Beta::class, 'distribution'],
|
||||||
'argumentCount' => '3-5',
|
'argumentCount' => '3-5',
|
||||||
],
|
],
|
||||||
'BETA.DIST' => [
|
'BETA.DIST' => [
|
||||||
|
|
@ -393,12 +393,12 @@ class Calculation
|
||||||
],
|
],
|
||||||
'BETAINV' => [
|
'BETAINV' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'BETAINV'],
|
'functionCall' => [Statistical\Distributions\Beta::class, 'inverse'],
|
||||||
'argumentCount' => '3-5',
|
'argumentCount' => '3-5',
|
||||||
],
|
],
|
||||||
'BETA.INV' => [
|
'BETA.INV' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'BETAINV'],
|
'functionCall' => [Statistical\Distributions\Beta::class, 'inverse'],
|
||||||
'argumentCount' => '3-5',
|
'argumentCount' => '3-5',
|
||||||
],
|
],
|
||||||
'BIN2DEC' => [
|
'BIN2DEC' => [
|
||||||
|
|
@ -488,7 +488,7 @@ class Calculation
|
||||||
],
|
],
|
||||||
'CHIDIST' => [
|
'CHIDIST' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'CHIDIST'],
|
'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distribution'],
|
||||||
'argumentCount' => '2',
|
'argumentCount' => '2',
|
||||||
],
|
],
|
||||||
'CHISQ.DIST' => [
|
'CHISQ.DIST' => [
|
||||||
|
|
@ -498,12 +498,12 @@ class Calculation
|
||||||
],
|
],
|
||||||
'CHISQ.DIST.RT' => [
|
'CHISQ.DIST.RT' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'CHIDIST'],
|
'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distribution'],
|
||||||
'argumentCount' => '2',
|
'argumentCount' => '2',
|
||||||
],
|
],
|
||||||
'CHIINV' => [
|
'CHIINV' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'CHIINV'],
|
'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverse'],
|
||||||
'argumentCount' => '2',
|
'argumentCount' => '2',
|
||||||
],
|
],
|
||||||
'CHISQ.INV' => [
|
'CHISQ.INV' => [
|
||||||
|
|
@ -513,7 +513,7 @@ class Calculation
|
||||||
],
|
],
|
||||||
'CHISQ.INV.RT' => [
|
'CHISQ.INV.RT' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'CHIINV'],
|
'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverse'],
|
||||||
'argumentCount' => '2',
|
'argumentCount' => '2',
|
||||||
],
|
],
|
||||||
'CHITEST' => [
|
'CHITEST' => [
|
||||||
|
|
@ -1055,12 +1055,12 @@ class Calculation
|
||||||
],
|
],
|
||||||
'FISHER' => [
|
'FISHER' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'FISHER'],
|
'functionCall' => [Statistical\Distributions\Fisher::class, 'distribution'],
|
||||||
'argumentCount' => '1',
|
'argumentCount' => '1',
|
||||||
],
|
],
|
||||||
'FISHERINV' => [
|
'FISHERINV' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'FISHERINV'],
|
'functionCall' => [Statistical\Distributions\Fisher::class, 'inverse'],
|
||||||
'argumentCount' => '1',
|
'argumentCount' => '1',
|
||||||
],
|
],
|
||||||
'FIXED' => [
|
'FIXED' => [
|
||||||
|
|
@ -1147,37 +1147,37 @@ class Calculation
|
||||||
],
|
],
|
||||||
'GAMMA' => [
|
'GAMMA' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'GAMMAFunction'],
|
'functionCall' => [Statistical\Distributions\Gamma::class, 'gamma'],
|
||||||
'argumentCount' => '1',
|
'argumentCount' => '1',
|
||||||
],
|
],
|
||||||
'GAMMADIST' => [
|
'GAMMADIST' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'GAMMADIST'],
|
'functionCall' => [Statistical\Distributions\Gamma::class, 'distribution'],
|
||||||
'argumentCount' => '4',
|
'argumentCount' => '4',
|
||||||
],
|
],
|
||||||
'GAMMA.DIST' => [
|
'GAMMA.DIST' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'GAMMADIST'],
|
'functionCall' => [Statistical\Distributions\Gamma::class, 'distribution'],
|
||||||
'argumentCount' => '4',
|
'argumentCount' => '4',
|
||||||
],
|
],
|
||||||
'GAMMAINV' => [
|
'GAMMAINV' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'GAMMAINV'],
|
'functionCall' => [Statistical\Distributions\Gamma::class, 'inverse'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'GAMMA.INV' => [
|
'GAMMA.INV' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'GAMMAINV'],
|
'functionCall' => [Statistical\Distributions\Gamma::class, 'inverse'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'GAMMALN' => [
|
'GAMMALN' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'GAMMALN'],
|
'functionCall' => [Statistical\Distributions\Gamma::class, 'ln'],
|
||||||
'argumentCount' => '1',
|
'argumentCount' => '1',
|
||||||
],
|
],
|
||||||
'GAMMALN.PRECISE' => [
|
'GAMMALN.PRECISE' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'GAMMALN'],
|
'functionCall' => [Statistical\Distributions\Gamma::class, 'ln'],
|
||||||
'argumentCount' => '1',
|
'argumentCount' => '1',
|
||||||
],
|
],
|
||||||
'GAUSS' => [
|
'GAUSS' => [
|
||||||
|
|
@ -1646,7 +1646,7 @@ class Calculation
|
||||||
],
|
],
|
||||||
'MEDIAN' => [
|
'MEDIAN' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'MEDIAN'],
|
'functionCall' => [Statistical\Averages::class, 'median'],
|
||||||
'argumentCount' => '1+',
|
'argumentCount' => '1+',
|
||||||
],
|
],
|
||||||
'MEDIANIF' => [
|
'MEDIANIF' => [
|
||||||
|
|
@ -1706,7 +1706,7 @@ class Calculation
|
||||||
],
|
],
|
||||||
'MODE' => [
|
'MODE' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'MODE'],
|
'functionCall' => [Statistical\Averages::class, 'mode'],
|
||||||
'argumentCount' => '1+',
|
'argumentCount' => '1+',
|
||||||
],
|
],
|
||||||
'MODE.MULT' => [
|
'MODE.MULT' => [
|
||||||
|
|
@ -1716,7 +1716,7 @@ class Calculation
|
||||||
],
|
],
|
||||||
'MODE.SNGL' => [
|
'MODE.SNGL' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'MODE'],
|
'functionCall' => [Statistical\Averages::class, 'mode'],
|
||||||
'argumentCount' => '1+',
|
'argumentCount' => '1+',
|
||||||
],
|
],
|
||||||
'MONTH' => [
|
'MONTH' => [
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class DAverage extends DatabaseAbstract
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Averages::AVERAGE(
|
return Averages::average(
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,13 @@ class Amortization
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* AMORDEGRC(cost,purchased,firstPeriod,salvage,period,rate[,basis])
|
* 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 $purchased Date of the purchase of the asset
|
||||||
* @param mixed $firstPeriod Date of the end of the first period
|
* @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 mixed $salvage The salvage value at the end of the life of the asset
|
||||||
* @param float $period The period
|
* @param mixed (float) $period The period
|
||||||
* @param float $rate Rate of depreciation
|
* @param mixed (float) $rate Rate of depreciation
|
||||||
* @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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
@ -88,13 +88,13 @@ class Amortization
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* AMORLINC(cost,purchased,firstPeriod,salvage,period,rate[,basis])
|
* 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 $purchased Date of the purchase of the asset
|
||||||
* @param mixed $firstPeriod Date of the end of the first period
|
* @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 mixed $salvage The salvage value at the end of the life of the asset
|
||||||
* @param float $period The period
|
* @param mixed (float) $period The period
|
||||||
* @param float $rate Rate of depreciation
|
* @param mixed (float) $rate Rate of depreciation
|
||||||
* @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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,12 @@ class Coupons
|
||||||
* date when the security is traded to the buyer.
|
* date when the security is traded to the buyer.
|
||||||
* @param mixed $maturity The security's maturity date.
|
* @param mixed $maturity The security's maturity date.
|
||||||
* The maturity date is the date when the security expires.
|
* 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:
|
* Valid frequency values are:
|
||||||
* 1 Annual
|
* 1 Annual
|
||||||
* 2 Semi-Annual
|
* 2 Semi-Annual
|
||||||
* 4 Quarterly
|
* 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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
@ -88,7 +88,7 @@ class Coupons
|
||||||
* 1 Annual
|
* 1 Annual
|
||||||
* 2 Semi-Annual
|
* 2 Semi-Annual
|
||||||
* 4 Quarterly
|
* 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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
@ -153,7 +153,7 @@ class Coupons
|
||||||
* 1 Annual
|
* 1 Annual
|
||||||
* 2 Semi-Annual
|
* 2 Semi-Annual
|
||||||
* 4 Quarterly
|
* 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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
@ -211,7 +211,7 @@ class Coupons
|
||||||
* 1 Annual
|
* 1 Annual
|
||||||
* 2 Semi-Annual
|
* 2 Semi-Annual
|
||||||
* 4 Quarterly
|
* 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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
@ -260,7 +260,7 @@ class Coupons
|
||||||
* 1 Annual
|
* 1 Annual
|
||||||
* 2 Semi-Annual
|
* 2 Semi-Annual
|
||||||
* 4 Quarterly
|
* 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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
@ -309,7 +309,7 @@ class Coupons
|
||||||
* 1 Annual
|
* 1 Annual
|
||||||
* 2 Semi-Annual
|
* 2 Semi-Annual
|
||||||
* 4 Quarterly
|
* 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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,14 @@ class Depreciation
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DB(cost,salvage,life,period[,month])
|
* DB(cost,salvage,life,period[,month])
|
||||||
*
|
*
|
||||||
* @param float $cost Initial cost of the asset
|
* @param mixed (float) $cost Initial cost of the asset
|
||||||
* @param float $salvage Value at the end of the depreciation.
|
* @param mixed (float) $salvage Value at the end of the depreciation.
|
||||||
* (Sometimes called the salvage value of the asset)
|
* (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)
|
* (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.
|
* 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.
|
* it defaults to 12.
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string
|
||||||
|
|
@ -85,14 +85,14 @@ class Depreciation
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DDB(cost,salvage,life,period[,factor])
|
* DDB(cost,salvage,life,period[,factor])
|
||||||
*
|
*
|
||||||
* @param float $cost Initial cost of the asset
|
* @param mixed (float) $cost Initial cost of the asset
|
||||||
* @param float $salvage Value at the end of the depreciation.
|
* @param mixed (float) $salvage Value at the end of the depreciation.
|
||||||
* (Sometimes called the salvage value of the asset)
|
* (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)
|
* (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.
|
* 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
|
* If factor is omitted, it is assumed to be 2 (the
|
||||||
* double-declining balance method).
|
* double-declining balance method).
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ class Dollar
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DOLLARDE(fractional_dollar,fraction)
|
* DOLLARDE(fractional_dollar,fraction)
|
||||||
*
|
*
|
||||||
* @param float $fractionalDollar Fractional Dollar
|
* @param mixed (float) $fractionalDollar Fractional Dollar
|
||||||
* @param int $fraction Fraction
|
* @param mixed (int) $fraction Fraction
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
|
|
@ -52,8 +52,8 @@ class Dollar
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DOLLARFR(decimal_dollar,fraction)
|
* DOLLARFR(decimal_dollar,fraction)
|
||||||
*
|
*
|
||||||
* @param float $decimalDollar Decimal Dollar
|
* @param mixed (float) $decimalDollar Decimal Dollar
|
||||||
* @param int $fraction Fraction
|
* @param mixed (int) $fraction Fraction
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ class InterestRate
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* EFFECT(nominal_rate,npery)
|
* EFFECT(nominal_rate,npery)
|
||||||
*
|
*
|
||||||
* @param float $nominalRate Nominal interest rate
|
* @param mixed (float) $nominalRate Nominal interest rate
|
||||||
* @param int $periodsPerYear Number of compounding payments per year
|
* @param mixed (int) $periodsPerYear Number of compounding payments per year
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @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.
|
* Returns the nominal interest rate given the effective rate and the number of compounding payments per year.
|
||||||
*
|
*
|
||||||
* @param float $effectiveRate Effective interest rate
|
* @param mixed (float) $effectiveRate Effective interest rate
|
||||||
* @param int $periodsPerYear Number of compounding payments per year
|
* @param mixed (int) $periodsPerYear Number of compounding payments per year
|
||||||
*
|
*
|
||||||
* @return float|string Result, or a string containing an error
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,14 @@ class Price extends BaseValidations
|
||||||
* is traded to the buyer.
|
* is traded to the buyer.
|
||||||
* @param mixed $maturity The security's maturity date.
|
* @param mixed $maturity The security's maturity date.
|
||||||
* The maturity date is the date when the security expires.
|
* The maturity date is the date when the security expires.
|
||||||
* @param float $rate the security's annual coupon rate
|
* @param mixed (float) $rate the security's annual coupon rate
|
||||||
* @param float $yield the security's annual yield
|
* @param mixed (float) $yield the security's annual yield
|
||||||
* @param float $redemption The number of coupon payments per year.
|
* @param mixed (float) $redemption The number of coupon payments per year.
|
||||||
* For annual payments, frequency = 1;
|
* For annual payments, frequency = 1;
|
||||||
* for semiannual, frequency = 2;
|
* for semiannual, frequency = 2;
|
||||||
* for quarterly, frequency = 4.
|
* for quarterly, frequency = 4.
|
||||||
* @param int $frequency
|
* @param mixed (int) $frequency
|
||||||
* @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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
@ -87,9 +87,9 @@ class Price extends BaseValidations
|
||||||
* is traded to the buyer.
|
* is traded to the buyer.
|
||||||
* @param mixed $maturity The security's maturity date.
|
* @param mixed $maturity The security's maturity date.
|
||||||
* The maturity date is the date when the security expires.
|
* The maturity date is the date when the security expires.
|
||||||
* @param float $discount The security's discount rate
|
* @param mixed (float) $discount The security's discount rate
|
||||||
* @param float $redemption The security's redemption value per $100 face value
|
* @param mixed (float) $redemption The security's redemption value per $100 face value
|
||||||
* @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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
@ -137,9 +137,9 @@ class Price extends BaseValidations
|
||||||
* @param mixed $maturity The security's maturity date.
|
* @param mixed $maturity The security's maturity date.
|
||||||
* The maturity date is the date when the security expires.
|
* The maturity date is the date when the security expires.
|
||||||
* @param mixed $issue The security's issue date
|
* @param mixed $issue The security's issue date
|
||||||
* @param float $rate The security's interest rate at date of issue
|
* @param mixed (float) $rate The security's interest rate at date of issue
|
||||||
* @param float $yield The security's annual yield
|
* @param mixed (float) $yield The security's annual yield
|
||||||
* @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
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class TreasuryBill
|
||||||
* when the Treasury bill is traded to the buyer.
|
* when the Treasury bill is traded to the buyer.
|
||||||
* @param mixed $maturity The Treasury bill's maturity date.
|
* @param mixed $maturity The Treasury bill's maturity date.
|
||||||
* The maturity date is the date when the Treasury bill expires.
|
* 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
|
* @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.
|
* when the Treasury bill is traded to the buyer.
|
||||||
* @param mixed $maturity The Treasury bill's maturity date.
|
* @param mixed $maturity The Treasury bill's maturity date.
|
||||||
* The maturity date is the date when the Treasury bill expires.
|
* 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
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
|
|
@ -117,7 +117,7 @@ class TreasuryBill
|
||||||
* the Treasury bill is traded to the buyer.
|
* the Treasury bill is traded to the buyer.
|
||||||
* @param mixed $maturity The Treasury bill's maturity date.
|
* @param mixed $maturity The Treasury bill's maturity date.
|
||||||
* The maturity date is the date when the Treasury bill expires.
|
* 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
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -25,15 +25,15 @@ class Address
|
||||||
*
|
*
|
||||||
* @param mixed $row Row number to use in the cell reference
|
* @param mixed $row Row number to use in the cell reference
|
||||||
* @param mixed $column Column 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
|
* 1 or omitted Absolute
|
||||||
* 2 Absolute row; relative column
|
* 2 Absolute row; relative column
|
||||||
* 3 Relative row; absolute column
|
* 3 Relative row; absolute column
|
||||||
* 4 Relative
|
* 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
|
* TRUE or omitted ADDRESS returns an A1-style reference
|
||||||
* FALSE ADDRESS returns an R1C1-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
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class Indirect
|
||||||
* NOTE - INDIRECT() does not yet support the optional a1 parameter introduced in Excel 2010
|
* 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 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
|
* @return array|string An array containing a cell or range of cells, or a string on error
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1156,7 +1156,7 @@ class MathTrig
|
||||||
$aArgs = self::filterFormulaArgs($cellReference, $aArgs);
|
$aArgs = self::filterFormulaArgs($cellReference, $aArgs);
|
||||||
switch ($subtotal) {
|
switch ($subtotal) {
|
||||||
case 1:
|
case 1:
|
||||||
return Statistical\Averages::AVERAGE($aArgs);
|
return Statistical\Averages::average($aArgs);
|
||||||
case 2:
|
case 2:
|
||||||
return Statistical\Counts::COUNT($aArgs);
|
return Statistical\Counts::COUNT($aArgs);
|
||||||
case 3:
|
case 3:
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -19,14 +19,14 @@ class Averages extends AggregateBase
|
||||||
*
|
*
|
||||||
* @return float|string (string if result is an error)
|
* @return float|string (string if result is an error)
|
||||||
*/
|
*/
|
||||||
public static function AVEDEV(...$args)
|
public static function averageDeviations(...$args)
|
||||||
{
|
{
|
||||||
$aArgs = Functions::flattenArrayIndexed($args);
|
$aArgs = Functions::flattenArrayIndexed($args);
|
||||||
|
|
||||||
// Return value
|
// Return value
|
||||||
$returnValue = 0;
|
$returnValue = 0;
|
||||||
|
|
||||||
$aMean = self::AVERAGE(...$args);
|
$aMean = self::average(...$args);
|
||||||
if ($aMean === Functions::DIV0()) {
|
if ($aMean === Functions::DIV0()) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
} elseif ($aMean === Functions::VALUE()) {
|
} elseif ($aMean === Functions::VALUE()) {
|
||||||
|
|
@ -68,7 +68,7 @@ class Averages extends AggregateBase
|
||||||
*
|
*
|
||||||
* @return float|string (string if result is an error)
|
* @return float|string (string if result is an error)
|
||||||
*/
|
*/
|
||||||
public static function AVERAGE(...$args)
|
public static function average(...$args)
|
||||||
{
|
{
|
||||||
$returnValue = $aCount = 0;
|
$returnValue = $aCount = 0;
|
||||||
|
|
||||||
|
|
@ -107,7 +107,7 @@ class Averages extends AggregateBase
|
||||||
*
|
*
|
||||||
* @return float|string (string if result is an error)
|
* @return float|string (string if result is an error)
|
||||||
*/
|
*/
|
||||||
public static function AVERAGEA(...$args)
|
public static function averageA(...$args)
|
||||||
{
|
{
|
||||||
$returnValue = null;
|
$returnValue = null;
|
||||||
|
|
||||||
|
|
@ -134,4 +134,126 @@ class Averages extends AggregateBase
|
||||||
|
|
||||||
return Functions::DIV0();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ class Confidence
|
||||||
*
|
*
|
||||||
* Returns the confidence interval for a population mean
|
* Returns the confidence interval for a population mean
|
||||||
*
|
*
|
||||||
* @param float $alpha
|
* @param mixed (float) $alpha
|
||||||
* @param float $stdDev Standard Deviation
|
* @param mixed (float) $stdDev Standard Deviation
|
||||||
* @param float $size
|
* @param mixed (float) $size
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
trait BaseValidations
|
||||||
|
{
|
||||||
|
protected static function validateFloat($value): float
|
||||||
|
{
|
||||||
|
if (!is_numeric($value)) {
|
||||||
|
throw new Exception(Functions::VALUE());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function validateInt($value): int
|
||||||
|
{
|
||||||
|
if (!is_numeric($value)) {
|
||||||
|
throw new Exception(Functions::VALUE());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) floor($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function validateBool($value): bool
|
||||||
|
{
|
||||||
|
if (!is_bool($value) && !is_numeric($value)) {
|
||||||
|
throw new Exception(Functions::VALUE());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,263 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
class Beta
|
||||||
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
|
private const MAX_ITERATIONS = 256;
|
||||||
|
|
||||||
|
private const LOG_GAMMA_X_MAX_VALUE = 2.55e305;
|
||||||
|
|
||||||
|
private const XMININ = 2.23e-308;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BETADIST.
|
||||||
|
*
|
||||||
|
* Returns the beta distribution.
|
||||||
|
*
|
||||||
|
* @param mixed (float) $value Value 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
|
||||||
|
* @param mixed (float) $rMax
|
||||||
|
*
|
||||||
|
* @return float|string
|
||||||
|
*/
|
||||||
|
public static function distribution($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);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$value = self::validateFloat($value);
|
||||||
|
$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 (($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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
class ChiSquared
|
||||||
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
|
private const MAX_ITERATIONS = 256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CHIDIST.
|
||||||
|
*
|
||||||
|
* Returns the one-tailed probability of the chi-squared distribution.
|
||||||
|
*
|
||||||
|
* @param mixed (float) $value Value for the function
|
||||||
|
* @param mixed (int) $degrees degrees of freedom
|
||||||
|
*
|
||||||
|
* @return float|string
|
||||||
|
*/
|
||||||
|
public static function distribution($value, $degrees)
|
||||||
|
{
|
||||||
|
$value = Functions::flattenSingleValue($value);
|
||||||
|
$degrees = Functions::flattenSingleValue($degrees);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$value = self::validateFloat($value);
|
||||||
|
$degrees = self::validateInt($degrees);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
class Fisher
|
||||||
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FISHER.
|
||||||
|
*
|
||||||
|
* Returns the Fisher transformation at x. This transformation produces a function that
|
||||||
|
* is normally distributed rather than skewed. Use this function to perform hypothesis
|
||||||
|
* testing on the correlation coefficient.
|
||||||
|
*
|
||||||
|
* @param mixed (float) $value
|
||||||
|
*
|
||||||
|
* @return float|string
|
||||||
|
*/
|
||||||
|
public static function distribution($value)
|
||||||
|
{
|
||||||
|
$value = Functions::flattenSingleValue($value);
|
||||||
|
|
||||||
|
try {
|
||||||
|
self::validateFloat($value);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
class Gamma extends GammaBase
|
||||||
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GAMMA.
|
||||||
|
*
|
||||||
|
* Return the gamma function value.
|
||||||
|
*
|
||||||
|
* @param mixed (float) $value
|
||||||
|
*
|
||||||
|
* @return float|string The result, or a string containing an error
|
||||||
|
*/
|
||||||
|
public static function gamma($value)
|
||||||
|
{
|
||||||
|
$value = Functions::flattenSingleValue($value);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$value = self::validateFloat($value);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,377 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
abstract class GammaBase
|
||||||
|
{
|
||||||
|
private const LOG_GAMMA_X_MAX_VALUE = 2.55e305;
|
||||||
|
|
||||||
|
private const EPS = 2.22e-16;
|
||||||
|
|
||||||
|
private const MAX_VALUE = 1.2e308;
|
||||||
|
|
||||||
|
private const SQRT2PI = 2.5066282746310005024157652848110452530069867406099;
|
||||||
|
|
||||||
|
private const MAX_ITERATIONS = 256;
|
||||||
|
|
||||||
|
protected static function calculateDistribution(float $value, float $a, float $b, bool $cumulative)
|
||||||
|
{
|
||||||
|
if ($cumulative) {
|
||||||
|
return self::incompleteGamma($a, $value / $b) / self::gammaValue($a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1 / ($b ** $a * self::gammaValue($a))) * $value ** ($a - 1) * exp(0 - ($value / $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function calculateInverse(float $probability, float $alpha, float $beta)
|
||||||
|
{
|
||||||
|
$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::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. <br />
|
||||||
|
* Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz <br />
|
||||||
|
* Applied Mathematics Division <br />
|
||||||
|
* Argonne National Laboratory <br />
|
||||||
|
* Argonne, IL 60439 <br />
|
||||||
|
* <p>
|
||||||
|
* References:
|
||||||
|
* <ol>
|
||||||
|
* <li>W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural
|
||||||
|
* Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.</li>
|
||||||
|
* <li>K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.</li>
|
||||||
|
* <li>Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.</li>
|
||||||
|
* </ol>
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* From the original documentation:
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Error returns: <br />
|
||||||
|
* 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.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,8 +16,8 @@ class Permutations
|
||||||
* combinations, for which the internal order is not significant. Use this function
|
* combinations, for which the internal order is not significant. Use this function
|
||||||
* for lottery-style probability calculations.
|
* for lottery-style probability calculations.
|
||||||
*
|
*
|
||||||
* @param int $numObjs Number of different objects
|
* @param mixed (int) $numObjs Number of different objects
|
||||||
* @param int $numInSet Number of objects in each permutation
|
* @param mixed (int) $numInSet Number of objects in each permutation
|
||||||
*
|
*
|
||||||
* @return int|string Number of permutations, or a string containing an error
|
* @return int|string Number of permutations, or a string containing an error
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class StandardDeviations extends VarianceBase
|
||||||
{
|
{
|
||||||
$aArgs = Functions::flattenArrayIndexed($args);
|
$aArgs = Functions::flattenArrayIndexed($args);
|
||||||
|
|
||||||
$aMean = Averages::AVERAGE($aArgs);
|
$aMean = Averages::average($aArgs);
|
||||||
|
|
||||||
if (!is_string($aMean)) {
|
if (!is_string($aMean)) {
|
||||||
$returnValue = 0.0;
|
$returnValue = 0.0;
|
||||||
|
|
@ -67,7 +67,7 @@ class StandardDeviations extends VarianceBase
|
||||||
{
|
{
|
||||||
$aArgs = Functions::flattenArrayIndexed($args);
|
$aArgs = Functions::flattenArrayIndexed($args);
|
||||||
|
|
||||||
$aMean = Averages::AVERAGEA($aArgs);
|
$aMean = Averages::averageA($aArgs);
|
||||||
|
|
||||||
if (!is_string($aMean)) {
|
if (!is_string($aMean)) {
|
||||||
$returnValue = 0.0;
|
$returnValue = 0.0;
|
||||||
|
|
@ -109,7 +109,7 @@ class StandardDeviations extends VarianceBase
|
||||||
{
|
{
|
||||||
$aArgs = Functions::flattenArrayIndexed($args);
|
$aArgs = Functions::flattenArrayIndexed($args);
|
||||||
|
|
||||||
$aMean = Averages::AVERAGE($aArgs);
|
$aMean = Averages::average($aArgs);
|
||||||
|
|
||||||
if (!is_string($aMean)) {
|
if (!is_string($aMean)) {
|
||||||
$returnValue = 0.0;
|
$returnValue = 0.0;
|
||||||
|
|
@ -153,7 +153,7 @@ class StandardDeviations extends VarianceBase
|
||||||
{
|
{
|
||||||
$aArgs = Functions::flattenArrayIndexed($args);
|
$aArgs = Functions::flattenArrayIndexed($args);
|
||||||
|
|
||||||
$aMean = Averages::AVERAGEA($aArgs);
|
$aMean = Averages::averageA($aArgs);
|
||||||
|
|
||||||
if (!is_string($aMean)) {
|
if (!is_string($aMean)) {
|
||||||
$returnValue = 0.0;
|
$returnValue = 0.0;
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ class Trends
|
||||||
* Calculates, or predicts, a future value by using existing values.
|
* Calculates, or predicts, a future value by using existing values.
|
||||||
* The predicted value is a y-value for a given x-value.
|
* 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 $yValues array of mixed Data Series Y
|
||||||
* @param mixed $xValues of mixed Data Series X
|
* @param mixed $xValues of mixed Data Series X
|
||||||
*
|
*
|
||||||
|
|
@ -140,7 +140,7 @@ class Trends
|
||||||
* @param mixed[] $yValues Data Series Y
|
* @param mixed[] $yValues Data Series Y
|
||||||
* @param mixed[] $xValues Data Series X
|
* @param mixed[] $xValues Data Series X
|
||||||
* @param mixed[] $newValues Values of X for which we want to find Y
|
* @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
|
* @return array of float
|
||||||
*/
|
*/
|
||||||
|
|
@ -196,8 +196,8 @@ class Trends
|
||||||
*
|
*
|
||||||
* @param mixed[] $yValues Data Series Y
|
* @param mixed[] $yValues Data Series Y
|
||||||
* @param null|mixed[] $xValues Data Series X
|
* @param null|mixed[] $xValues Data Series X
|
||||||
* @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
|
||||||
* @param bool $stats a logical value specifying whether to return additional regression statistics
|
* @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
|
* @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 mixed[] $yValues Data Series Y
|
||||||
* @param null|mixed[] $xValues Data Series X
|
* @param null|mixed[] $xValues Data Series X
|
||||||
* @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
|
||||||
* @param bool $stats a logical value specifying whether to return additional regression statistics
|
* @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
|
* @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[] $yValues Data Series Y
|
||||||
* @param mixed[] $xValues Data Series X
|
* @param mixed[] $xValues Data Series X
|
||||||
* @param mixed[] $newValues Values of X for which we want to find Y
|
* @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
|
* @return array of float
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ class CaseConvert
|
||||||
*
|
*
|
||||||
* Converts a string value to upper case.
|
* Converts a string value to upper case.
|
||||||
*
|
*
|
||||||
* @param string $mixedCaseValue
|
* @param mixed (string) $mixedCaseValue
|
||||||
*/
|
*/
|
||||||
public static function lower($mixedCaseValue): string
|
public static function lower($mixedCaseValue): string
|
||||||
{
|
{
|
||||||
|
|
@ -31,7 +31,7 @@ class CaseConvert
|
||||||
*
|
*
|
||||||
* Converts a string value to upper case.
|
* Converts a string value to upper case.
|
||||||
*
|
*
|
||||||
* @param string $mixedCaseValue
|
* @param mixed (string) $mixedCaseValue
|
||||||
*/
|
*/
|
||||||
public static function upper($mixedCaseValue): string
|
public static function upper($mixedCaseValue): string
|
||||||
{
|
{
|
||||||
|
|
@ -49,7 +49,7 @@ class CaseConvert
|
||||||
*
|
*
|
||||||
* Converts a string value to upper case.
|
* Converts a string value to upper case.
|
||||||
*
|
*
|
||||||
* @param string $mixedCaseValue
|
* @param mixed (string) $mixedCaseValue
|
||||||
*/
|
*/
|
||||||
public static function proper($mixedCaseValue): string
|
public static function proper($mixedCaseValue): string
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ class CharacterConvert
|
||||||
/**
|
/**
|
||||||
* CHARACTER.
|
* CHARACTER.
|
||||||
*
|
*
|
||||||
* @param string $character Value
|
* @param mixed (int) $character Value
|
||||||
*/
|
*/
|
||||||
public static function character($character): string
|
public static function character($character): string
|
||||||
{
|
{
|
||||||
|
|
@ -31,7 +31,7 @@ class CharacterConvert
|
||||||
/**
|
/**
|
||||||
* ASCIICODE.
|
* ASCIICODE.
|
||||||
*
|
*
|
||||||
* @param string $characters Value
|
* @param mixed (string) $characters Value
|
||||||
*
|
*
|
||||||
* @return int|string A string if arguments are invalid
|
* @return int|string A string if arguments are invalid
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ class Extract
|
||||||
/**
|
/**
|
||||||
* LEFT.
|
* LEFT.
|
||||||
*
|
*
|
||||||
* @param string $value Value
|
* @param mixed (string) $value Value
|
||||||
* @param int $chars Number of characters
|
* @param mixed (int) $chars Number of characters
|
||||||
*/
|
*/
|
||||||
public static function left($value = '', $chars = 1): string
|
public static function left($value = '', $chars = 1): string
|
||||||
{
|
{
|
||||||
|
|
@ -32,9 +32,9 @@ class Extract
|
||||||
/**
|
/**
|
||||||
* MID.
|
* MID.
|
||||||
*
|
*
|
||||||
* @param string $value Value
|
* @param mixed (string) $value Value
|
||||||
* @param int $start Start character
|
* @param mixed (int) $start Start character
|
||||||
* @param int $chars Number of characters
|
* @param mixed (int) $chars Number of characters
|
||||||
*/
|
*/
|
||||||
public static function mid($value = '', $start = 1, $chars = null): string
|
public static function mid($value = '', $start = 1, $chars = null): string
|
||||||
{
|
{
|
||||||
|
|
@ -56,8 +56,8 @@ class Extract
|
||||||
/**
|
/**
|
||||||
* RIGHT.
|
* RIGHT.
|
||||||
*
|
*
|
||||||
* @param string $value Value
|
* @param mixed (string) $value Value
|
||||||
* @param int $chars Number of characters
|
* @param mixed (int) $chars Number of characters
|
||||||
*/
|
*/
|
||||||
public static function right($value = '', $chars = 1): string
|
public static function right($value = '', $chars = 1): string
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ class Format
|
||||||
* This function converts a number to text using currency format, with the decimals rounded to the specified place.
|
* 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)..
|
* The format used is $#,##0.00_);($#,##0.00)..
|
||||||
*
|
*
|
||||||
* @param float $value The value to format
|
* @param mixed (float) $value The value to format
|
||||||
* @param int $decimals The number of digits to display to the right of the decimal point.
|
* @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 decimals is negative, number is rounded to the left of the decimal point.
|
||||||
* If you omit decimals, it is assumed to be 2
|
* If you omit decimals, it is assumed to be 2
|
||||||
*/
|
*/
|
||||||
|
|
@ -54,7 +54,7 @@ class Format
|
||||||
*
|
*
|
||||||
* @param mixed $value Value to check
|
* @param mixed $value Value to check
|
||||||
* @param mixed $decimals
|
* @param mixed $decimals
|
||||||
* @param bool $noCommas
|
* @param mixed (bool) $noCommas
|
||||||
*/
|
*/
|
||||||
public static function FIXEDFORMAT($value, $decimals = 2, $noCommas = false): string
|
public static function FIXEDFORMAT($value, $decimals = 2, $noCommas = false): string
|
||||||
{
|
{
|
||||||
|
|
@ -72,7 +72,7 @@ class Format
|
||||||
if ($decimals < 0) {
|
if ($decimals < 0) {
|
||||||
$decimals = 0;
|
$decimals = 0;
|
||||||
}
|
}
|
||||||
if (!$noCommas) {
|
if ($noCommas === false) {
|
||||||
$valueResult = number_format(
|
$valueResult = number_format(
|
||||||
$valueResult,
|
$valueResult,
|
||||||
$decimals,
|
$decimals,
|
||||||
|
|
@ -88,7 +88,7 @@ class Format
|
||||||
* TEXTFORMAT.
|
* TEXTFORMAT.
|
||||||
*
|
*
|
||||||
* @param mixed $value Value to check
|
* @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
|
public static function TEXTFORMAT($value, $format): string
|
||||||
{
|
{
|
||||||
|
|
@ -152,8 +152,8 @@ class Format
|
||||||
* NUMBERVALUE.
|
* NUMBERVALUE.
|
||||||
*
|
*
|
||||||
* @param mixed $value Value to check
|
* @param mixed $value Value to check
|
||||||
* @param string $decimalSeparator decimal separator, defaults to locale defined value
|
* @param mixed (string) $decimalSeparator decimal separator, defaults to locale defined value
|
||||||
* @param string $groupSeparator group/thosands separator, defaults to locale defined value
|
* @param mixed (string) $groupSeparator group/thosands separator, defaults to locale defined value
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ class Replace
|
||||||
/**
|
/**
|
||||||
* REPLACE.
|
* REPLACE.
|
||||||
*
|
*
|
||||||
* @param string $oldText String to modify
|
* @param mixed (string) $oldText String to modify
|
||||||
* @param int $start Start character
|
* @param mixed (int) $start Start character
|
||||||
* @param int $chars Number of characters
|
* @param mixed (int) $chars Number of characters
|
||||||
* @param string $newText String to replace in defined position
|
* @param mixed (string) $newText String to replace in defined position
|
||||||
*/
|
*/
|
||||||
public static function replace($oldText, $start, $chars, $newText): string
|
public static function replace($oldText, $start, $chars, $newText): string
|
||||||
{
|
{
|
||||||
|
|
@ -31,10 +31,10 @@ class Replace
|
||||||
/**
|
/**
|
||||||
* SUBSTITUTE.
|
* SUBSTITUTE.
|
||||||
*
|
*
|
||||||
* @param string $text Value
|
* @param mixed (string) $text Value
|
||||||
* @param string $fromText From Value
|
* @param mixed (string) $fromText From Value
|
||||||
* @param string $toText To Value
|
* @param mixed (string) $toText To Value
|
||||||
* @param int $instance Instance Number
|
* @param mixed (int) $instance Instance Number
|
||||||
*/
|
*/
|
||||||
public static function substitute($text = '', $fromText = '', $toText = '', $instance = 0): string
|
public static function substitute($text = '', $fromText = '', $toText = '', $instance = 0): string
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ class Search
|
||||||
/**
|
/**
|
||||||
* SEARCHSENSITIVE.
|
* SEARCHSENSITIVE.
|
||||||
*
|
*
|
||||||
* @param string $needle The string to look for
|
* @param mixed (string) $needle The string to look for
|
||||||
* @param string $haystack The string in which to look
|
* @param mixed (string) $haystack The string in which to look
|
||||||
* @param int $offset Offset within $haystack
|
* @param mixed (int) $offset Offset within $haystack
|
||||||
*
|
*
|
||||||
* @return int|string
|
* @return int|string
|
||||||
*/
|
*/
|
||||||
|
|
@ -46,9 +46,9 @@ class Search
|
||||||
/**
|
/**
|
||||||
* SEARCHINSENSITIVE.
|
* SEARCHINSENSITIVE.
|
||||||
*
|
*
|
||||||
* @param string $needle The string to look for
|
* @param mixed (string) $needle The string to look for
|
||||||
* @param string $haystack The string in which to look
|
* @param mixed (string) $haystack The string in which to look
|
||||||
* @param int $offset Offset within $haystack
|
* @param mixed (int) $offset Offset within $haystack
|
||||||
*
|
*
|
||||||
* @return int|string
|
* @return int|string
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ class Text
|
||||||
/**
|
/**
|
||||||
* STRINGLENGTH.
|
* STRINGLENGTH.
|
||||||
*
|
*
|
||||||
* @param string $value Value
|
* @param mixed (string) $value Value
|
||||||
*/
|
*/
|
||||||
public static function length($value = ''): int
|
public static function length($value = ''): int
|
||||||
{
|
{
|
||||||
|
|
@ -28,8 +28,8 @@ class Text
|
||||||
* EXACT is case-sensitive but ignores formatting differences.
|
* EXACT is case-sensitive but ignores formatting differences.
|
||||||
* Use EXACT to test text being entered into a document.
|
* Use EXACT to test text being entered into a document.
|
||||||
*
|
*
|
||||||
* @param $value1
|
* @param mixed (string) $value1
|
||||||
* @param $value2
|
* @param mixed (string) $value2
|
||||||
*/
|
*/
|
||||||
public static function exact($value1, $value2): bool
|
public static function exact($value1, $value2): bool
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ class Trim
|
||||||
/**
|
/**
|
||||||
* TRIMNONPRINTABLE.
|
* TRIMNONPRINTABLE.
|
||||||
*
|
*
|
||||||
* @param mixed $stringValue Value to check
|
* @param mixed (string) $stringValue Value to check
|
||||||
*
|
*
|
||||||
* @return null|string
|
* @return null|string
|
||||||
*/
|
*/
|
||||||
|
|
@ -38,7 +38,7 @@ class Trim
|
||||||
/**
|
/**
|
||||||
* TRIMSPACES.
|
* TRIMSPACES.
|
||||||
*
|
*
|
||||||
* @param mixed $stringValue Value to check
|
* @param mixed (string) $stringValue Value to check
|
||||||
*
|
*
|
||||||
* @return null|string
|
* @return null|string
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,56 @@ return [
|
||||||
0.685470581054,
|
0.685470581054,
|
||||||
2, 8, 10, 1, 3,
|
2, 8, 10, 1, 3,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
0.4059136,
|
||||||
|
0.4, 4, 5,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
'NAN', 8, 10, 1, 3,
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
2, 'NAN', 10, 1, 3,
|
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!',
|
'#NUM!',
|
||||||
2, -8, 10, 1, 3,
|
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,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,56 @@ return [
|
||||||
0.303225844664,
|
0.303225844664,
|
||||||
0.2, 4, 5, 0, 1,
|
0.2, 4, 5, 0, 1,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
'NAN', 4, 5, 0, 1,
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
0.2, 'NAN', 5, 0, 1,
|
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!',
|
'#NUM!',
|
||||||
0.2, -4, 5, 0, 1,
|
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,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -35,14 +35,18 @@ return [
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
'NAN', 3,
|
'NaN', 3,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
8, 0,
|
8, 'NaN',
|
||||||
],
|
],
|
||||||
[
|
'Value < 0' => [
|
||||||
'#NUM!',
|
'#NUM!',
|
||||||
-8, 3,
|
-8, 3,
|
||||||
],
|
],
|
||||||
|
'Degrees < 1' => [
|
||||||
|
'#NUM!',
|
||||||
|
8, 0,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,22 @@ return [
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#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,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,20 @@ return [
|
||||||
1.098612288668,
|
1.098612288668,
|
||||||
0.8,
|
0.8,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
0.972955074528,
|
||||||
|
0.75,
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
'NAN',
|
'NAN',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'#NUM!',
|
'#NUM!',
|
||||||
-2,
|
-1.5,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#NUM!',
|
||||||
|
1.5,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@ return [
|
||||||
0.992631520201,
|
0.992631520201,
|
||||||
2.8,
|
2.8,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
0.7499999990254,
|
||||||
|
0.9729550723,
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
'NAN',
|
'NAN',
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,10 @@ return [
|
||||||
[9.513507698669, 0.1],
|
[9.513507698669, 0.1],
|
||||||
[1.0, 1.0],
|
[1.0, 1.0],
|
||||||
[0.886226925453, 1.5],
|
[0.886226925453, 1.5],
|
||||||
|
[1.3293403881791, 2.5],
|
||||||
[17.837861981813, 4.8],
|
[17.837861981813, 4.8],
|
||||||
[52.342777784553, 5.5],
|
[52.342777784553, 5.5],
|
||||||
['#NUM!', -1],
|
'Zero value' => ['#NUM!', 0.0],
|
||||||
|
'Negative integer value' => ['#NUM!', -1],
|
||||||
['#VALUE!', 'NAN'],
|
['#VALUE!', 'NAN'],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,44 @@ return [
|
||||||
0.576809918873,
|
0.576809918873,
|
||||||
6, 3, 2, true,
|
6, 3, 2, true,
|
||||||
],
|
],
|
||||||
|
'Boolean as numeric' => [
|
||||||
|
0.576809918873,
|
||||||
|
6, 3, 2, 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
'NAN', 3, 2, true,
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
6, 'NAN', 2, true,
|
6, 'NAN', 2, true,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
6, 3, 'NAN', true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
6, 3, 2, 'NAN',
|
||||||
|
],
|
||||||
|
'Value < 0' => [
|
||||||
'#NUM!',
|
'#NUM!',
|
||||||
-6, 3, 2, true,
|
-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,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,38 @@ return [
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
'NAN', 3, 2,
|
'NaN', 3, 2,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
0.5, 'NaN', 2,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
0.5, 3, 'NaN',
|
||||||
|
],
|
||||||
|
'Probability < 0' => [
|
||||||
'#NUM!',
|
'#NUM!',
|
||||||
-0.5, 3, 2,
|
-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,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,12 @@ return [
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
'NAN',
|
'NAN',
|
||||||
],
|
],
|
||||||
[
|
'Value < 0' => [
|
||||||
'#NUM!',
|
'#NUM!',
|
||||||
-4.5,
|
-4.5,
|
||||||
],
|
],
|
||||||
|
'Value = 0' => [
|
||||||
|
'#NUM!',
|
||||||
|
0.0,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -101,4 +101,9 @@ return [
|
||||||
'Mark Baker',
|
'Mark Baker',
|
||||||
8,
|
8,
|
||||||
],
|
],
|
||||||
|
'Boolean Needle' => [
|
||||||
|
'#VALUE!',
|
||||||
|
true,
|
||||||
|
'Mark Baker',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -94,4 +94,9 @@ return [
|
||||||
'BITE',
|
'BITE',
|
||||||
'BIT',
|
'BIT',
|
||||||
],
|
],
|
||||||
|
'Boolean Needle' => [
|
||||||
|
'#VALUE!',
|
||||||
|
true,
|
||||||
|
'Mark Baker',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue