Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

classic Classic list List threaded Threaded
31 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

cool-RR
While debugging my code I found that the bug was because I assumed that something like `divmod(float('inf'), 1)` would be equal to `(float('inf'), float('nan'))`, while Python returns `(float('nan'), float('nan'))`. Why does Python make the division result be NaN in this case? `float('inf') / 1` is still `float('inf')`.


Thanks,
Ram.


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Terry Reedy
On 9/16/2014 5:40 PM, cool-RR wrote:
> While debugging my code I found that the bug was because I assumed
> that something like `divmod(float('inf'), 1)` would be equal to
> `(float('inf'), float('nan'))`,  while Python returns `(float('nan'),
> float('nan'))`. Why does Python make the division result be NaN in
> this case? `float('inf') / 1` is still `float('inf')`.

For integers, divmod(x, y) is defined as (x // y, x % y) == ((x - x%y)
// y, x % y) == ((x - x%y) / y, x % y).

For floats, Python is documented as using the third expression.

"Help on built-in function divmod in module builtins:
divmod(...)
     divmod(x, y) -> (div, mod)
     Return the tuple ((x-x%y)/y, x%y).  Invariant: div*y + mod == x."

It does not really matter, however, as infinity cannot be 'floored' as
required for //

 >>> math.floor(float('inf'))
Traceback (most recent call last):
   File "<pyshell#21>", line 1, in <module>
     math.floor(float('inf'))
OverflowError: cannot convert float infinity to integer

and hence

 >>> float('inf') // 1.0
nan

--
Terry Jan Reedy



Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

cool-RR
In reply to this post by cool-RR
Terry, that doesn't really answer the question "why", it just pushes it back to the documentation. Is there a real answer why? Why return NaN when Inf would make mathematical sense?

On Wednesday, September 17, 2014 4:13:38 AM UTC+3, Terry Reedy wrote:

> On 9/16/2014 5:40 PM, cool-RR wrote:
>
> > While debugging my code I found that the bug was because I assumed
>
> > that something like `divmod(float('inf'), 1)` would be equal to
>
> > `(float('inf'), float('nan'))`,  while Python returns `(float('nan'),
>
> > float('nan'))`. Why does Python make the division result be NaN in
>
> > this case? `float('inf') / 1` is still `float('inf')`.
>
>
>
> For integers, divmod(x, y) is defined as (x // y, x % y) == ((x - x%y)
>
> // y, x % y) == ((x - x%y) / y, x % y).
>
>
>
> For floats, Python is documented as using the third expression.
>
>
>
> "Help on built-in function divmod in module builtins:
>
> divmod(...)
>
>      divmod(x, y) -> (div, mod)
>
>      Return the tuple ((x-x%y)/y, x%y).  Invariant: div*y + mod == x."
>
>
>
> It does not really matter, however, as infinity cannot be 'floored' as
>
> required for //
>
>
>
>  >>> math.floor(float('inf'))
>
> Traceback (most recent call last):
>
>    File "<pyshell#21>", line 1, in <module>
>
>      math.floor(float('inf'))
>
> OverflowError: cannot convert float infinity to integer
>
>
>
> and hence
>
>
>
>  >>> float('inf') // 1.0
>
> nan
>
>
>
> --
>
> Terry Jan Reedy



Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Chris Angelico
On Thu, Sep 18, 2014 at 12:55 AM, cool-RR <ram.rachum at gmail.com> wrote:
> Terry, that doesn't really answer the question "why", it just pushes it back to the documentation. Is there a real answer why? Why return NaN when Inf would make mathematical sense?
>

To answer that, we have to first look at what it means to do
operations on Inf. The definition of "Infinity + 1" is the limit of "x
+ 1" as x goes toward positive infinity - which is positive infinity.
Same with infinity-1, infinity/1, infinity*1, etc, etc, etc. So far,
so good. But as x tends toward positive infinity, the value of "x //
1" (or simply of floor(x)) doesn't simply increase tidily. It goes up
in little jumps, every time x reaches a new integer. And while it's
conceivable to define that infinity divided by anything is infinity,
and infinity modulo anything is zero, that raises serious issues of
primality and such; I'm not sure that that would really help anything.
So there's no possible value for floor division of infinity, ergo the
result is NaN.

So. There you have an answer. Now, for your next question, can you
please use something better than Google Groups, or at least learn how
to use an interleaved posting style and trim out all the excess blank
lines? Thanks.

ChrisA


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

cool-RR
In reply to this post by cool-RR
On Wednesday, September 17, 2014 6:10:35 PM UTC+3, Chris Angelico wrote:

> On Thu, Sep 18, 2014 at 12:55 AM, cool-RR <ram.rachum at gmail.com> wrote:
> > Terry, that doesn't really answer the question "why", it just pushes it back to the documentation. Is there a real answer why? Why return NaN when Inf would make mathematical sense?
> >
> To answer that, we have to first look at what it means to do
> operations on Inf. The definition of "Infinity + 1" is the limit of "x
> + 1" as x goes toward positive infinity - which is positive infinity.
> Same with infinity-1, infinity/1, infinity*1, etc, etc, etc. So far,
> so good. But as x tends toward positive infinity, the value of "x //
> 1" (or simply of floor(x)) doesn't simply increase tidily. It goes up
> in little jumps, every time x reaches a new integer.

Despite the fact it goes up in jump, it still satisfies the mathematical condition needed for a limit. (I won't quote the epsilon-delta thing but I think you can find it.)

> And while it's
> conceivable to define that infinity divided by anything is infinity,
> and infinity modulo anything is zero, that raises serious issues of
> primality and such;
> I'm not sure that that would really help anything.

I didn't ask for the modulo, I agree it should remain NaN. I'm talking about the floor division. I don't see any problems this will cause with primality. "I'm not sure that that would really help anything" is a little bit too vague.


Thanks,
Ram.


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Chris Angelico
On Thu, Sep 18, 2014 at 1:16 AM, cool-RR <ram.rachum at gmail.com> wrote:
> I didn't ask for the modulo, I agree it should remain NaN. I'm talking about the floor division.
>

Invariant: div*y + mod == x.

If mod is NaN, there is no possible value for div that will make the
invariant true, ergo it too has to be NaN.

ChrisA


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Ian Kelly-2
On Wed, Sep 17, 2014 at 9:29 AM, Chris Angelico <rosuav at gmail.com> wrote:
> On Thu, Sep 18, 2014 at 1:16 AM, cool-RR <ram.rachum at gmail.com> wrote:
>> I didn't ask for the modulo, I agree it should remain NaN. I'm talking about the floor division.
>>
>
> Invariant: div*y + mod == x.
>
> If mod is NaN, there is no possible value for div that will make the
> invariant true, ergo it too has to be NaN.

That still doesn't make the invariant true. By this argument div could
be 42, and the invariant would hold equally well (i.e. not at all).


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Ian Kelly-2
In reply to this post by Terry Reedy
On Tue, Sep 16, 2014 at 7:12 PM, Terry Reedy <tjreedy at udel.edu> wrote:

> It does not really matter, however, as infinity cannot be 'floored' as
> required for //
>
>>>> math.floor(float('inf'))
> Traceback (most recent call last):
>   File "<pyshell#21>", line 1, in <module>
>     math.floor(float('inf'))
> OverflowError: cannot convert float infinity to integer
>
> and hence
>
>>>> float('inf') // 1.0
> nan

In C, floor(INFINITY) returns infinity (at least in the implementation
I just tested).


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Chris Angelico
In reply to this post by Ian Kelly-2
On Thu, Sep 18, 2014 at 1:34 AM, Ian Kelly <ian.g.kelly at gmail.com> wrote:

> On Wed, Sep 17, 2014 at 9:29 AM, Chris Angelico <rosuav at gmail.com> wrote:
>> On Thu, Sep 18, 2014 at 1:16 AM, cool-RR <ram.rachum at gmail.com> wrote:
>>> I didn't ask for the modulo, I agree it should remain NaN. I'm talking about the floor division.
>>>
>>
>> Invariant: div*y + mod == x.
>>
>> If mod is NaN, there is no possible value for div that will make the
>> invariant true, ergo it too has to be NaN.
>
> That still doesn't make the invariant true. By this argument div could
> be 42, and the invariant would hold equally well (i.e. not at all).

Nothing can possibly make it true, so there are only two
possibilities: return NaN, or raise an exception.

ChrisA


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Ian Kelly-2
On Wed, Sep 17, 2014 at 9:40 AM, Chris Angelico <rosuav at gmail.com> wrote:

> On Thu, Sep 18, 2014 at 1:34 AM, Ian Kelly <ian.g.kelly at gmail.com> wrote:
>> On Wed, Sep 17, 2014 at 9:29 AM, Chris Angelico <rosuav at gmail.com> wrote:
>>> On Thu, Sep 18, 2014 at 1:16 AM, cool-RR <ram.rachum at gmail.com> wrote:
>>>> I didn't ask for the modulo, I agree it should remain NaN. I'm talking about the floor division.
>>>>
>>>
>>> Invariant: div*y + mod == x.
>>>
>>> If mod is NaN, there is no possible value for div that will make the
>>> invariant true, ergo it too has to be NaN.
>>
>> That still doesn't make the invariant true. By this argument div could
>> be 42, and the invariant would hold equally well (i.e. not at all).
>
> Nothing can possibly make it true, so there are only two
> possibilities: return NaN, or raise an exception.

I could see raising an exception, since the docs state "the result is
(q, a % b), where q is usually math.floor(a / b) but may be 1 less
than that" and it's already been established that
math.floor(float('inf')) raises an exception (although interesting
note: in Python 2 the docs claimed the same thing, but
math.floor(float('inf')) returned float('inf') and divmod already
returned float('nan'); so I don't think that the behavior of
math.floor is really the origin of this).

But the point I'm trying to make is that returning NaN here is every
bit as arbitrary as returning None or False, because there *is* a
value that makes actual mathematical sense to return, even if it fails
to maintain the invariant on account of the modulus addition (which
should just be omitted in this case).

Here's another edge case that fails the invariant. Why should divmod
return inf here but not in the first case?

>>> divmod(1e300, 1e-300)
(inf, 4.891554850853602e-301)
>>> _[0] * 1e-300 + _[1]
inf


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Ian Kelly-2
In reply to this post by Chris Angelico
On Wed, Sep 17, 2014 at 9:40 AM, Chris Angelico <rosuav at gmail.com> wrote:

> On Thu, Sep 18, 2014 at 1:34 AM, Ian Kelly <ian.g.kelly at gmail.com> wrote:
>> On Wed, Sep 17, 2014 at 9:29 AM, Chris Angelico <rosuav at gmail.com> wrote:
>>> On Thu, Sep 18, 2014 at 1:16 AM, cool-RR <ram.rachum at gmail.com> wrote:
>>>> I didn't ask for the modulo, I agree it should remain NaN. I'm talking about the floor division.
>>>>
>>>
>>> Invariant: div*y + mod == x.
>>>
>>> If mod is NaN, there is no possible value for div that will make the
>>> invariant true, ergo it too has to be NaN.
>>
>> That still doesn't make the invariant true. By this argument div could
>> be 42, and the invariant would hold equally well (i.e. not at all).
>
> Nothing can possibly make it true, so there are only two
> possibilities: return NaN, or raise an exception.

Actually, I think we're focusing on the wrong element of the tuple.
The fact is that there are values that can make the invariant true.
For example, divmod(inf, 1) could return (inf, 0).  inf * 1 + 0 = inf.
(inf, 1), or (inf, <any finite value>) would work equally well.  The
*only* reason the invariant can't be maintained is because we're
committed to returning nan for the second element for some reason.


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

cool-RR
In reply to this post by cool-RR
On Wednesday, September 17, 2014 6:30:04 PM UTC+3, Chris Angelico wrote:
> On Thu, Sep 18, 2014 at 1:16 AM, cool-RR <ram.rachum at gmail.com> wrote:
> > I didn't ask for the modulo, I agree it should remain NaN. I'm talking about the floor division.
>
> Invariant: div*y + mod == x.
> If mod is NaN, there is no possible value for div that will make the
> invariant true, ergo it too has to be NaN.
> ChrisA

Chris, why is this invariant `div*y + mod == x` so important? Maybe it's more important to return a mathematically reasonable result for the the floor-division result than to maintain this invariant?


Thanks,
Ram.


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Chris Angelico
On Thu, Sep 18, 2014 at 2:33 AM, cool-RR <ram.rachum at gmail.com> wrote:

> On Wednesday, September 17, 2014 6:30:04 PM UTC+3, Chris Angelico wrote:
>> On Thu, Sep 18, 2014 at 1:16 AM, cool-RR <ram.rachum at gmail.com> wrote:
>> > I didn't ask for the modulo, I agree it should remain NaN. I'm talking about the floor division.
>>
>> Invariant: div*y + mod == x.
>> If mod is NaN, there is no possible value for div that will make the
>> invariant true, ergo it too has to be NaN.
>> ChrisA
>
> Chris, why is this invariant `div*y + mod == x` so important? Maybe it's more important to return a mathematically reasonable result for the the floor-division result than to maintain this invariant?

It's important because it's documented :) You can expect whatever you
like, but if something's a documented invariant, that's more important
than your expectations.

Now, why was divmod documented as returning values adhering to that
invariant? You'd have to ask the developers, I've no idea.

ChrisA


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Ian Kelly-2
In reply to this post by Chris Angelico
On Wed, Sep 17, 2014 at 9:10 AM, Chris Angelico <rosuav at gmail.com> wrote:
> And while it's
> conceivable to define that infinity divided by anything is infinity,
> and infinity modulo anything is zero, that raises serious issues of
> primality and such; I'm not sure that that would really help anything.

I missed that this point was already discussed. Can you elaborate on
the "serious issues of primality and such"? Since infinity is not a
natural number, its primality is undefined, so I don't see the issue
here.


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Chris Angelico
On Thu, Sep 18, 2014 at 4:03 AM, Ian Kelly <ian.g.kelly at gmail.com> wrote:

> On Wed, Sep 17, 2014 at 9:10 AM, Chris Angelico <rosuav at gmail.com> wrote:
>> And while it's
>> conceivable to define that infinity divided by anything is infinity,
>> and infinity modulo anything is zero, that raises serious issues of
>> primality and such; I'm not sure that that would really help anything.
>
> I missed that this point was already discussed. Can you elaborate on
> the "serious issues of primality and such"? Since infinity is not a
> natural number, its primality is undefined, so I don't see the issue
> here.

It's not something I've personally worked with, so I'm trying to
dredge stuff up from my brain, but I think there's something along the
lines of "stuff shouldn't be a multiple of everything" and the Prime
Number Theorem. But that may just be a case where float != real.

ChrisA


Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Terry Reedy
In reply to this post by cool-RR
On 9/17/2014 10:55 AM, cool-RR wrote:
> Terry, that doesn't really answer the question "why", it just pushes
> it back to the documentation. Is there a real answer why? Why return
> NaN when Inf would make mathematical sense?

IEEE float('inf') and float('nan') are engineering, not math constructs.
I showed that the result is consistent with the math definition.
Another result (including raising) might be also.  Many choices
concerting inf and nan are arbitrary and any 'why' can be debated.

--
Terry Jan Reedy



Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Steven D'Aprano-11
In reply to this post by Ian Kelly-2
Chris Angelico wrote:

> On Thu, Sep 18, 2014 at 1:34 AM, Ian Kelly <ian.g.kelly at gmail.com> wrote:
>> On Wed, Sep 17, 2014 at 9:29 AM, Chris Angelico <rosuav at gmail.com> wrote:

>>> Invariant: div*y + mod == x.
>>>
>>> If mod is NaN, there is no possible value for div that will make the
>>> invariant true, ergo it too has to be NaN.
>>
>> That still doesn't make the invariant true. By this argument div could
>> be 42, and the invariant would hold equally well (i.e. not at all).
>
> Nothing can possibly make it true, so there are only two
> possibilities: return NaN, or raise an exception.

If nothing can make it true, then it is not an invariant, and your argument
is no longer valid.



--
Steven



Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Steven D'Aprano-11
In reply to this post by cool-RR
cool-RR wrote:

> Chris, why is this invariant `div*y + mod == x` so important? Maybe it's
> more important to return a mathematically reasonable result for the the
> floor-division result than to maintain this invariant?

You keep talking about floor(inf) == inf being "mathematically reasonable",
but I'm not convinced that it is. Can you justify why you think it is
mathematically reasonable? Remember that IEEE-754 inf represents two
different concepts:

(1) A large but finite number which has overflowed.

(2) Actual mathematical infinity ?.

Even in the case of actual mathematical infinity[1], the result of floor(?)
isn't clear to me. Floor is supposed to return an integer, how do you know
that ? is integer valued? You can do ? % 1 to see what the fractional part
is, but that gives NaN, so justify your belief that ? is integer-valued.



[1] But *which* mathematical infinity? One of the cardinal infinities, the
alephs, or one of the ordinal infinities, the omegas and the epsilons?
(There are an infinite number of *all three*.) Is c just another name for
aleph-1, or is distinct from all the alephs? Even professional
mathematicians tread warily when doing arithmetic on infinities.

--
Steven



Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Steven D'Aprano-11
In reply to this post by Ian Kelly-2
Chris Angelico wrote:

> On Thu, Sep 18, 2014 at 4:03 AM, Ian Kelly <ian.g.kelly at gmail.com> wrote:
>> On Wed, Sep 17, 2014 at 9:10 AM, Chris Angelico <rosuav at gmail.com> wrote:
>>> And while it's
>>> conceivable to define that infinity divided by anything is infinity,
>>> and infinity modulo anything is zero, that raises serious issues of
>>> primality and such; I'm not sure that that would really help anything.
>>
>> I missed that this point was already discussed. Can you elaborate on
>> the "serious issues of primality and such"? Since infinity is not a
>> natural number, its primality is undefined, so I don't see the issue
>> here.
>
> It's not something I've personally worked with, so I'm trying to
> dredge stuff up from my brain, but I think there's something along the
> lines of "stuff shouldn't be a multiple of everything" and the Prime
> Number Theorem. But that may just be a case where float != real.

I don't think that the Prime Number Theorem has anything to say about
transfinite numbers (infinities). It says that for sufficiently large
values of n, the number of primes below n asymptotically approaches the the
integral of 1/ln(x) between 2 and n:

?(n) ~ Li(n)

(Note that in this case, ? is not pi = 3.1414... but is the "prime counting
function", thus proving that no matter how famous or well-known a
particular mathematical symbol is, somebody will insist on using it for
something else.)

http://mathworld.wolfram.com/PrimeNumberTheorem.html

Perhaps you are thinking of the Fundamental Theorem of Arithmetic, which
states that every positive integer except 1 can be uniquely factorized into
a product of one or more primes?

http://mathworld.wolfram.com/FundamentalTheoremofArithmetic.html

But that doesn't apply to infinity, which isn't an integer.


--
Steven



Reply | Threaded
Open this post in threaded view
|

Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

Chris Angelico
On Thu, Sep 18, 2014 at 1:29 PM, Steven D'Aprano
<steve+comp.lang.python at pearwood.info> wrote:
> Perhaps you are thinking of the Fundamental Theorem of Arithmetic, which
> states that every positive integer except 1 can be uniquely factorized into
> a product of one or more primes?
>
> http://mathworld.wolfram.com/FundamentalTheoremofArithmetic.html
>
> But that doesn't apply to infinity, which isn't an integer.

May have been that, or maybe was something different altogether. I was
trying to relocate the info I'd been reading (ages ago), but without
success. To be honest, I was hoping someone else would do the "Of
course, I know what you mean" part for me :) But it's ended up more
like the Goon Show: "How do you intend tipping Mount Everest on its
side?" "Well, isn't it obvious?" with no result forthcoming. Sorry for
the noise!

Infinities are plenty weird, just this one specific weirdness wasn't right.

ChrisA


12