views:

55

answers:

1

I am writing a simple app that takes a bunch of numerical inputs and calculates a set of results. (The app is in PyGTK but I don't think that's relevant.)

My problem is that if I want to just have NaN's and Inf's propagated through, then in every calculation I need to do something like:

# At the top of the module
nan = float("nan")
inf = float("inf")

try:
  res = (a + b) / (0.1*c + d)
except ZeroDivisionError:
  # replicate every little subtlety of IEEE 754 here
except OverflowError:
  # replicate every little subtlety of IEEE 754 here again

...or, of course, pre-empt it for every calculation:

numerator = a + b
denominator = 0.1*c + d

if denominator == 0:
  # etc
elif math.isnan(numerator):
  # *sigh*

How can I deal with this sanely in Python 2.6? Do I really need to install a massive 3rd-party module (numpy, scipy) on every target machine just to do IEEE 754 arithmetic? Or is there a simpler way?

+2  A: 

No, Python's built-in math raises exceptions for errors rather than returning them as NaN and INF. You'll need to use a library or your own code if you don't want this behavior.

(Thought I'd give the simple answer, since too many questions where the answer is "sorry, no" simply don't get answered.)

Glenn Maynard
Grrr. But thanks, "no" is still an answer. I think I was hoping for some standard library module I didn't know about (I'd call it `sanefloat`, with a context manager called `sanity`, so everyone cold write `from sanefloat import sanity` ... `with sanity: ...`)
detly
I personally find exceptions on math errors much more sane than silently propagating NaNs through values, and INFs are usually better avoided as they typically put FPUs in a slow path, though that matters less in Python. I think implementing something like this would require high-performance TLS, which I'd imagine is something the Python core would want to avoid requiring...
Glenn Maynard
It depends on the context. If someone puts 10 in the `c` box and 1 in the `d` box, I'd rather just have `inf` show up in the result box. And once you write more than about ten of these functions, you get really, really sick of catching the same three exceptions every time.
detly
So anyway, do you know of a library that can do IEEE 754 arithmetic? NumPy doesn't really seem to cover it either.
detly
I don't know of a library to do this. If I have a lot of expressions like that, I'd try to stick them in functions to handle the exceptions in the same place; there's also ArithmeticError so you don't need to handle them separately, if you don't mind just saying "err" rather than "inf" and "nan". If you really, specifically need INF/NAN results, it'd be pretty simple to write a small native math library of your own--just copy over the Python code and take out the exception handling, though of course you'd end up with a less pretty functional syntax.
Glenn Maynard
I'm not sure what you mean by "stick them in functions to handle the exceptions in the same place" — they are in separate functions, which means handling the same exceptions in every function. Handling `ArithmeticError` is a good idea, and returning NaN for all errors would work.
detly
I mean: if you have a large batch of similar expressions that are evaluated for user input, then arrange for them to be dispatched in the same place, so you can handle the exceptions from the caller rather than the function. Another option is a decorator: if the functions always return a float, catch the exceptions and return float('nan') from the decorator--not exact, of course, but good enough as an error sentinel for UI purposes.
Glenn Maynard
Ah I see what you mean. But no, the outputs are updated when each input is changed, so there's no single point of dispatch.
detly