diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 2026ce62..ef1be8c2 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -980,12 +980,12 @@ class Calculation ], 'EXPONDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'EXPONDIST'], + 'functionCall' => [Statistical\Distributions\Exponential::class, 'distribution'], 'argumentCount' => '3', ], 'EXPON.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'EXPONDIST'], + 'functionCall' => [Statistical\Distributions\Exponential::class, 'distribution'], 'argumentCount' => '3', ], 'FACT' => [ @@ -1010,7 +1010,7 @@ class Calculation ], 'F.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'FDIST2'], + 'functionCall' => [Statistical\Distributions\F::class, 'distribution'], 'argumentCount' => '4', ], 'F.DIST.RT' => [ @@ -1248,7 +1248,7 @@ class Calculation ], 'HYPGEOMDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'HYPGEOMDIST'], + 'functionCall' => [Statistical\Distributions\HyperGeometric::class, 'distribution'], 'argumentCount' => '4', ], 'HYPGEOM.DIST' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index bfa00918..1576af98 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -116,12 +116,12 @@ class Statistical * * @Deprecated 1.17.0 * + * @see Statistical\Averages::averageDeviations() + * Use the averageDeviations() method in the Statistical\Averages class instead + * * @param mixed ...$args Data values * * @return float|string - * - *@see Statistical\Averages::averageDeviations() - * Use the averageDeviations() method in the Statistical\Averages class instead */ public static function AVEDEV(...$args) { @@ -160,12 +160,12 @@ class Statistical * * @Deprecated 1.17.0 * + * @see Statistical\Averages::averageA() + * Use the averageA() method in the Statistical\Averages class instead + * * @param mixed ...$args Data values * * @return float|string - * - *@see Statistical\Averages::averageA() - * Use the averageA() method in the Statistical\Averages class instead */ public static function AVERAGEA(...$args) { @@ -203,7 +203,7 @@ class Statistical * * @Deprecated 1.18.0 * - *@see Statistical\Distributions\Beta::distribution() + * @see Statistical\Distributions\Beta::distribution() * Use the distribution() method in the Statistical\Distributions\Beta class instead * * @param float $value Value at which you want to evaluate the distribution @@ -498,11 +498,6 @@ class Statistical * @param float $alpha criterion value * * @return int|string - * - * @TODO Warning. This implementation differs from the algorithm detailed on the MS - * web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess - * This eliminates a potential endless loop error, but may have an adverse affect on the - * accuracy of the function (although all my tests have so far returned correct results). */ public static function CRITBINOM($trials, $probability, $alpha) { @@ -568,6 +563,11 @@ class Statistical * such as how long an automated bank teller takes to deliver cash. For example, you can * use EXPONDIST to determine the probability that the process takes at most 1 minute. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Exponential::distribution() + * Use the distribution() method in the Statistical\Distributions\Exponential class instead + * * @param float $value Value of the function * @param float $lambda The parameter value * @param bool $cumulative @@ -576,24 +576,7 @@ class Statistical */ public static function EXPONDIST($value, $lambda, $cumulative) { - $value = Functions::flattenSingleValue($value); - $lambda = Functions::flattenSingleValue($lambda); - $cumulative = Functions::flattenSingleValue($cumulative); - - if ((is_numeric($value)) && (is_numeric($lambda))) { - if (($value < 0) || ($lambda < 0)) { - return Functions::NAN(); - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - return 1 - exp(0 - $value * $lambda); - } - - return $lambda * exp(0 - $value * $lambda); - } - } - - return Functions::VALUE(); + return Statistical\Distributions\Exponential::distribution($value, $lambda, $cumulative); } /** @@ -604,6 +587,11 @@ class Statistical * For example, you can examine the test scores of men and women entering high school, and determine * if the variability in the females is different from that found in the males. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\F::distribution() + * Use the distribution() method in the Statistical\Distributions\Exponential class instead + * * @param float $value Value of the function * @param int $u The numerator degrees of freedom * @param int $v The denominator degrees of freedom @@ -614,34 +602,7 @@ class Statistical */ public static function FDIST2($value, $u, $v, $cumulative) { - $value = Functions::flattenSingleValue($value); - $u = Functions::flattenSingleValue($u); - $v = Functions::flattenSingleValue($v); - $cumulative = Functions::flattenSingleValue($cumulative); - - if (is_numeric($value) && is_numeric($u) && is_numeric($v)) { - if ($value < 0 || $u < 1 || $v < 1) { - return Functions::NAN(); - } - - $cumulative = (bool) $cumulative; - $u = (int) $u; - $v = (int) $v; - - if ($cumulative) { - $adjustedValue = ($u * $value) / ($u * $value + $v); - - return Statistical\Distributions\Beta::incompleteBeta($adjustedValue, $u / 2, $v / 2); - } - - return (Statistical\Distributions\Gamma::gammaValue(($v + $u) / 2) / - (Statistical\Distributions\Gamma::gammaValue($u / 2) * - Statistical\Distributions\Gamma::gammaValue($v / 2))) * - (($u / $v) ** ($u / 2)) * - (($value ** (($u - 2) / 2)) / ((1 + ($u / $v) * $value) ** (($u + $v) / 2))); - } - - return Functions::VALUE(); + return Statistical\Distributions\F::distribution($value, $u, $v, $cumulative); } /** @@ -908,42 +869,26 @@ class Statistical * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of * sample successes, given the sample size, population successes, and population size. * - * @param float $sampleSuccesses Number of successes in the sample - * @param float $sampleNumber Size of the sample - * @param float $populationSuccesses Number of successes in the population - * @param float $populationNumber Population size + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\HyperGeometric::distribution() + * Use the distribution() method in the Statistical\Distributions\HyperGeometric class instead + * + * @param mixed (int) $sampleSuccesses Number of successes in the sample + * @param mixed (int) $sampleNumber Size of the sample + * @param mixed (int) $populationSuccesses Number of successes in the population + * @param mixed (int) $populationNumber Population size * * @return float|string */ public static function HYPGEOMDIST($sampleSuccesses, $sampleNumber, $populationSuccesses, $populationNumber) { - $sampleSuccesses = Functions::flattenSingleValue($sampleSuccesses); - $sampleNumber = Functions::flattenSingleValue($sampleNumber); - $populationSuccesses = Functions::flattenSingleValue($populationSuccesses); - $populationNumber = Functions::flattenSingleValue($populationNumber); - - if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) { - $sampleSuccesses = floor($sampleSuccesses); - $sampleNumber = floor($sampleNumber); - $populationSuccesses = floor($populationSuccesses); - $populationNumber = floor($populationNumber); - - if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) { - return Functions::NAN(); - } - if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) { - return Functions::NAN(); - } - if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) { - return Functions::NAN(); - } - - return MathTrig::COMBIN($populationSuccesses, $sampleSuccesses) * - MathTrig::COMBIN($populationNumber - $populationSuccesses, $sampleNumber - $sampleSuccesses) / - MathTrig::COMBIN($populationNumber, $sampleNumber); - } - - return Functions::VALUE(); + return Statistical\Distributions\HyperGeometric::distribution( + $sampleSuccesses, + $sampleNumber, + $populationSuccesses, + $populationNumber + ); } /** @@ -2148,8 +2093,10 @@ class Statistical /** * ZTEST. * - * Returns the Weibull distribution. Use this distribution in reliability - * analysis, such as calculating a device's mean time to failure. + * Returns the one-tailed P-value of a z-test. + * + * For a given hypothesized population mean, x, Z.TEST returns the probability that the sample mean would be + * greater than the average of observations in the data set (array) — that is, the observed sample mean. * * @param float $dataSet * @param float $m0 Alpha Parameter diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php new file mode 100644 index 00000000..fe76816d --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php @@ -0,0 +1,49 @@ +getMessage(); + } + + if (($value < 0) || ($lambda < 0)) { + return Functions::NAN(); + } + + if ($cumulative === true) { + return 1 - exp(0 - $value * $lambda); + } + + return $lambda * exp(0 - $value * $lambda); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php new file mode 100644 index 00000000..84456873 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php @@ -0,0 +1,59 @@ +getMessage(); + } + + if ($value < 0 || $u < 1 || $v < 1) { + return Functions::NAN(); + } + + if ($cumulative) { + $adjustedValue = ($u * $value) / ($u * $value + $v); + + return Beta::incompleteBeta($adjustedValue, $u / 2, $v / 2); + } + + return (Gamma::gammaValue(($v + $u) / 2) / + (Gamma::gammaValue($u / 2) * Gamma::gammaValue($v / 2))) * + (($u / $v) ** ($u / 2)) * + (($value ** (($u - 2) / 2)) / ((1 + ($u / $v) * $value) ** (($u + $v) / 2))); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php new file mode 100644 index 00000000..e9848ed4 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php @@ -0,0 +1,56 @@ +getMessage(); + } + + if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) { + return Functions::NAN(); + } + if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) { + return Functions::NAN(); + } + if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) { + return Functions::NAN(); + } + + return MathTrig::COMBIN($populationSuccesses, $sampleSuccesses) * + MathTrig::COMBIN($populationNumber - $populationSuccesses, $sampleNumber - $sampleSuccesses) / + MathTrig::COMBIN($populationNumber, $sampleNumber); + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDist2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDistTest.php similarity index 70% rename from tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDist2Test.php rename to tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDistTest.php index a6e34429..525247f6 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDist2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDistTest.php @@ -5,21 +5,21 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; -class FDist2Test extends TestCase +class FDistTest extends TestCase { /** - * @dataProvider providerFDIST2 + * @dataProvider providerFDIST * * @param mixed $expectedResult */ - public function testFDIST2($expectedResult, ...$args): void + public function testFDIST($expectedResult, ...$args): void { $result = Statistical::FDIST2(...$args); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerFDIST2(): array + public function providerFDIST(): array { - return require 'tests/data/Calculation/Statistical/FDIST2.php'; + return require 'tests/data/Calculation/Statistical/FDIST.php'; } } diff --git a/tests/data/Calculation/Statistical/EXPONDIST.php b/tests/data/Calculation/Statistical/EXPONDIST.php index df150e19..fda340db 100644 --- a/tests/data/Calculation/Statistical/EXPONDIST.php +++ b/tests/data/Calculation/Statistical/EXPONDIST.php @@ -1,6 +1,14 @@