Why does “np.inf // 2” result in NaN and not infinity?
Asked Answered
M

3

41

I’m slightly disappointed that np.inf // 2 evaluates to np.nan and not to np.inf, as is the case for normal division.

Is there a reason I’m missing why nan is a better choice than inf?

Mellie answered 11/8, 2020 at 17:6 Comment(13)
It could be that floor_divide is more efficient than doing both operations separately.Muffin
I'd say inf would be an incorrect result of integer division because inf is not an integer. Now nan isn't an integer either, but at least it somehow expresses the fact that there is no correct answer to the question that was asked, i.e. there is no integer x such that x*2 equals inf. That's my take on it anyway.Eyed
@0x5453 - You are correct. So the question is why, here too, nan was considered a better choice than inf?Mellie
@Eyed - Would you consider then np.floor(np.inf) resulting in np.inf a correct result? You could claim there is no correct integer answer to this question as well.Mellie
@Eyed I agree with your answer in general, although I’m not sure the reason is because np.inf is not an integer. 13.2 // 2 returns 6.0. 13.2 and np.inf are both type float.Corrigan
@Eyed float('inf')*2 returns inf.Muffin
@Corrigan I still agree with the answer (that is in the comments for some reason). Integer division yields an integer. Yes the typing was changed such that it will be an integer represented as a float when floating point numbers are involved, but their is no integer representation of infinity.Nalda
@MarkRansom I think what was said still holds considering float('inf') isn't an integerNalda
@Nalda it's not called integer division though, it's called floor division. That means floating point numbers can be included without introducing any anomalies.Muffin
@Mellie yes, because floor(x) always differs from x by some finite value between 0 and 1, and the result of that subtraction would be Inf (according to IEEE semantics) no matter what value in that range was chosen.Hospitaler
@Mellie the general rule is that operations on Inf should give the limiting value of the same operation on ordinary numbers, unless that limit is indeterminate, in which case you get NaN. So floor(inf) == inf and floor(-inf) == -inf. And indeed POSIX floor does give that result.Hospitaler
I don't have an IEEE-754 spec at hand but according to this IEEE-754 requires INF - INF = NaN, (+/-)INF / (+/-)INF = NaN, and (+/-)INF * 0 = NaN. No idea about INF/x thoughTamp
@phuclv: Pretty sure INF divided by anything except INF or NaN is still +-INF. But that's for regular division, not floor-division; IDK if IEEE-754 defines that operation at all; C doesn't have it and real-world FPUs don't have it. (You can set the rounding mode to truncate or towards -Inf and still get Inf.)Frausto
L
33

I'm going to be the person who just points at the C level implementation without any attempt to explain intent or justification:

*mod = fmod(vx, wx);
div = (vx - *mod) / wx;

It looks like in order to calculate divmod for floats (which is called when you just do floor division) it first calculates the modulus and float('inf') %2 only makes sense to be NaN, so when it calculates vx - mod it ends up with NaN so everything propagates nan the rest of the way.

So in short, since the implementation of floor division uses modulus in the calculation and that is NaN, the result for floor division also ends up NaN

Lorenza answered 11/8, 2020 at 20:1 Comment(6)
If this really is the C code that implements floor division for floats, it's probably correct but very unsatisfying. You're really just kicking the can down the road.Muffin
yeah I recognize that, I'd very much like to see a better answer. However it is possible the reasoning is "no one has really considered it until now" in which case I'm afraid this may be the only answer.Lorenza
Why not just have a single line where *mod in div = (vx - *mod) / wx; is replaced by the part after the equal mark above it ?Sipper
@Sipper that is the source code calculating both the modulus and floor division, it needs to retain the modulus.Lorenza
@TadhgMcDonald-Jensen So the value is reused later ?Sipper
@Sipper If you follow the link in the answer, you will see for yourself how it is used.Lorenza
M
25

Floor division is defined in relation to modulo, both forming one part of the divmod operation.

Binary arithmetic operations

The floor division and modulo operators are connected by the following identity: x == (x//y)*y + (x%y). Floor division and modulo are also connected with the built-in function divmod(): divmod(x, y) == (x//y, x%y).

This equivalence cannot hold for x = inf — the remainder inf % y is undefined — making inf // y ambiguous. This means nan is at least as good a result as inf. For simplicity, CPython actually only implements divmod and derives both // and % by dropping a part of the result — this means // inherits nan from divmod.

Marijn answered 11/8, 2020 at 20:27 Comment(0)
P
1

Infinity is not a number. For example, you can't even say that infinity - infinity is zero. So you're going to run into limitations like this because NumPy is a numerical math package. I suggest using a symbolic math package like SymPy which can handle many different expressions using infinity:

import sympy as sp

sp.floor(sp.oo/2)
sp.oo - 1
sp.oo + sp.oo
Peewee answered 26/8, 2020 at 17:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.