Repository navigation
Round: round exact and arbitrary-precision numbers exactly - #2034
Conversation
Round converted its argument to a machine float before rounding, so any
number beyond 2^53 lost its last digits:
Round[10^20 + 1] gave 100000000000000000000
Round[Pi 10^20] gave 314159265358979334144
Round[1.5`30 10^25] gave 15000000000000000285212672
Round[1/2 + 10^-40] gave 0
Floor and Ceiling go through SymPy and were right. Round now rounds a
rational or a float (machine or arbitrary precision) exactly, ties to
even as before, and an exact irrational number by SymPy's floor of
x + 1/2. Complex arguments and anything not known to be real take the
old path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| return Expression(SymbolTimes, Integer(n), k) | ||
|
|
||
|
|
||
| def round_real_exactly(x) -> Optional[int]: |
There was a problem hiding this comment.
This kind of thing should be in mathics.eval.numeric.
What goes into mathics.buiitin are the kinds of properties associated with the Builtin, which in Mathics3, is are its class parameters (attributes, rules, custom error messages).
Things associated with evaluation that do not need "self" the class object should be under mathics.eval.
This way, evaluation routines can have access to those "helper" functions should they need it. It also makes it feasible to write a compiler to some sort of custom bytecode, if we ever get there.
There was a problem hiding this comment.
Also, in the future, please put in PRs in branches in this repository. Thanks.
I see this is being done on future PRs.
There was a problem hiding this comment.
Thanks, done in 5c9339c: the rounding logic and the round_real_exactly helper are now eval_Round in mathics.eval.numeric, and Round.eval_two_args only calls it.
The rounding logic and its round_real_exactly helper do not need the Builtin instance, so they now live in mathics.eval.numeric as eval_Round; Round.eval_two_args only calls it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # mathics/eval/numeric.py
|
LGTM |
Round converted its argument to a machine float before rounding, so any
number beyond 2^53 lost its last digits:
Floor and Ceiling go through SymPy and were right. Round now rounds a
rational or a float (machine or arbitrary precision) exactly, ties to
even as before, and an exact irrational number by SymPy's floor of
x + 1/2. Complex arguments and anything not known to be real take the
old path.
To reproduce on master:
Tests: new cases in
test/builtin/test_numeric.py(test_numeric). They fail on current master and pass with this change.The full pytest suite and the doctests pass with this change (run together with the other fixes from the same audit; the only pytest failures, in
test_main.pyandtest_returncode.py, are the same as on master and come from themathicsscript not being on PATH in our environment).Found in a correctness audit of Mathics3 (differential checks against SymPy/mpmath/exact computation, and calls of every builtin with edge-case arguments).
🤖 Generated with Claude Code