From c8dc5992d13d05e77d8c1eab13ce7795f5bf9454 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sat, 27 Mar 2021 21:11:18 +0100 Subject: [PATCH 1/8] Implementation of the CHITEST() statistical function --- CHANGELOG.md | 1 + .../Calculation/Calculation.php | 4 +- .../Statistical/Distributions/ChiSquared.php | 41 +++++++++++++++++++ .../Functions/Statistical/ChiTestTest.php | 25 +++++++++++ .../data/Calculation/Statistical/CHITEST.php | 29 +++++++++++++ 5 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php create mode 100644 tests/data/Calculation/Statistical/CHITEST.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b46323f52..d6d252d533 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added +- Implemented the CHITEST() Statistical function. - Support for ActiveSheet and SelectedCells in the ODS Reader and Writer. [PR #1908](https://github.com/PHPOffice/PhpSpreadsheet/pull/1908) ### Changed diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 6e98fcb083..62524c37a0 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -518,12 +518,12 @@ class Calculation ], 'CHITEST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'test'], 'argumentCount' => '2', ], 'CHISQ.TEST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'test'], 'argumentCount' => '2', ], 'CHOOSE' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index 636189b52b..766a23d097 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -82,4 +82,45 @@ public static function inverse($probability, $degrees) return $newtonRaphson->execute($probability); } + + public static function test($actual, $expected) + { + $rows = count($actual); + $actual = Functions::flattenArray($actual); + $expected = Functions::flattenArray($expected); + $columns = count($actual) / $rows; + + $countActuals = count($actual); + $countExpected = count($expected); + if ($countActuals !== $countExpected || $countActuals === 1) { + return Functions::NAN(); + } + + $result = 0.0; + for ($i = 0; $i < $countActuals; ++$i) { + if ($expected[$i] == 0.0) { + return Functions::DIV0(); + } elseif($expected[$i] < 0.0) { + return Functions::NAN(); + } + $result += (($actual[$i] - $expected[$i]) ** 2) / $expected[$i]; + } + + $degrees = self::degrees($rows, $columns); + + $result = self::distribution($result, $degrees); + + return $result; + } + + protected static function degrees(int $rows, int $columns): int + { + if ($rows === 1) { + return $columns - 1; + } elseif ($columns === 1) { + return $rows - 1; + } + + return ($columns - 1) * ($rows - 1); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php new file mode 100644 index 0000000000..95f252cd49 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php @@ -0,0 +1,25 @@ + Date: Sat, 27 Mar 2021 21:34:40 +0100 Subject: [PATCH 2/8] A couple of additional edge case tests (rows = 1, columns = 1) --- .../Statistical/Distributions/ChiSquared.php | 2 +- .../Functions/Statistical/ChiTestTest.php | 2 ++ tests/data/Calculation/Statistical/CHITEST.php | 14 ++++++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index 766a23d097..dfd090de6e 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -100,7 +100,7 @@ public static function test($actual, $expected) for ($i = 0; $i < $countActuals; ++$i) { if ($expected[$i] == 0.0) { return Functions::DIV0(); - } elseif($expected[$i] < 0.0) { + } elseif ($expected[$i] < 0.0) { return Functions::NAN(); } $result += (($actual[$i] - $expected[$i]) ** 2) / $expected[$i]; diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php index 95f252cd49..5f9f361ff4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php @@ -11,6 +11,8 @@ class ChiTestTest extends TestCase * @dataProvider providerCHITEST * * @param mixed $expectedResult + * @param mixed $actual + * @param mixed $expected */ public function testCHITEST($expectedResult, $actual, $expected): void { diff --git a/tests/data/Calculation/Statistical/CHITEST.php b/tests/data/Calculation/Statistical/CHITEST.php index aab9ad51e6..6f5cd05c6f 100644 --- a/tests/data/Calculation/Statistical/CHITEST.php +++ b/tests/data/Calculation/Statistical/CHITEST.php @@ -8,8 +8,18 @@ ], [ 0.000308192027, - [[58, 11], [10, 35], [25, 23]], - [[45.35, 17.56], [16.09, 47.65], [18.44, 16.91]], + [[58, 35], [11, 25], [10, 23]], + [[45.35, 47.65], [17.56, 18.44], [16.09, 16.91]], + ], + [ + 0.015888560447, + [[58], [11], [10]], + [[45.35], [17.56], [16.09]], + ], + [ + 0.008682970191, + [[58, 35]], + [[45.35, 47.65]], ], [ '#NUM!', From 6e1f93e2a13cfb617f75077ef1ceef894f639d28 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sat, 27 Mar 2021 23:06:10 +0100 Subject: [PATCH 3/8] Implement Left-tailed distribution of ChiSquared, for both cdf and pdf --- .../Calculation/Calculation.php | 2 +- .../Statistical/Distributions/ChiSquared.php | 44 +++++++++++++++++++ .../Functions/Statistical/ChiDist2Test.php | 31 +++++++++++++ .../data/Calculation/Statistical/CHIDIST2.php | 40 +++++++++++++++++ 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDist2Test.php create mode 100644 tests/data/Calculation/Statistical/CHIDIST2.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 62524c37a0..fe582bf7b6 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -493,7 +493,7 @@ class Calculation ], 'CHISQ.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distributionLeftTail'], 'argumentCount' => '3', ], 'CHISQ.DIST.RT' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index dfd090de6e..3a149f2b9c 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -47,6 +47,50 @@ public static function distribution($value, $degrees) return 1 - (Gamma::incompleteGamma($degrees / 2, $value / 2) / Gamma::gammaValue($degrees / 2)); } + /** + * 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 + * @param mixed $cumulative + * + * @return float|string + */ + public static function distributionLeftTail($value, $degrees, $cumulative) + { + $value = Functions::flattenSingleValue($value); + $degrees = Functions::flattenSingleValue($degrees); + $cumulative = Functions::flattenSingleValue($cumulative); + + try { + $value = self::validateFloat($value); + $degrees = self::validateInt($degrees); + $cumulative = self::validateBool($cumulative); + } 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(); + } + + if ($cumulative === true) { + return 1 - self::distribution($value, $degrees); + } + + return (($value ** (($degrees / 2) - 1) * exp(-$value / 2))) / + ((2 ** ($degrees / 2)) * Gamma::gammaValue($degrees / 2)); + } + /** * CHIINV. * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDist2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDist2Test.php new file mode 100644 index 0000000000..ce1cd4e5ca --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDist2Test.php @@ -0,0 +1,31 @@ + [ + '#NUM!', + -8, 3, true, + ], + 'Degrees < 1' => [ + '#NUM!', + 8, 0, true, + ], +]; From a1fd528bc66d127d1a7e15a78402eaeacbaaacc6 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sat, 27 Mar 2021 23:10:00 +0100 Subject: [PATCH 4/8] Update change log --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d252d533..d7b123efe7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added -- Implemented the CHITEST() Statistical function. +- Implemented the CHITEST() and CHISQ.DIST() Statistical function. - Support for ActiveSheet and SelectedCells in the ODS Reader and Writer. [PR #1908](https://github.com/PHPOffice/PhpSpreadsheet/pull/1908) ### Changed From ced7554d1b55c26b7a5aede3dcc4286ed94340ad Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sun, 28 Mar 2021 15:22:26 +0200 Subject: [PATCH 5/8] Update change log --- .../Calculation/Calculation.php | 8 ++--- .../Calculation/Statistical.php | 14 ++++---- .../Statistical/Distributions/ChiSquared.php | 10 +++--- .../Statistical/Distributions/GammaBase.php | 3 +- .../Distributions/NewtonRaphson.php | 33 +++++++++++++++++-- ...iDist2Test.php => ChiDistLeftTailTest.php} | 4 +-- ...iDistTest.php => ChiDistRightTailTest.php} | 4 +-- ...ChiInvTest.php => ChiInvRightTailTest.php} | 12 ++++--- .../{CHIDIST2.php => CHIDISTLeftTail.php} | 24 ++++++++++++++ .../{CHIDIST.php => CHIDISTRightTail.php} | 0 .../{CHIINV.php => CHIINVRightTail.php} | 12 +++++-- 11 files changed, 94 insertions(+), 30 deletions(-) rename tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/{ChiDist2Test.php => ChiDistLeftTailTest.php} (92%) rename tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/{ChiDistTest.php => ChiDistRightTailTest.php} (92%) rename tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/{ChiInvTest.php => ChiInvRightTailTest.php} (59%) rename tests/data/Calculation/Statistical/{CHIDIST2.php => CHIDISTLeftTail.php} (61%) rename tests/data/Calculation/Statistical/{CHIDIST.php => CHIDISTRightTail.php} (100%) rename tests/data/Calculation/Statistical/{CHIINV.php => CHIINVRightTail.php} (82%) diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index fe582bf7b6..c4a88bc3e5 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -488,7 +488,7 @@ class Calculation ], 'CHIDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distribution'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distributionRightTail'], 'argumentCount' => '2', ], 'CHISQ.DIST' => [ @@ -498,12 +498,12 @@ class Calculation ], 'CHISQ.DIST.RT' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distribution'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distributionRightTail'], 'argumentCount' => '2', ], 'CHIINV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverse'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverseRightTail'], 'argumentCount' => '2', ], 'CHISQ.INV' => [ @@ -513,7 +513,7 @@ class Calculation ], 'CHISQ.INV.RT' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverse'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverseRightTail'], 'argumentCount' => '2', ], 'CHITEST' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 5f55743115..01caba14a6 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -297,8 +297,8 @@ public static function BINOMDIST($value, $trials, $probability, $cumulative) * * @Deprecated 1.18.0 * - * @see Statistical\Distributions\ChiSquared::distribution() - * Use the distribution() method in the Statistical\Distributions\ChiSquared class instead + * @see Statistical\Distributions\ChiSquared::distributionRightTail() + * Use the distributionRightTail() method in the Statistical\Distributions\ChiSquared class instead * * @param float $value Value for the function * @param float $degrees degrees of freedom @@ -307,7 +307,7 @@ public static function BINOMDIST($value, $trials, $probability, $cumulative) */ public static function CHIDIST($value, $degrees) { - return Statistical\Distributions\ChiSquared::distribution($value, $degrees); + return Statistical\Distributions\ChiSquared::distributionRightTail($value, $degrees); } /** @@ -317,8 +317,8 @@ public static function CHIDIST($value, $degrees) * * @Deprecated 1.18.0 * - * @see Statistical\Distributions\ChiSquared::inverse() - * Use the inverse() method in the Statistical\Distributions\ChiSquared class instead + * @see Statistical\Distributions\ChiSquared::inverseRightTail() + * Use the inverseRightTail() method in the Statistical\Distributions\ChiSquared class instead * * @param float $probability Probability for the function * @param float $degrees degrees of freedom @@ -327,7 +327,7 @@ public static function CHIDIST($value, $degrees) */ public static function CHIINV($probability, $degrees) { - return Statistical\Distributions\ChiSquared::inverse($probability, $degrees); + return Statistical\Distributions\ChiSquared::inverseRightTail($probability, $degrees); } /** @@ -2159,7 +2159,7 @@ public static function TDIST($value, $degrees, $tails) /** * TINV. * - * Returns the one-tailed probability of the chi-squared distribution. + * Returns the one-tailed probability of the Student-T distribution. * * @Deprecated 1.18.0 * diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index 3a149f2b9c..409e5883a2 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -21,7 +21,7 @@ class ChiSquared * * @return float|string */ - public static function distribution($value, $degrees) + public static function distributionRightTail($value, $degrees) { $value = Functions::flattenSingleValue($value); $degrees = Functions::flattenSingleValue($degrees); @@ -84,7 +84,7 @@ public static function distributionLeftTail($value, $degrees, $cumulative) } if ($cumulative === true) { - return 1 - self::distribution($value, $degrees); + return 1 - self::distributionRightTail($value, $degrees); } return (($value ** (($degrees / 2) - 1) * exp(-$value / 2))) / @@ -94,14 +94,14 @@ public static function distributionLeftTail($value, $degrees, $cumulative) /** * CHIINV. * - * Returns the one-tailed probability of the chi-squared distribution. + * Returns the inverse of the right-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) + public static function inverseRightTail($probability, $degrees) { $probability = Functions::flattenSingleValue($probability); $degrees = Functions::flattenSingleValue($degrees); @@ -152,7 +152,7 @@ public static function test($actual, $expected) $degrees = self::degrees($rows, $columns); - $result = self::distribution($result, $degrees); + $result = self::distributionRightTail($result, $degrees); return $result; } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php index 3f76787d1e..89170f7cad 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php @@ -30,14 +30,15 @@ protected static function calculateInverse(float $probability, float $alpha, flo $xLo = 0; $xHi = $alpha * $beta * 5; - $x = $xNew = 1; $dx = 1024; + $x = $xNew = 1; $i = 0; while ((abs($dx) > Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) { // Apply Newton-Raphson step $result = self::calculateDistribution($x, $alpha, $beta, true); $error = $result - $probability; + if ($error == 0.0) { $dx = 0; } elseif ($error < 0.0) { diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php index 298cdfaf34..9a0ba4ed27 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php @@ -10,18 +10,45 @@ class NewtonRaphson protected $callback; + protected $low = 100.0; + + protected $high = 0.0; + + protected $dx = 1; + public function __construct(callable $callback) { $this->callback = $callback; } + public function setLow(float $lowValue): self + { + $this->low = $lowValue; + + return $this; + } + + public function setHigh(float $highValue): self + { + $this->low = $highValue; + + return $this; + } + + public function setDx(float $dxValue): self + { + $this->dx = $dxValue; + + return $this; + } + public function execute($probability) { - $xLo = 100; - $xHi = 0; + $xLo = $this->low; + $xHi = $this->high; + $dx = $this->dx; $x = $xNew = 1; - $dx = 1; $i = 0; while ((abs($dx) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDist2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php similarity index 92% rename from tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDist2Test.php rename to tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php index ce1cd4e5ca..3c7a8d4ec6 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDist2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; -class ChiDist2Test extends TestCase +class ChiDistLeftTailTest extends TestCase { protected function setUp(): void { @@ -26,6 +26,6 @@ public function testCHIDIST($expectedResult, ...$args): void public function providerCHIDIST() { - return require 'tests/data/Calculation/Statistical/CHIDIST2.php'; + return require 'tests/data/Calculation/Statistical/CHIDISTLeftTail.php'; } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php similarity index 92% rename from tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistTest.php rename to tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php index 9dc7326c6f..26bf5ab764 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; -class ChiDistTest extends TestCase +class ChiDistRightTailTest extends TestCase { protected function setUp(): void { @@ -26,6 +26,6 @@ public function testCHIDIST($expectedResult, ...$args): void public function providerCHIDIST() { - return require 'tests/data/Calculation/Statistical/CHIDIST.php'; + return require 'tests/data/Calculation/Statistical/CHIDISTRightTail.php'; } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php similarity index 59% rename from tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvTest.php rename to tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php index 7268091493..afc4b023c7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; -class ChiInvTest extends TestCase +class ChiInvRightTailTest extends TestCase { protected function setUp(): void { @@ -18,14 +18,18 @@ protected function setUp(): void * * @param mixed $expectedResult */ - public function testCHIINV($expectedResult, ...$args): void + public function testCHIINV($expectedResult, $probability, $degrees): void { - $result = Statistical::CHIINV(...$args); + $result = Statistical::CHIINV($probability, $degrees); + if (!is_string($expectedResult)) { + $reverse = Statistical\Distributions\ChiSquared::distributionRightTail($result, $degrees); + self::assertEqualsWithDelta($probability, $reverse, 1E-12); + } self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } public function providerCHIINV() { - return require 'tests/data/Calculation/Statistical/CHIINV.php'; + return require 'tests/data/Calculation/Statistical/CHIINVRightTail.php'; } } diff --git a/tests/data/Calculation/Statistical/CHIDIST2.php b/tests/data/Calculation/Statistical/CHIDISTLeftTail.php similarity index 61% rename from tests/data/Calculation/Statistical/CHIDIST2.php rename to tests/data/Calculation/Statistical/CHIDISTLeftTail.php index 5bc6761732..313061ac99 100644 --- a/tests/data/Calculation/Statistical/CHIDIST2.php +++ b/tests/data/Calculation/Statistical/CHIDISTLeftTail.php @@ -17,6 +17,30 @@ 0.776869839852, 3, 2, true, ], + [ + 0.039646370521, + 3, 9, false, + ], + [ + 0.035705027315, + 3, 9, true, + ], + [ + 0.103349469094, + 7.5, 8, false, + ], + [ + 0.516232618446, + 7.5, 8, true, + ], + [ + 0.020666985354, + 8, 3, false, + ], + [ + 0.953988294311, + 8, 3, true, + ], [ '#VALUE!', 'NaN', 3, true, diff --git a/tests/data/Calculation/Statistical/CHIDIST.php b/tests/data/Calculation/Statistical/CHIDISTRightTail.php similarity index 100% rename from tests/data/Calculation/Statistical/CHIDIST.php rename to tests/data/Calculation/Statistical/CHIDISTRightTail.php diff --git a/tests/data/Calculation/Statistical/CHIINV.php b/tests/data/Calculation/Statistical/CHIINVRightTail.php similarity index 82% rename from tests/data/Calculation/Statistical/CHIINV.php rename to tests/data/Calculation/Statistical/CHIINVRightTail.php index f931a78098..58b317e59e 100644 --- a/tests/data/Calculation/Statistical/CHIINV.php +++ b/tests/data/Calculation/Statistical/CHIINVRightTail.php @@ -10,13 +10,21 @@ 0.75, 10, ], [ - 18.30697345702, - 0.050001, 10, + 0.007716715545, + 0.93, 1, + ], + [ + 1.021651247532, + 0.6, 2, ], [ 0.45493642312, 0.5, 1, ], + [ + 4.351460191096, + 0.5, 5, + ], [ 0.101531044268, 0.75, 1, From 01a7b1965d5c969d43f81ff31f2a0cba8528b3e1 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sun, 28 Mar 2021 15:41:17 +0200 Subject: [PATCH 6/8] Remove unused methods from Newton-Raphson --- .../Distributions/NewtonRaphson.php | 33 ++----------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php index 9a0ba4ed27..d4025f6f5b 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php @@ -10,44 +10,17 @@ class NewtonRaphson protected $callback; - protected $low = 100.0; - - protected $high = 0.0; - - protected $dx = 1; - public function __construct(callable $callback) { $this->callback = $callback; } - public function setLow(float $lowValue): self - { - $this->low = $lowValue; - - return $this; - } - - public function setHigh(float $highValue): self - { - $this->low = $highValue; - - return $this; - } - - public function setDx(float $dxValue): self - { - $this->dx = $dxValue; - - return $this; - } - public function execute($probability) { - $xLo = $this->low; - $xHi = $this->high; + $xLo = 100; + $xHi = 0; - $dx = $this->dx; + $dx = 1; $x = $xNew = 1; $i = 0; From 96e451fdedfe60569b4221dcfa7bd183d23dfbf0 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sun, 28 Mar 2021 15:50:17 +0200 Subject: [PATCH 7/8] PHPCS --- .../Calculation/Statistical/Distributions/NewtonRaphson.php | 2 +- .../Calculation/Functions/Statistical/ChiInvRightTailTest.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php index d4025f6f5b..6b2eb108d2 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php @@ -15,7 +15,7 @@ public function __construct(callable $callback) $this->callback = $callback; } - public function execute($probability) + public function execute($probability): float { $xLo = 100; $xHi = 0; diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php index afc4b023c7..75949f398b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php @@ -17,6 +17,8 @@ protected function setUp(): void * @dataProvider providerCHIINV * * @param mixed $expectedResult + * @param mixed $probability + * @param mixed $degrees */ public function testCHIINV($expectedResult, $probability, $degrees): void { From 0ec851e24b74b8068d434eddf7e85b6c3fef0d34 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sun, 28 Mar 2021 16:01:54 +0200 Subject: [PATCH 8/8] Newton-Raphson can return a string if max iterations is reached --- .../Calculation/Statistical/Distributions/NewtonRaphson.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php index 6b2eb108d2..d4025f6f5b 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php @@ -15,7 +15,7 @@ public function __construct(callable $callback) $this->callback = $callback; } - public function execute($probability): float + public function execute($probability) { $xLo = 100; $xHi = 0;