Skip to content

Issue 2551 - Enable array-readiness for more Math/Trig functions #2583

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions src/PhpSpreadsheet/Calculation/MathTrig.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down
37 changes: 32 additions & 5 deletions src/PhpSpreadsheet/Calculation/MathTrig/Operations.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 12 additions & 1 deletion src/PhpSpreadsheet/Calculation/MathTrig/Roman.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand Down Expand Up @@ -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)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;

use PhpOffice\PhpSpreadsheet\Calculation\Calculation;

class ModTest extends AllSetupTeardown
{
/**
Expand Down Expand Up @@ -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'],
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;

use PhpOffice\PhpSpreadsheet\Calculation\Calculation;

class PowerTest extends AllSetupTeardown
{
/**
Expand Down Expand Up @@ -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'],
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;

use PhpOffice\PhpSpreadsheet\Calculation\Calculation;

class QuotientTest extends AllSetupTeardown
{
/**
Expand Down Expand Up @@ -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'],
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;

use PhpOffice\PhpSpreadsheet\Calculation\Calculation;

class RomanTest extends AllSetupTeardown
{
/**
Expand All @@ -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'],
];
}
}