类库更新

This commit is contained in:
gongfuxiang
2022-03-14 17:02:07 +08:00
parent c75c0b6802
commit a6eebae613
172 changed files with 6073 additions and 4082 deletions

View File

@ -8,6 +8,7 @@ $baseDir = dirname($vendorDir);
return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',

View File

@ -9,7 +9,7 @@ return array(
'think\\view\\driver\\' => array($vendorDir . '/topthink/think-view/src'),
'think\\trace\\' => array($vendorDir . '/topthink/think-trace/src'),
'think\\app\\' => array($vendorDir . '/topthink/think-multi-app/src'),
'think\\' => array($vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-template/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/framework/src/think'),
'think\\' => array($vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/think-template/src'),
'app\\' => array($baseDir . '/app'),
'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),

View File

@ -81,10 +81,10 @@ class ComposerStaticInit1ed187777399b73a018d9a6af63a57d1
),
'think\\' =>
array (
0 => __DIR__ . '/..' . '/topthink/think-helper/src',
1 => __DIR__ . '/..' . '/topthink/think-template/src',
0 => __DIR__ . '/..' . '/topthink/framework/src/think',
1 => __DIR__ . '/..' . '/topthink/think-helper/src',
2 => __DIR__ . '/..' . '/topthink/think-orm/src',
3 => __DIR__ . '/..' . '/topthink/framework/src/think',
3 => __DIR__ . '/..' . '/topthink/think-template/src',
),
'app\\' =>
array (
@ -182,6 +182,7 @@ class ComposerStaticInit1ed187777399b73a018d9a6af63a57d1
public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',

View File

@ -558,17 +558,17 @@
},
{
"name": "phpoffice/phpspreadsheet",
"version": "1.21.0",
"version_normalized": "1.21.0.0",
"version": "1.22.0",
"version_normalized": "1.22.0.0",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "1a359d2ccbb89c05f5dffb32711a95f4afc67964"
"reference": "3a9e29b4f386a08a151a33578e80ef1747037a48"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/1a359d2ccbb89c05f5dffb32711a95f4afc67964",
"reference": "1a359d2ccbb89c05f5dffb32711a95f4afc67964",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/3a9e29b4f386a08a151a33578e80ef1747037a48",
"reference": "3a9e29b4f386a08a151a33578e80ef1747037a48",
"shasum": "",
"mirrors": [
{
@ -605,7 +605,7 @@
"dompdf/dompdf": "^1.0",
"friendsofphp/php-cs-fixer": "^3.2",
"jpgraph/jpgraph": "^4.0",
"mpdf/mpdf": "^8.0",
"mpdf/mpdf": "8.0.17",
"phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^1.1",
"phpstan/phpstan-phpunit": "^1.0",
@ -619,7 +619,7 @@
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)"
},
"time": "2022-01-06T11:10:08+00:00",
"time": "2022-02-18T12:57:07+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -665,7 +665,7 @@
],
"support": {
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.21.0"
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.22.0"
},
"install-path": "../phpoffice/phpspreadsheet"
},
@ -1074,8 +1074,8 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.24.0",
"version_normalized": "1.24.0.0",
"version": "v1.25.0",
"version_normalized": "1.25.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
@ -1115,12 +1115,12 @@
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -1146,7 +1146,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
},
"funding": [
{
@ -1166,8 +1166,8 @@
},
{
"name": "symfony/polyfill-php72",
"version": "v1.24.0",
"version_normalized": "1.24.0.0",
"version": "v1.25.0",
"version_normalized": "1.25.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
@ -1201,12 +1201,12 @@
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
},
"files": [
"bootstrap.php"
]
],
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -1231,7 +1231,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.24.0"
"source": "https://github.com/symfony/polyfill-php72/tree/v1.25.0"
},
"funding": [
{
@ -1251,17 +1251,17 @@
},
{
"name": "symfony/polyfill-php80",
"version": "v1.24.0",
"version_normalized": "1.24.0.0",
"version": "v1.25.0",
"version_normalized": "1.25.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "57b712b08eddb97c762a8caa32c84e037892d2e9"
"reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9",
"reference": "57b712b08eddb97c762a8caa32c84e037892d2e9",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c",
"reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c",
"shasum": "",
"mirrors": [
{
@ -1273,7 +1273,7 @@
"require": {
"php": ">=7.1"
},
"time": "2021-09-13T13:58:33+00:00",
"time": "2022-03-04T08:16:47+00:00",
"type": "library",
"extra": {
"branch-alias": {
@ -1286,12 +1286,12 @@
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
@ -1323,7 +1323,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.24.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0"
},
"funding": [
{
@ -1343,17 +1343,17 @@
},
{
"name": "symfony/var-dumper",
"version": "v4.4.36",
"version_normalized": "4.4.36.0",
"version": "v4.4.39",
"version_normalized": "4.4.39.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "02685c62fcbc4262235cc72a54fbd45ab719ce3c"
"reference": "35237c5e5dcb6593a46a860ba5b29c1d4683d80e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/02685c62fcbc4262235cc72a54fbd45ab719ce3c",
"reference": "02685c62fcbc4262235cc72a54fbd45ab719ce3c",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/35237c5e5dcb6593a46a860ba5b29c1d4683d80e",
"reference": "35237c5e5dcb6593a46a860ba5b29c1d4683d80e",
"shasum": "",
"mirrors": [
{
@ -1383,7 +1383,7 @@
"ext-intl": "To show region name in time zone dump",
"symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
},
"time": "2021-12-29T09:28:53+00:00",
"time": "2022-02-25T10:38:15+00:00",
"bin": [
"Resources/bin/var-dump-server"
],
@ -1421,7 +1421,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v4.4.36"
"source": "https://github.com/symfony/var-dumper/tree/v4.4.39"
},
"funding": [
{
@ -1623,17 +1623,17 @@
},
{
"name": "topthink/think-orm",
"version": "v2.0.51",
"version_normalized": "2.0.51.0",
"version": "v2.0.52",
"version_normalized": "2.0.52.0",
"source": {
"type": "git",
"url": "https://github.com/top-think/think-orm.git",
"reference": "149d266acdc4b2f07c6a94f1733b6b97d340e0e2"
"reference": "407a60658f37fc57422ab95a9922c6f69af90f46"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/top-think/think-orm/zipball/149d266acdc4b2f07c6a94f1733b6b97d340e0e2",
"reference": "149d266acdc4b2f07c6a94f1733b6b97d340e0e2",
"url": "https://api.github.com/repos/top-think/think-orm/zipball/407a60658f37fc57422ab95a9922c6f69af90f46",
"reference": "407a60658f37fc57422ab95a9922c6f69af90f46",
"shasum": "",
"mirrors": [
{
@ -1653,16 +1653,16 @@
"require-dev": {
"phpunit/phpunit": "^7|^8|^9.5"
},
"time": "2022-01-21T06:25:25+00:00",
"time": "2022-01-25T06:00:05+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"think\\": "src"
},
"files": [
"stubs/load_stubs.php"
]
],
"psr-4": {
"think\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -1681,7 +1681,7 @@
],
"support": {
"issues": "https://github.com/top-think/think-orm/issues",
"source": "https://github.com/top-think/think-orm/tree/v2.0.51"
"source": "https://github.com/top-think/think-orm/tree/v2.0.52"
},
"install-path": "../topthink/think-orm"
},

View File

@ -5,7 +5,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '921d28f9ce7fcc47b9b8312f92080643eddfe75a',
'reference' => 'c75c0b6802d97c28dd0256593f3df9c71a6b5a5f',
'name' => 'shopxo/shopxo',
'dev' => true,
),
@ -83,12 +83,12 @@
'dev_requirement' => false,
),
'phpoffice/phpspreadsheet' => array(
'pretty_version' => '1.21.0',
'version' => '1.21.0.0',
'pretty_version' => '1.22.0',
'version' => '1.22.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet',
'aliases' => array(),
'reference' => '1a359d2ccbb89c05f5dffb32711a95f4afc67964',
'reference' => '3a9e29b4f386a08a151a33578e80ef1747037a48',
'dev_requirement' => false,
),
'psr/cache' => array(
@ -160,12 +160,12 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '921d28f9ce7fcc47b9b8312f92080643eddfe75a',
'reference' => 'c75c0b6802d97c28dd0256593f3df9c71a6b5a5f',
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.24.0',
'version' => '1.24.0.0',
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
@ -173,8 +173,8 @@
'dev_requirement' => false,
),
'symfony/polyfill-php72' => array(
'pretty_version' => 'v1.24.0',
'version' => '1.24.0.0',
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php72',
'aliases' => array(),
@ -182,21 +182,21 @@
'dev_requirement' => true,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.24.0',
'version' => '1.24.0.0',
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'reference' => '57b712b08eddb97c762a8caa32c84e037892d2e9',
'reference' => '4407588e0d3f1f52efb65fbe92babe41f37fe50c',
'dev_requirement' => true,
),
'symfony/var-dumper' => array(
'pretty_version' => 'v4.4.36',
'version' => '4.4.36.0',
'pretty_version' => 'v4.4.39',
'version' => '4.4.39.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-dumper',
'aliases' => array(),
'reference' => '02685c62fcbc4262235cc72a54fbd45ab719ce3c',
'reference' => '35237c5e5dcb6593a46a860ba5b29c1d4683d80e',
'dev_requirement' => true,
),
'topthink/framework' => array(
@ -227,12 +227,12 @@
'dev_requirement' => false,
),
'topthink/think-orm' => array(
'pretty_version' => 'v2.0.51',
'version' => '2.0.51.0',
'pretty_version' => 'v2.0.52',
'version' => '2.0.52.0',
'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-orm',
'aliases' => array(),
'reference' => '149d266acdc4b2f07c6a94f1733b6b97d340e0e2',
'reference' => '407a60658f37fc57422ab95a9922c6f69af90f46',
'dev_requirement' => false,
),
'topthink/think-template' => array(

View File

@ -55,7 +55,7 @@ $config
'function_declaration' => true,
'function_to_constant' => true,
'function_typehint_space' => true,
'general_phpdoc_annotation_remove' => ['annotations' => ['access', 'category', 'copyright', 'method', 'throws']],
'general_phpdoc_annotation_remove' => ['annotations' => ['access', 'category', 'copyright', 'throws']],
'global_namespace_import' => true,
'header_comment' => false, // We don't use common header in all our files
'heredoc_indentation' => false, // Requires PHP >= 7.3

View File

@ -5,6 +5,96 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com)
and this project adheres to [Semantic Versioning](https://semver.org).
## 1.22.0 - 2022-02-18
### Added
- Namespacing phase 2 - styles.
[PR #2471](https://github.com/PHPOffice/PhpSpreadsheet/pull/2471)
- 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)
- Support for the Excel365 Math/Trig RANDARRAY() function [PR #2540](https://github.com/PHPOffice/PhpSpreadsheet/pull/2540)
Note that the Spill Operator is not yet supported in the Calculation Engine; but this can still be useful for defining array constants.
- Improved support for Conditional Formatting Rules [PR #2491](https://github.com/PHPOffice/PhpSpreadsheet/pull/2491)
- Provide support for a wider range of Conditional Formatting Rules for Xlsx Reader/Writer:
- Cells Containing (cellIs)
- Specific Text (containing, notContaining, beginsWith, endsWith)
- Dates Occurring (all supported timePeriods)
- Blanks/NoBlanks
- Errors/NoErrors
- Duplicates/Unique
- Expression
- Provision of CF Wizards (for all the above listed rule types) to help create/modify CF Rules without having to manage all the combinations of types/operators, and the complexities of formula expressions, or the text/timePeriod attributes.
See [documentation](https://phpspreadsheet.readthedocs.io/en/latest/topics/conditional-formatting/) for details
- Full support of the above CF Rules for the Xlsx Reader and Writer; even when the file being loaded has CF rules listed in the `<extLst><ext><ConditionalFormattings>` element for the worksheet rather than the `<ConditionalFormatting>` element.
- Provision of a CellMatcher to identify if rules are matched for a cell, and which matching style will be applied.
- Improved documentation and examples, covering all supported CF rule types.
- Add support for one digit decimals (FORMAT_NUMBER_0, FORMAT_PERCENTAGE_0). [PR #2525](https://github.com/PHPOffice/PhpSpreadsheet/pull/2525)
- Initial work enabling Excel function implementations for handling arrays as arguments when used in "array formulae" [#2562](https://github.com/PHPOffice/PhpSpreadsheet/issues/2562)
- Enable most of the Date/Time functions to accept array arguments [#2573](https://github.com/PHPOffice/PhpSpreadsheet/issues/2573)
- Array ready functions - Text, Math/Trig, Statistical, Engineering and Logical [#2580](https://github.com/PHPOffice/PhpSpreadsheet/issues/2580)
### Changed
- Additional Russian translations for Excel Functions (courtesy of aleks-samurai).
- Improved code coverage for NumberFormat. [PR #2556](https://github.com/PHPOffice/PhpSpreadsheet/pull/2556)
- Extract some methods from the Calculation Engine into dedicated classes [#2537](https://github.com/PHPOffice/PhpSpreadsheet/issues/2537)
- Eliminate calls to `flattenSingleValue()` that are no longer required when we're checking for array values as arguments [#2590](https://github.com/PHPOffice/PhpSpreadsheet/issues/2590)
### Deprecated
- Nothing
### Removed
- Nothing
### Fixed
- Fixed `ReferenceHelper@insertNewBefore` behavior when removing column before last column with null value
[PR #2541](https://github.com/PHPOffice/PhpSpreadsheet/pull/2541)
- Fix bug with `DOLLARDE()` and `DOLLARFR()` functions when the dollar value is negative [Issue #2578](https://github.com/PHPOffice/PhpSpreadsheet/issues/2578) [PR #2579](https://github.com/PHPOffice/PhpSpreadsheet/pull/2579)
- Fix partial function name matching when translating formulae from Russian to English [Issue #2533](https://github.com/PHPOffice/PhpSpreadsheet/issues/2533) [PR #2534](https://github.com/PHPOffice/PhpSpreadsheet/pull/2534)
- Various bugs related to Conditional Formatting Rules, and errors in the Xlsx Writer for Conditional Formatting [PR #2491](https://github.com/PHPOffice/PhpSpreadsheet/pull/2491)
- Xlsx Reader merge range fixes.
[Issue #2501](https://github.com/PHPOffice/PhpSpreadsheet/issues/2501)
[PR #2504](https://github.com/PHPOffice/PhpSpreadsheet/pull/2504)
- Handle explicit "date" type for Cell in Xlsx Reader.
[Issue #2373](https://github.com/PHPOffice/PhpSpreadsheet/issues/2373)
[PR #2485](https://github.com/PHPOffice/PhpSpreadsheet/pull/2485)
- Recalibrate Row/Column Dimensions after removeRow/Column.
[Issue #2442](https://github.com/PHPOffice/PhpSpreadsheet/issues/2442)
[PR #2486](https://github.com/PHPOffice/PhpSpreadsheet/pull/2486)
- Refinement for XIRR.
[Issue #2469](https://github.com/PHPOffice/PhpSpreadsheet/issues/2469)
[PR #2487](https://github.com/PHPOffice/PhpSpreadsheet/pull/2487)
- Xlsx Reader handle cell with non-null explicit type but null value.
[Issue #2488](https://github.com/PHPOffice/PhpSpreadsheet/issues/2488)
[PR #2489](https://github.com/PHPOffice/PhpSpreadsheet/pull/2489)
- Xlsx Reader fix height and width for oneCellAnchorDrawings.
[PR #2492](https://github.com/PHPOffice/PhpSpreadsheet/pull/2492)
- Fix rounding error in NumberFormat::NUMBER_PERCENTAGE, NumberFormat::NUMBER_PERCENTAGE_00. [PR #2555](https://github.com/PHPOffice/PhpSpreadsheet/pull/2555)
- Don't treat thumbnail file as xml.
[Issue #2516](https://github.com/PHPOffice/PhpSpreadsheet/issues/2516)
[PR #2517](https://github.com/PHPOffice/PhpSpreadsheet/pull/2517)
- Eliminating Xlsx Reader warning when no sz tag for RichText.
[Issue #2542](https://github.com/PHPOffice/PhpSpreadsheet/issues/2542)
[PR #2550](https://github.com/PHPOffice/PhpSpreadsheet/pull/2550)
- Fix Xlsx/Xls Writer handling of inline strings.
[Issue #353](https://github.com/PHPOffice/PhpSpreadsheet/issues/353)
[PR #2569](https://github.com/PHPOffice/PhpSpreadsheet/pull/2569)
- Richtext colors were not being read correctly after namespace change [#2458](https://github.com/PHPOffice/PhpSpreadsheet/issues/2458)
- Fix discrepancy between the way markdown tables are rendered in ReadTheDocs and in PHPStorm [#2520](https://github.com/PHPOffice/PhpSpreadsheet/issues/2520)
- Update Russian Functions Text File [#2557](https://github.com/PHPOffice/PhpSpreadsheet/issues/2557)
- Fix documentation, instantiation example [#2564](https://github.com/PHPOffice/PhpSpreadsheet/issues/2564)
## 1.21.0 - 2022-01-06
### Added

View File

@ -12,7 +12,10 @@
"spreadsheet"
],
"config": {
"sort-packages": true
"sort-packages": true,
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
},
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
"type": "library",
@ -79,7 +82,7 @@
"dompdf/dompdf": "^1.0",
"friendsofphp/php-cs-fixer": "^3.2",
"jpgraph/jpgraph": "^4.0",
"mpdf/mpdf": "^8.0",
"mpdf/mpdf": "8.0.17",
"phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^1.1",
"phpstan/phpstan-phpunit": "^1.0",

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@ if (PHP_VERSION_ID < 80000) {
];
// Erroneous analysis by Phpstan before PHP8 - mb_strlen does not return false
$config['parameters']['ignoreErrors'][] = [
'message' => '#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:countCharacters\\(\\) should return int but returns int\\|false\\.$#',
'message' => '#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:countCharacters\\(\\) should return int but returns int(<0, max>)?\\|false\\.$#',
'path' => __DIR__ . '/src/PhpSpreadsheet/Shared/StringHelper.php',
'count' => 1,
];

View File

@ -5,7 +5,7 @@ includes:
- vendor/phpstan/phpstan-phpunit/rules.neon
parameters:
level: max
level: 8
paths:
- src/
- tests/

View File

@ -0,0 +1,56 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Engine\ArrayArgumentHelper;
use PhpOffice\PhpSpreadsheet\Calculation\Engine\ArrayArgumentProcessor;
trait ArrayEnabled
{
/**
* @var ArrayArgumentHelper
*/
private static $arrayArgumentHelper;
private static function initialiseHelper(array $arguments): void
{
if (self::$arrayArgumentHelper === null) {
self::$arrayArgumentHelper = new ArrayArgumentHelper();
}
self::$arrayArgumentHelper->initialise($arguments);
}
protected static function evaluateSingleArgumentArray(callable $method, array $values): array
{
$result = [];
foreach ($values as $value) {
$result[] = $method($value);
}
return $result;
}
/**
* @param mixed ...$arguments
*/
protected static function evaluateArrayArguments(callable $method, ...$arguments): array
{
self::initialiseHelper($arguments);
$arguments = self::$arrayArgumentHelper->arguments();
return ArrayArgumentProcessor::processArguments(self::$arrayArgumentHelper, $method, ...$arguments);
}
/**
* @param mixed ...$arguments
*/
protected static function evaluateArrayArgumentsSubset(callable $method, int $limit, ...$arguments): array
{
self::initialiseHelper(array_slice($arguments, 0, $limit));
$trailingArguments = array_slice($arguments, $limit);
$arguments = self::$arrayArgumentHelper->arguments();
$arguments = array_merge($arguments, $trailingArguments);
return ArrayArgumentProcessor::processArguments(self::$arrayArgumentHelper, $method, ...$arguments);
}
}

View File

@ -0,0 +1,181 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
class BinaryComparison
{
/**
* Epsilon Precision used for comparisons in calculations.
*/
private const DELTA = 0.1e-12;
/**
* Compare two strings in the same way as strcmp() except that lowercase come before uppercase letters.
*
* @param null|string $str1 First string value for the comparison
* @param null|string $str2 Second string value for the comparison
*/
private static function strcmpLowercaseFirst($str1, $str2): int
{
$inversedStr1 = StringHelper::strCaseReverse($str1 ?? '');
$inversedStr2 = StringHelper::strCaseReverse($str2 ?? '');
return strcmp($inversedStr1, $inversedStr2);
}
/**
* PHP8.1 deprecates passing null to strcmp.
*
* @param null|string $str1 First string value for the comparison
* @param null|string $str2 Second string value for the comparison
*/
private static function strcmpAllowNull($str1, $str2): int
{
return strcmp($str1 ?? '', $str2 ?? '');
}
/**
* @param mixed $operand1
* @param mixed $operand2
*/
public static function compare($operand1, $operand2, string $operator): bool
{
// Simple validate the two operands if they are string values
if (is_string($operand1) && $operand1 > '' && $operand1[0] == Calculation::FORMULA_STRING_QUOTE) {
$operand1 = Calculation::unwrapResult($operand1);
}
if (is_string($operand2) && $operand2 > '' && $operand2[0] == Calculation::FORMULA_STRING_QUOTE) {
$operand2 = Calculation::unwrapResult($operand2);
}
// Use case insensitive comparaison if not OpenOffice mode
if (Functions::getCompatibilityMode() != Functions::COMPATIBILITY_OPENOFFICE) {
if (is_string($operand1)) {
$operand1 = StringHelper::strToUpper($operand1);
}
if (is_string($operand2)) {
$operand2 = StringHelper::strToUpper($operand2);
}
}
$useLowercaseFirstComparison = is_string($operand1) &&
is_string($operand2) &&
Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE;
return self::evaluateComparison($operand1, $operand2, $operator, $useLowercaseFirstComparison);
}
/**
* @param mixed $operand1
* @param mixed $operand2
*/
private static function evaluateComparison($operand1, $operand2, string $operator, bool $useLowercaseFirstComparison): bool
{
switch ($operator) {
// Equality
case '=':
return self::equal($operand1, $operand2);
// Greater than
case '>':
return self::greaterThan($operand1, $operand2, $useLowercaseFirstComparison);
// Less than
case '<':
return self::lessThan($operand1, $operand2, $useLowercaseFirstComparison);
// Greater than or equal
case '>=':
return self::greaterThanOrEqual($operand1, $operand2, $useLowercaseFirstComparison);
// Less than or equal
case '<=':
return self::lessThanOrEqual($operand1, $operand2, $useLowercaseFirstComparison);
// Inequality
case '<>':
return self::notEqual($operand1, $operand2);
default:
throw new Exception('Unsupported binary comparison operator');
}
}
/**
* @param mixed $operand1
* @param mixed $operand2
*/
private static function equal($operand1, $operand2): bool
{
if (is_numeric($operand1) && is_numeric($operand2)) {
$result = (abs($operand1 - $operand2) < self::DELTA);
} elseif (($operand1 === null && is_numeric($operand2)) || ($operand2 === null && is_numeric($operand1))) {
$result = $operand1 == $operand2;
} else {
$result = self::strcmpAllowNull($operand1, $operand2) == 0;
}
return $result;
}
/**
* @param mixed $operand1
* @param mixed $operand2
*/
private static function greaterThanOrEqual($operand1, $operand2, bool $useLowercaseFirstComparison): bool
{
if (is_numeric($operand1) && is_numeric($operand2)) {
$result = ((abs($operand1 - $operand2) < self::DELTA) || ($operand1 > $operand2));
} elseif (($operand1 === null && is_numeric($operand2)) || ($operand2 === null && is_numeric($operand1))) {
$result = $operand1 >= $operand2;
} elseif ($useLowercaseFirstComparison) {
$result = self::strcmpLowercaseFirst($operand1, $operand2) >= 0;
} else {
$result = self::strcmpAllowNull($operand1, $operand2) >= 0;
}
return $result;
}
/**
* @param mixed $operand1
* @param mixed $operand2
*/
private static function lessThanOrEqual($operand1, $operand2, bool $useLowercaseFirstComparison): bool
{
if (is_numeric($operand1) && is_numeric($operand2)) {
$result = ((abs($operand1 - $operand2) < self::DELTA) || ($operand1 < $operand2));
} elseif (($operand1 === null && is_numeric($operand2)) || ($operand2 === null && is_numeric($operand1))) {
$result = $operand1 <= $operand2;
} elseif ($useLowercaseFirstComparison) {
$result = self::strcmpLowercaseFirst($operand1, $operand2) <= 0;
} else {
$result = self::strcmpAllowNull($operand1, $operand2) <= 0;
}
return $result;
}
/**
* @param mixed $operand1
* @param mixed $operand2
*/
private static function greaterThan($operand1, $operand2, bool $useLowercaseFirstComparison): bool
{
return self::lessThanOrEqual($operand1, $operand2, $useLowercaseFirstComparison) !== true;
}
/**
* @param mixed $operand1
* @param mixed $operand2
*/
private static function lessThan($operand1, $operand2, bool $useLowercaseFirstComparison): bool
{
return self::greaterThanOrEqual($operand1, $operand2, $useLowercaseFirstComparison) !== true;
}
/**
* @param mixed $operand1
* @param mixed $operand2
*/
private static function notEqual($operand1, $operand2): bool
{
return self::equal($operand1, $operand2) !== true;
}
}

View File

@ -173,13 +173,6 @@ class Calculation
*/
public $cyclicFormulaCount = 1;
/**
* Epsilon Precision used for comparisons in calculations.
*
* @var float
*/
private $delta = 0.1e-12;
/**
* The current locale setting.
*
@ -223,7 +216,7 @@ class Calculation
*
* @var array<string, mixed>
*/
private static $excelConstants = [
public static $excelConstants = [
'TRUE' => true,
'FALSE' => false,
'NULL' => null,
@ -1041,7 +1034,7 @@ class Calculation
'FILTER' => [
'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '3+',
'argumentCount' => '2-3',
],
'FILTERXML' => [
'category' => Category::CATEGORY_WEB,
@ -2078,7 +2071,7 @@ class Calculation
],
'RANDARRAY' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [Functions::class, 'DUMMY'],
'functionCall' => [MathTrig\Random::class, 'randArray'],
'argumentCount' => '0-5',
],
'RANDBETWEEN' => [
@ -2220,8 +2213,8 @@ class Calculation
],
'SEQUENCE' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '2',
'functionCall' => [MathTrig\MatrixFunctions::class, 'sequence'],
'argumentCount' => '1-4',
],
'SERIESSUM' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
@ -2759,8 +2752,6 @@ class Calculation
public function __construct(?Spreadsheet $spreadsheet = null)
{
$this->delta = 1 * 10 ** (0 - ini_get('precision'));
$this->spreadsheet = $spreadsheet;
$this->cyclicReferenceStack = new CyclicReferenceStack();
$this->debugLog = new Logger($this->cyclicReferenceStack);
@ -3170,10 +3161,10 @@ class Calculation
if (self::$functionReplaceFromExcel === null) {
self::$functionReplaceFromExcel = [];
foreach (array_keys(self::$localeFunctions) as $excelFunctionName) {
self::$functionReplaceFromExcel[] = '/(@?[^\w\.])' . preg_quote($excelFunctionName, '/') . '([\s]*\()/Ui';
self::$functionReplaceFromExcel[] = '/(@?[^\w\.])' . preg_quote($excelFunctionName, '/') . '([\s]*\()/ui';
}
foreach (array_keys(self::$localeBoolean) as $excelBoolean) {
self::$functionReplaceFromExcel[] = '/(@?[^\w\.])' . preg_quote($excelBoolean, '/') . '([^\w\.])/Ui';
self::$functionReplaceFromExcel[] = '/(@?[^\w\.])' . preg_quote($excelBoolean, '/') . '([^\w\.])/ui';
}
}
@ -3187,7 +3178,13 @@ class Calculation
}
}
return self::translateFormula(self::$functionReplaceFromExcel, self::$functionReplaceToLocale, $formula, ',', self::$localeArgumentSeparator);
return self::translateFormula(
self::$functionReplaceFromExcel,
self::$functionReplaceToLocale,
$formula,
',',
self::$localeArgumentSeparator
);
}
private static $functionReplaceFromLocale;
@ -3199,10 +3196,10 @@ class Calculation
if (self::$functionReplaceFromLocale === null) {
self::$functionReplaceFromLocale = [];
foreach (self::$localeFunctions as $localeFunctionName) {
self::$functionReplaceFromLocale[] = '/(@?[^\w\.])' . preg_quote($localeFunctionName, '/') . '([\s]*\()/Ui';
self::$functionReplaceFromLocale[] = '/(@?[^\w\.])' . preg_quote($localeFunctionName, '/') . '([\s]*\()/ui';
}
foreach (self::$localeBoolean as $excelBoolean) {
self::$functionReplaceFromLocale[] = '/(@?[^\w\.])' . preg_quote($excelBoolean, '/') . '([^\w\.])/Ui';
self::$functionReplaceFromLocale[] = '/(@?[^\w\.])' . preg_quote($excelBoolean, '/') . '([^\w\.])/ui';
}
}
@ -3742,6 +3739,8 @@ class Calculation
return self::FORMULA_STRING_QUOTE . $value . self::FORMULA_STRING_QUOTE;
} elseif (is_bool($value)) {
return ($value) ? self::$localeBoolean['TRUE'] : self::$localeBoolean['FALSE'];
} elseif ($value === null) {
return self::$localeBoolean['NULL'];
}
}
@ -4369,6 +4368,12 @@ class Calculation
if (($operandData['reference'] === null) && (is_array($operand))) {
$rKeys = array_keys($operand);
$rowKey = array_shift($rKeys);
if (is_array($operand[$rowKey]) === false) {
$operandData['value'] = $operand[$rowKey];
return $operand[$rowKey];
}
$cKeys = array_keys(array_keys($operand[$rowKey]));
$colKey = array_shift($cKeys);
if (ctype_upper("$colKey")) {
@ -4509,7 +4514,7 @@ class Calculation
case '<=': // Less than or Equal to
case '=': // Equality
case '<>': // Inequality
$result = $this->executeBinaryComparisonOperation($cellID, $operand1, $operand2, $token, $stack);
$result = $this->executeBinaryComparisonOperation($operand1, $operand2, (string) $token, $stack);
if (isset($storeKey)) {
$branchStore[$storeKey] = $result;
}
@ -4952,21 +4957,20 @@ class Calculation
}
/**
* @param null|string $cellID
* @param mixed $operand1
* @param mixed $operand2
* @param string $operation
*
* @return array
*/
private function executeArrayComparison($cellID, $operand1, $operand2, $operation, Stack &$stack, bool $recursingArrays)
private function executeArrayComparison($operand1, $operand2, $operation, Stack &$stack, bool $recursingArrays)
{
$result = [];
if (!is_array($operand2)) {
// Operand 1 is an array, Operand 2 is a scalar
foreach ($operand1 as $x => $operandData) {
$this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2));
$this->executeBinaryComparisonOperation($cellID, $operandData, $operand2, $operation, $stack);
$this->executeBinaryComparisonOperation($operandData, $operand2, $operation, $stack);
$r = $stack->pop();
$result[$x] = $r['value'];
}
@ -4974,7 +4978,7 @@ class Calculation
// Operand 1 is a scalar, Operand 2 is an array
foreach ($operand2 as $x => $operandData) {
$this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operand1), ' ', $operation, ' ', $this->showValue($operandData));
$this->executeBinaryComparisonOperation($cellID, $operand1, $operandData, $operation, $stack);
$this->executeBinaryComparisonOperation($operand1, $operandData, $operation, $stack);
$r = $stack->pop();
$result[$x] = $r['value'];
}
@ -4985,7 +4989,7 @@ class Calculation
}
foreach ($operand1 as $x => $operandData) {
$this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2[$x]));
$this->executeBinaryComparisonOperation($cellID, $operandData, $operand2[$x], $operation, $stack, true);
$this->executeBinaryComparisonOperation($operandData, $operand2[$x], $operation, $stack, true);
$r = $stack->pop();
$result[$x] = $r['value'];
}
@ -4999,7 +5003,6 @@ class Calculation
}
/**
* @param null|string $cellID
* @param mixed $operand1
* @param mixed $operand2
* @param string $operation
@ -5007,97 +5010,14 @@ class Calculation
*
* @return mixed
*/
private function executeBinaryComparisonOperation($cellID, $operand1, $operand2, $operation, Stack &$stack, $recursingArrays = false)
private function executeBinaryComparisonOperation($operand1, $operand2, $operation, Stack &$stack, $recursingArrays = false)
{
// If we're dealing with matrix operations, we want a matrix result
if ((is_array($operand1)) || (is_array($operand2))) {
return $this->executeArrayComparison($cellID, $operand1, $operand2, $operation, $stack, $recursingArrays);
return $this->executeArrayComparison($operand1, $operand2, $operation, $stack, $recursingArrays);
}
// Simple validate the two operands if they are string values
if (is_string($operand1) && $operand1 > '' && $operand1[0] == self::FORMULA_STRING_QUOTE) {
$operand1 = self::unwrapResult($operand1);
}
if (is_string($operand2) && $operand2 > '' && $operand2[0] == self::FORMULA_STRING_QUOTE) {
$operand2 = self::unwrapResult($operand2);
}
// Use case insensitive comparaison if not OpenOffice mode
if (Functions::getCompatibilityMode() != Functions::COMPATIBILITY_OPENOFFICE) {
if (is_string($operand1)) {
$operand1 = Shared\StringHelper::strToUpper($operand1);
}
if (is_string($operand2)) {
$operand2 = Shared\StringHelper::strToUpper($operand2);
}
}
$useLowercaseFirstComparison = is_string($operand1) && is_string($operand2) && Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE;
// execute the necessary operation
switch ($operation) {
// Greater than
case '>':
if ($useLowercaseFirstComparison) {
$result = $this->strcmpLowercaseFirst($operand1, $operand2) > 0;
} else {
$result = ($operand1 > $operand2);
}
break;
// Less than
case '<':
if ($useLowercaseFirstComparison) {
$result = $this->strcmpLowercaseFirst($operand1, $operand2) < 0;
} else {
$result = ($operand1 < $operand2);
}
break;
// Equality
case '=':
if (is_numeric($operand1) && is_numeric($operand2)) {
$result = (abs($operand1 - $operand2) < $this->delta);
} else {
$result = $this->strcmpAllowNull($operand1, $operand2) == 0;
}
break;
// Greater than or equal
case '>=':
if (is_numeric($operand1) && is_numeric($operand2)) {
$result = ((abs($operand1 - $operand2) < $this->delta) || ($operand1 > $operand2));
} elseif ($useLowercaseFirstComparison) {
$result = $this->strcmpLowercaseFirst($operand1, $operand2) >= 0;
} else {
$result = $this->strcmpAllowNull($operand1, $operand2) >= 0;
}
break;
// Less than or equal
case '<=':
if (is_numeric($operand1) && is_numeric($operand2)) {
$result = ((abs($operand1 - $operand2) < $this->delta) || ($operand1 < $operand2));
} elseif ($useLowercaseFirstComparison) {
$result = $this->strcmpLowercaseFirst($operand1, $operand2) <= 0;
} else {
$result = $this->strcmpAllowNull($operand1, $operand2) <= 0;
}
break;
// Inequality
case '<>':
if (is_numeric($operand1) && is_numeric($operand2)) {
$result = (abs($operand1 - $operand2) > 1E-14);
} else {
$result = $this->strcmpAllowNull($operand1, $operand2) != 0;
}
break;
default:
throw new Exception('Unsupported binary comparison operation');
}
$result = BinaryComparison::compare($operand1, $operand2, $operation);
// Log the result details
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
@ -5107,35 +5027,6 @@ class Calculation
return $result;
}
/**
* Compare two strings in the same way as strcmp() except that lowercase come before uppercase letters.
*
* @param null|string $str1 First string value for the comparison
* @param null|string $str2 Second string value for the comparison
*
* @return int
*/
private function strcmpLowercaseFirst($str1, $str2)
{
$inversedStr1 = Shared\StringHelper::strCaseReverse($str1);
$inversedStr2 = Shared\StringHelper::strCaseReverse($str2);
return strcmp($inversedStr1 ?? '', $inversedStr2 ?? '');
}
/**
* PHP8.1 deprecates passing null to strcmp.
*
* @param null|string $str1 First string value for the comparison
* @param null|string $str2 Second string value for the comparison
*
* @return int
*/
private function strcmpAllowNull($str1, $str2)
{
return strcmp($str1 ?? '', $str2 ?? '');
}
/**
* @param mixed $operand1
* @param mixed $operand2

View File

@ -278,9 +278,9 @@ class DateTime
* or a standard date string
* @param mixed $endDate Excel date serial value, PHP date/time stamp, PHP DateTime object
* or a standard date string
* @param string $unit
* @param array|string $unit
*
* @return int|string Interval between the dates
* @return array|int|string Interval between the dates
*/
public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D')
{
@ -300,12 +300,12 @@ class DateTime
* @See DateTimeExcel\Days::between()
* Use the between method in the DateTimeExcel\Days class instead
*
* @param DateTimeInterface|float|int|string $endDate Excel date serial value (float),
* @param array|DateTimeInterface|float|int|string $endDate Excel date serial value (float),
* PHP date timestamp (integer), PHP DateTime object, or a standard date string
* @param DateTimeInterface|float|int|string $startDate Excel date serial value (float),
* @param array|DateTimeInterface|float|int|string $startDate Excel date serial value (float),
* PHP date timestamp (integer), PHP DateTime object, or a standard date string
*
* @return int|string Number of days between start date and end date or an error
* @return array|int|string Number of days between start date and end date or an error
*/
public static function DAYS($endDate = 0, $startDate = 0)
{
@ -331,7 +331,7 @@ class DateTime
* PHP DateTime object, or a standard date string
* @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param bool $method US or European Method
* @param array|bool $method US or European Method
* FALSE or omitted: U.S. (NASD) method. If the starting date is
* the last day of a month, it becomes equal to the 30th of the
* same month. If the ending date is the last day of a month and
@ -343,7 +343,7 @@ class DateTime
* occur on the 31st of a month become equal to the 30th of the
* same month.
*
* @return int|string Number of days between start date and end date
* @return array|int|string Number of days between start date and end date
*/
public static function DAYS360($startDate = 0, $endDate = 0, $method = false)
{
@ -373,14 +373,14 @@ class DateTime
* PHP DateTime object, or a standard date string
* @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $method Method used for the calculation
* @param array|int $method Method used for the calculation
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
* 3 Actual/365
* 4 European 30/360
*
* @return float|string fraction of the year, or a string containing an error
* @return array|float|string fraction of the year, or a string containing an error
*/
public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0)
{
@ -409,7 +409,7 @@ class DateTime
* PHP DateTime object, or a standard date string
* @param mixed $dateArgs
*
* @return int|string Interval between the dates
* @return array|int|string Interval between the dates
*/
public static function NETWORKDAYS($startDate, $endDate, ...$dateArgs)
{
@ -464,7 +464,7 @@ class DateTime
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int|string Day of the month
* @return array|int|string Day of the month
*/
public static function DAYOFMONTH($dateValue = 1)
{
@ -492,7 +492,7 @@ class DateTime
* 2 Numbers 1 (Monday) through 7 (Sunday).
* 3 Numbers 0 (Monday) through 6 (Sunday).
*
* @return int|string Day of the week value
* @return array|int|string Day of the week value
*/
public static function WEEKDAY($dateValue = 1, $style = 1)
{
@ -704,7 +704,7 @@ class DateTime
* 17 Week begins on Sunday.
* 21 ISO (Jan. 4 is week 1, begins on Monday).
*
* @return int|string Week Number
* @return array|int|string Week Number
*/
public static function WEEKNUM($dateValue = 1, $method = self::STARTWEEK_SUNDAY)
{
@ -727,7 +727,7 @@ class DateTime
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int|string Week Number
* @return array|int|string Week Number
*/
public static function ISOWEEKNUM($dateValue = 1)
{
@ -751,7 +751,7 @@ class DateTime
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int|string Month of the year
* @return array|int|string Month of the year
*/
public static function MONTHOFYEAR($dateValue = 1)
{
@ -775,7 +775,7 @@ class DateTime
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int|string Year
* @return array|int|string Year
*/
public static function YEAR($dateValue = 1)
{
@ -799,7 +799,7 @@ class DateTime
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
*
* @return int|string Hour
* @return array|int|string Hour
*/
public static function HOUROFDAY($timeValue = 0)
{
@ -823,7 +823,7 @@ class DateTime
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
*
* @return int|string Minute
* @return array|int|string Minute
*/
public static function MINUTE($timeValue = 0)
{
@ -847,7 +847,7 @@ class DateTime
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
*
* @return int|string Second
* @return array|int|string Second
*/
public static function SECOND($timeValue = 0)
{

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
@ -9,6 +10,8 @@ use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
class Date
{
use ArrayEnabled;
/**
* DATE.
*
@ -24,7 +27,7 @@ class Date
* A Month name or abbreviation (English only at this point) such as 'January' or 'Jan' will still be accepted,
* as will a day value with a suffix (e.g. '21st' rather than simply 21); again only English language.
*
* @param int $year The value of the year argument can include one to four digits.
* @param array|int $year The value of the year argument can include one to four digits.
* Excel interprets the year argument according to the configured
* date system: 1900 or 1904.
* If year is between 0 (zero) and 1899 (inclusive), Excel adds that
@ -35,7 +38,7 @@ class Date
* 2008.
* If year is less than 0 or is 10000 or greater, Excel returns the
* #NUM! error value.
* @param int $month A positive or negative integer representing the month of the year
* @param array|int $month A positive or negative integer representing the month of the year
* from 1 to 12 (January to December).
* If month is greater than 12, month adds that number of months to
* the first month in the year specified. For example, DATE(2008,14,2)
@ -44,7 +47,7 @@ class Date
* number of months, plus 1, from the first month in the year
* specified. For example, DATE(2008,-3,2) returns the serial number
* representing September 2, 2007.
* @param int $day A positive or negative integer representing the day of the month
* @param array|int $day A positive or negative integer representing the day of the month
* from 1 to 31.
* If day is greater than the number of days in the month specified,
* day adds that number of days to the first day in the month. For
@ -57,9 +60,15 @@ class Date
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function fromYMD($year, $month, $day)
{
if (is_array($year) || is_array($month) || is_array($day)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $year, $month, $day);
}
$baseYear = SharedDateHelper::getExcelCalendar();
try {
@ -84,7 +93,6 @@ class Date
*/
private static function getYear($year, int $baseYear): int
{
$year = Functions::flattenSingleValue($year);
$year = ($year !== null) ? StringHelper::testStringAsNumeric((string) $year) : 0;
if (!is_numeric($year)) {
throw new Exception(Functions::VALUE());
@ -112,8 +120,6 @@ class Date
*/
private static function getMonth($month): int
{
$month = Functions::flattenSingleValue($month);
if (($month !== null) && (!is_numeric($month))) {
$month = SharedDateHelper::monthStringToNumber($month);
}
@ -133,8 +139,6 @@ class Date
*/
private static function getDay($day): int
{
$day = Functions::flattenSingleValue($day);
if (($day !== null) && (!is_numeric($day))) {
$day = SharedDateHelper::dayStringToNumber($day);
}

View File

@ -2,12 +2,15 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
class DateParts
{
use ArrayEnabled;
/**
* DAYOFMONTH.
*
@ -19,11 +22,18 @@ class DateParts
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
*
* @return int|string Day of the month
* @return array|int|string Day of the month
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function day($dateValue)
{
if (is_array($dateValue)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue);
}
$weirdResult = self::weirdCondition($dateValue);
if ($weirdResult >= 0) {
return $weirdResult;
@ -52,11 +62,18 @@ class DateParts
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
*
* @return int|string Month of the year
* @return array|int|string Month of the year
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function month($dateValue)
{
if (is_array($dateValue)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue);
}
try {
$dateValue = Helpers::getDateValue($dateValue);
} catch (Exception $e) {
@ -83,11 +100,18 @@ class DateParts
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
*
* @return int|string Year
* @return array|int|string Year
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function year($dateValue)
{
if (is_array($dateValue)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue);
}
try {
$dateValue = Helpers::getDateValue($dateValue);
} catch (Exception $e) {

View File

@ -3,11 +3,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTimeImmutable;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
class DateValue
{
use ArrayEnabled;
/**
* DATEVALUE.
*
@ -21,7 +24,7 @@ class DateValue
* Excel Function:
* DATEVALUE(dateValue)
*
* @param string $dateValue Text that represents a date in a Microsoft Excel date format.
* @param array|string $dateValue Text that represents a date in a Microsoft Excel date format.
* For example, "1/30/2008" or "30-Jan-2008" are text strings within
* quotation marks that represent dates. Using the default date
* system in Excel for Windows, date_text must represent a date from
@ -29,15 +32,22 @@ class DateValue
* system in Excel for the Macintosh, date_text must represent a date
* from January 1, 1904, to December 31, 9999. DATEVALUE returns the
* #VALUE! error value if date_text is out of this range.
* Or can be an array of date values
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function fromString($dateValue)
{
if (is_array($dateValue)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue);
}
$dti = new DateTimeImmutable();
$baseYear = SharedDateHelper::getExcelCalendar();
$dateValue = trim(Functions::flattenSingleValue($dateValue ?? ''), '"');
$dateValue = trim($dateValue ?? '', '"');
// Strip any ordinals because they're allowed in Excel (English only)
$dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue) ?? '';
// Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany)

View File

@ -3,12 +3,15 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTimeInterface;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
class Days
{
use ArrayEnabled;
/**
* DAYS.
*
@ -17,15 +20,23 @@ class Days
* Excel Function:
* DAYS(endDate, startDate)
*
* @param DateTimeInterface|float|int|string $endDate Excel date serial value (float),
* PHP date timestamp (integer), PHP DateTime object, or a standard date string
* @param DateTimeInterface|float|int|string $startDate Excel date serial value (float),
* PHP date timestamp (integer), PHP DateTime object, or a standard date string
* @param array|DateTimeInterface|float|int|string $endDate Excel date serial value (float),
* PHP date timestamp (integer), PHP DateTime object, or a standard date string
* Or can be an array of date values
* @param array|DateTimeInterface|float|int|string $startDate Excel date serial value (float),
* PHP date timestamp (integer), PHP DateTime object, or a standard date string
* Or can be an array of date values
*
* @return int|string Number of days between start date and end date or an error
* @return array|int|string Number of days between start date and end date or an error
* If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
* will also be an array with matching dimensions
*/
public static function between($endDate, $startDate)
{
if (is_array($endDate) || is_array($startDate)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $endDate, $startDate);
}
try {
$startDate = Helpers::getDateValue($startDate);
$endDate = Helpers::getDateValue($endDate);

View File

@ -2,12 +2,15 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
class Days360
{
use ArrayEnabled;
/**
* DAYS360.
*
@ -18,11 +21,13 @@ class Days360
* Excel Function:
* DAYS360(startDate,endDate[,method])
*
* @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* @param array|mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* Or can be an array of date values
* @param array|mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param mixed $method US or European Method as a bool
* Or can be an array of date values
* @param array|mixed $method US or European Method as a bool
* FALSE or omitted: U.S. (NASD) method. If the starting date is
* the last day of a month, it becomes equal to the 30th of the
* same month. If the ending date is the last day of a month and
@ -33,11 +38,18 @@ class Days360
* TRUE: European method. Starting dates and ending dates that
* occur on the 31st of a month become equal to the 30th of the
* same month.
* Or can be an array of methods
*
* @return int|string Number of days between start date and end date
* @return array|int|string Number of days between start date and end date
* If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
* will also be an array with matching dimensions
*/
public static function between($startDate = 0, $endDate = 0, $method = false)
{
if (is_array($startDate) || is_array($endDate) || is_array($method)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $startDate, $endDate, $method);
}
try {
$startDate = Helpers::getDateValue($startDate);
$endDate = Helpers::getDateValue($endDate);

View File

@ -4,30 +4,42 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateInterval;
use DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
class Difference
{
use ArrayEnabled;
/**
* DATEDIF.
*
* @param mixed $startDate Excel date serial value, PHP date/time stamp, PHP DateTime object
* or a standard date string
* Or can be an array of date values
* @param mixed $endDate Excel date serial value, PHP date/time stamp, PHP DateTime object
* or a standard date string
* @param string $unit
* Or can be an array of date values
* @param array|string $unit
* Or can be an array of unit values
*
* @return int|string Interval between the dates
* @return array|int|string Interval between the dates
* If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
* will also be an array with matching dimensions
*/
public static function interval($startDate, $endDate, $unit = 'D')
{
if (is_array($startDate) || is_array($endDate) || is_array($unit)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $startDate, $endDate, $unit);
}
try {
$startDate = Helpers::getDateValue($startDate);
$endDate = Helpers::getDateValue($endDate);
$difference = self::initialDiff($startDate, $endDate);
$unit = strtoupper(Functions::flattenSingleValue($unit));
$unit = strtoupper($unit);
} catch (Exception $e) {
return $e->getMessage();
}

View File

@ -2,10 +2,13 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class Month
{
use ArrayEnabled;
/**
* EDATE.
*
@ -19,15 +22,23 @@ class Month
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $adjustmentMonths The number of months before or after start_date.
* Or can be an array of date values
* @param array|int $adjustmentMonths The number of months before or after start_date.
* A positive value for months yields a future date;
* a negative value yields a past date.
* Or can be an array of adjustment values
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array|mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of values is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function adjust($dateValue, $adjustmentMonths)
{
if (is_array($dateValue) || is_array($adjustmentMonths)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $dateValue, $adjustmentMonths);
}
try {
$dateValue = Helpers::getDateValue($dateValue, false);
$adjustmentMonths = Helpers::validateNumericNull($adjustmentMonths);
@ -54,15 +65,23 @@ class Month
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $adjustmentMonths The number of months before or after start_date.
* Or can be an array of date values
* @param array|int $adjustmentMonths The number of months before or after start_date.
* A positive value for months yields a future date;
* a negative value yields a past date.
* Or can be an array of adjustment values
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array|mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of values is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function lastDay($dateValue, $adjustmentMonths)
{
if (is_array($dateValue) || is_array($adjustmentMonths)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $dateValue, $adjustmentMonths);
}
try {
$dateValue = Helpers::getDateValue($dateValue, false);
$adjustmentMonths = Helpers::validateNumericNull($adjustmentMonths);

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class NetworkDays
{
use ArrayEnabled;
/**
* NETWORKDAYS.
*
@ -20,14 +23,28 @@ class NetworkDays
*
* @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
* @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param mixed $dateArgs
* Or can be an array of date values
* @param mixed $dateArgs An array of dates (such as holidays) to exclude from the calculation
*
* @return int|string Interval between the dates
* @return array|int|string Interval between the dates
* If an array of values is passed for the $startDate or $endDate arguments, then the returned result
* will also be an array with matching dimensions
*/
public static function count($startDate, $endDate, ...$dateArgs)
{
if (is_array($startDate) || is_array($endDate)) {
return self::evaluateArrayArgumentsSubset(
[self::class, __FUNCTION__],
2,
$startDate,
$endDate,
...$dateArgs
);
}
try {
// Retrieve the mandatory start and end date that are referenced in the function definition
$sDate = Helpers::getDateValue($startDate);

View File

@ -3,12 +3,15 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
class Time
{
use ArrayEnabled;
/**
* TIME.
*
@ -20,23 +23,31 @@ class Time
* Excel Function:
* TIME(hour,minute,second)
*
* @param mixed $hour A number from 0 (zero) to 32767 representing the hour.
* @param array|int $hour A number from 0 (zero) to 32767 representing the hour.
* Any value greater than 23 will be divided by 24 and the remainder
* will be treated as the hour value. For example, TIME(27,0,0) =
* TIME(3,0,0) = .125 or 3:00 AM.
* @param mixed $minute A number from 0 to 32767 representing the minute.
* @param array|int $minute A number from 0 to 32767 representing the minute.
* Any value greater than 59 will be converted to hours and minutes.
* For example, TIME(0,750,0) = TIME(12,30,0) = .520833 or 12:30 PM.
* @param mixed $second A number from 0 to 32767 representing the second.
* @param array|int $second A number from 0 to 32767 representing the second.
* Any value greater than 59 will be converted to hours, minutes,
* and seconds. For example, TIME(0,0,2000) = TIME(0,33,22) = .023148
* or 12:33:20 AM
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array|mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function fromHMS($hour, $minute, $second)
{
if (is_array($hour) || is_array($minute) || is_array($second)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $hour, $minute, $second);
}
try {
$hour = self::toIntWithNullBool($hour);
$minute = self::toIntWithNullBool($minute);
@ -105,7 +116,6 @@ class Time
*/
private static function toIntWithNullBool($value): int
{
$value = Functions::flattenSingleValue($value);
$value = $value ?? 0;
if (is_bool($value)) {
$value = (int) $value;

View File

@ -2,12 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
class TimeParts
{
use ArrayEnabled;
/**
* HOUROFDAY.
*
@ -19,13 +21,19 @@ class TimeParts
*
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
* Or can be an array of date/time values
*
* @return int|string Hour
* @return array|int|string Hour
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function hour($timeValue)
{
if (is_array($timeValue)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $timeValue);
}
try {
$timeValue = Functions::flattenSingleValue($timeValue);
Helpers::nullFalseTrueToNumber($timeValue);
if (!is_numeric($timeValue)) {
$timeValue = Helpers::getTimeValue($timeValue);
@ -53,13 +61,19 @@ class TimeParts
*
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
* Or can be an array of date/time values
*
* @return int|string Minute
* @return array|int|string Minute
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function minute($timeValue)
{
if (is_array($timeValue)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $timeValue);
}
try {
$timeValue = Functions::flattenSingleValue($timeValue);
Helpers::nullFalseTrueToNumber($timeValue);
if (!is_numeric($timeValue)) {
$timeValue = Helpers::getTimeValue($timeValue);
@ -87,13 +101,19 @@ class TimeParts
*
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
* Or can be an array of date/time values
*
* @return int|string Second
* @return array|int|string Second
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function second($timeValue)
{
if (is_array($timeValue)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $timeValue);
}
try {
$timeValue = Functions::flattenSingleValue($timeValue);
Helpers::nullFalseTrueToNumber($timeValue);
if (!is_numeric($timeValue)) {
$timeValue = Helpers::getTimeValue($timeValue);

View File

@ -3,11 +3,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Datetime;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
class TimeValue
{
use ArrayEnabled;
/**
* TIMEVALUE.
*
@ -21,17 +24,24 @@ class TimeValue
* Excel Function:
* TIMEVALUE(timeValue)
*
* @param string $timeValue A text string that represents a time in any one of the Microsoft
* @param array|string $timeValue A text string that represents a time in any one of the Microsoft
* Excel time formats; for example, "6:45 PM" and "18:45" text strings
* within quotation marks that represent time.
* Date information in time_text is ignored.
* Or can be an array of date/time values
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function fromString($timeValue)
{
$timeValue = trim(Functions::flattenSingleValue($timeValue ?? ''), '"');
if (is_array($timeValue)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $timeValue);
}
$timeValue = trim($timeValue ?? '', '"');
$timeValue = str_replace(['/', '.'], '-', $timeValue);
$arraySplit = preg_split('/[\/:\-\s]/', $timeValue) ?: [];

View File

@ -3,12 +3,15 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
class Week
{
use ArrayEnabled;
/**
* WEEKNUM.
*
@ -24,7 +27,8 @@ class Week
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $method Week begins on Sunday or Monday
* Or can be an array of date values
* @param array|int $method Week begins on Sunday or Monday
* 1 or omitted Week begins on Sunday.
* 2 Week begins on Monday.
* 11 Week begins on Monday.
@ -35,11 +39,18 @@ class Week
* 16 Week begins on Saturday.
* 17 Week begins on Sunday.
* 21 ISO (Jan. 4 is week 1, begins on Monday).
* Or can be an array of methods
*
* @return int|string Week Number
* @return array|int|string Week Number
* If an array of values is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function number($dateValue, $method = Constants::STARTWEEK_SUNDAY)
{
if (is_array($dateValue) || is_array($method)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $dateValue, $method);
}
$origDateValueNull = empty($dateValue);
try {
@ -88,11 +99,18 @@ class Week
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
*
* @return int|string Week Number
* @return array|int|string Week Number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isoWeekNumber($dateValue)
{
if (is_array($dateValue)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue);
}
if (self::apparentBug($dateValue)) {
return 52;
}
@ -119,17 +137,25 @@ class Week
* Excel Function:
* WEEKDAY(dateValue[,style])
*
* @param null|float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer),
* @param null|array|float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of date values
* @param mixed $style A number that determines the type of return value
* 1 or omitted Numbers 1 (Sunday) through 7 (Saturday).
* 2 Numbers 1 (Monday) through 7 (Sunday).
* 3 Numbers 0 (Monday) through 6 (Sunday).
* Or can be an array of styles
*
* @return int|string Day of the week value
* @return array|int|string Day of the week value
* If an array of values is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function day($dateValue, $style = 1)
{
if (is_array($dateValue) || is_array($style)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $dateValue, $style);
}
try {
$dateValue = Helpers::getDateValue($dateValue);
$style = self::validateStyle($style);
@ -165,8 +191,6 @@ class Week
*/
private static function validateStyle($style): int
{
$style = Functions::flattenSingleValue($style);
if (!is_numeric($style)) {
throw new Exception(Functions::VALUE());
}
@ -225,7 +249,7 @@ class Week
if ($method === null) {
$method = Constants::STARTWEEK_SUNDAY;
}
$method = Functions::flattenSingleValue($method);
if (!is_numeric($method)) {
throw new Exception(Functions::VALUE());
}

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class WorkDay
{
use ArrayEnabled;
/**
* WORKDAY.
*
@ -18,27 +21,37 @@ class WorkDay
* Excel Function:
* WORKDAY(startDate,endDays[,holidays[,holiday[,...]]])
*
* @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* @param array|mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $endDays The number of nonweekend and nonholiday days before or after
* Or can be an array of date values
* @param array|int $endDays The number of nonweekend and nonholiday days before or after
* startDate. A positive value for days yields a future date; a
* negative value yields a past date.
* @param mixed $dateArgs
* Or can be an array of int values
* @param null|mixed $dateArgs An array of dates (such as holidays) to exclude from the calculation
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* @return array|mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
* If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
* will also be an array with matching dimensions
*/
public static function date($startDate, $endDays, ...$dateArgs)
{
if (is_array($startDate) || is_array($endDays)) {
return self::evaluateArrayArgumentsSubset(
[self::class, __FUNCTION__],
2,
$startDate,
$endDays,
...$dateArgs
);
}
// Retrieve the mandatory start date and days that are referenced in the function definition
try {
$startDate = Helpers::getDateValue($startDate);
$endDays = Helpers::validateNumericNull($endDays);
$dateArgs = Functions::flattenArray($dateArgs);
$holidayArray = [];
foreach ($dateArgs as $holidayDate) {
$holidayArray[] = Helpers::getDateValue($holidayDate);
}
$holidayArray = array_map([Helpers::class, 'getDateValue'], Functions::flattenArray($dateArgs));
} catch (Exception $e) {
return $e->getMessage();
}
@ -64,9 +77,8 @@ class WorkDay
private static function incrementing(float $startDate, int $endDays, array $holidayArray)
{
// Adjust the start date if it falls over a weekend
$startDoW = self::getWeekDay($startDate, 3);
if (self::getWeekDay($startDate, 3) >= 5) {
if ($startDoW >= 5) {
$startDate += 7 - $startDoW;
--$endDays;
}
@ -126,9 +138,8 @@ class WorkDay
private static function decrementing(float $startDate, int $endDays, array $holidayArray)
{
// Adjust the start date if it falls over a weekend
$startDoW = self::getWeekDay($startDate, 3);
if (self::getWeekDay($startDate, 3) >= 5) {
if ($startDoW >= 5) {
$startDate += -$startDoW + 4;
++$endDays;
}
@ -172,6 +183,7 @@ class WorkDay
}
// Adjust the calculated end date if it falls over a weekend
$endDoW = self::getWeekDay($endDate, 3);
/** int $endDoW */
if ($endDoW >= 5) {
$endDate += -$endDoW + 4;
}
@ -182,8 +194,8 @@ class WorkDay
private static function getWeekDay(float $date, int $wd): int
{
$result = Week::day($date, $wd);
$result = Functions::scalar(Week::day($date, $wd));
return is_string($result) ? -1 : $result;
return is_int($result) ? $result : -1;
}
}

View File

@ -2,12 +2,15 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
class YearFrac
{
use ArrayEnabled;
/**
* YEARFRAC.
*
@ -23,19 +26,28 @@ class YearFrac
*
* @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* Or can be an array of values
* @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $method Method used for the calculation
* Or can be an array of methods
* @param array|int $method Method used for the calculation
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
* 3 Actual/365
* 4 European 30/360
* Or can be an array of methods
*
* @return float|string fraction of the year, or a string containing an error
* @return array|float|string fraction of the year, or a string containing an error
* If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
* will also be an array with matching dimensions
*/
public static function fraction($startDate, $endDate, $method = 0)
{
if (is_array($startDate) || is_array($endDate) || is_array($method)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $startDate, $endDate, $method);
}
try {
$method = (int) Helpers::validateNumericNull($method);
$sDate = Helpers::getDateValue($startDate);
@ -50,15 +62,15 @@ class YearFrac
switch ($method) {
case 0:
return Days360::between($startDate, $endDate) / 360;
return Functions::scalar(Days360::between($startDate, $endDate)) / 360;
case 1:
return self::method1($startDate, $endDate);
case 2:
return Difference::interval($startDate, $endDate) / 360;
return Functions::scalar(Difference::interval($startDate, $endDate)) / 360;
case 3:
return Difference::interval($startDate, $endDate) / 365;
return Functions::scalar(Difference::interval($startDate, $endDate)) / 365;
case 4:
return Days360::between($startDate, $endDate, true) / 360;
return Functions::scalar(Days360::between($startDate, $endDate, true)) / 360;
}
return Functions::NAN();
@ -87,7 +99,7 @@ class YearFrac
private static function method1(float $startDate, float $endDate): float
{
$days = Difference::interval($startDate, $endDate);
$days = Functions::scalar(Difference::interval($startDate, $endDate));
$startYear = (int) DateParts::year($startDate);
$endYear = (int) DateParts::year($endDate);
$years = $endYear - $startYear + 1;

View File

@ -0,0 +1,202 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\Engine;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class ArrayArgumentHelper
{
/**
* @var array
*/
protected $arguments;
/**
* @var int
*/
protected $argumentCount;
/**
* @var array
*/
protected $rows;
/**
* @var array
*/
protected $columns;
public function initialise(array $arguments): void
{
$this->rows = $this->rows($arguments);
$this->columns = $this->columns($arguments);
$this->argumentCount = count($arguments);
$this->arguments = $this->flattenSingleCellArrays($arguments, $this->rows, $this->columns);
$this->rows = $this->rows($arguments);
$this->columns = $this->columns($arguments);
if ($this->arrayArguments() > 2) {
throw new Exception('Formulae with more than two array arguments are not supported');
}
}
public function arguments(): array
{
return $this->arguments;
}
public function hasArrayArgument(): bool
{
return $this->arrayArguments() > 0;
}
public function getFirstArrayArgumentNumber(): int
{
$rowArrays = $this->filterArray($this->rows);
$columnArrays = $this->filterArray($this->columns);
for ($index = 0; $index < $this->argumentCount; ++$index) {
if (isset($rowArrays[$index]) || isset($columnArrays[$index])) {
return ++$index;
}
}
return 0;
}
public function getSingleRowVector(): ?int
{
$rowVectors = $this->getRowVectors();
return count($rowVectors) === 1 ? array_pop($rowVectors) : null;
}
private function getRowVectors(): array
{
$rowVectors = [];
for ($index = 0; $index < $this->argumentCount; ++$index) {
if ($this->rows[$index] === 1 && $this->columns[$index] > 1) {
$rowVectors[] = $index;
}
}
return $rowVectors;
}
public function getSingleColumnVector(): ?int
{
$columnVectors = $this->getColumnVectors();
return count($columnVectors) === 1 ? array_pop($columnVectors) : null;
}
private function getColumnVectors(): array
{
$columnVectors = [];
for ($index = 0; $index < $this->argumentCount; ++$index) {
if ($this->rows[$index] > 1 && $this->columns[$index] === 1) {
$columnVectors[] = $index;
}
}
return $columnVectors;
}
public function getMatrixPair(): array
{
for ($i = 0; $i < ($this->argumentCount - 1); ++$i) {
for ($j = $i + 1; $j < $this->argumentCount; ++$j) {
if (isset($this->rows[$i], $this->rows[$j])) {
return [$i, $j];
}
}
}
return [];
}
public function isVector(int $argument): bool
{
return $this->rows[$argument] === 1 || $this->columns[$argument] === 1;
}
public function isRowVector(int $argument): bool
{
return $this->rows[$argument] === 1;
}
public function isColumnVector(int $argument): bool
{
return $this->columns[$argument] === 1;
}
public function rowCount(int $argument): int
{
return $this->rows[$argument];
}
public function columnCount(int $argument): int
{
return $this->columns[$argument];
}
private function rows(array $arguments): array
{
return array_map(
function ($argument) {
return is_countable($argument) ? count($argument) : 1;
},
$arguments
);
}
private function columns(array $arguments): array
{
return array_map(
function ($argument) {
return is_array($argument) && is_array($argument[array_keys($argument)[0]])
? count($argument[array_keys($argument)[0]])
: 1;
},
$arguments
);
}
public function arrayArguments(): int
{
$count = 0;
foreach (array_keys($this->arguments) as $argument) {
if ($this->rows[$argument] > 1 || $this->columns[$argument] > 1) {
++$count;
}
}
return $count;
}
private function flattenSingleCellArrays(array $arguments, array $rows, array $columns): array
{
foreach ($arguments as $index => $argument) {
if ($rows[$index] === 1 && $columns[$index] === 1) {
while (is_array($argument)) {
$argument = array_pop($argument);
}
$arguments[$index] = $argument;
}
}
return $arguments;
}
private function filterArray(array $array): array
{
return array_filter(
$array,
function ($value) {
return $value > 1;
}
);
}
}

View File

@ -0,0 +1,174 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\Engine;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class ArrayArgumentProcessor
{
/**
* @var ArrayArgumentHelper
*/
private static $arrayArgumentHelper;
/**
* @param mixed ...$arguments
*/
public static function processArguments(
ArrayArgumentHelper $arrayArgumentHelper,
callable $method,
...$arguments
): array {
self::$arrayArgumentHelper = $arrayArgumentHelper;
if (self::$arrayArgumentHelper->hasArrayArgument() === false) {
return [$method(...$arguments)];
}
if (self::$arrayArgumentHelper->arrayArguments() === 1) {
$nthArgument = self::$arrayArgumentHelper->getFirstArrayArgumentNumber();
return self::evaluateNthArgumentAsArray($method, $nthArgument, ...$arguments);
}
$singleRowVectorIndex = self::$arrayArgumentHelper->getSingleRowVector();
$singleColumnVectorIndex = self::$arrayArgumentHelper->getSingleColumnVector();
if ($singleRowVectorIndex !== null && $singleColumnVectorIndex !== null) {
// Basic logic for a single row vector and a single column vector
return self::evaluateVectorPair($method, $singleRowVectorIndex, $singleColumnVectorIndex, ...$arguments);
}
$matrixPair = self::$arrayArgumentHelper->getMatrixPair();
if ($matrixPair !== []) {
if (
(self::$arrayArgumentHelper->isVector($matrixPair[0]) === true &&
self::$arrayArgumentHelper->isVector($matrixPair[1]) === false) ||
(self::$arrayArgumentHelper->isVector($matrixPair[0]) === false &&
self::$arrayArgumentHelper->isVector($matrixPair[1]) === true)
) {
// Logic for a matrix and a vector (row or column)
return self::evaluateVectorMatrixPair($method, $matrixPair, ...$arguments);
}
// Logic for matrix/matrix, column vector/column vector or row vector/row vector
return self::evaluateMatrixPair($method, $matrixPair, ...$arguments);
}
// Still need to work out the logic for more than two array arguments,
// For the moment, we're throwing an Exception when we initialise the ArrayArgumentHelper
return ['#VALUE!'];
}
/**
* @param mixed ...$arguments
*/
private static function evaluateVectorMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array
{
$matrix2 = array_pop($matrixIndexes);
/** @var array $matrixValues2 */
$matrixValues2 = $arguments[$matrix2];
$matrix1 = array_pop($matrixIndexes);
/** @var array $matrixValues1 */
$matrixValues1 = $arguments[$matrix1];
$rows = min(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
$columns = min(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
if ($rows === 1) {
$rows = max(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
}
if ($columns === 1) {
$columns = max(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
}
$result = [];
for ($rowIndex = 0; $rowIndex < $rows; ++$rowIndex) {
for ($columnIndex = 0; $columnIndex < $columns; ++$columnIndex) {
$rowIndex1 = self::$arrayArgumentHelper->isRowVector($matrix1) ? 0 : $rowIndex;
$columnIndex1 = self::$arrayArgumentHelper->isColumnVector($matrix1) ? 0 : $columnIndex;
$value1 = $matrixValues1[$rowIndex1][$columnIndex1];
$rowIndex2 = self::$arrayArgumentHelper->isRowVector($matrix2) ? 0 : $rowIndex;
$columnIndex2 = self::$arrayArgumentHelper->isColumnVector($matrix2) ? 0 : $columnIndex;
$value2 = $matrixValues2[$rowIndex2][$columnIndex2];
$arguments[$matrix1] = $value1;
$arguments[$matrix2] = $value2;
$result[$rowIndex][$columnIndex] = $method(...$arguments);
}
}
return $result;
}
/**
* @param mixed ...$arguments
*/
private static function evaluateMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array
{
$matrix2 = array_pop($matrixIndexes);
/** @var array $matrixValues2 */
$matrixValues2 = $arguments[$matrix2];
$matrix1 = array_pop($matrixIndexes);
/** @var array $matrixValues1 */
$matrixValues1 = $arguments[$matrix1];
$result = [];
foreach ($matrixValues1 as $rowIndex => $row) {
foreach ($row as $columnIndex => $value1) {
if (isset($matrixValues2[$rowIndex][$columnIndex]) === false) {
continue;
}
$value2 = $matrixValues2[$rowIndex][$columnIndex];
$arguments[$matrix1] = $value1;
$arguments[$matrix2] = $value2;
$result[$rowIndex][$columnIndex] = $method(...$arguments);
}
}
return $result;
}
/**
* @param mixed ...$arguments
*/
private static function evaluateVectorPair(callable $method, int $rowIndex, int $columnIndex, ...$arguments): array
{
$rowVector = Functions::flattenArray($arguments[$rowIndex]);
$columnVector = Functions::flattenArray($arguments[$columnIndex]);
$result = [];
foreach ($columnVector as $column) {
$rowResults = [];
foreach ($rowVector as $row) {
$arguments[$rowIndex] = $row;
$arguments[$columnIndex] = $column;
$rowResults[] = $method(...$arguments);
}
$result[] = $rowResults;
}
return $result;
}
/**
* Note, offset is from 1 (for the first argument) rather than from 0.
*
* @param mixed ...$arguments
*/
private static function evaluateNthArgumentAsArray(callable $method, int $nthArgument, ...$arguments): array
{
$values = array_slice($arguments, $nthArgument - 1, 1);
/** @var array $values */
$values = array_pop($values);
$result = [];
foreach ($values as $value) {
$arguments[$nthArgument - 1] = $value;
$result[] = $method(...$arguments);
}
return $result;
}
}

View File

@ -61,7 +61,7 @@ class Engineering
* If $ord is nonnumeric, BESSELI returns the #VALUE! error value.
* If $ord < 0, BESSELI returns the #NUM! error value.
*
* @return float|string Result, or a string containing an error
* @return array|float|string Result, or a string containing an error
*/
public static function BESSELI($x, $ord)
{
@ -86,7 +86,7 @@ class Engineering
* If $ord is nonnumeric, BESSELJ returns the #VALUE! error value.
* If $ord < 0, BESSELJ returns the #NUM! error value.
*
* @return float|string Result, or a string containing an error
* @return array|float|string Result, or a string containing an error
*/
public static function BESSELJ($x, $ord)
{
@ -112,7 +112,7 @@ class Engineering
* If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
* If $ord < 0, BESSELK returns the #NUM! error value.
*
* @return float|string Result, or a string containing an error
* @return array|float|string Result, or a string containing an error
*/
public static function BESSELK($x, $ord)
{
@ -137,7 +137,7 @@ class Engineering
* If $ord is nonnumeric, BESSELY returns the #VALUE! error value.
* If $ord < 0, BESSELY returns the #NUM! error value.
*
* @return float|string Result, or a string containing an error
* @return array|float|string Result, or a string containing an error
*/
public static function BESSELY($x, $ord)
{
@ -163,7 +163,7 @@ class Engineering
* If number is not a valid binary number, or if number contains more than
* 10 characters (10 bits), BIN2DEC returns the #NUM! error value.
*
* @return string
* @return array|string
*/
public static function BINTODEC($x)
{
@ -195,7 +195,7 @@ class Engineering
* If places is nonnumeric, BIN2HEX returns the #VALUE! error value.
* If places is negative, BIN2HEX returns the #NUM! error value.
*
* @return string
* @return array|string
*/
public static function BINTOHEX($x, $places = null)
{
@ -227,7 +227,7 @@ class Engineering
* If places is nonnumeric, BIN2OCT returns the #VALUE! error value.
* If places is negative, BIN2OCT returns the #NUM! error value.
*
* @return string
* @return array|string
*/
public static function BINTOOCT($x, $places = null)
{
@ -263,7 +263,7 @@ class Engineering
* If places is nonnumeric, DEC2BIN returns the #VALUE! error value.
* If places is zero or negative, DEC2BIN returns the #NUM! error value.
*
* @return string
* @return array|string
*/
public static function DECTOBIN($x, $places = null)
{
@ -299,7 +299,7 @@ class Engineering
* If places is nonnumeric, DEC2HEX returns the #VALUE! error value.
* If places is zero or negative, DEC2HEX returns the #NUM! error value.
*
* @return string
* @return array|string
*/
public static function DECTOHEX($x, $places = null)
{
@ -335,7 +335,7 @@ class Engineering
* If places is nonnumeric, DEC2OCT returns the #VALUE! error value.
* If places is zero or negative, DEC2OCT returns the #NUM! error value.
*
* @return string
* @return array|string
*/
public static function DECTOOCT($x, $places = null)
{
@ -371,7 +371,7 @@ class Engineering
* If places is nonnumeric, HEX2BIN returns the #VALUE! error value.
* If places is negative, HEX2BIN returns the #NUM! error value.
*
* @return string
* @return array|string
*/
public static function HEXTOBIN($x, $places = null)
{
@ -398,7 +398,7 @@ class Engineering
* If number is not a valid hexadecimal number, HEX2DEC returns the
* #NUM! error value.
*
* @return string
* @return array|string
*/
public static function HEXTODEC($x)
{
@ -438,7 +438,7 @@ class Engineering
* value.
* If places is negative, HEX2OCT returns the #NUM! error value.
*
* @return string
* @return array|string
*/
public static function HEXTOOCT($x, $places = null)
{
@ -480,7 +480,7 @@ class Engineering
* If places is negative, OCT2BIN returns the #NUM! error
* value.
*
* @return string
* @return array|string
*/
public static function OCTTOBIN($x, $places = null)
{
@ -507,7 +507,7 @@ class Engineering
* If number is not a valid octal number, OCT2DEC returns the
* #NUM! error value.
*
* @return string
* @return array|string
*/
public static function OCTTODEC($x)
{
@ -544,7 +544,7 @@ class Engineering
* If places is nonnumeric, OCT2HEX returns the #VALUE! error value.
* If places is negative, OCT2HEX returns the #NUM! error value.
*
* @return string
* @return array|string
*/
public static function OCTTOHEX($x, $places = null)
{
@ -563,12 +563,12 @@ class Engineering
*
* @see Use the COMPLEX() method in the Engineering\Complex class instead
*
* @param float $realNumber the real coefficient of the complex number
* @param float $imaginary the imaginary coefficient of the complex number
* @param string $suffix The suffix for the imaginary component of the complex number.
* @param array|float $realNumber the real coefficient of the complex number
* @param array|float $imaginary the imaginary coefficient of the complex number
* @param array|string $suffix The suffix for the imaginary component of the complex number.
* If omitted, the suffix is assumed to be "i".
*
* @return string
* @return array|string
*/
public static function COMPLEX($realNumber = 0.0, $imaginary = 0.0, $suffix = 'i')
{
@ -590,7 +590,7 @@ class Engineering
* @param string $complexNumber the complex number for which you want the imaginary
* coefficient
*
* @return float|string
* @return array|float|string
*/
public static function IMAGINARY($complexNumber)
{
@ -611,7 +611,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the real coefficient
*
* @return float|string
* @return array|float|string
*/
public static function IMREAL($complexNumber)
{
@ -632,7 +632,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the absolute value
*
* @return float|string
* @return array|float|string
*/
public static function IMABS($complexNumber)
{
@ -652,9 +652,9 @@ class Engineering
*
* @see Use the IMARGUMENT() method in the Engineering\ComplexFunctions class instead
*
* @param string $complexNumber the complex number for which you want the argument theta
* @param array|string $complexNumber the complex number for which you want the argument theta
*
* @return float|string
* @return array|float|string
*/
public static function IMARGUMENT($complexNumber)
{
@ -673,9 +673,9 @@ class Engineering
*
* @see Use the IMARGUMENT() method in the Engineering\ComplexFunctions class instead
*
* @param string $complexNumber the complex number for which you want the conjugate
* @param array|string $complexNumber the complex number for which you want the conjugate
*
* @return string
* @return array|string
*/
public static function IMCONJUGATE($complexNumber)
{
@ -694,9 +694,9 @@ class Engineering
*
* @see Use the IMCOS() method in the Engineering\ComplexFunctions class instead
*
* @param string $complexNumber the complex number for which you want the cosine
* @param array|string $complexNumber the complex number for which you want the cosine
*
* @return float|string
* @return array|float|string
*/
public static function IMCOS($complexNumber)
{
@ -715,9 +715,9 @@ class Engineering
*
* @see Use the IMCOSH() method in the Engineering\ComplexFunctions class instead
*
* @param string $complexNumber the complex number for which you want the hyperbolic cosine
* @param array|string $complexNumber the complex number for which you want the hyperbolic cosine
*
* @return float|string
* @return array|float|string
*/
public static function IMCOSH($complexNumber)
{
@ -736,9 +736,9 @@ class Engineering
*
* @see Use the IMCOT() method in the Engineering\ComplexFunctions class instead
*
* @param string $complexNumber the complex number for which you want the cotangent
* @param array|string $complexNumber the complex number for which you want the cotangent
*
* @return float|string
* @return array|float|string
*/
public static function IMCOT($complexNumber)
{
@ -757,9 +757,9 @@ class Engineering
*
* @see Use the IMCSC() method in the Engineering\ComplexFunctions class instead
*
* @param string $complexNumber the complex number for which you want the cosecant
* @param array|string $complexNumber the complex number for which you want the cosecant
*
* @return float|string
* @return array|float|string
*/
public static function IMCSC($complexNumber)
{
@ -778,9 +778,9 @@ class Engineering
*
* @see Use the IMCSCH() method in the Engineering\ComplexFunctions class instead
*
* @param string $complexNumber the complex number for which you want the hyperbolic cosecant
* @param array|string $complexNumber the complex number for which you want the hyperbolic cosecant
*
* @return float|string
* @return array|float|string
*/
public static function IMCSCH($complexNumber)
{
@ -801,7 +801,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the sine
*
* @return float|string
* @return array|float|string
*/
public static function IMSIN($complexNumber)
{
@ -822,7 +822,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the hyperbolic sine
*
* @return float|string
* @return array|float|string
*/
public static function IMSINH($complexNumber)
{
@ -843,7 +843,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the secant
*
* @return float|string
* @return array|float|string
*/
public static function IMSEC($complexNumber)
{
@ -864,7 +864,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the hyperbolic secant
*
* @return float|string
* @return array|float|string
*/
public static function IMSECH($complexNumber)
{
@ -885,7 +885,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the tangent
*
* @return float|string
* @return array|float|string
*/
public static function IMTAN($complexNumber)
{
@ -906,7 +906,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the square root
*
* @return string
* @return array|string
*/
public static function IMSQRT($complexNumber)
{
@ -927,7 +927,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the natural logarithm
*
* @return string
* @return array|string
*/
public static function IMLN($complexNumber)
{
@ -948,7 +948,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the common logarithm
*
* @return string
* @return array|string
*/
public static function IMLOG10($complexNumber)
{
@ -969,7 +969,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the base-2 logarithm
*
* @return string
* @return array|string
*/
public static function IMLOG2($complexNumber)
{
@ -990,7 +990,7 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the exponential
*
* @return string
* @return array|string
*/
public static function IMEXP($complexNumber)
{
@ -1012,7 +1012,7 @@ class Engineering
* @param string $complexNumber the complex number you want to raise to a power
* @param float $realNumber the power to which you want to raise the complex number
*
* @return string
* @return array|string
*/
public static function IMPOWER($complexNumber, $realNumber)
{
@ -1034,7 +1034,7 @@ class Engineering
* @param string $complexDividend the complex numerator or dividend
* @param string $complexDivisor the complex denominator or divisor
*
* @return string
* @return array|string
*/
public static function IMDIV($complexDividend, $complexDivisor)
{
@ -1056,7 +1056,7 @@ class Engineering
* @param string $complexNumber1 the complex number from which to subtract complexNumber2
* @param string $complexNumber2 the complex number to subtract from complexNumber1
*
* @return string
* @return array|string
*/
public static function IMSUB($complexNumber1, $complexNumber2)
{
@ -1123,7 +1123,7 @@ class Engineering
* @param float $a the first number
* @param float $b The second number. If omitted, b is assumed to be zero.
*
* @return int|string (string in the event of an error)
* @return array|int|string (string in the event of an error)
*/
public static function DELTA($a, $b = 0)
{
@ -1147,7 +1147,7 @@ class Engineering
* @param float $number the value to test against step
* @param float $step The threshold value. If you omit a value for step, GESTEP uses zero.
*
* @return int|string (string in the event of an error)
* @return array|int|string (string in the event of an error)
*/
public static function GESTEP($number, $step = 0)
{
@ -1169,7 +1169,7 @@ class Engineering
* @param int $number1
* @param int $number2
*
* @return int|string
* @return array|int|string
*/
public static function BITAND($number1, $number2)
{
@ -1191,7 +1191,7 @@ class Engineering
* @param int $number1
* @param int $number2
*
* @return int|string
* @return array|int|string
*/
public static function BITOR($number1, $number2)
{
@ -1213,7 +1213,7 @@ class Engineering
* @param int $number1
* @param int $number2
*
* @return int|string
* @return array|int|string
*/
public static function BITXOR($number1, $number2)
{
@ -1235,7 +1235,7 @@ class Engineering
* @param int $number
* @param int $shiftAmount
*
* @return int|string
* @return array|float|int|string
*/
public static function BITLSHIFT($number, $shiftAmount)
{
@ -1257,7 +1257,7 @@ class Engineering
* @param int $number
* @param int $shiftAmount
*
* @return int|string
* @return array|float|int|string
*/
public static function BITRSHIFT($number, $shiftAmount)
{
@ -1285,7 +1285,7 @@ class Engineering
* @param float $upper upper bound for integrating ERF.
* If omitted, ERF integrates between zero and lower_limit
*
* @return float|string
* @return array|float|string
*/
public static function ERF($lower, $upper = null)
{
@ -1306,7 +1306,7 @@ class Engineering
*
* @param float $limit bound for integrating ERF
*
* @return float|string
* @return array|float|string
*/
public static function ERFPRECISE($limit)
{
@ -1332,7 +1332,7 @@ class Engineering
*
* @param float $x The lower bound for integrating ERFC
*
* @return float|string
* @return array|float|string
*/
public static function ERFC($x)
{
@ -1437,7 +1437,7 @@ class Engineering
* @param string $fromUOM the units for value
* @param string $toUOM the units for the result
*
* @return float|string
* @return array|float|string
*/
public static function CONVERTUOM($value, $fromUOM, $toUOM)
{

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class BesselI
{
use ArrayEnabled;
/**
* BESSELI.
*
@ -21,17 +24,22 @@ class BesselI
*
* @param mixed $x A float value at which to evaluate the function.
* If x is nonnumeric, BESSELI returns the #VALUE! error value.
* Or can be an array of values
* @param mixed $ord The integer order of the Bessel function.
* If ord is not an integer, it is truncated.
* If $ord is nonnumeric, BESSELI returns the #VALUE! error value.
* If $ord < 0, BESSELI returns the #NUM! error value.
* Or can be an array of values
*
* @return float|string Result, or a string containing an error
* @return array|float|string 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 BESSELI($x, $ord)
{
$x = Functions::flattenSingleValue($x);
$ord = Functions::flattenSingleValue($ord);
if (is_array($x) || is_array($ord)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $x, $ord);
}
try {
$x = EngineeringValidations::validateFloat($x);

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class BesselJ
{
use ArrayEnabled;
/**
* BESSELJ.
*
@ -20,17 +23,22 @@ class BesselJ
*
* @param mixed $x A float value at which to evaluate the function.
* If x is nonnumeric, BESSELJ returns the #VALUE! error value.
* Or can be an array of values
* @param mixed $ord The integer order of the Bessel function.
* If ord is not an integer, it is truncated.
* If $ord is nonnumeric, BESSELJ returns the #VALUE! error value.
* If $ord < 0, BESSELJ returns the #NUM! error value.
* Or can be an array of values
*
* @return float|string Result, or a string containing an error
* @return array|float|string 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 BESSELJ($x, $ord)
{
$x = Functions::flattenSingleValue($x);
$ord = Functions::flattenSingleValue($ord);
if (is_array($x) || is_array($ord)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $x, $ord);
}
try {
$x = EngineeringValidations::validateFloat($x);

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class BesselK
{
use ArrayEnabled;
/**
* BESSELK.
*
@ -18,17 +21,22 @@ class BesselK
*
* @param mixed $x A float value at which to evaluate the function.
* If x is nonnumeric, BESSELK returns the #VALUE! error value.
* Or can be an array of values
* @param mixed $ord The integer order of the Bessel function.
* If ord is not an integer, it is truncated.
* If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
* If $ord < 0, BESSELKI returns the #NUM! error value.
* Or can be an array of values
*
* @return float|string Result, or a string containing an error
* @return array|float|string 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 BESSELK($x, $ord)
{
$x = Functions::flattenSingleValue($x);
$ord = Functions::flattenSingleValue($ord);
if (is_array($x) || is_array($ord)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $x, $ord);
}
try {
$x = EngineeringValidations::validateFloat($x);

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class BesselY
{
use ArrayEnabled;
/**
* BESSELY.
*
@ -17,17 +20,22 @@ class BesselY
*
* @param mixed $x A float value at which to evaluate the function.
* If x is nonnumeric, BESSELY returns the #VALUE! error value.
* Or can be an array of values
* @param mixed $ord The integer order of the Bessel function.
* If ord is not an integer, it is truncated.
* If $ord is nonnumeric, BESSELY returns the #VALUE! error value.
* If $ord < 0, BESSELY returns the #NUM! error value.
* Or can be an array of values
*
* @return float|string Result, or a string containing an error
* @return array|float|string 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 BESSELY($x, $ord)
{
$x = Functions::flattenSingleValue($x);
$ord = Functions::flattenSingleValue($ord);
if (is_array($x) || is_array($ord)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $x, $ord);
}
try {
$x = EngineeringValidations::validateFloat($x);

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class BitWise
{
use ArrayEnabled;
const SPLIT_DIVISOR = 2 ** 24;
/**
@ -27,13 +30,21 @@ class BitWise
* Excel Function:
* BITAND(number1, number2)
*
* @param int $number1
* @param int $number2
* @param array|int $number1
* Or can be an array of values
* @param array|int $number2
* 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 BITAND($number1, $number2)
{
if (is_array($number1) || is_array($number2)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number1, $number2);
}
try {
$number1 = self::validateBitwiseArgument($number1);
$number2 = self::validateBitwiseArgument($number2);
@ -54,13 +65,21 @@ class BitWise
* Excel Function:
* BITOR(number1, number2)
*
* @param int $number1
* @param int $number2
* @param array|int $number1
* Or can be an array of values
* @param array|int $number2
* 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 BITOR($number1, $number2)
{
if (is_array($number1) || is_array($number2)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number1, $number2);
}
try {
$number1 = self::validateBitwiseArgument($number1);
$number2 = self::validateBitwiseArgument($number2);
@ -82,13 +101,21 @@ class BitWise
* Excel Function:
* BITXOR(number1, number2)
*
* @param int $number1
* @param int $number2
* @param array|int $number1
* Or can be an array of values
* @param array|int $number2
* 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 BITXOR($number1, $number2)
{
if (is_array($number1) || is_array($number2)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number1, $number2);
}
try {
$number1 = self::validateBitwiseArgument($number1);
$number2 = self::validateBitwiseArgument($number2);
@ -110,13 +137,21 @@ class BitWise
* Excel Function:
* BITLSHIFT(number, shift_amount)
*
* @param int $number
* @param int $shiftAmount
* @param array|int $number
* Or can be an array of values
* @param array|int $shiftAmount
* Or can be an array of values
*
* @return float|int|string
* @return array|float|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 BITLSHIFT($number, $shiftAmount)
{
if (is_array($number) || is_array($shiftAmount)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $shiftAmount);
}
try {
$number = self::validateBitwiseArgument($number);
$shiftAmount = self::validateShiftAmount($shiftAmount);
@ -140,13 +175,21 @@ class BitWise
* Excel Function:
* BITRSHIFT(number, shift_amount)
*
* @param int $number
* @param int $shiftAmount
* @param array|int $number
* Or can be an array of values
* @param array|int $shiftAmount
* Or can be an array of values
*
* @return float|int|string
* @return array|float|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 BITRSHIFT($number, $shiftAmount)
{
if (is_array($number) || is_array($shiftAmount)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $shiftAmount);
}
try {
$number = self::validateBitwiseArgument($number);
$shiftAmount = self::validateShiftAmount($shiftAmount);
@ -171,7 +214,7 @@ class BitWise
*/
private static function validateBitwiseArgument($value)
{
self::nullFalseTrueToNumber($value);
$value = self::nullFalseTrueToNumber($value);
if (is_numeric($value)) {
if ($value == floor($value)) {
@ -197,7 +240,7 @@ class BitWise
*/
private static function validateShiftAmount($value)
{
self::nullFalseTrueToNumber($value);
$value = self::nullFalseTrueToNumber($value);
if (is_numeric($value)) {
if (abs($value) > 53) {
@ -214,14 +257,17 @@ class BitWise
* Many functions accept null/false/true argument treated as 0/0/1.
*
* @param mixed $number
*
* @return mixed
*/
public static function nullFalseTrueToNumber(&$number): void
private static function nullFalseTrueToNumber(&$number)
{
$number = Functions::flattenSingleValue($number);
if ($number === null) {
$number = 0;
} elseif (is_bool($number)) {
$number = (int) $number;
}
return $number;
}
}

View File

@ -2,11 +2,13 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Compare
{
use ArrayEnabled;
/**
* DELTA.
*
@ -18,15 +20,20 @@ class Compare
* functions you calculate the count of equal pairs. This function is also known as the
* Kronecker Delta function.
*
* @param float $a the first number
* @param float $b The second number. If omitted, b is assumed to be zero.
* @param array|float $a the first number
* Or can be an array of values
* @param array|float $b The second number. If omitted, b is assumed to be zero.
* Or can be an array of values
*
* @return int|string (string in the event of an error)
* @return array|int|string (string in the event of 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 DELTA($a, $b = 0)
public static function DELTA($a, $b = 0.0)
{
$a = Functions::flattenSingleValue($a);
$b = Functions::flattenSingleValue($b);
if (is_array($a) || is_array($b)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $a, $b);
}
try {
$a = EngineeringValidations::validateFloat($a);
@ -35,7 +42,7 @@ class Compare
return $e->getMessage();
}
return (int) ($a == $b);
return (int) (abs($a - $b) < 1.0e-15);
}
/**
@ -48,15 +55,20 @@ class Compare
* Use this function to filter a set of values. For example, by summing several GESTEP
* functions you calculate the count of values that exceed a threshold.
*
* @param float $number the value to test against step
* @param float $step The threshold value. If you omit a value for step, GESTEP uses zero.
* @param array|float $number the value to test against step
* Or can be an array of values
* @param array|float $step The threshold value. If you omit a value for step, GESTEP uses zero.
* Or can be an array of values
*
* @return int|string (string in the event of an error)
* @return array|int|string (string in the event of 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 GESTEP($number, $step = 0)
public static function GESTEP($number, $step = 0.0)
{
$number = Functions::flattenSingleValue($number);
$step = Functions::flattenSingleValue($step);
if (is_array($number) || is_array($step)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $step);
}
try {
$number = EngineeringValidations::validateFloat($number);

View File

@ -4,11 +4,14 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use Complex\Complex as ComplexObject;
use Complex\Exception as ComplexException;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Complex
{
use ArrayEnabled;
/**
* COMPLEX.
*
@ -18,17 +21,26 @@ class Complex
* COMPLEX(realNumber,imaginary[,suffix])
*
* @param mixed $realNumber the real float coefficient of the complex number
* Or can be an array of values
* @param mixed $imaginary the imaginary float coefficient of the complex number
* Or can be an array of values
* @param mixed $suffix The character suffix for the imaginary component of the complex number.
* If omitted, the suffix is assumed to be "i".
* Or can be an array of values
*
* @return string
* @return array|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 COMPLEX($realNumber = 0.0, $imaginary = 0.0, $suffix = 'i')
{
$realNumber = ($realNumber === null) ? 0.0 : Functions::flattenSingleValue($realNumber);
$imaginary = ($imaginary === null) ? 0.0 : Functions::flattenSingleValue($imaginary);
$suffix = ($suffix === null) ? 'i' : Functions::flattenSingleValue($suffix);
if (is_array($realNumber) || is_array($imaginary) || is_array($suffix)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $realNumber, $imaginary, $suffix);
}
$realNumber = $realNumber ?? 0.0;
$imaginary = $imaginary ?? 0.0;
$suffix = $suffix ?? 'i';
try {
$realNumber = EngineeringValidations::validateFloat($realNumber);
@ -54,14 +66,19 @@ class Complex
* Excel Function:
* IMAGINARY(complexNumber)
*
* @param string $complexNumber the complex number for which you want the imaginary
* @param array|string $complexNumber the complex number for which you want the imaginary
* coefficient
* Or can be an array of values
*
* @return float|string
* @return array|float|string (string if 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 IMAGINARY($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -80,13 +97,18 @@ class Complex
* Excel Function:
* IMREAL(complexNumber)
*
* @param string $complexNumber the complex number for which you want the real coefficient
* @param array|string $complexNumber the complex number for which you want the real coefficient
* Or can be an array of values
*
* @return float|string
* @return array|float|string (string if 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 IMREAL($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);

View File

@ -4,10 +4,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use Complex\Complex as ComplexObject;
use Complex\Exception as ComplexException;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class ComplexFunctions
{
use ArrayEnabled;
/**
* IMABS.
*
@ -16,13 +19,18 @@ class ComplexFunctions
* Excel Function:
* IMABS(complexNumber)
*
* @param string $complexNumber the complex number for which you want the absolute value
* @param array|string $complexNumber the complex number for which you want the absolute value
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMABS($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -42,13 +50,18 @@ class ComplexFunctions
* Excel Function:
* IMARGUMENT(complexNumber)
*
* @param string $complexNumber the complex number for which you want the argument theta
* @param array|string $complexNumber the complex number for which you want the argument theta
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMARGUMENT($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -71,13 +84,18 @@ class ComplexFunctions
* Excel Function:
* IMCONJUGATE(complexNumber)
*
* @param string $complexNumber the complex number for which you want the conjugate
* @param array|string $complexNumber the complex number for which you want the conjugate
* Or can be an array of values
*
* @return string
* @return array|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 IMCONJUGATE($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -96,13 +114,18 @@ class ComplexFunctions
* Excel Function:
* IMCOS(complexNumber)
*
* @param string $complexNumber the complex number for which you want the cosine
* @param array|string $complexNumber the complex number for which you want the cosine
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMCOS($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -121,13 +144,18 @@ class ComplexFunctions
* Excel Function:
* IMCOSH(complexNumber)
*
* @param string $complexNumber the complex number for which you want the hyperbolic cosine
* @param array|string $complexNumber the complex number for which you want the hyperbolic cosine
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMCOSH($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -146,13 +174,18 @@ class ComplexFunctions
* Excel Function:
* IMCOT(complexNumber)
*
* @param string $complexNumber the complex number for which you want the cotangent
* @param array|string $complexNumber the complex number for which you want the cotangent
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMCOT($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -171,13 +204,18 @@ class ComplexFunctions
* Excel Function:
* IMCSC(complexNumber)
*
* @param string $complexNumber the complex number for which you want the cosecant
* @param array|string $complexNumber the complex number for which you want the cosecant
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMCSC($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -196,13 +234,18 @@ class ComplexFunctions
* Excel Function:
* IMCSCH(complexNumber)
*
* @param string $complexNumber the complex number for which you want the hyperbolic cosecant
* @param array|string $complexNumber the complex number for which you want the hyperbolic cosecant
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMCSCH($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -221,13 +264,18 @@ class ComplexFunctions
* Excel Function:
* IMSIN(complexNumber)
*
* @param string $complexNumber the complex number for which you want the sine
* @param array|string $complexNumber the complex number for which you want the sine
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMSIN($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -246,13 +294,18 @@ class ComplexFunctions
* Excel Function:
* IMSINH(complexNumber)
*
* @param string $complexNumber the complex number for which you want the hyperbolic sine
* @param array|string $complexNumber the complex number for which you want the hyperbolic sine
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMSINH($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -271,13 +324,18 @@ class ComplexFunctions
* Excel Function:
* IMSEC(complexNumber)
*
* @param string $complexNumber the complex number for which you want the secant
* @param array|string $complexNumber the complex number for which you want the secant
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMSEC($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -296,13 +354,18 @@ class ComplexFunctions
* Excel Function:
* IMSECH(complexNumber)
*
* @param string $complexNumber the complex number for which you want the hyperbolic secant
* @param array|string $complexNumber the complex number for which you want the hyperbolic secant
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMSECH($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -321,13 +384,18 @@ class ComplexFunctions
* Excel Function:
* IMTAN(complexNumber)
*
* @param string $complexNumber the complex number for which you want the tangent
* @param array|string $complexNumber the complex number for which you want the tangent
* Or can be an array of values
*
* @return float|string
* @return array|float|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 IMTAN($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -346,13 +414,18 @@ class ComplexFunctions
* Excel Function:
* IMSQRT(complexNumber)
*
* @param string $complexNumber the complex number for which you want the square root
* @param array|string $complexNumber the complex number for which you want the square root
* Or can be an array of values
*
* @return string
* @return array|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 IMSQRT($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -376,13 +449,18 @@ class ComplexFunctions
* Excel Function:
* IMLN(complexNumber)
*
* @param string $complexNumber the complex number for which you want the natural logarithm
* @param array|string $complexNumber the complex number for which you want the natural logarithm
* Or can be an array of values
*
* @return string
* @return array|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 IMLN($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -405,13 +483,18 @@ class ComplexFunctions
* Excel Function:
* IMLOG10(complexNumber)
*
* @param string $complexNumber the complex number for which you want the common logarithm
* @param array|string $complexNumber the complex number for which you want the common logarithm
* Or can be an array of values
*
* @return string
* @return array|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 IMLOG10($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -434,13 +517,18 @@ class ComplexFunctions
* Excel Function:
* IMLOG2(complexNumber)
*
* @param string $complexNumber the complex number for which you want the base-2 logarithm
* @param array|string $complexNumber the complex number for which you want the base-2 logarithm
* Or can be an array of values
*
* @return string
* @return array|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 IMLOG2($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -463,13 +551,18 @@ class ComplexFunctions
* Excel Function:
* IMEXP(complexNumber)
*
* @param string $complexNumber the complex number for which you want the exponential
* @param array|string $complexNumber the complex number for which you want the exponential
* Or can be an array of values
*
* @return string
* @return array|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 IMEXP($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
if (is_array($complexNumber)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $complexNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -488,15 +581,20 @@ class ComplexFunctions
* Excel Function:
* IMPOWER(complexNumber,realNumber)
*
* @param string $complexNumber the complex number you want to raise to a power
* @param float $realNumber the power to which you want to raise the complex number
* @param array|string $complexNumber the complex number you want to raise to a power
* Or can be an array of values
* @param array|float|int|string $realNumber the power to which you want to raise the complex number
* Or can be an array of values
*
* @return string
* @return array|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 IMPOWER($complexNumber, $realNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$realNumber = Functions::flattenSingleValue($realNumber);
if (is_array($complexNumber) || is_array($realNumber)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $complexNumber, $realNumber);
}
try {
$complex = new ComplexObject($complexNumber);
@ -508,6 +606,6 @@ class ComplexFunctions
return Functions::VALUE();
}
return (string) $complex->pow($realNumber);
return (string) $complex->pow((float) $realNumber);
}
}

View File

@ -4,10 +4,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use Complex\Complex as ComplexObject;
use Complex\Exception as ComplexException;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class ComplexOperations
{
use ArrayEnabled;
/**
* IMDIV.
*
@ -16,15 +19,20 @@ class ComplexOperations
* Excel Function:
* IMDIV(complexDividend,complexDivisor)
*
* @param string $complexDividend the complex numerator or dividend
* @param string $complexDivisor the complex denominator or divisor
* @param array|string $complexDividend the complex numerator or dividend
* Or can be an array of values
* @param array|string $complexDivisor the complex denominator or divisor
* Or can be an array of values
*
* @return string
* @return array|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 IMDIV($complexDividend, $complexDivisor)
{
$complexDividend = Functions::flattenSingleValue($complexDividend);
$complexDivisor = Functions::flattenSingleValue($complexDivisor);
if (is_array($complexDividend) || is_array($complexDivisor)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $complexDividend, $complexDivisor);
}
try {
return (string) (new ComplexObject($complexDividend))->divideby(new ComplexObject($complexDivisor));
@ -41,15 +49,20 @@ class ComplexOperations
* Excel Function:
* IMSUB(complexNumber1,complexNumber2)
*
* @param string $complexNumber1 the complex number from which to subtract complexNumber2
* @param string $complexNumber2 the complex number to subtract from complexNumber1
* @param array|string $complexNumber1 the complex number from which to subtract complexNumber2
* Or can be an array of values
* @param array|string $complexNumber2 the complex number to subtract from complexNumber1
* Or can be an array of values
*
* @return string
* @return array|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 IMSUB($complexNumber1, $complexNumber2)
{
$complexNumber1 = Functions::flattenSingleValue($complexNumber1);
$complexNumber2 = Functions::flattenSingleValue($complexNumber2);
if (is_array($complexNumber1) || is_array($complexNumber2)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $complexNumber1, $complexNumber2);
}
try {
return (string) (new ComplexObject($complexNumber1))->subtract(new ComplexObject($complexNumber2));

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class ConvertBase
abstract class ConvertBase
{
use ArrayEnabled;
protected static function validateValue($value): string
{
if (is_bool($value)) {

View File

@ -15,17 +15,26 @@ class ConvertBinary extends ConvertBase
* Excel Function:
* BIN2DEC(x)
*
* @param string $value The binary number (as a string) that you want to convert. The number
* @param array|string $value The binary number (as a string) that you want to convert. The number
* cannot contain more than 10 characters (10 bits). The most significant
* bit of number is the sign bit. The remaining 9 bits are magnitude bits.
* Negative numbers are represented using two's-complement notation.
* If number is not a valid binary number, or if number contains more than
* 10 characters (10 bits), BIN2DEC returns the #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toDecimal($value): string
public static function toDecimal($value)
{
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateBinary($value);
} catch (Exception $e) {
return $e->getMessage();
@ -49,25 +58,35 @@ class ConvertBinary extends ConvertBase
* Excel Function:
* BIN2HEX(x[,places])
*
* @param string $value The binary number (as a string) that you want to convert. The number
* @param array|string $value The binary number (as a string) that you want to convert. The number
* cannot contain more than 10 characters (10 bits). The most significant
* bit of number is the sign bit. The remaining 9 bits are magnitude bits.
* Negative numbers are represented using two's-complement notation.
* If number is not a valid binary number, or if number contains more than
* 10 characters (10 bits), BIN2HEX returns the #NUM! error value.
* @param int $places The number of characters to use. If places is omitted, BIN2HEX uses the
* Or can be an array of values
* @param array|int $places The number of characters to use. If places is omitted, BIN2HEX uses the
* minimum number of characters necessary. Places is useful for padding the
* return value with leading 0s (zeros).
* If places is not an integer, it is truncated.
* If places is nonnumeric, BIN2HEX returns the #VALUE! error value.
* If places is negative, BIN2HEX returns the #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toHex($value, $places = null): string
public static function toHex($value, $places = null)
{
if (is_array($value) || is_array($places)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateBinary($value);
$places = self::validatePlaces(Functions::flattenSingleValue($places));
$places = self::validatePlaces($places);
} catch (Exception $e) {
return $e->getMessage();
}
@ -92,25 +111,35 @@ class ConvertBinary extends ConvertBase
* Excel Function:
* BIN2OCT(x[,places])
*
* @param string $value The binary number (as a string) that you want to convert. The number
* @param array|string $value The binary number (as a string) that you want to convert. The number
* cannot contain more than 10 characters (10 bits). The most significant
* bit of number is the sign bit. The remaining 9 bits are magnitude bits.
* Negative numbers are represented using two's-complement notation.
* If number is not a valid binary number, or if number contains more than
* 10 characters (10 bits), BIN2OCT returns the #NUM! error value.
* @param int $places The number of characters to use. If places is omitted, BIN2OCT uses the
* Or can be an array of values
* @param array|int $places The number of characters to use. If places is omitted, BIN2OCT uses the
* minimum number of characters necessary. Places is useful for padding the
* return value with leading 0s (zeros).
* If places is not an integer, it is truncated.
* If places is nonnumeric, BIN2OCT returns the #VALUE! error value.
* If places is negative, BIN2OCT returns the #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toOctal($value, $places = null): string
public static function toOctal($value, $places = null)
{
if (is_array($value) || is_array($places)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateBinary($value);
$places = self::validatePlaces(Functions::flattenSingleValue($places));
$places = self::validatePlaces($places);
} catch (Exception $e) {
return $e->getMessage();
}

View File

@ -22,7 +22,7 @@ class ConvertDecimal extends ConvertBase
* Excel Function:
* DEC2BIN(x[,places])
*
* @param string $value The decimal integer you want to convert. If number is negative,
* @param array|string $value The decimal integer you want to convert. If number is negative,
* valid place values are ignored and DEC2BIN returns a 10-character
* (10-bit) binary number in which the most significant bit is the sign
* bit. The remaining 9 bits are magnitude bits. Negative numbers are
@ -32,19 +32,29 @@ class ConvertDecimal extends ConvertBase
* If number is nonnumeric, DEC2BIN returns the #VALUE! error value.
* If DEC2BIN requires more than places characters, it returns the #NUM!
* error value.
* @param int $places The number of characters to use. If places is omitted, DEC2BIN uses
* Or can be an array of values
* @param array|int $places The number of characters to use. If places is omitted, DEC2BIN uses
* the minimum number of characters necessary. Places is useful for
* padding the return value with leading 0s (zeros).
* If places is not an integer, it is truncated.
* If places is nonnumeric, DEC2BIN returns the #VALUE! error value.
* If places is zero or negative, DEC2BIN returns the #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toBinary($value, $places = null): string
public static function toBinary($value, $places = null)
{
if (is_array($value) || is_array($places)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateDecimal($value);
$places = self::validatePlaces(Functions::flattenSingleValue($places));
$places = self::validatePlaces($places);
} catch (Exception $e) {
return $e->getMessage();
}
@ -69,7 +79,7 @@ class ConvertDecimal extends ConvertBase
* Excel Function:
* DEC2HEX(x[,places])
*
* @param string $value The decimal integer you want to convert. If number is negative,
* @param array|string $value The decimal integer you want to convert. If number is negative,
* places is ignored and DEC2HEX returns a 10-character (40-bit)
* hexadecimal number in which the most significant bit is the sign
* bit. The remaining 39 bits are magnitude bits. Negative numbers
@ -79,19 +89,29 @@ class ConvertDecimal extends ConvertBase
* If number is nonnumeric, DEC2HEX returns the #VALUE! error value.
* If DEC2HEX requires more than places characters, it returns the
* #NUM! error value.
* @param int $places The number of characters to use. If places is omitted, DEC2HEX uses
* Or can be an array of values
* @param array|int $places The number of characters to use. If places is omitted, DEC2HEX uses
* the minimum number of characters necessary. Places is useful for
* padding the return value with leading 0s (zeros).
* If places is not an integer, it is truncated.
* If places is nonnumeric, DEC2HEX returns the #VALUE! error value.
* If places is zero or negative, DEC2HEX returns the #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toHex($value, $places = null): string
public static function toHex($value, $places = null)
{
if (is_array($value) || is_array($places)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateDecimal($value);
$places = self::validatePlaces(Functions::flattenSingleValue($places));
$places = self::validatePlaces($places);
} catch (Exception $e) {
return $e->getMessage();
}
@ -135,7 +155,7 @@ class ConvertDecimal extends ConvertBase
* Excel Function:
* DEC2OCT(x[,places])
*
* @param string $value The decimal integer you want to convert. If number is negative,
* @param array|string $value The decimal integer you want to convert. If number is negative,
* places is ignored and DEC2OCT returns a 10-character (30-bit)
* octal number in which the most significant bit is the sign bit.
* The remaining 29 bits are magnitude bits. Negative numbers are
@ -145,19 +165,29 @@ class ConvertDecimal extends ConvertBase
* If number is nonnumeric, DEC2OCT returns the #VALUE! error value.
* If DEC2OCT requires more than places characters, it returns the
* #NUM! error value.
* @param int $places The number of characters to use. If places is omitted, DEC2OCT uses
* Or can be an array of values
* @param array|int $places The number of characters to use. If places is omitted, DEC2OCT uses
* the minimum number of characters necessary. Places is useful for
* padding the return value with leading 0s (zeros).
* If places is not an integer, it is truncated.
* If places is nonnumeric, DEC2OCT returns the #VALUE! error value.
* If places is zero or negative, DEC2OCT returns the #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toOctal($value, $places = null): string
public static function toOctal($value, $places = null)
{
if (is_array($value) || is_array($places)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateDecimal($value);
$places = self::validatePlaces(Functions::flattenSingleValue($places));
$places = self::validatePlaces($places);
} catch (Exception $e) {
return $e->getMessage();
}

View File

@ -15,7 +15,7 @@ class ConvertHex extends ConvertBase
* Excel Function:
* HEX2BIN(x[,places])
*
* @param string $value The hexadecimal number you want to convert.
* @param array|string $value The hexadecimal number you want to convert.
* Number cannot contain more than 10 characters.
* The most significant bit of number is the sign bit (40th bit from the right).
* The remaining 9 bits are magnitude bits.
@ -25,19 +25,29 @@ class ConvertHex extends ConvertBase
* and if number is positive, it cannot be greater than 1FF.
* If number is not a valid hexadecimal number, HEX2BIN returns the #NUM! error value.
* If HEX2BIN requires more than places characters, it returns the #NUM! error value.
* @param int $places The number of characters to use. If places is omitted,
* Or can be an array of values
* @param array|int $places The number of characters to use. If places is omitted,
* HEX2BIN uses the minimum number of characters necessary. Places
* is useful for padding the return value with leading 0s (zeros).
* If places is not an integer, it is truncated.
* If places is nonnumeric, HEX2BIN returns the #VALUE! error value.
* If places is negative, HEX2BIN returns the #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toBinary($value, $places = null): string
public static function toBinary($value, $places = null)
{
if (is_array($value) || is_array($places)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateHex($value);
$places = self::validatePlaces(Functions::flattenSingleValue($places));
$places = self::validatePlaces($places);
} catch (Exception $e) {
return $e->getMessage();
}
@ -55,18 +65,27 @@ class ConvertHex extends ConvertBase
* Excel Function:
* HEX2DEC(x)
*
* @param string $value The hexadecimal number you want to convert. This number cannot
* @param array|string $value The hexadecimal number you want to convert. This number cannot
* contain more than 10 characters (40 bits). The most significant
* bit of number is the sign bit. The remaining 39 bits are magnitude
* bits. Negative numbers are represented using two's-complement
* notation.
* If number is not a valid hexadecimal number, HEX2DEC returns the
* #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toDecimal($value): string
public static function toDecimal($value)
{
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateHex($value);
} catch (Exception $e) {
return $e->getMessage();
@ -99,7 +118,7 @@ class ConvertHex extends ConvertBase
* Excel Function:
* HEX2OCT(x[,places])
*
* @param string $value The hexadecimal number you want to convert. Number cannot
* @param array|string $value The hexadecimal number you want to convert. Number cannot
* contain more than 10 characters. The most significant bit of
* number is the sign bit. The remaining 39 bits are magnitude
* bits. Negative numbers are represented using two's-complement
@ -112,20 +131,30 @@ class ConvertHex extends ConvertBase
* the #NUM! error value.
* If HEX2OCT requires more than places characters, it returns
* the #NUM! error value.
* @param int $places The number of characters to use. If places is omitted, HEX2OCT
* Or can be an array of values
* @param array|int $places The number of characters to use. If places is omitted, HEX2OCT
* uses the minimum number of characters necessary. Places is
* useful for padding the return value with leading 0s (zeros).
* If places is not an integer, it is truncated.
* If places is nonnumeric, HEX2OCT returns the #VALUE! error
* value.
* If places is negative, HEX2OCT returns the #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toOctal($value, $places = null): string
public static function toOctal($value, $places = null)
{
if (is_array($value) || is_array($places)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateHex($value);
$places = self::validatePlaces(Functions::flattenSingleValue($places));
$places = self::validatePlaces($places);
} catch (Exception $e) {
return $e->getMessage();
}

View File

@ -15,7 +15,7 @@ class ConvertOctal extends ConvertBase
* Excel Function:
* OCT2BIN(x[,places])
*
* @param string $value The octal number you want to convert. Number may not
* @param array|string $value The octal number you want to convert. Number may not
* contain more than 10 characters. The most significant
* bit of number is the sign bit. The remaining 29 bits
* are magnitude bits. Negative numbers are represented
@ -28,7 +28,8 @@ class ConvertOctal extends ConvertBase
* the #NUM! error value.
* If OCT2BIN requires more than places characters, it
* returns the #NUM! error value.
* @param int $places The number of characters to use. If places is omitted,
* Or can be an array of values
* @param array|int $places The number of characters to use. If places is omitted,
* OCT2BIN uses the minimum number of characters necessary.
* Places is useful for padding the return value with
* leading 0s (zeros).
@ -37,13 +38,22 @@ class ConvertOctal extends ConvertBase
* error value.
* If places is negative, OCT2BIN returns the #NUM! error
* value.
* Or can be an array of values
*
* @return array|string Result, or 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 toBinary($value, $places = null): string
public static function toBinary($value, $places = null)
{
if (is_array($value) || is_array($places)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateOctal($value);
$places = self::validatePlaces(Functions::flattenSingleValue($places));
$places = self::validatePlaces($places);
} catch (Exception $e) {
return $e->getMessage();
}
@ -59,18 +69,27 @@ class ConvertOctal extends ConvertBase
* Excel Function:
* OCT2DEC(x)
*
* @param string $value The octal number you want to convert. Number may not contain
* @param array|string $value The octal number you want to convert. Number may not contain
* more than 10 octal characters (30 bits). The most significant
* bit of number is the sign bit. The remaining 29 bits are
* magnitude bits. Negative numbers are represented using
* two's-complement notation.
* If number is not a valid octal number, OCT2DEC returns the
* #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toDecimal($value): string
public static function toDecimal($value)
{
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateOctal($value);
} catch (Exception $e) {
return $e->getMessage();
@ -99,7 +118,7 @@ class ConvertOctal extends ConvertBase
* Excel Function:
* OCT2HEX(x[,places])
*
* @param string $value The octal number you want to convert. Number may not contain
* @param array|string $value The octal number you want to convert. Number may not contain
* more than 10 octal characters (30 bits). The most significant
* bit of number is the sign bit. The remaining 29 bits are
* magnitude bits. Negative numbers are represented using
@ -110,25 +129,35 @@ class ConvertOctal extends ConvertBase
* #NUM! error value.
* If OCT2HEX requires more than places characters, it returns
* the #NUM! error value.
* @param int $places The number of characters to use. If places is omitted, OCT2HEX
* Or can be an array of values
* @param array|int $places The number of characters to use. If places is omitted, OCT2HEX
* uses the minimum number of characters necessary. Places is useful
* for padding the return value with leading 0s (zeros).
* If places is not an integer, it is truncated.
* If places is nonnumeric, OCT2HEX returns the #VALUE! error value.
* If places is negative, OCT2HEX returns the #NUM! error value.
* Or can be an array of values
*
* @return array|string Result, or 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 toHex($value, $places = null): string
public static function toHex($value, $places = null)
{
if (is_array($value) || is_array($places)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
}
try {
$value = self::validateValue(Functions::flattenSingleValue($value));
$value = self::validateValue($value);
$value = self::validateOctal($value);
$places = self::validatePlaces(Functions::flattenSingleValue($places));
$places = self::validatePlaces($places);
} catch (Exception $e) {
return $e->getMessage();
}
$hexVal = strtoupper(dechex((int) self::toDecimal($value)));
$hexVal = (PHP_INT_SIZE === 4 && strlen($value) === 10 && $value[0] >= '4') ? "FF$hexVal" : $hexVal;
$hexVal = (PHP_INT_SIZE === 4 && strlen($value) === 10 && $value[0] >= '4') ? "FF{$hexVal}" : $hexVal;
return self::nbrConversionFormat($hexVal, $places);
}

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class ConvertUOM
{
use ArrayEnabled;
public const CATEGORY_WEIGHT_AND_MASS = 'Weight and Mass';
public const CATEGORY_DISTANCE = 'Distance';
public const CATEGORY_TIME = 'Time';
@ -518,17 +521,22 @@ class ConvertUOM
* Excel Function:
* CONVERT(value,fromUOM,toUOM)
*
* @param float|int $value the value in fromUOM to convert
* @param string $fromUOM the units for value
* @param string $toUOM the units for the result
* @param array|float|int|string $value the value in fromUOM to convert
* Or can be an array of values
* @param array|string $fromUOM the units for value
* Or can be an array of values
* @param array|string $toUOM the units for the result
* Or can be an array of values
*
* @return float|string
* @return array|float|string 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 CONVERT($value, $fromUOM, $toUOM)
{
$value = Functions::flattenSingleValue($value);
$fromUOM = Functions::flattenSingleValue($fromUOM);
$toUOM = Functions::flattenSingleValue($toUOM);
if (is_array($value) || is_array($fromUOM) || is_array($toUOM)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $fromUOM, $toUOM);
}
if (!is_numeric($value)) {
return Functions::VALUE();
@ -545,6 +553,7 @@ class ConvertUOM
return Functions::NA();
}
// @var float $value
$value *= $fromMultiplier;
if (($fromUOM === $toUOM) && ($fromMultiplier === $toMultiplier)) {

View File

@ -2,10 +2,13 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Erf
{
use ArrayEnabled;
private static $twoSqrtPi = 1.128379167095512574;
/**
@ -22,15 +25,20 @@ class Erf
* ERF(lower[,upper])
*
* @param mixed $lower Lower bound float for integrating ERF
* Or can be an array of values
* @param mixed $upper Upper bound float for integrating ERF.
* If omitted, ERF integrates between zero and lower_limit
* Or can be an array of values
*
* @return float|string
* @return array|float|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 ERF($lower, $upper = null)
{
$lower = Functions::flattenSingleValue($lower);
$upper = Functions::flattenSingleValue($upper);
if (is_array($lower) || is_array($upper)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $lower, $upper);
}
if (is_numeric($lower)) {
if ($upper === null) {
@ -53,12 +61,17 @@ class Erf
* ERF.PRECISE(limit)
*
* @param mixed $limit Float bound for integrating ERF, other bound is zero
* Or can be an array of values
*
* @return float|string
* @return array|float|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 ERFPRECISE($limit)
{
$limit = Functions::flattenSingleValue($limit);
if (is_array($limit)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $limit);
}
return self::ERF($limit);
}

View File

@ -2,10 +2,13 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class ErfC
{
use ArrayEnabled;
/**
* ERFC.
*
@ -20,12 +23,17 @@ class ErfC
* ERFC(x)
*
* @param mixed $value The float lower bound for integrating ERFC
* Or can be an array of values
*
* @return float|string
* @return array|float|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 ERFC($value)
{
$value = Functions::flattenSingleValue($value);
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
if (is_numeric($value)) {
return self::erfcValue($value);
@ -45,7 +53,7 @@ class ErfC
return 1 - Erf::erfValue($value);
}
if ($value < 0) {
return 2 - self::ERFC(-$value);
return 2 - self::erfcValue(-$value);
}
$a = $n = 1;
$b = $c = $value;

View File

@ -587,10 +587,10 @@ class Financial
* @see Financial\Dollar::decimal()
* Use the decimal() method in the Financial\Dollar class instead
*
* @param float $fractional_dollar Fractional Dollar
* @param int $fraction Fraction
* @param array|float $fractional_dollar Fractional Dollar
* @param array|int $fraction Fraction
*
* @return float|string
* @return array|float|string
*/
public static function DOLLARDE($fractional_dollar = null, $fraction = 0)
{
@ -612,10 +612,10 @@ class Financial
* @see Financial\Dollar::fractional()
* Use the fractional() method in the Financial\Dollar class instead
*
* @param float $decimal_dollar Decimal Dollar
* @param int $fraction Fraction
* @param array|float $decimal_dollar Decimal Dollar
* @param array|int $fraction Fraction
*
* @return float|string
* @return array|float|string
*/
public static function DOLLARFR($decimal_dollar = null, $fraction = 0)
{

View File

@ -168,7 +168,7 @@ class Amortization
if (
($basis == FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL) &&
($yearFrac < 1) && (DateTimeExcel\Helpers::isLeapYear($purchasedYear))
($yearFrac < 1) && (Functions::scalar(DateTimeExcel\Helpers::isLeapYear($purchasedYear)))
) {
$yearFrac *= 365 / 366;
}

View File

@ -12,6 +12,8 @@ class NonPeriodic
const FINANCIAL_PRECISION = 1.0e-08;
const DEFAULT_GUESS = 0.1;
/**
* XIRR.
*
@ -25,11 +27,11 @@ class NonPeriodic
* @param mixed[] $dates A series of payment dates
* The first payment date indicates the beginning of the schedule of payments
* All other dates must be later than this date, but they may occur in any order
* @param float $guess An optional guess at the expected answer
* @param mixed $guess An optional guess at the expected answer
*
* @return float|string
*/
public static function rate($values, $dates, $guess = 0.1)
public static function rate($values, $dates, $guess = self::DEFAULT_GUESS)
{
$rslt = self::xirrPart1($values, $dates);
if ($rslt !== '') {
@ -37,9 +39,13 @@ class NonPeriodic
}
// create an initial range, with a root somewhere between 0 and guess
$guess = Functions::flattenSingleValue($guess);
$guess = Functions::flattenSingleValue($guess) ?? self::DEFAULT_GUESS;
if (!is_numeric($guess)) {
return Functions::VALUE();
}
$guess = ($guess + 0.0) ?: self::DEFAULT_GUESS;
$x1 = 0.0;
$x2 = $guess ?: 0.1;
$x2 = $guess + 0.0;
$f1 = self::xnpvOrdered($x1, $values, $dates, false);
$f2 = self::xnpvOrdered($x2, $values, $dates, false);
$found = false;
@ -54,9 +60,11 @@ class NonPeriodic
break;
} elseif (abs($f1) < abs($f2)) {
$f1 = self::xnpvOrdered($x1 += 1.6 * ($x1 - $x2), $values, $dates, false);
$x1 += 1.6 * ($x1 - $x2);
$f1 = self::xnpvOrdered($x1, $values, $dates, false);
} else {
$f2 = self::xnpvOrdered($x2 += 1.6 * ($x2 - $x1), $values, $dates, false);
$x2 += 1.6 * ($x2 - $x1);
$f2 = self::xnpvOrdered($x2, $values, $dates, false);
}
}
if (!$found) {
@ -104,11 +112,13 @@ class NonPeriodic
*/
private static function xirrPart1(&$values, &$dates): string
{
if (!is_array($values) && !is_array($dates)) {
return Functions::NA();
}
$values = Functions::flattenArray($values);
$dates = Functions::flattenArray($dates);
$valuesIsArray = count($values) > 1;
$datesIsArray = count($dates) > 1;
if (!$valuesIsArray && !$datesIsArray) {
return Functions::NA();
}
if (count($values) != count($dates)) {
return Functions::NAN();
}
@ -219,7 +229,11 @@ class NonPeriodic
if (!is_numeric($dif)) {
return $dif;
}
$xnpv += $values[$i] / (1 + $rate) ** ($dif / 365);
if ($rate <= -1.0) {
$xnpv += -abs($values[$i]) / (-1 - $rate) ** ($dif / 365);
} else {
$xnpv += $values[$i] / (1 + $rate) ** ($dif / 365);
}
}
return is_finite($xnpv) ? $xnpv : Functions::VALUE();

View File

@ -64,7 +64,7 @@ class Coupons
return $e->getMessage();
}
$daysPerYear = Helpers::daysPerYear(DateTimeExcel\DateParts::year($settlement), $basis);
$daysPerYear = Helpers::daysPerYear(Functions::scalar(DateTimeExcel\DateParts::year($settlement)), $basis);
if (is_string($daysPerYear)) {
return Functions::VALUE();
}
@ -134,7 +134,7 @@ class Coupons
case FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL:
// Actual/actual
if ($frequency == FinancialConstants::FREQUENCY_ANNUAL) {
$daysPerYear = Helpers::daysPerYear(DateTimeExcel\DateParts::year($settlement), $basis);
$daysPerYear = (int) Helpers::daysPerYear(Functions::scalar(DateTimeExcel\DateParts::year($settlement)), $basis);
return $daysPerYear / $frequency;
}

View File

@ -2,23 +2,33 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\TextData\Format;
class Dollar
{
use ArrayEnabled;
/**
* DOLLAR.
*
* This function converts a number to text using currency format, with the decimals rounded to the specified place.
* The format used is $#,##0.00_);($#,##0.00)..
*
* @param mixed $number The value to format
* @param mixed $number The value to format, or can be an array of numbers
* Or can be an array of values
* @param mixed $precision The number of digits to display to the right of the decimal point (as an integer).
* If precision is negative, number is rounded to the left of the decimal point.
* If you omit precision, it is assumed to be 2
* Or can be an array of precision values
*
* @return array|string
* If an array of values is passed for either of the arguments, then the returned result
* will also be an array with matching dimensions
*/
public static function format($number, $precision = 2): string
public static function format($number, $precision = 2)
{
return Format::DOLLAR($number, $precision);
}
@ -34,25 +44,37 @@ class Dollar
* DOLLARDE(fractional_dollar,fraction)
*
* @param mixed $fractionalDollar Fractional Dollar
* Or can be an array of values
* @param mixed $fraction Fraction
* Or can be an array of values
*
* @return float|string
* @return array|float|string
*/
public static function decimal($fractionalDollar = null, $fraction = 0)
{
$fractionalDollar = Functions::flattenSingleValue($fractionalDollar);
$fraction = (int) Functions::flattenSingleValue($fraction);
if (is_array($fractionalDollar) || is_array($fraction)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $fractionalDollar, $fraction);
}
// Validate parameters
if ($fractionalDollar === null || $fraction < 0) {
try {
$fractionalDollar = FinancialValidations::validateFloat(
Functions::flattenSingleValue($fractionalDollar) ?? 0.0
);
$fraction = FinancialValidations::validateInt(Functions::flattenSingleValue($fraction));
} catch (Exception $e) {
return $e->getMessage();
}
// Additional parameter validations
if ($fraction < 0) {
return Functions::NAN();
}
if ($fraction == 0) {
return Functions::DIV0();
}
$dollars = floor($fractionalDollar);
$cents = fmod($fractionalDollar, 1);
$dollars = ($fractionalDollar < 0) ? ceil($fractionalDollar) : floor($fractionalDollar);
$cents = fmod($fractionalDollar, 1.0);
$cents /= $fraction;
$cents *= 10 ** ceil(log10($fraction));
@ -70,24 +92,36 @@ class Dollar
* DOLLARFR(decimal_dollar,fraction)
*
* @param mixed $decimalDollar Decimal Dollar
* Or can be an array of values
* @param mixed $fraction Fraction
* Or can be an array of values
*
* @return float|string
* @return array|float|string
*/
public static function fractional($decimalDollar = null, $fraction = 0)
{
$decimalDollar = Functions::flattenSingleValue($decimalDollar);
$fraction = (int) Functions::flattenSingleValue($fraction);
if (is_array($decimalDollar) || is_array($fraction)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $decimalDollar, $fraction);
}
// Validate parameters
if ($decimalDollar === null || $fraction < 0) {
try {
$decimalDollar = FinancialValidations::validateFloat(
Functions::flattenSingleValue($decimalDollar) ?? 0.0
);
$fraction = FinancialValidations::validateInt(Functions::flattenSingleValue($fraction));
} catch (Exception $e) {
return $e->getMessage();
}
// Additional parameter validations
if ($fraction < 0) {
return Functions::NAN();
}
if ($fraction == 0) {
return Functions::DIV0();
}
$dollars = floor($decimalDollar);
$dollars = ($decimalDollar < 0.0) ? ceil($decimalDollar) : floor($decimalDollar);
$cents = fmod($decimalDollar, 1);
$cents *= $fraction;
$cents *= 10 ** (-ceil(log10($fraction)));

View File

@ -78,12 +78,12 @@ class AccruedInterest
return $e->getMessage();
}
$daysBetweenIssueAndSettlement = YearFrac::fraction($issue, $settlement, $basis);
$daysBetweenIssueAndSettlement = Functions::scalar(YearFrac::fraction($issue, $settlement, $basis));
if (!is_numeric($daysBetweenIssueAndSettlement)) {
// return date error
return $daysBetweenIssueAndSettlement;
}
$daysBetweenFirstInterestAndSettlement = YearFrac::fraction($firstInterest, $settlement, $basis);
$daysBetweenFirstInterestAndSettlement = Functions::scalar(YearFrac::fraction($firstInterest, $settlement, $basis));
if (!is_numeric($daysBetweenFirstInterestAndSettlement)) {
// return date error
return $daysBetweenFirstInterestAndSettlement;
@ -140,7 +140,7 @@ class AccruedInterest
return $e->getMessage();
}
$daysBetweenIssueAndSettlement = YearFrac::fraction($issue, $settlement, $basis);
$daysBetweenIssueAndSettlement = Functions::scalar(YearFrac::fraction($issue, $settlement, $basis));
if (!is_numeric($daysBetweenIssueAndSettlement)) {
// return date error
return $daysBetweenIssueAndSettlement;

View File

@ -134,7 +134,7 @@ class Price
return $e->getMessage();
}
$daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis);
$daysBetweenSettlementAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis));
if (!is_numeric($daysBetweenSettlementAndMaturity)) {
// return date error
return $daysBetweenSettlementAndMaturity;
@ -194,23 +194,23 @@ class Price
return $e->getMessage();
}
$daysPerYear = Helpers::daysPerYear(DateTimeExcel\DateParts::year($settlement), $basis);
$daysPerYear = Functions::scalar(Helpers::daysPerYear(DateTimeExcel\DateParts::year($settlement), $basis));
if (!is_numeric($daysPerYear)) {
return $daysPerYear;
}
$daysBetweenIssueAndSettlement = DateTimeExcel\YearFrac::fraction($issue, $settlement, $basis);
$daysBetweenIssueAndSettlement = Functions::scalar(DateTimeExcel\YearFrac::fraction($issue, $settlement, $basis));
if (!is_numeric($daysBetweenIssueAndSettlement)) {
// return date error
return $daysBetweenIssueAndSettlement;
}
$daysBetweenIssueAndSettlement *= $daysPerYear;
$daysBetweenIssueAndMaturity = DateTimeExcel\YearFrac::fraction($issue, $maturity, $basis);
$daysBetweenIssueAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($issue, $maturity, $basis));
if (!is_numeric($daysBetweenIssueAndMaturity)) {
// return date error
return $daysBetweenIssueAndMaturity;
}
$daysBetweenIssueAndMaturity *= $daysPerYear;
$daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis);
$daysBetweenSettlementAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis));
if (!is_numeric($daysBetweenSettlementAndMaturity)) {
// return date error
return $daysBetweenSettlementAndMaturity;

View File

@ -63,7 +63,7 @@ class Rates
return Functions::NAN();
}
$daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis);
$daysBetweenSettlementAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis));
if (!is_numeric($daysBetweenSettlementAndMaturity)) {
// return date error
return $daysBetweenSettlementAndMaturity;
@ -126,7 +126,7 @@ class Rates
return Functions::NAN();
}
$daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis);
$daysBetweenSettlementAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis));
if (!is_numeric($daysBetweenSettlementAndMaturity)) {
// return date error
return $daysBetweenSettlementAndMaturity;

View File

@ -61,7 +61,7 @@ class Yields
if (!is_numeric($daysPerYear)) {
return $daysPerYear;
}
$daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis);
$daysBetweenSettlementAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis));
if (!is_numeric($daysBetweenSettlementAndMaturity)) {
// return date error
return $daysBetweenSettlementAndMaturity;
@ -126,19 +126,19 @@ class Yields
if (!is_numeric($daysPerYear)) {
return $daysPerYear;
}
$daysBetweenIssueAndSettlement = DateTimeExcel\YearFrac::fraction($issue, $settlement, $basis);
$daysBetweenIssueAndSettlement = Functions::scalar(DateTimeExcel\YearFrac::fraction($issue, $settlement, $basis));
if (!is_numeric($daysBetweenIssueAndSettlement)) {
// return date error
return $daysBetweenIssueAndSettlement;
}
$daysBetweenIssueAndSettlement *= $daysPerYear;
$daysBetweenIssueAndMaturity = DateTimeExcel\YearFrac::fraction($issue, $maturity, $basis);
$daysBetweenIssueAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($issue, $maturity, $basis));
if (!is_numeric($daysBetweenIssueAndMaturity)) {
// return date error
return $daysBetweenIssueAndMaturity;
}
$daysBetweenIssueAndMaturity *= $daysPerYear;
$daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis);
$daysBetweenSettlementAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis));
if (!is_numeric($daysBetweenSettlementAndMaturity)) {
// return date error
return $daysBetweenSettlementAndMaturity;

View File

@ -43,7 +43,7 @@ class TreasuryBill
$daysBetweenSettlementAndMaturity = $maturity - $settlement;
$daysPerYear = Helpers::daysPerYear(
DateTimeExcel\DateParts::year($maturity),
Functions::scalar(DateTimeExcel\DateParts::year($maturity)),
FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL
);
@ -88,7 +88,7 @@ class TreasuryBill
$daysBetweenSettlementAndMaturity = $maturity - $settlement;
$daysPerYear = Helpers::daysPerYear(
DateTimeExcel\DateParts::year($maturity),
Functions::scalar(DateTimeExcel\DateParts::year($maturity)),
FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL
);
@ -134,7 +134,7 @@ class TreasuryBill
$daysBetweenSettlementAndMaturity = $maturity - $settlement;
$daysPerYear = Helpers::daysPerYear(
DateTimeExcel\DateParts::year($maturity),
Functions::scalar(DateTimeExcel\DateParts::year($maturity)),
FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL
);

View File

@ -608,6 +608,24 @@ class Functions
return $arrayValues;
}
/**
* @param mixed $value
*
* @return null|mixed
*/
public static function scalar($value)
{
if (!is_array($value)) {
return $value;
}
do {
$value = array_pop($value);
} while (is_array($value));
return $value;
}
/**
* Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing.
*

View File

@ -163,7 +163,7 @@ class Logical
*
* @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE
*
* @return bool|string the boolean inverse of the argument
* @return array|bool|string the boolean inverse of the argument
*/
public static function NOT($logical = false)
{

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Conditional
{
use ArrayEnabled;
/**
* STATEMENT_IF.
*
@ -34,7 +37,9 @@ class Conditional
*
* @param mixed $condition Condition to evaluate
* @param mixed $returnIfTrue Value to return when condition is true
* Note that this can be an array value
* @param mixed $returnIfFalse Optional value to return when condition is false
* Note that this can be an array value
*
* @return mixed The value of returnIfTrue or returnIfFalse determined by condition
*/
@ -45,8 +50,8 @@ class Conditional
}
$condition = ($condition === null) ? true : (bool) Functions::flattenSingleValue($condition);
$returnIfTrue = ($returnIfTrue === null) ? 0 : Functions::flattenSingleValue($returnIfTrue);
$returnIfFalse = ($returnIfFalse === null) ? false : Functions::flattenSingleValue($returnIfFalse);
$returnIfTrue = $returnIfTrue ?? 0;
$returnIfFalse = $returnIfFalse ?? false;
return ($condition) ? $returnIfTrue : $returnIfFalse;
}
@ -67,9 +72,11 @@ class Conditional
* result1, result2, ... result_n
* A list of results. The SWITCH function returns the corresponding result when a value
* matches expression.
* Note that these can be array values to be returned
* default
* Optional. It is the default to return if expression does not match any of the values
* (value1, value2, ... value_n).
* Note that this can be an array value to be returned
*
* @param mixed $arguments Statement arguments
*
@ -113,14 +120,21 @@ class Conditional
* =IFERROR(testValue,errorpart)
*
* @param mixed $testValue Value to check, is also the value returned when no error
* Or can be an array of values
* @param mixed $errorpart Value to return when testValue is an error condition
* Note that this can be an array value to be returned
*
* @return mixed The value of errorpart or testValue determined by error condition
* If an array of values is passed as the $testValue argument, then the returned result will also be
* an array with the same dimensions
*/
public static function IFERROR($testValue = '', $errorpart = '')
{
$testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue);
$errorpart = ($errorpart === null) ? '' : Functions::flattenSingleValue($errorpart);
if (is_array($testValue)) {
return self::evaluateArrayArgumentsSubset([self::class, __FUNCTION__], 1, $testValue, $errorpart);
}
$errorpart = $errorpart ?? '';
return self::statementIf(Functions::isError($testValue), $errorpart, $testValue);
}
@ -132,14 +146,21 @@ class Conditional
* =IFNA(testValue,napart)
*
* @param mixed $testValue Value to check, is also the value returned when not an NA
* Or can be an array of values
* @param mixed $napart Value to return when testValue is an NA condition
* Note that this can be an array value to be returned
*
* @return mixed The value of errorpart or testValue determined by error condition
* If an array of values is passed as the $testValue argument, then the returned result will also be
* an array with the same dimensions
*/
public static function IFNA($testValue = '', $napart = '')
{
$testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue);
$napart = ($napart === null) ? '' : Functions::flattenSingleValue($napart);
if (is_array($testValue)) {
return self::evaluateArrayArgumentsSubset([self::class, __FUNCTION__], 1, $testValue, $napart);
}
$napart = $napart ?? '';
return self::statementIf(Functions::isNa($testValue), $napart, $testValue);
}
@ -156,6 +177,7 @@ class Conditional
* Value returned if corresponding testValue (nth) was true
*
* @param mixed ...$arguments Statement arguments
* Note that this can be an array value to be returned
*
* @return mixed|string The value of returnIfTrue_n, if testValue_n was true. #N/A if none of testValues was true
*/
@ -170,7 +192,7 @@ class Conditional
$falseValueException = new Exception();
for ($i = 0; $i < $argumentCount; $i += 2) {
$testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]);
$returnIfTrue = ($arguments[$i + 1] === null) ? '' : Functions::flattenSingleValue($arguments[$i + 1]);
$returnIfTrue = ($arguments[$i + 1] === null) ? '' : $arguments[$i + 1];
$result = self::statementIf($testValue, $returnIfTrue, $falseValueException);
if ($result !== $falseValueException) {

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Operations
{
use ArrayEnabled;
/**
* LOGICAL_AND.
*
@ -146,12 +149,17 @@ class Operations
* holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
*
* @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE
* Or can be an array of values
*
* @return bool|string the boolean inverse of the argument
* @return array|bool|string the boolean inverse of the argument
* If an array of values is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function NOT($logical = false)
{
$logical = Functions::flattenSingleValue($logical);
if (is_array($logical)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $logical);
}
if (is_string($logical)) {
$logical = mb_strtoupper($logical, 'UTF-8');

View File

@ -20,9 +20,9 @@ class MathTrig
* @See MathTrig\Arabic::evaluate()
* Use the evaluate method in the MathTrig\Arabic class instead
*
* @param string $roman
* @param array|string $roman
*
* @return int|string the arabic numberal contrived from the roman numeral
* @return array|int|string the arabic numberal contrived from the roman numeral
*/
public static function ARABIC($roman)
{
@ -50,10 +50,10 @@ class MathTrig
* @See MathTrig\Trig\Tangent::atan2()
* Use the atan2 method in the MathTrig\Trig\Tangent class instead
*
* @param float $xCoordinate the x-coordinate of the point
* @param float $yCoordinate the y-coordinate of the point
* @param array|float $xCoordinate the x-coordinate of the point
* @param array|float $yCoordinate the y-coordinate of the point
*
* @return float|string the inverse tangent of the specified x- and y-coordinates, or a string containing an error
* @return array|float|string the inverse tangent of the specified x- and y-coordinates, or a string containing an error
*/
public static function ATAN2($xCoordinate = null, $yCoordinate = null)
{
@ -77,7 +77,7 @@ class MathTrig
* @param float $radix
* @param int $minLength
*
* @return string the text representation with the given radix (base)
* @return array|string the text representation with the given radix (base)
*/
public static function BASE($number, $radix, $minLength = null)
{
@ -100,7 +100,7 @@ class MathTrig
* @param float $number the number you want to round
* @param float $significance the multiple to which you want to round
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
*
* @see MathTrig\Ceiling::ceiling()
* Use the ceiling() method in the MathTrig\Ceiling class instead
@ -124,10 +124,10 @@ class MathTrig
* @see MathTrig\Combinations::withoutRepetition()
* Use the withoutRepetition() method in the MathTrig\Combinations class instead
*
* @param int $numObjs Number of different objects
* @param int $numInSet Number of objects in each combination
* @param array|int $numObjs Number of different objects
* @param array|int $numInSet Number of objects in each combination
*
* @return float|int|string Number of combinations, or a string containing an error
* @return array|float|int|string Number of combinations, or a string containing an error
*/
public static function COMBIN($numObjs, $numInSet)
{
@ -151,9 +151,9 @@ class MathTrig
* @see MathTrig\Round::even()
* Use the even() method in the MathTrig\Round class instead
*
* @param float $number Number to round
* @param array|float $number Number to round
*
* @return float|int|string Rounded Number, or a string containing an error
* @return array|float|int|string Rounded Number, or a string containing an error
*/
public static function EVEN($number)
{
@ -184,9 +184,9 @@ class MathTrig
*
* @Deprecated 1.18.0
*
* @param float $factVal Factorial Value
* @param array|float $factVal Factorial Value
*
* @return float|int|string Factorial, or a string containing an error
* @return array|float|int|string Factorial, or a string containing an error
*
*@see MathTrig\Factorial::fact()
* Use the fact() method in the MathTrig\Factorial class instead
@ -206,9 +206,9 @@ class MathTrig
*
* @Deprecated 1.18.0
*
* @param float $factVal Factorial Value
* @param array|float $factVal Factorial Value
*
* @return float|int|string Double Factorial, or a string containing an error
* @return array|float|int|string Double Factorial, or a string containing an error
*
*@see MathTrig\Factorial::factDouble()
* Use the factDouble() method in the MathTrig\Factorial class instead
@ -231,7 +231,7 @@ class MathTrig
* @param float $number Number to round
* @param float $significance Significance
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
*
*@see MathTrig\Floor::floor()
* Use the floor() method in the MathTrig\Floor class instead
@ -255,7 +255,7 @@ class MathTrig
* @param float $significance Significance
* @param int $mode direction to round negative numbers
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
*
*@see MathTrig\Floor::math()
* Use the math() method in the MathTrig\Floor class instead
@ -278,7 +278,7 @@ class MathTrig
* @param float $number Number to round
* @param float $significance Significance
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
*
*@see MathTrig\Floor::precise()
* Use the precise() method in the MathTrig\Floor class instead
@ -301,9 +301,9 @@ class MathTrig
* @see MathTrig\IntClass::evaluate()
* Use the evaluate() method in the MathTrig\IntClass class instead
*
* @param float $number Number to cast to an integer
* @param array|float $number Number to cast to an integer
*
* @return int|string Integer value, or a string containing an error
* @return array|int|string Integer value, or a string containing an error
*/
public static function INT($number)
{
@ -375,7 +375,7 @@ class MathTrig
* @param float $number The positive real number for which you want the logarithm
* @param float $base The base of the logarithm. If base is omitted, it is assumed to be 10.
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function logBase($number, $base = 10)
{
@ -455,7 +455,7 @@ class MathTrig
* @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)
{
@ -470,9 +470,9 @@ class MathTrig
* @Deprecated 1.17.0
*
* @param float $number Number to round
* @param int $multiple Multiple to which you want to round $number
* @param array|int $multiple Multiple to which you want to round $number
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
*
*@see MathTrig\Round::multiple()
* Use the multiple() method in the MathTrig\Mround class instead
@ -511,9 +511,9 @@ class MathTrig
* @See MathTrig\Round::odd()
* Use the odd method in the MathTrig\Round class instead
*
* @param float $number Number to round
* @param array|float $number Number to round
*
* @return float|int|string Rounded Number, or a string containing an error
* @return array|float|int|string Rounded Number, or a string containing an error
*/
public static function ODD($number)
{
@ -533,7 +533,7 @@ class MathTrig
* @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 @@ class MathTrig
* @param mixed $numerator
* @param mixed $denominator
*
* @return int|string
* @return array|int|string
*/
public static function QUOTIENT($numerator, $denominator)
{
@ -597,7 +597,7 @@ class MathTrig
* @param int $min Minimal value
* @param int $max Maximal value
*
* @return float|int|string Random number
* @return array|float|int|string Random number
*/
public static function RAND($min = 0, $max = 0)
{
@ -617,7 +617,7 @@ class MathTrig
* @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)
{
@ -634,10 +634,10 @@ class MathTrig
* @See MathTrig\Round::up()
* Use the up() method in the MathTrig\Round class instead
*
* @param float $number Number to round
* @param int $digits Number of digits to which you want to round $number
* @param array|float $number Number to round
* @param array|int $digits Number of digits to which you want to round $number
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
*/
public static function ROUNDUP($number, $digits)
{
@ -654,10 +654,10 @@ class MathTrig
* @See MathTrig\Round::down()
* Use the down() method in the MathTrig\Round class instead
*
* @param float $number Number to round
* @param int $digits Number of digits to which you want to round $number
* @param array|float $number Number to round
* @param array|int $digits Number of digits to which you want to round $number
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
*/
public static function ROUNDDOWN($number, $digits)
{
@ -679,7 +679,7 @@ class MathTrig
* @param mixed $m Step
* @param mixed[] $args An array of coefficients for the Data Series
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function SERIESSUM($x, $n, $m, ...$args)
{
@ -697,9 +697,9 @@ class MathTrig
* @See MathTrig\Sign::evaluate()
* Use the evaluate method in the MathTrig\Sign class instead
*
* @param float $number Number to round
* @param array|float $number Number to round
*
* @return int|string sign value, or a string containing an error
* @return array|int|string sign value, or a string containing an error
*/
public static function SIGN($number)
{
@ -729,9 +729,9 @@ class MathTrig
* @See MathTrig\Sqrt::sqrt()
* Use the pi method in the MathTrig\Sqrt class instead
*
* @param float $number Number
* @param array|float $number Number
*
* @return float|string Square Root of Number * Pi, or a string containing an error
* @return array|float|string Square Root of Number * Pi, or a string containing an error
*/
public static function SQRTPI($number)
{
@ -941,7 +941,7 @@ class MathTrig
* @param float $value
* @param int $digits
*
* @return float|string Truncated value, or a string containing an error
* @return array|float|string Truncated value, or a string containing an error
*/
public static function TRUNC($value = 0, $digits = 0)
{
@ -958,9 +958,9 @@ class MathTrig
* @See MathTrig\Trig\Secant::sec()
* Use the sec method in the MathTrig\Trig\Secant class instead
*
* @param float $angle Number
* @param array|float $angle Number
*
* @return float|string The secant of the angle
* @return array|float|string The secant of the angle
*/
public static function SEC($angle)
{
@ -977,9 +977,9 @@ class MathTrig
* @See MathTrig\Trig\Secant::sech()
* Use the sech method in the MathTrig\Trig\Secant class instead
*
* @param float $angle Number
* @param array|float $angle Number
*
* @return float|string The hyperbolic secant of the angle
* @return array|float|string The hyperbolic secant of the angle
*/
public static function SECH($angle)
{
@ -996,9 +996,9 @@ class MathTrig
* @See MathTrig\Trig\Cosecant::csc()
* Use the csc method in the MathTrig\Trig\Cosecant class instead
*
* @param float $angle Number
* @param array|float $angle Number
*
* @return float|string The cosecant of the angle
* @return array|float|string The cosecant of the angle
*/
public static function CSC($angle)
{
@ -1015,9 +1015,9 @@ class MathTrig
* @See MathTrig\Trig\Cosecant::csch()
* Use the csch method in the MathTrig\Trig\Cosecant class instead
*
* @param float $angle Number
* @param array|float $angle Number
*
* @return float|string The hyperbolic cosecant of the angle
* @return array|float|string The hyperbolic cosecant of the angle
*/
public static function CSCH($angle)
{
@ -1034,9 +1034,9 @@ class MathTrig
* @See MathTrig\Trig\Cotangent::cot()
* Use the cot method in the MathTrig\Trig\Cotangent class instead
*
* @param float $angle Number
* @param array|float $angle Number
*
* @return float|string The cotangent of the angle
* @return array|float|string The cotangent of the angle
*/
public static function COT($angle)
{
@ -1053,9 +1053,9 @@ class MathTrig
* @See MathTrig\Trig\Cotangent::coth()
* Use the coth method in the MathTrig\Trig\Cotangent class instead
*
* @param float $angle Number
* @param array|float $angle Number
*
* @return float|string The hyperbolic cotangent of the angle
* @return array|float|string The hyperbolic cotangent of the angle
*/
public static function COTH($angle)
{
@ -1072,9 +1072,9 @@ class MathTrig
* @See MathTrig\Trig\Cotangent::acot()
* Use the acot method in the MathTrig\Trig\Cotangent class instead
*
* @param float $number Number
* @param array|float $number Number
*
* @return float|string The arccotangent of the number
* @return array|float|string The arccotangent of the number
*/
public static function ACOT($number)
{
@ -1108,9 +1108,9 @@ class MathTrig
* @See MathTrig\Trig\Cotangent::acoth()
* Use the acoth method in the MathTrig\Trig\Cotangent class instead
*
* @param float $number Number
* @param array|float $number Number
*
* @return float|string The hyperbolic arccotangent of the number
* @return array|float|string The hyperbolic arccotangent of the number
*/
public static function ACOTH($number)
{
@ -1127,10 +1127,10 @@ class MathTrig
* @See MathTrig\Round::round()
* Use the round() method in the MathTrig\Round class instead
*
* @param mixed $number Should be numeric
* @param mixed $precision Should be int
* @param array|mixed $number Should be numeric
* @param array|mixed $precision Should be int
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinROUND($number, $precision)
{
@ -1147,9 +1147,9 @@ class MathTrig
* @See MathTrig\Absolute::evaluate()
* Use the evaluate method in the MathTrig\Absolute class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|int|string Rounded number
* @return array|float|int|string Rounded number
*/
public static function builtinABS($number)
{
@ -1166,9 +1166,9 @@ class MathTrig
*
* Returns the result of builtin function acos after validating args.
*
* @param mixed $number Should be numeric
* @param array|float $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinACOS($number)
{
@ -1185,9 +1185,9 @@ class MathTrig
* @See MathTrig\Trig\Cosine::acosh()
* Use the acosh method in the MathTrig\Trig\Cosine class instead
*
* @param mixed $number Should be numeric
* @param array|float $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinACOSH($number)
{
@ -1204,9 +1204,9 @@ class MathTrig
* @See MathTrig\Trig\Sine::asin()
* Use the asin method in the MathTrig\Trig\Sine class instead
*
* @param mixed $number Should be numeric
* @param array|float $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinASIN($number)
{
@ -1223,9 +1223,9 @@ class MathTrig
* @See MathTrig\Trig\Sine::asinh()
* Use the asinh method in the MathTrig\Trig\Sine class instead
*
* @param mixed $number Should be numeric
* @param array|float $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinASINH($number)
{
@ -1242,9 +1242,9 @@ class MathTrig
* @See MathTrig\Trig\Tangent::atan()
* Use the atan method in the MathTrig\Trig\Tangent class instead
*
* @param mixed $number Should be numeric
* @param array|float $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinATAN($number)
{
@ -1261,9 +1261,9 @@ class MathTrig
* @See MathTrig\Trig\Tangent::atanh()
* Use the atanh method in the MathTrig\Trig\Tangent class instead
*
* @param mixed $number Should be numeric
* @param array|float $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinATANH($number)
{
@ -1280,9 +1280,9 @@ class MathTrig
* @See MathTrig\Trig\Cosine::cos()
* Use the cos method in the MathTrig\Trig\Cosine class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinCOS($number)
{
@ -1299,9 +1299,9 @@ class MathTrig
* @See MathTrig\Trig\Cosine::cosh()
* Use the cosh method in the MathTrig\Trig\Cosine class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinCOSH($number)
{
@ -1318,9 +1318,9 @@ class MathTrig
* @See MathTrig\Angle::toDegrees()
* Use the toDegrees method in the MathTrig\Angle class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinDEGREES($number)
{
@ -1337,9 +1337,9 @@ class MathTrig
* @See MathTrig\Exp::evaluate()
* Use the evaluate method in the MathTrig\Exp class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinEXP($number)
{
@ -1358,7 +1358,7 @@ class MathTrig
*
* @param mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinLN($number)
{
@ -1377,7 +1377,7 @@ class MathTrig
*
* @param mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinLOG10($number)
{
@ -1394,9 +1394,9 @@ class MathTrig
* @See MathTrig\Angle::toRadians()
* Use the toRadians method in the MathTrig\Angle class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinRADIANS($number)
{
@ -1413,9 +1413,9 @@ class MathTrig
* @See MathTrig\Trig\Sine::evaluate()
* Use the sin method in the MathTrig\Trig\Sine class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|string sine
* @return array|float|string sine
*/
public static function builtinSIN($number)
{
@ -1432,9 +1432,9 @@ class MathTrig
* @See MathTrig\Trig\Sine::sinh()
* Use the sinh method in the MathTrig\Trig\Sine class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinSINH($number)
{
@ -1451,9 +1451,9 @@ class MathTrig
* @See MathTrig\Sqrt::sqrt()
* Use the sqrt method in the MathTrig\Sqrt class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinSQRT($number)
{
@ -1470,9 +1470,9 @@ class MathTrig
* @See MathTrig\Trig\Tangent::tan()
* Use the tan method in the MathTrig\Trig\Tangent class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinTAN($number)
{
@ -1489,9 +1489,9 @@ class MathTrig
* @See MathTrig\Trig\Tangent::tanh()
* Use the tanh method in the MathTrig\Trig\Tangent class instead
*
* @param mixed $number Should be numeric
* @param array|mixed $number Should be numeric
*
* @return float|string Rounded number
* @return array|float|string Rounded number
*/
public static function builtinTANH($number)
{

View File

@ -2,21 +2,30 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class Absolute
{
use ArrayEnabled;
/**
* ABS.
*
* Returns the result of builtin function abs after validating args.
*
* @param mixed $number Should be numeric
* @param mixed $number Should be numeric, or can be an array of numbers
*
* @return float|int|string Rounded number
* @return array|float|int|string rounded number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function evaluate($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {

View File

@ -2,21 +2,30 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class Angle
{
use ArrayEnabled;
/**
* DEGREES.
*
* Returns the result of builtin function rad2deg after validating args.
*
* @param mixed $number Should be numeric
* @param mixed $number Should be numeric, or can be an array of numbers
*
* @return float|string Rounded number
* @return array|float|string Rounded number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function toDegrees($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {
@ -31,12 +40,18 @@ class Angle
*
* Returns the result of builtin function deg2rad after validating args.
*
* @param mixed $number Should be numeric
* @param mixed $number Should be numeric, or can be an array of numbers
*
* @return float|string Rounded number
* @return array|float|string Rounded number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function toRadians($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {

View File

@ -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 Arabic
{
use ArrayEnabled;
private const ROMAN_LOOKUP = [
'M' => 1000,
'D' => 500,
@ -70,14 +73,20 @@ class Arabic
* Excel Function:
* ARABIC(text)
*
* @param string $roman
* @param mixed $roman Should be a string, or can be an array of strings
*
* @return int|string the arabic numberal contrived from the roman numeral
* @return array|int|string the arabic numberal contrived from the roman numeral
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function evaluate($roman)
{
if (is_array($roman)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $roman);
}
// An empty string should return 0
$roman = substr(trim(strtoupper((string) Functions::flattenSingleValue($roman))), 0, 255);
$roman = substr(trim(strtoupper((string) $roman)), 0, 255);
if ($roman === '') {
return 0;
}

View File

@ -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 Base
{
use ArrayEnabled;
/**
* BASE.
*
@ -16,21 +19,37 @@ class Base
* BASE(Number, Radix [Min_length])
*
* @param mixed $number expect float
* Or can be an array of values
* @param mixed $radix expect float
* Or can be an array of values
* @param mixed $minLength expect int or null
* Or can be an array of values
*
* @return string the text representation with the given radix (base)
* @return array|string the text representation with the given radix (base)
* 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($number, $radix, $minLength = null)
{
if (is_array($number) || is_array($radix) || is_array($minLength)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $radix, $minLength);
}
try {
$number = (float) floor(Helpers::validateNumericNullBool($number));
$radix = (int) Helpers::validateNumericNullBool($radix);
} catch (Exception $e) {
return $e->getMessage();
}
$minLength = Functions::flattenSingleValue($minLength);
return self::calculate($number, $radix, $minLength);
}
/**
* @param mixed $minLength
*/
private static function calculate(float $number, int $radix, $minLength): string
{
if ($minLength === null || is_numeric($minLength)) {
if ($number < 0 || $number >= 2 ** 53 || $radix < 2 || $radix > 36) {
return Functions::NAN(); // Numeric range constraints

View File

@ -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 Ceiling
{
use ArrayEnabled;
/**
* CEILING.
*
@ -18,13 +21,21 @@ class Ceiling
* Excel Function:
* CEILING(number[,significance])
*
* @param float $number the number you want the ceiling
* @param float $significance the multiple to which you want to round
* @param array|float $number the number you want the ceiling
* Or can be an array of values
* @param array|float $significance the multiple to which you want to round
* Or can be an array of values
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, 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 ceiling($number, $significance = null)
{
if (is_array($number) || is_array($significance)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $significance);
}
if ($significance === null) {
self::floorCheck1Arg();
}
@ -48,13 +59,22 @@ class Ceiling
* CEILING.MATH(number[,significance[,mode]])
*
* @param mixed $number Number to round
* Or can be an array of values
* @param mixed $significance Significance
* @param int $mode direction to round negative numbers
* Or can be an array of values
* @param array|int $mode direction to round negative numbers
* Or can be an array of values
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, 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 math($number, $significance = null, $mode = 0)
{
if (is_array($number) || is_array($significance) || is_array($mode)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $significance, $mode);
}
try {
$number = Helpers::validateNumericNullBool($number);
$significance = Helpers::validateNumericNullSubstitution($significance, ($number < 0) ? -1 : 1);
@ -82,12 +102,20 @@ class Ceiling
* CEILING.PRECISE(number[,significance])
*
* @param mixed $number the number you want to round
* @param float $significance the multiple to which you want to round
* Or can be an array of values
* @param array|float $significance the multiple to which you want to round
* Or can be an array of values
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, 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 precise($number, $significance = 1)
{
if (is_array($number) || is_array($significance)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $significance);
}
try {
$number = Helpers::validateNumericNullBool($number);
$significance = Helpers::validateNumericNullSubstitution($significance, null);

View File

@ -2,10 +2,13 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class Combinations
{
use ArrayEnabled;
/**
* COMBIN.
*
@ -15,13 +18,19 @@ class Combinations
* Excel Function:
* COMBIN(numObjs,numInSet)
*
* @param mixed $numObjs Number of different objects
* @param mixed $numInSet Number of objects in each combination
* @param mixed $numObjs Number of different objects, or can be an array of numbers
* @param mixed $numInSet Number of objects in each combination, or can be an array of numbers
*
* @return float|int|string Number of combinations, or a string containing an error
* @return array|float|int|string Number of combinations, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function withoutRepetition($numObjs, $numInSet)
{
if (is_array($numObjs) || is_array($numInSet)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $numObjs, $numInSet);
}
try {
$numObjs = Helpers::validateNumericNullSubstitution($numObjs, null);
$numInSet = Helpers::validateNumericNullSubstitution($numInSet, null);
@ -35,21 +44,27 @@ class Combinations
}
/**
* COMBIN.
* COMBINA.
*
* Returns the number of combinations for a given number of items. Use COMBIN to
* determine the total possible number of groups for a given number of items.
*
* Excel Function:
* COMBIN(numObjs,numInSet)
* COMBINA(numObjs,numInSet)
*
* @param mixed $numObjs Number of different objects
* @param mixed $numInSet Number of objects in each combination
* @param mixed $numObjs Number of different objects, or can be an array of numbers
* @param mixed $numInSet Number of objects in each combination, or can be an array of numbers
*
* @return float|int|string Number of combinations, or a string containing an error
* @return array|float|int|string Number of combinations, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function withRepetition($numObjs, $numInSet)
{
if (is_array($numObjs) || is_array($numInSet)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $numObjs, $numInSet);
}
try {
$numObjs = Helpers::validateNumericNullSubstitution($numObjs, null);
$numInSet = Helpers::validateNumericNullSubstitution($numInSet, null);
@ -69,6 +84,8 @@ class Combinations
return $e->getMessage();
}
return round(Factorial::fact($numObjs + $numInSet - 1) / Factorial::fact($numObjs - 1)) / Factorial::fact($numInSet);
return round(
Factorial::fact($numObjs + $numInSet - 1) / Factorial::fact($numObjs - 1)
) / Factorial::fact($numInSet);
}
}

View File

@ -2,21 +2,30 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class Exp
{
use ArrayEnabled;
/**
* EXP.
*
* Returns the result of builtin function exp after validating args.
*
* @param mixed $number Should be numeric
* @param mixed $number Should be numeric, or can be an array of numbers
*
* @return float|string Rounded number
* @return array|float|string Rounded number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function evaluate($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {

View File

@ -2,12 +2,15 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
class Factorial
{
use ArrayEnabled;
/**
* FACT.
*
@ -17,12 +20,18 @@ class Factorial
* Excel Function:
* FACT(factVal)
*
* @param float $factVal Factorial Value
* @param array|float $factVal Factorial Value, or can be an array of numbers
*
* @return float|int|string Factorial, or a string containing an error
* @return array|float|int|string Factorial, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function fact($factVal)
{
if (is_array($factVal)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $factVal);
}
try {
$factVal = Helpers::validateNumericNullBool($factVal);
Helpers::validateNotNegative($factVal);
@ -53,12 +62,18 @@ class Factorial
* Excel Function:
* FACTDOUBLE(factVal)
*
* @param float $factVal Factorial Value
* @param array|float $factVal Factorial Value, or can be an array of numbers
*
* @return float|int|string Double Factorial, or a string containing an error
* @return array|float|int|string Double Factorial, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function factDouble($factVal)
{
if (is_array($factVal)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $factVal);
}
try {
$factVal = Helpers::validateNumericNullSubstitution($factVal, 0);
Helpers::validateNotNegative($factVal);

View File

@ -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 Floor
{
use ArrayEnabled;
private static function floorCheck1Arg(): void
{
$compatibility = Functions::getCompatibilityMode();
@ -24,12 +27,20 @@ class Floor
* FLOOR(number[,significance])
*
* @param mixed $number Expect float. Number to round
* Or can be an array of values
* @param mixed $significance Expect float. Significance
* Or can be an array of values
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, 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 floor($number, $significance = null)
{
if (is_array($number) || is_array($significance)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $significance);
}
if ($significance === null) {
self::floorCheck1Arg();
}
@ -53,13 +64,22 @@ class Floor
* FLOOR.MATH(number[,significance[,mode]])
*
* @param mixed $number Number to round
* Or can be an array of values
* @param mixed $significance Significance
* Or can be an array of values
* @param mixed $mode direction to round negative numbers
* Or can be an array of values
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, 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 math($number, $significance = null, $mode = 0)
{
if (is_array($number) || is_array($significance) || is_array($mode)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $significance, $mode);
}
try {
$number = Helpers::validateNumericNullBool($number);
$significance = Helpers::validateNumericNullSubstitution($significance, ($number < 0) ? -1 : 1);
@ -79,13 +99,21 @@ class Floor
* Excel Function:
* FLOOR.PRECISE(number[,significance])
*
* @param float $number Number to round
* @param float $significance Significance
* @param array|float $number Number to round
* Or can be an array of values
* @param array|float $significance Significance
* Or can be an array of values
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, 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 precise($number, $significance = 1)
{
if (is_array($number) || is_array($significance)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $significance);
}
try {
$number = Helpers::validateNumericNullBool($number);
$significance = Helpers::validateNumericNullSubstitution($significance, null);

View File

@ -2,10 +2,13 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class IntClass
{
use ArrayEnabled;
/**
* INT.
*
@ -14,12 +17,18 @@ class IntClass
* Excel Function:
* INT(number)
*
* @param float $number Number to cast to an integer
* @param array|float $number Number to cast to an integer, or can be an array of numbers
*
* @return int|string Integer value, or a string containing an error
* @return array|string Integer value, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function evaluate($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {

View File

@ -2,10 +2,13 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class Logarithms
{
use ArrayEnabled;
/**
* LOG_BASE.
*
@ -15,12 +18,20 @@ class Logarithms
* LOG(number[,base])
*
* @param mixed $number The positive real number for which you want the logarithm
* Or can be an array of values
* @param mixed $base The base of the logarithm. If base is omitted, it is assumed to be 10.
* Or can be an array of values
*
* @return float|string The result, or a string containing an error
* @return array|float|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 withBase($number, $base = 10)
{
if (is_array($number) || is_array($base)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $base);
}
try {
$number = Helpers::validateNumericNullBool($number);
Helpers::validatePositive($number);
@ -39,11 +50,18 @@ class Logarithms
* Returns the result of builtin function log after validating args.
*
* @param mixed $number Should be numeric
* Or can be an array of values
*
* @return float|string Rounded number
* @return array|float|string Rounded number
* 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 base10($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
Helpers::validatePositive($number);
@ -60,11 +78,18 @@ class Logarithms
* Returns the result of builtin function log after validating args.
*
* @param mixed $number Should be numeric
* Or can be an array of values
*
* @return float|string Rounded number
* @return array|float|string Rounded number
* 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 natural($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
Helpers::validatePositive($number);

View File

@ -12,7 +12,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class MatrixFunctions
{
/**
* Convert parameter to matrix.
* Convert parameter to Matrix.
*
* @param mixed $matrixValues A matrix of values
*/
@ -42,6 +42,47 @@ class MatrixFunctions
return new Matrix($matrixData);
}
/**
* SEQUENCE.
*
* Generates a list of sequential numbers in an array.
*
* Excel Function:
* SEQUENCE(rows,[columns],[start],[step])
*
* @param mixed $rows the number of rows to return, defaults to 1
* @param mixed $columns the number of columns to return, defaults to 1
* @param mixed $start the first number in the sequence, defaults to 1
* @param mixed $step the amount to increment each subsequent value in the array, defaults to 1
*
* @return array|string The resulting array, or a string containing an error
*/
public static function sequence($rows = 1, $columns = 1, $start = 1, $step = 1)
{
try {
$rows = (int) Helpers::validateNumericNullSubstitution($rows, 1);
Helpers::validatePositive($rows);
$columns = (int) Helpers::validateNumericNullSubstitution($columns, 1);
Helpers::validatePositive($columns);
$start = Helpers::validateNumericNullSubstitution($start, 1);
$step = Helpers::validateNumericNullSubstitution($step, 1);
} catch (Exception $e) {
return $e->getMessage();
}
if ($step === 0) {
return array_chunk(
array_fill(0, $rows * $columns, $start),
max($columns, 1)
);
}
return array_chunk(
range($start, $start + (($rows * $columns - 1) * $step), $step),
max($columns, 1)
);
}
/**
* MDETERM.
*

View File

@ -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 @@ class Operations
*
* 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 @@ class Operations
* 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);

View File

@ -2,10 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Random
{
use ArrayEnabled;
/**
* RAND.
*
@ -20,12 +24,20 @@ class Random
* RANDBETWEEN.
*
* @param mixed $min Minimal value
* Or can be an array of values
* @param mixed $max Maximal value
* Or can be an array of values
*
* @return float|int|string Random number
* @return array|float|int|string Random number
* 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 randBetween($min, $max)
{
if (is_array($min) || is_array($max)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $min, $max);
}
try {
$min = (int) Helpers::validateNumericNullBool($min);
$max = (int) Helpers::validateNumericNullBool($max);
@ -36,4 +48,52 @@ class Random
return mt_rand($min, $max);
}
/**
* RANDARRAY.
*
* Generates a list of sequential numbers in an array.
*
* Excel Function:
* RANDARRAY([rows],[columns],[start],[step])
*
* @param mixed $rows the number of rows to return, defaults to 1
* @param mixed $columns the number of columns to return, defaults to 1
* @param mixed $min the minimum number to be returned, defaults to 0
* @param mixed $max the maximum number to be returned, defaults to 1
* @param bool $wholeNumber the type of numbers to return:
* False - Decimal numbers to 15 decimal places. (default)
* True - Whole (integer) numbers
*
* @return array|string The resulting array, or a string containing an error
*/
public static function randArray($rows = 1, $columns = 1, $min = 0, $max = 1, $wholeNumber = false)
{
try {
$rows = (int) Helpers::validateNumericNullSubstitution($rows, 1);
Helpers::validatePositive($rows);
$columns = (int) Helpers::validateNumericNullSubstitution($columns, 1);
Helpers::validatePositive($columns);
$min = Helpers::validateNumericNullSubstitution($min, 1);
$max = Helpers::validateNumericNullSubstitution($max, 1);
if ($max <= $min) {
return Functions::VALUE();
}
} catch (Exception $e) {
return $e->getMessage();
}
return array_chunk(
array_map(
function () use ($min, $max, $wholeNumber) {
return $wholeNumber
? mt_rand((int) $min, (int) $max)
: (mt_rand() / mt_getrandmax()) * ($max - $min) + $min;
},
array_fill(0, $rows * $columns, $min)
),
max($columns, 1)
);
}
}

View File

@ -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 @@ class Roman
* 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)) {

View File

@ -2,23 +2,32 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Round
{
use ArrayEnabled;
/**
* ROUND.
*
* Returns the result of builtin function round after validating args.
*
* @param mixed $number Should be numeric
* @param mixed $precision Should be int
* @param mixed $number Should be numeric, or can be an array of numbers
* @param mixed $precision Should be int, or can be an array of numbers
*
* @return float|string Rounded number
* @return array|float|string Rounded number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function round($number, $precision)
{
if (is_array($number) || is_array($precision)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $precision);
}
try {
$number = Helpers::validateNumericNullBool($number);
$precision = Helpers::validateNumericNullBool($precision);
@ -34,13 +43,19 @@ class Round
*
* Rounds a number up to a specified number of decimal places
*
* @param float $number Number to round
* @param int $digits Number of digits to which you want to round $number
* @param array|float $number Number to round, or can be an array of numbers
* @param array|int $digits Number of digits to which you want to round $number, or can be an array of numbers
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function up($number, $digits)
{
if (is_array($number) || is_array($digits)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $digits);
}
try {
$number = Helpers::validateNumericNullBool($number);
$digits = (int) Helpers::validateNumericNullSubstitution($digits, null);
@ -64,13 +79,19 @@ class Round
*
* Rounds a number down to a specified number of decimal places
*
* @param float $number Number to round
* @param int $digits Number of digits to which you want to round $number
* @param array|float $number Number to round, or can be an array of numbers
* @param array|int $digits Number of digits to which you want to round $number, or can be an array of numbers
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function down($number, $digits)
{
if (is_array($number) || is_array($digits)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $digits);
}
try {
$number = Helpers::validateNumericNullBool($number);
$digits = (int) Helpers::validateNumericNullSubstitution($digits, null);
@ -94,13 +115,19 @@ class Round
*
* Rounds a number to the nearest multiple of a specified value
*
* @param mixed $number Expect float. Number to round.
* @param mixed $multiple Expect int. Multiple to which you want to round.
* @param mixed $number Expect float. Number to round, or can be an array of numbers
* @param mixed $multiple Expect int. Multiple to which you want to round, or can be an array of numbers.
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function multiple($number, $multiple)
{
if (is_array($number) || is_array($multiple)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $multiple);
}
try {
$number = Helpers::validateNumericNullSubstitution($number, 0);
$multiple = Helpers::validateNumericNullSubstitution($multiple, null);
@ -132,12 +159,18 @@ class Round
* Excel Function:
* EVEN(number)
*
* @param float $number Number to round
* @param array|float $number Number to round, or can be an array of numbers
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function even($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {
@ -152,12 +185,18 @@ class Round
*
* Returns number rounded up to the nearest odd integer.
*
* @param float $number Number to round
* @param array|float $number Number to round, or can be an array of numbers
*
* @return float|string Rounded Number, or a string containing an error
* @return array|float|string Rounded Number, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function odd($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {

View File

@ -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 SeriesSum
{
use ArrayEnabled;
/**
* SERIESSUM.
*
@ -17,10 +20,14 @@ class SeriesSum
* @param mixed $m Step
* @param mixed[] $args An array of coefficients for the Data Series
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function evaluate($x, $n, $m, ...$args)
{
if (is_array($x) || is_array($n) || is_array($m)) {
return self::evaluateArrayArgumentsSubset([self::class, __FUNCTION__], 3, $x, $n, $m, ...$args);
}
try {
$x = Helpers::validateNumericNullSubstitution($x, 0);
$n = Helpers::validateNumericNullSubstitution($n, 0);

View File

@ -2,22 +2,31 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class Sign
{
use ArrayEnabled;
/**
* SIGN.
*
* Determines the sign of a number. Returns 1 if the number is positive, zero (0)
* if the number is 0, and -1 if the number is negative.
*
* @param float $number Number to round
* @param array|float $number Number to round, or can be an array of numbers
*
* @return int|string sign value, or a string containing an error
* @return array|int|string sign value, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function evaluate($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {

View File

@ -2,21 +2,30 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class Sqrt
{
use ArrayEnabled;
/**
* SQRT.
*
* Returns the result of builtin function sqrt after validating args.
*
* @param mixed $number Should be numeric
* @param mixed $number Should be numeric, or can be an array of numbers
*
* @return float|string square roor
* @return array|float|string square root
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function sqrt($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {
@ -31,12 +40,18 @@ class Sqrt
*
* Returns the square root of (number * pi).
*
* @param float $number Number
* @param array|float $number Number, or can be an array of numbers
*
* @return float|string Square Root of Number * Pi, or a string containing an error
* @return array|float|string Square Root of Number * Pi, or a string containing an error
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function pi($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullSubstitution($number, 0);
Helpers::validateNotNegative($number);

View File

@ -39,7 +39,10 @@ class Subtotal
if ($cellReference->getWorksheet()->cellExists($column . $row)) {
//take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula
$isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula();
$cellFormula = !preg_match('/^=.*\b(SUBTOTAL|AGGREGATE)\s*\(/i', $cellReference->getWorksheet()->getCell($column . $row)->getValue());
$cellFormula = !preg_match(
'/^=.*\b(SUBTOTAL|AGGREGATE)\s*\(/i',
$cellReference->getWorksheet()->getCell($column . $row)->getValue() ?? ''
);
$retVal = !$isFormula || $cellFormula;
}
@ -52,17 +55,17 @@ class Subtotal
/** @var callable[] */
private const CALL_FUNCTIONS = [
1 => [Statistical\Averages::class, 'average'],
[Statistical\Counts::class, 'COUNT'], // 2
[Statistical\Counts::class, 'COUNTA'], // 3
[Statistical\Maximum::class, 'max'], // 4
[Statistical\Minimum::class, 'min'], // 5
[Operations::class, 'product'], // 6
[Statistical\StandardDeviations::class, 'STDEV'], // 7
[Statistical\StandardDeviations::class, 'STDEVP'], // 8
[Sum::class, 'sumIgnoringStrings'], // 9
[Statistical\Variances::class, 'VAR'], // 10
[Statistical\Variances::class, 'VARP'], // 11
1 => [Statistical\Averages::class, 'average'], // 1 and 101
[Statistical\Counts::class, 'COUNT'], // 2 and 102
[Statistical\Counts::class, 'COUNTA'], // 3 and 103
[Statistical\Maximum::class, 'max'], // 4 and 104
[Statistical\Minimum::class, 'min'], // 5 and 105
[Operations::class, 'product'], // 6 and 106
[Statistical\StandardDeviations::class, 'STDEV'], // 7 and 107
[Statistical\StandardDeviations::class, 'STDEVP'], // 8 and 108
[Sum::class, 'sumIgnoringStrings'], // 9 and 109
[Statistical\Variances::class, 'VAR'], // 10 and 110
[Statistical\Variances::class, 'VARP'], // 111 and 111
];
/**

View File

@ -2,22 +2,31 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Helpers;
class Cosecant
{
use ArrayEnabled;
/**
* CSC.
*
* Returns the cosecant of an angle.
*
* @param float $angle Number
* @param array|float $angle Number, or can be an array of numbers
*
* @return float|string The cosecant of the angle
* @return array|float|string The cosecant of the angle
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function csc($angle)
{
if (is_array($angle)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle);
}
try {
$angle = Helpers::validateNumericNullBool($angle);
} catch (Exception $e) {
@ -32,12 +41,18 @@ class Cosecant
*
* Returns the hyperbolic cosecant of an angle.
*
* @param float $angle Number
* @param array|float $angle Number, or can be an array of numbers
*
* @return float|string The hyperbolic cosecant of the angle
* @return array|float|string The hyperbolic cosecant of the angle
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function csch($angle)
{
if (is_array($angle)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle);
}
try {
$angle = Helpers::validateNumericNullBool($angle);
} catch (Exception $e) {

View File

@ -2,22 +2,31 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Helpers;
class Cosine
{
use ArrayEnabled;
/**
* COS.
*
* Returns the result of builtin function cos after validating args.
*
* @param mixed $number Should be numeric
* @param mixed $number Should be numeric, or can be an array of numbers
*
* @return float|string cosine
* @return array|float|string cosine
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function cos($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {
@ -32,12 +41,18 @@ class Cosine
*
* Returns the result of builtin function cosh after validating args.
*
* @param mixed $number Should be numeric
* @param mixed $number Should be numeric, or can be an array of numbers
*
* @return float|string hyperbolic cosine
* @return array|float|string hyperbolic cosine
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function cosh($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {
@ -52,12 +67,18 @@ class Cosine
*
* Returns the arccosine of a number.
*
* @param float $number Number
* @param array|float $number Number, or can be an array of numbers
*
* @return float|string The arccosine of the number
* @return array|float|string The arccosine of the number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function acos($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {
@ -72,12 +93,18 @@ class Cosine
*
* Returns the arc inverse hyperbolic cosine of a number.
*
* @param float $number Number
* @param array|float $number Number, or can be an array of numbers
*
* @return float|string The inverse hyperbolic cosine of the number, or an error string
* @return array|float|string The inverse hyperbolic cosine of the number, or an error string
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function acosh($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {

View File

@ -2,22 +2,31 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Helpers;
class Cotangent
{
use ArrayEnabled;
/**
* COT.
*
* Returns the cotangent of an angle.
*
* @param float $angle Number
* @param array|float $angle Number, or can be an array of numbers
*
* @return float|string The cotangent of the angle
* @return array|float|string The cotangent of the angle
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function cot($angle)
{
if (is_array($angle)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle);
}
try {
$angle = Helpers::validateNumericNullBool($angle);
} catch (Exception $e) {
@ -32,12 +41,18 @@ class Cotangent
*
* Returns the hyperbolic cotangent of an angle.
*
* @param float $angle Number
* @param array|float $angle Number, or can be an array of numbers
*
* @return float|string The hyperbolic cotangent of the angle
* @return array|float|string The hyperbolic cotangent of the angle
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function coth($angle)
{
if (is_array($angle)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle);
}
try {
$angle = Helpers::validateNumericNullBool($angle);
} catch (Exception $e) {
@ -52,12 +67,18 @@ class Cotangent
*
* Returns the arccotangent of a number.
*
* @param float $number Number
* @param array|float $number Number, or can be an array of numbers
*
* @return float|string The arccotangent of the number
* @return array|float|string The arccotangent of the number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function acot($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {
@ -72,12 +93,18 @@ class Cotangent
*
* Returns the hyperbolic arccotangent of a number.
*
* @param float $number Number
* @param array|float $number Number, or can be an array of numbers
*
* @return float|string The hyperbolic arccotangent of the number
* @return array|float|string The hyperbolic arccotangent of the number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function acoth($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {

View File

@ -2,22 +2,31 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Helpers;
class Secant
{
use ArrayEnabled;
/**
* SEC.
*
* Returns the secant of an angle.
*
* @param float $angle Number
* @param array|float $angle Number, or can be an array of numbers
*
* @return float|string The secant of the angle
* @return array|float|string The secant of the angle
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function sec($angle)
{
if (is_array($angle)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle);
}
try {
$angle = Helpers::validateNumericNullBool($angle);
} catch (Exception $e) {
@ -32,12 +41,18 @@ class Secant
*
* Returns the hyperbolic secant of an angle.
*
* @param float $angle Number
* @param array|float $angle Number, or can be an array of numbers
*
* @return float|string The hyperbolic secant of the angle
* @return array|float|string The hyperbolic secant of the angle
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function sech($angle)
{
if (is_array($angle)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle);
}
try {
$angle = Helpers::validateNumericNullBool($angle);
} catch (Exception $e) {

View File

@ -2,22 +2,31 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Helpers;
class Sine
{
use ArrayEnabled;
/**
* SIN.
*
* Returns the result of builtin function sin after validating args.
*
* @param mixed $angle Should be numeric
* @param mixed $angle Should be numeric, or can be an array of numbers
*
* @return float|string sine
* @return array|float|string sine
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function sin($angle)
{
if (is_array($angle)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle);
}
try {
$angle = Helpers::validateNumericNullBool($angle);
} catch (Exception $e) {
@ -32,12 +41,18 @@ class Sine
*
* Returns the result of builtin function sinh after validating args.
*
* @param mixed $angle Should be numeric
* @param mixed $angle Should be numeric, or can be an array of numbers
*
* @return float|string hyperbolic sine
* @return array|float|string hyperbolic sine
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function sinh($angle)
{
if (is_array($angle)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle);
}
try {
$angle = Helpers::validateNumericNullBool($angle);
} catch (Exception $e) {
@ -52,12 +67,18 @@ class Sine
*
* Returns the arcsine of a number.
*
* @param float $number Number
* @param array|float $number Number, or can be an array of numbers
*
* @return float|string The arcsine of the number
* @return array|float|string The arcsine of the number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function asin($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {
@ -72,12 +93,18 @@ class Sine
*
* Returns the inverse hyperbolic sine of a number.
*
* @param float $number Number
* @param array|float $number Number, or can be an array of numbers
*
* @return float|string The inverse hyperbolic sine of the number
* @return array|float|string The inverse hyperbolic sine of the number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function asinh($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {

View File

@ -2,23 +2,32 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Helpers;
class Tangent
{
use ArrayEnabled;
/**
* TAN.
*
* Returns the result of builtin function tan after validating args.
*
* @param mixed $angle Should be numeric
* @param mixed $angle Should be numeric, or can be an array of numbers
*
* @return float|string tangent
* @return array|float|string tangent
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function tan($angle)
{
if (is_array($angle)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle);
}
try {
$angle = Helpers::validateNumericNullBool($angle);
} catch (Exception $e) {
@ -33,12 +42,18 @@ class Tangent
*
* Returns the result of builtin function sinh after validating args.
*
* @param mixed $angle Should be numeric
* @param mixed $angle Should be numeric, or can be an array of numbers
*
* @return float|string hyperbolic tangent
* @return array|float|string hyperbolic tangent
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function tanh($angle)
{
if (is_array($angle)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $angle);
}
try {
$angle = Helpers::validateNumericNullBool($angle);
} catch (Exception $e) {
@ -53,12 +68,18 @@ class Tangent
*
* Returns the arctangent of a number.
*
* @param float $number Number
* @param array|float $number Number, or can be an array of numbers
*
* @return float|string The arctangent of the number
* @return array|float|string The arctangent of the number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function atan($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {
@ -73,12 +94,18 @@ class Tangent
*
* Returns the inverse hyperbolic tangent of a number.
*
* @param float $number Number
* @param array|float $number Number, or can be an array of numbers
*
* @return float|string The inverse hyperbolic tangent of the number
* @return array|float|string The inverse hyperbolic tangent of the number
* If an array of numbers is passed as the argument, then the returned result will also be an array
* with the same dimensions
*/
public static function atanh($number)
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
try {
$number = Helpers::validateNumericNullBool($number);
} catch (Exception $e) {
@ -104,13 +131,20 @@ class Tangent
* Excel Function:
* ATAN2(xCoordinate,yCoordinate)
*
* @param mixed $xCoordinate should be float, the x-coordinate of the point
* @param mixed $yCoordinate should be float, the y-coordinate of the point
* @param mixed $xCoordinate should be float, the x-coordinate of the point, or can be an array of numbers
* @param mixed $yCoordinate should be float, the y-coordinate of the point, or can be an array of numbers
*
* @return float|string the inverse tangent of the specified x- and y-coordinates, or a string containing an error
* @return array|float|string
* The inverse tangent of the specified x- and y-coordinates, or a string containing an error
* If an array of numbers is passed as one of the arguments, then the returned result will also be an array
* with the same dimensions
*/
public static function atan2($xCoordinate, $yCoordinate)
{
if (is_array($xCoordinate) || is_array($yCoordinate)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $xCoordinate, $yCoordinate);
}
try {
$xCoordinate = Helpers::validateNumericNullBool($xCoordinate);
$yCoordinate = Helpers::validateNumericNullBool($yCoordinate);

View File

@ -2,22 +2,33 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
class Trunc
{
use ArrayEnabled;
/**
* TRUNC.
*
* Truncates value to the number of fractional digits by number_digits.
*
* @param float $value
* @param int $digits
* @param array|float $value
* Or can be an array of values
* @param array|int $digits
* Or can be an array of values
*
* @return float|string Truncated value, or a string containing an error
* @return array|float|string Truncated value, 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($value = 0, $digits = 0)
{
if (is_array($value) || is_array($digits)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $digits);
}
try {
$value = Helpers::validateNumericNullBool($value);
$digits = Helpers::validateNumericNullSubstitution($digits, null);

View File

@ -130,7 +130,7 @@ class Statistical
* @param mixed $rMin
* @param mixed $rMax
*
* @return float|string
* @return array|float|string
*/
public static function BETADIST($value, $alpha, $beta, $rMin = 0, $rMax = 1)
{
@ -153,7 +153,7 @@ class Statistical
* @param float $rMin Minimum value
* @param float $rMax Maximum value
*
* @return float|string
* @return array|float|string
*/
public static function BETAINV($probability, $alpha, $beta, $rMin = 0, $rMax = 1)
{
@ -179,7 +179,7 @@ class Statistical
* @param mixed $probability Probability of success on each trial
* @param mixed $cumulative
*
* @return float|string
* @return array|float|string
*/
public static function BINOMDIST($value, $trials, $probability, $cumulative)
{
@ -199,7 +199,7 @@ class Statistical
* @param float $value Value for the function
* @param float $degrees degrees of freedom
*
* @return float|string
* @return array|float|string
*/
public static function CHIDIST($value, $degrees)
{
@ -219,7 +219,7 @@ class Statistical
* @param float $probability Probability for the function
* @param float $degrees degrees of freedom
*
* @return float|string
* @return array|float|string
*/
public static function CHIINV($probability, $degrees)
{
@ -240,7 +240,7 @@ class Statistical
* @param float $stdDev Standard Deviation
* @param float $size
*
* @return float|string
* @return array|float|string
*/
public static function CONFIDENCE($alpha, $stdDev, $size)
{
@ -415,7 +415,7 @@ class Statistical
* @param float $probability probability of a success on each trial
* @param float $alpha criterion value
*
* @return int|string
* @return array|int|string
*/
public static function CRITBINOM($trials, $probability, $alpha)
{
@ -460,7 +460,7 @@ class Statistical
* @param float $lambda The parameter value
* @param bool $cumulative
*
* @return float|string
* @return array|float|string
*/
public static function EXPONDIST($value, $lambda, $cumulative)
{
@ -486,7 +486,7 @@ class Statistical
* @param bool $cumulative If cumulative is TRUE, F.DIST returns the cumulative distribution function;
* if FALSE, it returns the probability density function.
*
* @return float|string
* @return array|float|string
*/
public static function FDIST2($value, $u, $v, $cumulative)
{
@ -507,7 +507,7 @@ class Statistical
*
* @param float $value
*
* @return float|string
* @return array|float|string
*/
public static function FISHER($value)
{
@ -528,7 +528,7 @@ class Statistical
*
* @param float $value
*
* @return float|string
* @return array|float|string
*/
public static function FISHERINV($value)
{
@ -549,7 +549,7 @@ class Statistical
* @param mixed $yValues array of mixed Data Series Y
* @param mixed $xValues of mixed Data Series X
*
* @return bool|float|string
* @return array|bool|float|string
*/
public static function FORECAST($xValue, $yValues, $xValues)
{
@ -568,7 +568,7 @@ class Statistical
*
* @param float $value
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function GAMMAFunction($value)
{
@ -590,7 +590,7 @@ class Statistical
* @param float $b Parameter to the distribution
* @param bool $cumulative
*
* @return float|string
* @return array|float|string
*/
public static function GAMMADIST($value, $a, $b, $cumulative)
{
@ -611,7 +611,7 @@ class Statistical
* @param float $alpha Parameter to the distribution
* @param float $beta Parameter to the distribution
*
* @return float|string
* @return array|float|string
*/
public static function GAMMAINV($probability, $alpha, $beta)
{
@ -630,7 +630,7 @@ class Statistical
*
* @param float $value
*
* @return float|string
* @return array|float|string
*/
public static function GAMMALN($value)
{
@ -650,7 +650,7 @@ class Statistical
*
* @param float $value
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function GAUSS($value)
{
@ -742,7 +742,7 @@ class Statistical
* @param mixed $populationSuccesses Number of successes in the population
* @param mixed $populationNumber Population size
*
* @return float|string
* @return array|float|string
*/
public static function HYPGEOMDIST($sampleSuccesses, $sampleNumber, $populationSuccesses, $populationNumber)
{
@ -879,7 +879,7 @@ class Statistical
* @param float $mean
* @param float $stdDev
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*
* @TODO Try implementing P J Acklam's refinement algorithm for greater
* accuracy if I can get my head round the mathematics
@ -905,7 +905,7 @@ class Statistical
* @param float $mean
* @param float $stdDev
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function LOGNORMDIST($value, $mean, $stdDev)
{
@ -928,7 +928,7 @@ class Statistical
* @param float $stdDev
* @param bool $cumulative
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function LOGNORMDIST2($value, $mean, $stdDev, $cumulative = false)
{
@ -1131,7 +1131,7 @@ class Statistical
* @param mixed $successes Threshold number of Successes
* @param mixed $probability Probability of success on each trial
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NEGBINOMDIST($failures, $successes, $probability)
{
@ -1155,7 +1155,7 @@ class Statistical
* @param mixed $stdDev Standard Deviation
* @param mixed $cumulative
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NORMDIST($value, $mean, $stdDev, $cumulative)
{
@ -1176,7 +1176,7 @@ class Statistical
* @param mixed $mean Mean Value
* @param mixed $stdDev Standard Deviation
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NORMINV($probability, $mean, $stdDev)
{
@ -1197,7 +1197,7 @@ class Statistical
*
* @param mixed $value
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NORMSDIST($value)
{
@ -1219,7 +1219,7 @@ class Statistical
* @param mixed $value
* @param mixed $cumulative
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NORMSDIST2($value, $cumulative)
{
@ -1238,7 +1238,7 @@ class Statistical
*
* @param mixed $value
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NORMSINV($value)
{
@ -1308,7 +1308,7 @@ class Statistical
* @param int $numObjs Number of different objects
* @param int $numInSet Number of objects in each permutation
*
* @return float|int|string Number of permutations, or a string containing an error
* @return array|float|int|string Number of permutations, or a string containing an error
*/
public static function PERMUT($numObjs, $numInSet)
{
@ -1331,7 +1331,7 @@ class Statistical
* @param mixed $mean Mean Value
* @param mixed $cumulative
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function POISSON($value, $mean, $cumulative)
{
@ -1480,7 +1480,7 @@ class Statistical
* @param float $mean Mean Value
* @param float $stdDev Standard Deviation
*
* @return float|string Standardized value, or a string containing an error
* @return array|float|string Standardized value, or a string containing an error
*/
public static function STANDARDIZE($value, $mean, $stdDev)
{
@ -1610,7 +1610,7 @@ class Statistical
* @param float $degrees degrees of freedom
* @param float $tails number of tails (1 or 2)
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function TDIST($value, $degrees, $tails)
{
@ -1630,7 +1630,7 @@ class Statistical
* @param float $probability Probability for the function
* @param float $degrees degrees of freedom
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function TINV($probability, $degrees)
{
@ -1787,7 +1787,7 @@ class Statistical
* @param float $beta Beta Parameter
* @param bool $cumulative
*
* @return float|string (string if result is an error)
* @return array|float|string (string if result is an error)
*/
public static function WEIBULL($value, $alpha, $beta, $cumulative)
{

View File

@ -24,7 +24,7 @@ class Averages extends AggregateBase
$aArgs = Functions::flattenArrayIndexed($args);
// Return value
$returnValue = 0;
$returnValue = 0.0;
$aMean = self::average(...$args);
if ($aMean === Functions::DIV0()) {

View File

@ -2,27 +2,35 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Confidence
{
use ArrayEnabled;
/**
* CONFIDENCE.
*
* Returns the confidence interval for a population mean
*
* @param mixed $alpha As a float
* Or can be an array of values
* @param mixed $stdDev Standard Deviation as a float
* Or can be an array of values
* @param mixed $size As an integer
* Or can be an array of values
*
* @return float|string
* @return array|float|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 CONFIDENCE($alpha, $stdDev, $size)
{
$alpha = Functions::flattenSingleValue($alpha);
$stdDev = Functions::flattenSingleValue($stdDev);
$size = Functions::flattenSingleValue($size);
if (is_array($alpha) || is_array($stdDev) || is_array($size)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $alpha, $stdDev, $size);
}
try {
$alpha = StatisticalValidations::validateFloat($alpha);
@ -36,6 +44,6 @@ class Confidence
return Functions::NAN();
}
return Distributions\StandardNormal::inverse(1 - $alpha / 2) * $stdDev / sqrt($size);
return Functions::scalar(Distributions\StandardNormal::inverse(1 - $alpha / 2) * $stdDev / sqrt($size));
}
}

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Beta
{
use ArrayEnabled;
private const MAX_ITERATIONS = 256;
private const LOG_GAMMA_X_MAX_VALUE = 2.55e305;
@ -19,20 +22,28 @@ class Beta
* Returns the beta distribution.
*
* @param mixed $value Float value at which you want to evaluate the distribution
* Or can be an array of values
* @param mixed $alpha Parameter to the distribution as a float
* Or can be an array of values
* @param mixed $beta Parameter to the distribution as a float
* Or can be an array of values
* @param mixed $rMin as an float
* Or can be an array of values
* @param mixed $rMax as an float
* Or can be an array of values
*
* @return float|string
* @return array|float|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 distribution($value, $alpha, $beta, $rMin = 0.0, $rMax = 1.0)
{
$value = Functions::flattenSingleValue($value);
$alpha = Functions::flattenSingleValue($alpha);
$beta = Functions::flattenSingleValue($beta);
$rMin = ($rMin === null) ? 0.0 : Functions::flattenSingleValue($rMin);
$rMax = ($rMax === null) ? 1.0 : Functions::flattenSingleValue($rMax);
if (is_array($value) || is_array($alpha) || is_array($beta) || is_array($rMin) || is_array($rMax)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $alpha, $beta, $rMin, $rMax);
}
$rMin = $rMin ?? 0.0;
$rMax = $rMax ?? 1.0;
try {
$value = DistributionValidations::validateFloat($value);
@ -65,20 +76,28 @@ class Beta
* Returns the inverse of the Beta distribution.
*
* @param mixed $probability Float probability at which you want to evaluate the distribution
* Or can be an array of values
* @param mixed $alpha Parameter to the distribution as a float
* Or can be an array of values
* @param mixed $beta Parameter to the distribution as a float
* Or can be an array of values
* @param mixed $rMin Minimum value as a float
* Or can be an array of values
* @param mixed $rMax Maximum value as a float
* Or can be an array of values
*
* @return float|string
* @return array|float|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 inverse($probability, $alpha, $beta, $rMin = 0.0, $rMax = 1.0)
{
$probability = Functions::flattenSingleValue($probability);
$alpha = Functions::flattenSingleValue($alpha);
$beta = Functions::flattenSingleValue($beta);
$rMin = ($rMin === null) ? 0.0 : Functions::flattenSingleValue($rMin);
$rMax = ($rMax === null) ? 1.0 : Functions::flattenSingleValue($rMax);
if (is_array($probability) || is_array($alpha) || is_array($beta) || is_array($rMin) || is_array($rMax)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $probability, $alpha, $beta, $rMin, $rMax);
}
$rMin = $rMin ?? 0.0;
$rMax = $rMax ?? 1.0;
try {
$probability = DistributionValidations::validateProbability($probability);

View File

@ -2,12 +2,15 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Combinations;
class Binomial
{
use ArrayEnabled;
/**
* BINOMDIST.
*
@ -18,17 +21,23 @@ class Binomial
* babies born are male.
*
* @param mixed $value Integer number of successes in trials
* Or can be an array of values
* @param mixed $trials Integer umber of trials
* Or can be an array of values
* @param mixed $probability Probability of success on each trial as a float
* Or can be an array of values
* @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false)
* Or can be an array of values
*
* @return float|string
* @return array|float|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 distribution($value, $trials, $probability, $cumulative)
{
$value = Functions::flattenSingleValue($value);
$trials = Functions::flattenSingleValue($trials);
$probability = Functions::flattenSingleValue($probability);
if (is_array($value) || is_array($trials) || is_array($probability) || is_array($cumulative)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $trials, $probability, $cumulative);
}
try {
$value = DistributionValidations::validateInt($value);
@ -58,19 +67,26 @@ class Binomial
* of trials falling into a specified range.
*
* @param mixed $trials Integer number of trials
* Or can be an array of values
* @param mixed $probability Probability of success on each trial as a float
* Or can be an array of values
* @param mixed $successes The integer number of successes in trials
* Or can be an array of values
* @param mixed $limit Upper limit for successes in trials as null, or an integer
* If null, then this will indicate the same as the number of Successes
* Or can be an array of values
*
* @return float|string
* @return array|float|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 range($trials, $probability, $successes, $limit = null)
{
$trials = Functions::flattenSingleValue($trials);
$probability = Functions::flattenSingleValue($probability);
$successes = Functions::flattenSingleValue($successes);
$limit = ($limit === null) ? $successes : Functions::flattenSingleValue($limit);
if (is_array($trials) || is_array($probability) || is_array($successes) || is_array($limit)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $trials, $probability, $successes, $limit);
}
$limit = $limit ?? $successes;
try {
$trials = DistributionValidations::validateInt($trials);
@ -107,19 +123,24 @@ class Binomial
* variable. Like the binomial, trials are assumed to be independent.
*
* @param mixed $failures Number of Failures as an integer
* Or can be an array of values
* @param mixed $successes Threshold number of Successes as an integer
* Or can be an array of values
* @param mixed $probability Probability of success on each trial as a float
* Or can be an array of values
*
* @return float|string The result, or a string containing an error
* @return array|float|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
*
* TODO Add support for the cumulative flag not present for NEGBINOMDIST, but introduced for NEGBINOM.DIST
* The cumulative default should be false to reflect the behaviour of NEGBINOMDIST
*/
public static function negative($failures, $successes, $probability)
{
$failures = Functions::flattenSingleValue($failures);
$successes = Functions::flattenSingleValue($successes);
$probability = Functions::flattenSingleValue($probability);
if (is_array($failures) || is_array($successes) || is_array($probability)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $failures, $successes, $probability);
}
try {
$failures = DistributionValidations::validateInt($failures);
@ -143,22 +164,27 @@ class Binomial
}
/**
* CRITBINOM.
* BINOM.INV.
*
* Returns the smallest value for which the cumulative binomial distribution is greater
* than or equal to a criterion value
*
* @param mixed $trials number of Bernoulli trials as an integer
* Or can be an array of values
* @param mixed $probability probability of a success on each trial as a float
* Or can be an array of values
* @param mixed $alpha criterion value as a float
* 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 inverse($trials, $probability, $alpha)
{
$trials = Functions::flattenSingleValue($trials);
$probability = Functions::flattenSingleValue($probability);
$alpha = Functions::flattenSingleValue($alpha);
if (is_array($trials) || is_array($probability) || is_array($alpha)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $trials, $probability, $alpha);
}
try {
$trials = DistributionValidations::validateInt($trials);

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class ChiSquared
{
use ArrayEnabled;
private const MAX_ITERATIONS = 256;
private const EPS = 2.22e-16;
@ -17,14 +20,19 @@ class ChiSquared
* Returns the one-tailed probability of the chi-squared distribution.
*
* @param mixed $value Float value for which we want the probability
* Or can be an array of values
* @param mixed $degrees Integer degrees of freedom
* Or can be an array of values
*
* @return float|string
* @return array|float|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 distributionRightTail($value, $degrees)
{
$value = Functions::flattenSingleValue($value);
$degrees = Functions::flattenSingleValue($degrees);
if (is_array($value) || is_array($degrees)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $degrees);
}
try {
$value = DistributionValidations::validateFloat($value);
@ -53,16 +61,21 @@ class ChiSquared
* Returns the one-tailed probability of the chi-squared distribution.
*
* @param mixed $value Float value for which we want the probability
* Or can be an array of values
* @param mixed $degrees Integer degrees of freedom
* Or can be an array of values
* @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false)
* Or can be an array of values
*
* @return float|string
* @return array|float|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 distributionLeftTail($value, $degrees, $cumulative)
{
$value = Functions::flattenSingleValue($value);
$degrees = Functions::flattenSingleValue($degrees);
$cumulative = Functions::flattenSingleValue($cumulative);
if (is_array($value) || is_array($degrees) || is_array($cumulative)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $degrees, $cumulative);
}
try {
$value = DistributionValidations::validateFloat($value);
@ -97,14 +110,19 @@ class ChiSquared
* Returns the inverse of the right-tailed probability of the chi-squared distribution.
*
* @param mixed $probability Float probability at which you want to evaluate the distribution
* Or can be an array of values
* @param mixed $degrees Integer degrees of freedom
* Or can be an array of values
*
* @return float|string
* @return array|float|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 inverseRightTail($probability, $degrees)
{
$probability = Functions::flattenSingleValue($probability);
$degrees = Functions::flattenSingleValue($degrees);
if (is_array($probability) || is_array($degrees)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $probability, $degrees);
}
try {
$probability = DistributionValidations::validateProbability($probability);
@ -133,14 +151,19 @@ class ChiSquared
* Returns the inverse of the left-tailed probability of the chi-squared distribution.
*
* @param mixed $probability Float probability at which you want to evaluate the distribution
* Or can be an array of values
* @param mixed $degrees Integer degrees of freedom
* Or can be an array of values
*
* @return float|string
* @return array|float|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 inverseLeftTail($probability, $degrees)
{
$probability = Functions::flattenSingleValue($probability);
$degrees = Functions::flattenSingleValue($degrees);
if (is_array($probability) || is_array($degrees)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $probability, $degrees);
}
try {
$probability = DistributionValidations::validateProbability($probability);
@ -193,7 +216,7 @@ class ChiSquared
$degrees = self::degrees($rows, $columns);
$result = self::distributionRightTail($result, $degrees);
$result = Functions::scalar(self::distributionRightTail($result, $degrees));
return $result;
}

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Exponential
{
use ArrayEnabled;
/**
* EXPONDIST.
*
@ -15,16 +18,21 @@ class Exponential
* use EXPONDIST to determine the probability that the process takes at most 1 minute.
*
* @param mixed $value Float value for which we want the probability
* Or can be an array of values
* @param mixed $lambda The parameter value as a float
* Or can be an array of values
* @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false)
* Or can be an array of values
*
* @return float|string
* @return array|float|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 distribution($value, $lambda, $cumulative)
{
$value = Functions::flattenSingleValue($value);
$lambda = Functions::flattenSingleValue($lambda);
$cumulative = Functions::flattenSingleValue($cumulative);
if (is_array($value) || is_array($lambda) || is_array($cumulative)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $lambda, $cumulative);
}
try {
$value = DistributionValidations::validateFloat($value);

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class F
{
use ArrayEnabled;
/**
* F.DIST.
*
@ -16,18 +19,23 @@ class F
* if the variability in the females is different from that found in the males.
*
* @param mixed $value Float value for which we want the probability
* Or can be an array of values
* @param mixed $u The numerator degrees of freedom as an integer
* Or can be an array of values
* @param mixed $v The denominator degrees of freedom as an integer
* Or can be an array of values
* @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false)
* Or can be an array of values
*
* @return float|string
* @return array|float|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 distribution($value, $u, $v, $cumulative)
{
$value = Functions::flattenSingleValue($value);
$u = Functions::flattenSingleValue($u);
$v = Functions::flattenSingleValue($v);
$cumulative = Functions::flattenSingleValue($cumulative);
if (is_array($value) || is_array($u) || is_array($v) || is_array($cumulative)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $u, $v, $cumulative);
}
try {
$value = DistributionValidations::validateFloat($value);

View File

@ -2,11 +2,14 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Fisher
{
use ArrayEnabled;
/**
* FISHER.
*
@ -15,12 +18,17 @@ class Fisher
* testing on the correlation coefficient.
*
* @param mixed $value Float value for which we want the probability
* Or can be an array of values
*
* @return float|string
* @return array|float|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 distribution($value)
{
$value = Functions::flattenSingleValue($value);
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
try {
DistributionValidations::validateFloat($value);
@ -43,12 +51,17 @@ class Fisher
* FISHERINV(y) = x.
*
* @param mixed $probability Float probability at which you want to evaluate the distribution
* Or can be an array of values
*
* @return float|string
* @return array|float|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 inverse($probability)
{
$probability = Functions::flattenSingleValue($probability);
if (is_array($probability)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $probability);
}
try {
DistributionValidations::validateFloat($probability);

Some files were not shown because too many files have changed in this diff Show More