Skip to content

BUG: __floordiv__ gives NaN and invalid warning for 1//0 #14900

Closed

Description

@DevinShanahan

The __floordiv__ and __mod__ operators do not raise an exception for zero division with np.errstate(divide='raise'), instead replacing those instances with nan as if errstate is in the default state.

import numpy as np
x = np.ones((3, 3))
y = np.zeros((3, 3))

with np.errstate(divide='raise'):
    fdiv = x // y # expecting exception
    mod = x % y # expecting exception

Numpy: 1.17.3

Activity

  1. Sriharsha-hatwar commented on Nov 25, 2019

    @Sriharsha-hatwar

    Very curious about working on this. but seems a little tricky, any inputs ? @eric-wieser ?

  2. seberg commented on Nov 25, 2019

    @seberg
    Member

    Ah, the issue is that npy_divmod in numpy/core/src/npymath/npy_math_internal.h.src has a special path for b == 0. This does not set the divide by 0 error flag (since it is hit before the divide happens). Maybe even reorganizing the code works (not sure what the compilers will do here).
    I suppose the fmod causes an invalid warning to be set before, so I wonder if both should be set or only one?

  3. Sriharsha-hatwar commented on Nov 25, 2019

    @Sriharsha-hatwar

    Hey @seberg any place where we can learn the internals of this working or an overall architectural view of the system? and what is this extension *.h.src ?

  4. seberg commented on Nov 25, 2019

    @seberg
    Member

    The development workflow documents describe the .src extension. It is basically a very very simple templating language used in NumPy. It just repeats the code and fills in the @variable@. The overall architecture is sometimes a bit tricky, I would suggest grepping a bit, you will find this function is used in the umath folder which has everything to define ufuncs in it. Since there are some code generators, etc. please just ask if you are confused by something specific.

  5. anirudh2290 commented on May 4, 2020

    @anirudh2290
    Member

    hi @seberg, i started looking more into this. is this still an issue. looks like fmod sets nan and probably causes invalid warning to be set. Tried to dig more into this and found : #7709 where it seems to indicate that this is intended behavior and not a bug. I also tried to dig into the code, to see where the invalid flag is set (either through NPY_FPE_INVALID or npy_set_floatstatus_invalid) for fmod but couldn't find it.

  6. seberg commented on May 4, 2020

    @seberg
    Member

    Seems there are actually two things here, since we unfortunately never fixed the thing that we should return Inf and not NaN.

    @anirudh2290 there probably is no explicit setting, the flag probably gets set by the CPU during the modulo operation written in C (or similar). So the correct behaviour is arguably to return inf and set the "divide" warning.

    What we need to figure out is which warning is correct. Python returns ZeroDivisionError also for 1 % 0, but that seems wrong when returning NaN (which is arguably correct). Now np.divmod() returns both, so which warning to pick? (I guess the one we currently have).

  7. changed the title [-]errstate divide has no effect on __floordiv__ and __mod__[/-] [+]BUG: `__floordiv__` gives NaN and invalid warning for `1//0`[/+] on May 5, 2020
  8. added
    triage reviewIssue/PR to be discussed at the next triage meeting
    on May 5, 2020
  9. anirudh2290 commented on May 5, 2020

    @anirudh2290
    Member

    thanks @seberg! Currently for np.divmod , it behaves differently for scalars and arrays. for scalar it returns (0, 0) and gives a divide by 0 warning. For arrays, it gives an array of nans (for both quotient and remainder) and gives an invalid warning. Is my understanding correct, that your preference is to return (inf, nan) and set the dividebyzero warning for both scalars and arrays ?

    import numpy as np
    x = np.ones((3, 3))
    y = np.zeros((3, 3))
    
    with np.errstate(all='warn'):
        print(np.divmod(1, 0))  # this will warn divide by 0, and print (0, 0)
        print(np.divmod(x, y))  # this will warn invalid and prints array of nans for both
    
  10. seberg commented on May 5, 2020

    @seberg
    Member

    I did not realize the 0, 0 result the issue you linked sounds like it should, but I am not sure, maybe I am missing something about divmod being special. 1//0 should return inf (unless you say that the floor(inf) gives NaN, I guess? So honestly, I am not quite sure immediately :)

  11. modified the milestone: 1.19.0 release on May 5, 2020
  12. added
    Priority: highHigh priority, also add milestones for urgent issues
    and removed
    triage reviewIssue/PR to be discussed at the next triage meeting
    on May 5, 2020
  13. anirudh2290 commented on May 5, 2020

    @anirudh2290
    Member

    I guess I was not completely accurate before. Float division for example np.divmod(1.0, 0.0) do print (inf, nan) print(nan, nan). But it has a different behavior for int or long division which is (0, 0).

    EDIT: I meant print (nan, nan).

  14. seberg commented on May 5, 2020

    @seberg
    Member

    Ah, thanks for making it more clear. Right for integers it is a bit more tricky, since the only other thing we could do is either always raise or return INT_MIN, which is also not ideal... I wonder if we have any prior art somewhere... What does C do?

  15. anirudh2290 commented on May 5, 2020

    @anirudh2290
    Member

    for c 1/0 is undefined behavior, on my compiler it gives floating point error core dumped. 1.0/0.0 returns inf, conforming to IEEE754 standard.

  16. anirudh2290 commented on May 5, 2020

    @anirudh2290
    Member

    Ah, thanks for making it more clear. Right for integers it is a bit more tricky, since the only other thing we could do is either always raise or return INT_MIN, which is also not ideal... I wonder if we have any prior art somewhere... What does C do?

    This may be a stupid question but why can't we have the same behavior for int and float, that is set the div error and return inf and nan.

  17. anirudh2290 commented on May 5, 2020

    @anirudh2290
    Member

    Ah, thanks for making it more clear. Right for integers it is a bit more tricky, since the only other thing we could do is either always raise or return INT_MIN, which is also not ideal... I wonder if we have any prior art somewhere... What does C do?

    This may be a stupid question but why can't we have the same behavior for int and float, that is set the div error and return inf and nan.

    okay, my bad. inf doesnt really make sense for int.

  18. anirudh2290 commented on May 5, 2020

    @anirudh2290
    Member

    I wonder if we have any prior art somewhere...

    Digging into some history, I found this : #7510 , which raises ValueError, the discussion that happened on the issue seems to have converged to this comment : #7510 (comment) . I guess we decided to incrementally fix this and raise ValueError wherever we find such cases ?

  19. anirudh2290 commented on May 5, 2020

    @anirudh2290
    Member

    np.power(0, -1) today:

    >>> np.power(0, -1)
    
    Evaluating ufunc power
    Getting arguments
    Finding inner loop
    input types:
    dtype('int64') dtype('int64')
    output types:
    dtype('int64')
    Executing legacy inner loop
    trivial 2 input with allocated output
    three operand loop count 1
    Returning failure code -1
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: Integers to negative integer powers are not allowed.
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions