1

After having searched around a little bit, I'm still struggling with divisions by zero in numpy. I am stunned by the contradiction I report right away:

from numpy import *

seterr(all='ignore')    # Trying to avoid ZeroDivisionError, but unsuccessful.

def f(x) :
    return 1./(x-1.)

With this, when I execute f(1.), I get ZeroDivisionError: float division by zero.

However, when I define z = array( [ 1., 1. ] ) and execute f(z), I do not get any error, but array([ inf, inf]).

As you can see, there is kind of a contradiction between both outputs. My first question is why.

Ideally, I would like to get inf as the output of f(1.), or at least nan, but not an error (and therefore the stoppage of the calculation). My second question is how to manage this. Notice my failed attempt by making use of seterr.

Godoy
  • 87
  • 2
  • 9
  • Isn't it just that in the first case you're acting on an integer, while in the second you're working with a numpy array? Those are different things and the behavior will be different depending on how the operations are defined for each. I think if you want consistent output, you have to feed the function consistent input types, or at least types that behave the same way under operations. – JCVanHamme Jan 07 '16 at 20:16

3 Answers3

2

1. is an ordinary Python float, and these raise exceptions instead of using nan/inf. When you call f(1.), numpy is not involved in any way. Just doing from numpy import * (or calling numpy functions like seterr) doesn't change anything about how ordinary Python types work; it will only affect operations on numpy objects, and you only get numpy objects if you explicitly create them.

When you do explicitly create a numpy object, as in your f(z) example, you involve numpy, which has its own types that differ from the basic Python types. Notably, numpy numeric types do use nan/inf.

As far as I know, there is no way to get plain Python floats to start returning nan or inf instead of raising exceptions, so you'll have to use numpy scalars instead of plain Python floats (as described in this question) if you want to support both scalar and vector operations.

Community
  • 1
  • 1
BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • `np.divide(1.0,0.0)` returns `inf` with a warning. Would it be possible to import `divide` somehow from `numpy`? Does this make sense in the first place? – Andras Deak -- Слава Україні Jan 07 '16 at 20:19
  • 1
    @AndrasDeak: You're getting the warning because you're still passing in plain Python floats. If you do, e.g., `np.divide(np.float64(1.0), 0)` then you won't get the warning. If you want everything to happen within numpy, you need your objects to be numpy types before you start doing numpy math on them. (Or you can just live with the warning.) – BrenBarn Jan 07 '16 at 20:20
  • 1
    @AndrasDeak: And yes, you can import `divide` from numpy, but that won't change how the `/` operator works on plain Python floats. Nothing numpy can do will make plain `1.0/0.0` work differently. – BrenBarn Jan 07 '16 at 20:22
1

Numpy is not involved in your function f. You'll have to catch the ZeroDivisionError if you want to alter the output.

import numpy

def f(x) :
    try:
        return 1./(x-1.)
    except ZeroDivisionError:
        return numpy.nan

Or use numpy's division:

import numpy

def f(x) :
    return numpy.divide(1., (x-1.))

Or only pass numpy types to f:

import numpy

def f(x) :
    return 1./(x-1.)

x = numpy.float_(1)
print f(x) # prints inf
  • It works great, thanks. But imagine that I have many functions in my script and I want every function to behave like that without the need of appending the code you suggest to each of them. Do you know if it is possible? – Godoy Jan 07 '16 at 20:31
  • Yes it is! But what you should do is to use numpy.divide(). That will give you `inf` as default. Updated my answer. – Alexander Holmbäck Jan 07 '16 at 20:43
  • I find your last suggestion particularly useful, since with it, I do not have to change anything in my original function `f(x)` (in the script I am dealing with, I have lots of complicated functions, and I would not like to change every slash there by `numpy.divide`). I mean that `f`can be easily redefined to calculate `f(numpy.float_(x))`, and that does the job. Thanks a lot for your editing! – Godoy Jan 07 '16 at 22:49
0

It looks like seterr is intended to be used with Numpy types; how could it be used with Python native type. On the other hand, if you do:

f(np.array((1,)))

No error should occur with your seterr.

Thomas Baruchel
  • 7,236
  • 2
  • 27
  • 46