Repository navigation
Pass return value on ValueError exceptions in the cmath/math modules #133895
Description
Activity
- addedtype-featureA feature request or enhancementA feature request or enhancementextension-modulesC modules in the Modules dirC modules in the Modules dir
on May 11, 2025 CC @tim-one, @mdickinson
CC @serhiy-storchaka, does this make sense for you?
I don't know how useful this feature would be. On the one hand, it adds overhead in case an exception was raised. It is unfortunate because the EAFP principle is commonly used in Python. On other hand, if the user needs such information, there is no way to get it in other way. And the cost of raising and catching an exception is already high, so relative overhead is not so great. But I do not know if anyone really need it. This needs a wider discussion.
Should the value be added also for
ZeroDivisionError(NaN or infinities) andOverflowError(plus/minus infinity for conversion from int or division)? For now,0/2**2000returns0.0, but0.0/2**2000raises OverflowError.But I do not know if anyone really need it.
@serhiy-storchaka, my major motivation was the mpmath's fp context (fixed precision). It uses Python's floats and math/cmath functions.
But other mpmath contexts have (just like gmpy2) a different defaults: exceptions are not raised. Unfortunately, it's not easy to fix the fp context to match this behavior: essentially this require to re-implement handling of special values in all stdlib's functions. With proposed solution I could just wrap such functions with try-except block.
Should the value be added also for ZeroDivisionError (NaN or infinities) and OverflowError (plus/minus infinity for conversion from int or division)?
Yes, I think you are right, i.e.:
>>> gmpy2.mpfr(1)/gmpy2.mpfr(0) mpfr('inf')
This needs a wider discussion.
Maybe.
Alternative solution might be some context notion for floating-point math, just like for the decimal module.
With this we can open door to more features of the platform's floating-point arithmetic, e.g. support different rounding modes. (This is a kinda possible with ctypes, but FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO and FE_UPWARD values are system-specific.) And it's essentially for free.
What do you think?
BTW, as I expected, computed values in exceptional cases (special values, overflows) might be incorrect in the cmath module. I found two examples in our test suite so far, fixed in #134995.
CC @picnixz ?
I like the context notion as in C but this probably requires a PEP because it affects not just (c)math functions but the entire fp arithmetic. So for now, I wouldn't consider this solution though it's probably the cleanest.
Raising ValueError with an attribute containing the special value would be more user friendly. Users indeed expect some exceptions if the arithmetic has issue and if we can add some canonical replacement as per ISO standards, that would probably be the best compromise.
If we are worried because of some overhead in exceptions, how about a global flag for cmath and math functions that, if true, add the information. We should check if the overhead is really big or not, but I think people doing such computations only care about successful paths. I also thought that we had almost 0-cost exceptions for successful paths but was I wrong? (namely try-except are cheap if nothing bad occurs). When the exception occurs, I think the processing of this branch is likely to take more time than the processing of good inputs.
So I am inclined in adding the information, whether conditionally or not. Alternatively we could create a ValueError subclass which holds the C value (not a PyObject) and transforms it on demand (only when calling .value for instance).
I like the context notion as in C but this probably requires a PEP because it affects not just (c)math functions but the entire fp arithmetic.
Yes, it does. Though, most of the complexity will be hidden per default. Unless user import the math module (I think it's a natural place to keep here context-related interfaces) and start changing the current context options.
how about a global flag for cmath and math functions that, if true, add the information.
That sounds as a bad version of context notion.
I think people doing such computations only care about successful paths.
Yes. I'm not sure that the EAFP principle is relevant here. Exception usually means the end of computation.
we could create a ValueError subclass which holds the C value (not a PyObject) and transforms it on demand
That will remove most of overhead, yes. And math/cmath modules deserve specialized version of a ValueError, which is too generic.
Here d.p.o post, per @serhiy-storchaka suggestion: https://discuss.python.org/t/104388
Closing in favor of d.p.o thread.
Feature or enhancement
Proposal:
Currently the error handling happens this way for the cmath module (taken from module comments):
The ValueError raised for EDOM and the OverflowError - for ERANGE, but the Annex G result is hidden from the pure-Python world. Though, it might be helpful for applications. E.g.
clog(-0+0i)returns-∞+πiandclog(+0+0i)returns-∞+0i- correct one-sided limits in the pole of log(). (BTW, something like PoleError could be better here, but that's another story.)The mpmath and the gmpy2 (per default, if
trap_divzeroand/ortrap_invalidcontext options aren't enabled) rather return special values per the C standard, not raise exceptions. And the mpmath also uses builtin float's and math/cmath functions for the fp context. Thus, to override current behavior of the stdlib - we need to catch ValueError from the called function and then process function arguments to return special values, i.e. essentially re-implement handling of special values. But they already are computed in cmath/math functions, so why not return this information with an exception? An example:Initial patch, working for most functions, not using math_error().
Similar happens in the math module and fix looks simple as well. I didn't check all cases, but it seems that most functions in the cmath/math modules actually compute correct (per C standard and Annex G) answers for special values.
Alternative approach: some global flag to turn on the gmpy2-like behavior (i.e. raise no exceptions, but return special values instead).
Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
No response
Linked PRs