From 9683e5be189080a9c75298e00efb72be3f5c866a Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 29 Jul 2020 23:56:37 +0200 Subject: [PATCH] More unit tests for statistical functions, including a bugfix to LARGE() (#1601) * More unit tests for statistical functions, including a bugfix to LARGE() that was identified in testing --- src/PhpSpreadsheet/Calculation/Database.php | 4 +-- src/PhpSpreadsheet/Calculation/LookupRef.php | 6 ++-- src/PhpSpreadsheet/Calculation/MathTrig.php | 13 +++---- .../Calculation/Statistical.php | 31 +++++++++-------- src/PhpSpreadsheet/Calculation/TextData.php | 5 +-- .../Functions/Statistical/LargeTest.php | 27 +++++++++++++++ .../Functions/Statistical/LinEstTest.php | 33 ++++++++++++++++++ .../Functions/Statistical/LogEstTest.php | 33 ++++++++++++++++++ .../Functions/Statistical/LogInvTest.php | 25 ++++++++++++++ .../Functions/Statistical/MaxATest.php | 25 ++++++++++++++ .../Functions/Statistical/MaxTest.php | 25 ++++++++++++++ .../Functions/Statistical/MinATest.php | 25 ++++++++++++++ .../Functions/Statistical/MinTest.php | 25 ++++++++++++++ .../Functions/Statistical/SmallTest.php | 27 +++++++++++++++ tests/data/Calculation/Statistical/LARGE.php | 34 +++++++++++++++++++ tests/data/Calculation/Statistical/LINEST.php | 11 ++++++ tests/data/Calculation/Statistical/LOGEST.php | 11 ++++++ tests/data/Calculation/Statistical/LOGINV.php | 24 +++++++++++++ tests/data/Calculation/Statistical/MAX.php | 16 +++++++++ tests/data/Calculation/Statistical/MAXA.php | 28 +++++++++++++++ tests/data/Calculation/Statistical/MIN.php | 16 +++++++++ tests/data/Calculation/Statistical/MINA.php | 28 +++++++++++++++ tests/data/Calculation/Statistical/SMALL.php | 34 +++++++++++++++++++ 23 files changed, 478 insertions(+), 28 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LargeTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LinEstTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogInvTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxATest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinATest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SmallTest.php create mode 100644 tests/data/Calculation/Statistical/LARGE.php create mode 100644 tests/data/Calculation/Statistical/LINEST.php create mode 100644 tests/data/Calculation/Statistical/LOGEST.php create mode 100644 tests/data/Calculation/Statistical/LOGINV.php create mode 100644 tests/data/Calculation/Statistical/MAX.php create mode 100644 tests/data/Calculation/Statistical/MAXA.php create mode 100644 tests/data/Calculation/Statistical/MIN.php create mode 100644 tests/data/Calculation/Statistical/MINA.php create mode 100644 tests/data/Calculation/Statistical/SMALL.php diff --git a/src/PhpSpreadsheet/Calculation/Database.php b/src/PhpSpreadsheet/Calculation/Database.php index 965990884d..2ba4af2dc4 100644 --- a/src/PhpSpreadsheet/Calculation/Database.php +++ b/src/PhpSpreadsheet/Calculation/Database.php @@ -552,7 +552,7 @@ public static function DSUM($database, $field, $criteria) * the column label in which you specify a condition for the * column. * - * @return float + * @return float|string (string if result is an error) */ public static function DVAR($database, $field, $criteria) { @@ -591,7 +591,7 @@ public static function DVAR($database, $field, $criteria) * the column label in which you specify a condition for the * column. * - * @return float + * @return float|string (string if result is an error) */ public static function DVARP($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/LookupRef.php b/src/PhpSpreadsheet/Calculation/LookupRef.php index 0636258bc2..45aa923964 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef.php @@ -126,7 +126,7 @@ public static function COLUMN($cellAddress = null) * * @param null|array|string $cellAddress An array or array formula, or a reference to a range of cells for which you want the number of columns * - * @return int The number of columns in cellAddress + * @return int|string The number of columns in cellAddress, or a string if arguments are invalid */ public static function COLUMNS($cellAddress = null) { @@ -160,7 +160,7 @@ public static function COLUMNS($cellAddress = null) * * @param null|array|string $cellAddress A reference to a range of cells for which you want the row numbers * - * @return int or array of integer + * @return int|mixed[]|string */ public static function ROW($cellAddress = null) { @@ -203,7 +203,7 @@ public static function ROW($cellAddress = null) * * @param null|array|string $cellAddress An array or array formula, or a reference to a range of cells for which you want the number of rows * - * @return int The number of rows in cellAddress + * @return int|string The number of rows in cellAddress, or a string if arguments are invalid */ public static function ROWS($cellAddress = null) { diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index fa4c74d39d..7539659ec2 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -871,7 +871,7 @@ public static function MROUND($number, $multiple) * * Returns the ratio of the factorial of a sum of values to the product of factorials. * - * @param array of mixed Data Series + * @param mixed[] $args An array of mixed values for the Data Series * * @return float|string The result, or a string containing an error */ @@ -1149,7 +1149,7 @@ public static function ROUNDDOWN($number, $digits) * * Returns the sum of a power series * - * @param array of mixed Data Series + * @param mixed[] $args An array of mixed values for the Data Series * * @return float|string The result, or a string containing an error */ @@ -1273,21 +1273,22 @@ function ($index) use ($cellReference) { * * Returns a subtotal in a list or database. * - * @param int the number 1 to 11 that specifies which function to + * @param int $functionType + * A number 1 to 11 that specifies which function to * use in calculating subtotals within a range * list * Numbers 101 to 111 shadow the functions of 1 to 11 * but ignore any values in the range that are * in hidden rows or columns - * @param array of mixed Data Series + * @param mixed[] $args A mixed data series of values * * @return float|string */ - public static function SUBTOTAL(...$args) + public static function SUBTOTAL($functionType, ...$args) { $cellReference = array_pop($args); $aArgs = Functions::flattenArrayIndexed($args); - $subtotal = array_shift($aArgs); + $subtotal = Functions::flattenSingleValue($functionType); // Calculate if ((is_numeric($subtotal)) && (!is_string($subtotal))) { diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 4b11372669..19f40f2d4a 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -1445,7 +1445,7 @@ public static function DEVSQ(...$args) return $returnValue; } - return self::NA(); + return Functions::NA(); } /** @@ -1701,7 +1701,6 @@ public static function GAMMAINV($probability, $alpha, $beta) $xHi = $alpha * $beta * 5; $x = $xNew = 1; - $error = $pdf = 0; $dx = 1024; $i = 0; @@ -2019,11 +2018,12 @@ public static function KURT(...$args) public static function LARGE(...$args) { $aArgs = Functions::flattenArray($args); - - // Calculate - $entry = floor(array_pop($aArgs)); + $entry = array_pop($aArgs); if ((is_numeric($entry)) && (!is_string($entry))) { + $entry = (int) floor($entry); + + // Calculate $mArgs = []; foreach ($aArgs as $arg) { // Is it a numeric value? @@ -2032,7 +2032,7 @@ public static function LARGE(...$args) } } $count = self::COUNT($mArgs); - $entry = floor(--$entry); + --$entry; if (($entry < 0) || ($entry >= $count) || ($count == 0)) { return Functions::NAN(); } @@ -2873,7 +2873,7 @@ public static function PERCENTILE(...$args) * @param int $value the number whose rank you want to find * @param int $significance the number of significant digits for the returned percentage value * - * @return float + * @return float|string (string if result is an error) */ public static function PERCENTRANK($valueSet, $value, $significance = 3) { @@ -3169,6 +3169,8 @@ public static function SMALL(...$args) $entry = array_pop($aArgs); if ((is_numeric($entry)) && (!is_string($entry))) { + $entry = (int) floor($entry); + $mArgs = []; foreach ($aArgs as $arg) { // Is it a numeric value? @@ -3177,7 +3179,7 @@ public static function SMALL(...$args) } } $count = self::COUNT($mArgs); - $entry = floor(--$entry); + --$entry; if (($entry < 0) || ($entry >= $count) || ($count == 0)) { return Functions::NAN(); } @@ -3481,7 +3483,6 @@ public static function TDIST($value, $degrees, $tails) $ttheta = atan2($value, sqrt($tterm)); $tc = cos($ttheta); $ts = sin($ttheta); - $tsum = 0; if (($degrees % 2) == 1) { $ti = 3; @@ -3657,7 +3658,7 @@ public static function TRIMMEAN(...$args) * * @param mixed ...$args Data values * - * @return float + * @return float|string (string if result is an error) */ public static function VARFunc(...$args) { @@ -3699,7 +3700,7 @@ public static function VARFunc(...$args) * * @param mixed ...$args Data values * - * @return float + * @return float|string (string if result is an error) */ public static function VARA(...$args) { @@ -3754,7 +3755,7 @@ public static function VARA(...$args) * * @param mixed ...$args Data values * - * @return float + * @return float|string (string if result is an error) */ public static function VARP(...$args) { @@ -3797,7 +3798,7 @@ public static function VARP(...$args) * * @param mixed ...$args Data values * - * @return float + * @return float|string (string if result is an error) */ public static function VARPA(...$args) { @@ -3853,7 +3854,7 @@ public static function VARPA(...$args) * @param float $beta Beta Parameter * @param bool $cumulative * - * @return float + * @return float|string (string if result is an error) */ public static function WEIBULL($value, $alpha, $beta, $cumulative) { @@ -3887,7 +3888,7 @@ public static function WEIBULL($value, $alpha, $beta, $cumulative) * @param float $m0 Alpha Parameter * @param float $sigma Beta Parameter * - * @return float|string + * @return float|string (string if result is an error) */ public static function ZTEST($dataSet, $m0, $sigma = null) { diff --git a/src/PhpSpreadsheet/Calculation/TextData.php b/src/PhpSpreadsheet/Calculation/TextData.php index 8f4b7d87b4..da958836ce 100644 --- a/src/PhpSpreadsheet/Calculation/TextData.php +++ b/src/PhpSpreadsheet/Calculation/TextData.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; +use DateTimeInterface; use PhpOffice\PhpSpreadsheet\Shared\Date; use PhpOffice\PhpSpreadsheet\Shared\StringHelper; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; @@ -98,7 +99,7 @@ private static function convertBooleanValue($value) * * @param string $characters Value * - * @return int + * @return int|string A string if arguments are invalid */ public static function ASCIICODE($characters) { @@ -543,7 +544,7 @@ public static function TEXTFORMAT($value, $format) * * @param mixed $value Value to check * - * @return bool + * @return DateTimeInterface|float|int|string A string if arguments are invalid */ public static function VALUE($value = '') { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LargeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LargeTest.php new file mode 100644 index 0000000000..194248d0fe --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LargeTest.php @@ -0,0 +1,27 @@ +