Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

ROUND Accepts null, false, and true as First Parameter #1837

Merged
merged 7 commits into from Feb 13, 2021
Merged

ROUND Accepts null, false, and true as First Parameter #1837

merged 7 commits into from Feb 13, 2021

Conversation

oleibman
Copy link
Collaborator

@oleibman oleibman commented Feb 11, 2021

Issue #1789 was addressed by PR #1799. In a follow-up discussion,
it came to light that ROUND was not handling the unexpected case where the
first parameter is an empty cell in the same manner that Excel does.
Subsequent investigation showed that a boolean first parameter is permitted.
I broadened my investigation to include the following related functions.

  • ROUNDUP
  • ROUNDDOWN
  • MROUND
  • TRUNC
  • INT
  • FLOOR
  • FLOOR.MATH
  • FLOOR.PRECISE
  • CEILING
  • CEILING.MATH
  • CEILING.PRECISE

All of these allow a NULL first parameter, and all except MROUND allow boolean.
For completeness, I will note that all treat null string as invalid.
I suspect there are other functions which permit
similarly unexpected parameters, but I consider them out of scope for this PR.

CEILING.MATH and CEILING.PRECISE were unimplemented, and are now supported
as part of this PR.

The tests for each of these functions have been re-coded, though all the original
test data is still included in the test cases, plus several new cases for each.
The new tests now take place as a user would invoke the functions,
through a spreadsheet cell rather than a
direct call to the appropriate function within Calculation/MathTrig.
Aside from being more realistic, the new tests are also more complete.
For example, FLOOR.MATH can take from 1-3 arguments, and the existing tests
confirmed that the function in Calculation could handle a single argument.
However, the function list in Calculation.php erroneously set the number of
arguments for FLOOR.MATH to exactly 3, so, if a user tried to get the calculated
result of a cell containing FLOOR.MATH(1.2), the result would be an Exception.

Aside from the parameter support, there are a few minor code changes.
Ods, as well as Gnumeric, allows the omission of the second parameter for
FLOAT and CEILING; Excel does not. A potential divide-by-zero error is
avoided in CEILING, FLOOR, and FLOORMATH.

I will note that it would probably be beneficial in terms of maintainability
to break MathTrig up into many individual modules. The same would hold for the
other Calculation modules. I would be willing to look into this if you agree
that it would be worthwhile.

This is:

- [x] a bugfix
- [x] a new feature

Checklist:

Why this change is needed?

Issue #1789 was addressed by PR #1799. In a follow-up discussion,
it came to light that ROUND was not handling the unexpected case where the
first parameter is an empty cell in the same manner that Excel does.
Subsequent investigation showed that a boolean first parameter is permitted.
I broadened my investigation to include the following related functions.
- ROUNDUP
- ROUNDDOWN
- MROUND
- TRUNC
- INT
- FLOOR
- FLOOR.MATH
- FLOOR.PRECISE
- CEILING
- CEILING.MATH
- CEILING.PRECISE

All of these allow a NULL first parameter, and all except MROUND allow boolean.
For completeness, I will note that all treat null string as invalid.
I suspect there are other functions which permit
similarly unexpected parameters, but I consider them out of scope for this PR.

CEILING.MATH and CEILING.PRECISE were unimplemented, and are now supported
as part of this PR.

The tests for each of these functions have been re-coded, though all the original
test data is still included in the test cases, plus several new cases for each.
The new tests now take place as a user would invoke the functions,
through a spreadsheet cell rather than a
direct call to the appropriate function within Calculation/MathTrig.
Aside from being more realistic, the new tests are also more complete.
For example, FLOOR.MATH can take from 1-3 arguments, and the existing tests
confirmed that the function in Calculation could handle a single argument.
However, the function list in Calculation.php erroneously set the number of
arguments for FLOOR.MATH to exactly 3, so, if a user tried to get the calculated
result of a cell containing FLOOR.MATH(1.2), the result would be an Exception.

Aside from the parameter support, there are a few minor code changes.
Ods, as well as Gnumeric, allows the omission of the second parameter for
FLOAT and CEILING; Excel does not. A potential divide-by-zero error is
avoided in CEILING, FLOOR, and FLOORMATH.

I will note that it would probably be beneficial in terms of maintainability
to break MathTrig up into many individual modules. The same would hold for the
other Calculation modules. I would be willing to look into this if you agree
that it would be worthwhile.
One of the 2 new functions had Complexity C.
Erroneous return type in Docblock.
Can't duplicate on my system. Trying an alternative.

I think it's kind of tacky that php-cs-main step can fail,
without indicating what member it failed in, let alone what line.
@MarkBaker
Copy link
Member

I will note that it would probably be beneficial in terms of maintainability
to break MathTrig up into many individual modules. The same would hold for the
other Calculation modules. I would be willing to look into this if you agree
that it would be worthwhile.

I very much agree.
Not just MathTrig, but all those calculation function classes. I'd already started considering this when I updated the CONVERT() function in Engineering, and moved it into its own separate class. My thinking was that I would gradually move other functions or groups of functions into their own separate classes (the BESSEL and Complex functions would be other prime candidates in Engineering). As you can see with ConvertUOM(), the method still exists inside Engineering.php, but only as a wrapper to call the Engineering\CONVERTUOM class methods, and flagged as Deprecated, with a view to removing it completely for a version 2 release at the end of this year.

I should also have modified the entry in Calculation.php to reference 'functionCall' => [Engineering\ConvertUOM::class, 'CONVERTUOM'] instead of simply leaving it as 'functionCall' => [Engineering::class, 'CONVERTUOM']

It will take a bit of effort, especially in Financial where so many functions are dependent on calculations within other functions; but at least it can be done gradually, group by group over a period of time.


I'd also considered one other major change to the way the Calculation engine handles Excel errors for the version 2 release; and that is to use an ExcelException class to represent Excel errors rather than the '#NUM!' type string as at present. This should allow better error trapping/handling in the code, and make it a lot easier to bubble errors through more complex formulae. I'd even created a branch to test the principle of this approach, but got rather bogged down in the implementation. It's large chunk of work, but I think it would also help make the function code easier when it came to Excel error handling. What do you think?

@oleibman
Copy link
Collaborator Author

I haven't thought about it, so I will just give you my immediate gut reaction. I think issuing Exception instead of the Excel error strings could be disruptive. It might make it difficult to read an existing spreadsheet that contained this type of error. And, even when creating a new one, I believe that you don't automatically perform an evaluation when you set a cell to a formula, so the Exception may occur long after the damage. In particular, it may not show up until you attempt to save the spreadsheet to a file, an unexpected and difficult-to-debug situation. If you do this, it might be best to have a global setting so that, depending on the setting, Function::NAN() etc. either returns the error string or issues an Exception.

@oleibman
Copy link
Collaborator Author

Based upon your agreement about breaking up MathTrig, I will start that effort by continuing to work on this change to move the affected functions to their own classes. Expect a new version by the end of the weekend.

Move functions involved in this PR to their own classes.
Minor error - potential mis-typing.
@oleibman
Copy link
Collaborator Author

All 12 functions are now moved to their own classes. No further changes planned for this PR.

Retain deprecated versions of functions in MathTrig.
Use explicit typing when possible.
@MarkBaker MarkBaker merged commit cabcfaa into PHPOffice:master Feb 13, 2021
MarkBaker pushed a commit that referenced this pull request Feb 13, 2021
* Support 'Forms' for ROMAN Function

This seems like an exceptionally silly thing for MS to have implemented
(Wikipedia on Roman Numerals: "There is no indication this is anything
other than an invention by the programmer").
Nevertheless, we can, and therefore probably should, implement it.

Not that I can implement it by an algorithm - Excel describes the various extra
styles as "more concise", "more concise", "more concise", and "simplified".
Nevertheless, since the universe of potential calls is relatively small,
it can be implemented as a table of values where the new forms would return
a different value than "classic". This table is relatively large, so I have
put it its own member to avoid overhead when the function is needed.

* Move ROMAN To Its Own Class

See discussion in PR #1837

* PHP 8.1 Deprecations

PHP8.1 Unit tests failed. 1 line fixes are available for
- Shared/Font
- Shared/XMLWriter
- Style/Color
- Writer/HTML

The problem is that an error is also reported for a strcmp at
line 272 of Cell/Cell. Not only does that line not invoke strcmp,
there is no strcmp in all of Cell/Cell, so I don't know what to make
of the error message. Oh well, let's fix what can be fixed.

Still dealing with the mysterious PHP8.1 unit test failure in Cell\Cell,
which seems to have something to do with strcmp. The only uses of
strcmp that I can find in src/ are in Calculation. I can't find any
use of it in test/ or samples/. So, if this doesn't fix the problem,
I may have to give up.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants