diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f4703295a..67dbe2384b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added -- Improved support for passing of array arguments to Excel function implementations to return array results (where appropriate). [PR #2562](https://github.com/PHPOffice/PhpSpreadsheet/pull/2562) +- Improved support for passing of array arguments to Excel function implementations to return array results (where appropriate). [Issue #2551](https://github.com/PHPOffice/PhpSpreadsheet/issues/2551) This is the first stage in an ongoing process of adding array support to all appropriate function implementations, - Support for the Excel365 Math/Trig SEQUENCE() function [PR #2536](https://github.com/PHPOffice/PhpSpreadsheet/pull/2536) diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index cfd673385c..aa8672cdb5 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -455,7 +455,7 @@ public static function MMULT($matrixData1, $matrixData2) * @param int $a Dividend * @param int $b Divisor * - * @return float|int|string Remainder, or a string containing an error + * @return array|float|int|string Remainder, or a string containing an error */ public static function MOD($a = 1, $b = 1) { @@ -533,7 +533,7 @@ public static function ODD($number) * @param float $x * @param float $y * - * @return float|int|string The result, or a string containing an error + * @return array|float|int|string The result, or a string containing an error */ public static function POWER($x = 0, $y = 2) { @@ -579,7 +579,7 @@ public static function PRODUCT(...$args) * @param mixed $numerator * @param mixed $denominator * - * @return int|string + * @return array|int|string */ public static function QUOTIENT($numerator, $denominator) { @@ -617,7 +617,7 @@ public static function RAND($min = 0, $max = 0) * @param mixed $aValue Number to convert * @param mixed $style Number indicating one of five possible forms * - * @return string Roman numeral, or a string containing an error + * @return array|string Roman numeral, or a string containing an error */ public static function ROMAN($aValue, $style = 0) { diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Operations.php b/src/PhpSpreadsheet/Calculation/MathTrig/Operations.php index 595c7fdcce..4e481512ac 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Operations.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Operations.php @@ -2,21 +2,32 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Operations { + use ArrayEnabled; + /** * MOD. * * @param mixed $dividend Dividend + * Or can be an array of values * @param mixed $divisor Divisor + * Or can be an array of values * - * @return float|int|string Remainder, or a string containing an error + * @return array|float|int|string Remainder, or a string containing an error + * If an array of numbers is passed as an argument, then the returned result will also be an array + * with the same dimensions */ public static function mod($dividend, $divisor) { + if (is_array($dividend) || is_array($divisor)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $dividend, $divisor); + } + try { $dividend = Helpers::validateNumericNullBool($dividend); $divisor = Helpers::validateNumericNullBool($divisor); @@ -40,13 +51,21 @@ public static function mod($dividend, $divisor) * * Computes x raised to the power y. * - * @param float|int $x - * @param float|int $y + * @param array|float|int $x + * Or can be an array of values + * @param array|float|int $y + * Or can be an array of values * - * @return float|int|string The result, or a string containing an error + * @return array|float|int|string The result, or a string containing an error + * If an array of numbers is passed as an argument, then the returned result will also be an array + * with the same dimensions */ public static function power($x, $y) { + if (is_array($x) || is_array($y)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $x, $y); + } + try { $x = Helpers::validateNumericNullBool($x); $y = Helpers::validateNumericNullBool($y); @@ -117,12 +136,20 @@ public static function product(...$args) * QUOTIENT(value1,value2) * * @param mixed $numerator Expect float|int + * Or can be an array of values * @param mixed $denominator Expect float|int + * Or can be an array of values * - * @return int|string + * @return array|int|string + * If an array of numbers is passed as an argument, then the returned result will also be an array + * with the same dimensions */ public static function quotient($numerator, $denominator) { + if (is_array($numerator) || is_array($denominator)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $numerator, $denominator); + } + try { $numerator = Helpers::validateNumericNullSubstitution($numerator, 0); $denominator = Helpers::validateNumericNullSubstitution($denominator, 0); diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php b/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php index 71a6df3ad7..7d771b296b 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php @@ -2,11 +2,14 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Roman { + use ArrayEnabled; + private const VALUES = [ 45 => ['VL'], 46 => ['VLI'], @@ -814,12 +817,20 @@ public static function calculateRoman(int $aValue, int $style): string * Converts a number to Roman numeral * * @param mixed $aValue Number to convert + * Or can be an array of numbers * @param mixed $style Number indicating one of five possible forms + * Or can be an array of styles * - * @return string Roman numeral, or a string containing an error + * @return array|string Roman numeral, or a string containing an error + * If an array of numbers is passed as an argument, then the returned result will also be an array + * with the same dimensions */ public static function evaluate($aValue, $style = 0) { + if (is_array($aValue) || is_array($style)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $aValue, $style); + } + try { $aValue = Helpers::validateNumericNullBool($aValue); if (is_bool($style)) { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php index 2035d26fb2..029f8392cd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class ModTest extends AllSetupTeardown { /** @@ -36,4 +38,23 @@ public function providerMOD(): array { return require 'tests/data/Calculation/MathTrig/MOD.php'; } + + /** + * @dataProvider providerModArray + */ + public function testModArray(array $expectedResult, string $argument1, string $argument2): void + { + $calculation = Calculation::getInstance(); + + $formula = "=MOD({$argument1}, {$argument2})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerModArray(): array + { + return [ + 'matrix' => [[[4, 3, 2], [1, 0, 4], [3, 2, 1]], '{9, 8, 7; 6, 5, 4; 3, 2, 1}', '5'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php index 179f7ea9f9..c9e35a3e78 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class PowerTest extends AllSetupTeardown { /** @@ -36,4 +38,23 @@ public function providerPOWER(): array { return require 'tests/data/Calculation/MathTrig/POWER.php'; } + + /** + * @dataProvider providerPowerArray + */ + public function testPowerArray(array $expectedResult, string $argument1, string $argument2): void + { + $calculation = Calculation::getInstance(); + + $formula = "=POWER({$argument1}, {$argument2})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerPowerArray(): array + { + return [ + 'matrix' => [[[729, 512, 343], [216, 125, 64], [27, 8, 1]], '{9, 8, 7; 6, 5, 4; 3, 2, 1}', '3'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php index f5bced1eff..1019b35f08 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class QuotientTest extends AllSetupTeardown { /** @@ -36,4 +38,23 @@ public function providerQUOTIENT(): array { return require 'tests/data/Calculation/MathTrig/QUOTIENT.php'; } + + /** + * @dataProvider providerQuotientArray + */ + public function testQuotientArray(array $expectedResult, string $argument1, string $argument2): void + { + $calculation = Calculation::getInstance(); + + $formula = "=QUOTIENT({$argument1}, {$argument2})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerQuotientArray(): array + { + return [ + 'matrix' => [[[3, 3, 2], [2, 2, 1], [1, 0, 0]], '{9, 8, 7; 6, 5, 4; 3, 2, 1}', '2.5'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php index 2690c8d296..dbde63d189 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class RomanTest extends AllSetupTeardown { /** @@ -24,4 +26,25 @@ public function providerROMAN(): array { return require 'tests/data/Calculation/MathTrig/ROMAN.php'; } + + /** + * @dataProvider providerRomanArray + */ + public function testRomanArray(array $expectedResult, string $values, string $styles): void + { + $calculation = Calculation::getInstance(); + + $formula = "=ROMAN({$values}, {$styles})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerRomanArray(): array + { + return [ + 'row vector' => [[['XLIX', 'MMXXII', 'CDXCIX']], '{49, 2022, 499}', '0'], + 'column vector' => [[['XLIX'], ['MMXXII'], ['CDXCIX']], '{49; 2022; 499}', '0'], + 'matrix' => [[['XLIX', 'MMXXII'], ['LXIV', 'CDXCIX']], '{49, 2022; 64, 499}', '0'], + ]; + } }