Fwd: Make `float('inf') //1 == float('inf')`
---------- Forwarded message ---------- From: Ian Cordasco <graffatcolmingov@gmail.com> Date: Wed, Sep 17, 2014 at 4:51 PM Subject: Re: [Python-ideas] Make `float('inf') //1 == float('inf')` To: Ram Rachum <ram.rachum@gmail.com> Cc: "python-ideas@googlegroups.com" <python-ideas@googlegroups.com> On Wed, Sep 17, 2014 at 11:42 AM, Ram Rachum <ram.rachum@gmail.com> wrote:
Please see this discussion on python-list:
https://groups.google.com/forum/#!topic/comp.lang.python/maDZoc-n4bA
Currently `float('inf') //1` is equal to NaN. I think that this is really weird. If I understand correctly it's to maintain the invariant `div*y + mod == x`. The question is, do we really care more about maintaining this invariant rather than providing a mathematically reasonable value for floor division?
Actually there are 2 things here: 1. Mathematically speaking, infinity is a real number and modulo arithmetic is algebraically not defined for it. So the "mathematically reasonable value" is NaN. Is it intuitive for someone who hasn't studied abstract algebra? Probably not. Is it functional for the scientific python community? Almost certainly although I won't pretend to speak on their behalf 2. Changing this behaviour is not something I think we should do in a minor version of 3.4 or in 3.5 (or really 3.x).
On 18 September 2014 07:52, Ian Cordasco <graffatcolmingov@gmail.com> wrote:
Actually there are 2 things here:
1. Mathematically speaking, infinity is a real number and modulo arithmetic is algebraically not defined for it. So the "mathematically reasonable value" is NaN. Is it intuitive for someone who hasn't studied abstract algebra? Probably not. Is it functional for the scientific python community? Almost certainly although I won't pretend to speak on their behalf
Right, as with NaN, infinity is a concept rather than a value. The fact that they both map to "kinda sorta values" in a programming language like Python is a limitation of the computer's underlying representational system, and the end result is a leaky abstraction that has some weird artefacts like this one (the fact that key lookup based containers enforce reflexivity, even though floating point NaN comparisons are explicitly defined as non-reflexive, is another). There's no real way to make floating point arithmetic "not surprising" as soon as NaN and infinities get involved (while I'd be surprised if anyone was inclined to dispute that, here's a fun link on the "infinite values" side that will hopefully deter the unduly optimistic: https://en.wikipedia.org/wiki/Aleph_number).
2. Changing this behaviour is not something I think we should do in a minor version of 3.4 or in 3.5 (or really 3.x).
For a topic as inherently confusing as infinite values, I believe it would take a battery of extensive usability studies to make the case that any change in behaviour from the status quo would be worth the hassle, and most researchers are going to have more interesting things to do with their time. Some of the things we changed in the Python 3 transition (like rearranging modules) were based on intuition as to what would be easier for newcomers to learn, and if I learned anything from that, it's to rely more heavily on the ethos of "status quo wins a stalemate" when it comes to the way we represent concepts that are just plain hard to learn in their own right. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
For the record, this gives inf in Numpy.
import numpy numpy.array(float('inf')) // 1 inf
AFAIK this and http://bugs.python.org/issue22198 are the only differences from Python floats, at least on my machine. On Thu, Sep 18, 2014 at 12:08 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On 18 September 2014 07:52, Ian Cordasco <graffatcolmingov@gmail.com> wrote:
Actually there are 2 things here:
1. Mathematically speaking, infinity is a real number and modulo arithmetic is algebraically not defined for it. So the "mathematically reasonable value" is NaN. Is it intuitive for someone who hasn't studied abstract algebra? Probably not. Is it functional for the scientific python community? Almost certainly although I won't pretend to speak on their behalf
Right, as with NaN, infinity is a concept rather than a value. The fact that they both map to "kinda sorta values" in a programming language like Python is a limitation of the computer's underlying representational system, and the end result is a leaky abstraction that has some weird artefacts like this one (the fact that key lookup based containers enforce reflexivity, even though floating point NaN comparisons are explicitly defined as non-reflexive, is another).
There's no real way to make floating point arithmetic "not surprising" as soon as NaN and infinities get involved (while I'd be surprised if anyone was inclined to dispute that, here's a fun link on the "infinite values" side that will hopefully deter the unduly optimistic: https://en.wikipedia.org/wiki/Aleph_number).
2. Changing this behaviour is not something I think we should do in a minor version of 3.4 or in 3.5 (or really 3.x).
For a topic as inherently confusing as infinite values, I believe it would take a battery of extensive usability studies to make the case that any change in behaviour from the status quo would be worth the hassle, and most researchers are going to have more interesting things to do with their time.
Some of the things we changed in the Python 3 transition (like rearranging modules) were based on intuition as to what would be easier for newcomers to learn, and if I learned anything from that, it's to rely more heavily on the ethos of "status quo wins a stalemate" when it comes to the way we represent concepts that are just plain hard to learn in their own right.
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Sep 18, 2014 2:31 AM, "Petr Viktorin" <encukou@gmail.com> wrote:
For the record, this gives inf in Numpy.
import numpy numpy.array(float('inf')) // 1 inf
AFAIK this and http://bugs.python.org/issue22198 are the only differences from Python floats, at least on my machine.
That's an interesting bug report and it's significantly different (mathematically speaking) from the discussion here. That aside, I have to wonder if numpy has its own way of representing infinity and how that behaves. I still maintain that it's least surprising for float('inf') // 1 to be NaN. You're trying to satisfy float('inf') = mod + 1 * y and in this case mod and y are both indeterminate (because this is basically a nonsensical equation).
On Thu, Sep 18, 2014 at 3:38 PM, Ian Cordasco <graffatcolmingov@gmail.com> wrote:
On Sep 18, 2014 2:31 AM, "Petr Viktorin" <encukou@gmail.com> wrote:
For the record, this gives inf in Numpy.
import numpy numpy.array(float('inf')) // 1 inf
AFAIK this and http://bugs.python.org/issue22198 are the only differences from Python floats, at least on my machine.
That's an interesting bug report and it's significantly different (mathematically speaking) from the discussion here. That aside, I have to wonder if numpy has its own way of representing infinity and how that behaves. I still maintain that it's least surprising for float('inf') // 1 to be NaN. You're trying to satisfy float('inf') = mod + 1 * y and in this case mod and y are both indeterminate (because this is basically a nonsensical equation).
Well, in `x = y // a`, as y tends towards infinity, x will also tend towards infinity, though in discrete steps. Yes, you get an indeterminate value, but one that's larger than any real number. Are any Numpy developers around? Is there a reason it has different behavior from Python?
On Thu, Sep 18, 2014 at 9:09 AM, Petr Viktorin <encukou@gmail.com> wrote:
On Thu, Sep 18, 2014 at 3:38 PM, Ian Cordasco <graffatcolmingov@gmail.com> wrote:
On Sep 18, 2014 2:31 AM, "Petr Viktorin" <encukou@gmail.com> wrote:
For the record, this gives inf in Numpy.
import numpy numpy.array(float('inf')) // 1 inf
AFAIK this and http://bugs.python.org/issue22198 are the only differences from Python floats, at least on my machine.
That's an interesting bug report and it's significantly different (mathematically speaking) from the discussion here. That aside, I have to wonder if numpy has its own way of representing infinity and how that behaves. I still maintain that it's least surprising for float('inf') // 1 to be NaN. You're trying to satisfy float('inf') = mod + 1 * y and in this case mod and y are both indeterminate (because this is basically a nonsensical equation).
Well, in `x = y // a`, as y tends towards infinity, x will also tend towards infinity, though in discrete steps. Yes, you get an indeterminate value, but one that's larger than any real number.
Sorry? If you've studied mathematics you'd know there's no discrete value that is the same as infinity. I'm not even sure how anyone could begin define floor(infinity). Infinity is not present in any discrete set. Yes float('inf') / 1 should be float('inf'), no one is arguing that. That's easily shown through limits. floor(float('inf') / 1) has no intrinsic meaning. Discrete sets such as the naturals, integers, and rationals are all "countably infinite" but there's no bijective mapping between them and the real numbers (and therefore, no such mapping to the complex numbers) because the are uncountably infinite real numbers. I understand that intuitively float('inf') // 1 being equal to infinity is nice, but it is inherently undefined. We don't really have the concept of undefined so NaN seems most acceptable.
Are any Numpy developers around? Is there a reason it has different behavior from Python?
I expect because of np.array semantics it is different. I'm not sure if it's intentional or if it's a bug, but I'm curious as well.
On 2014-09-18 16:20, Ian Cordasco wrote:
On Thu, Sep 18, 2014 at 9:09 AM, Petr Viktorin <encukou@gmail.com> wrote:
On Thu, Sep 18, 2014 at 3:38 PM, Ian Cordasco <graffatcolmingov@gmail.com> wrote:
On Sep 18, 2014 2:31 AM, "Petr Viktorin" <encukou@gmail.com> wrote:
For the record, this gives inf in Numpy.
> import numpy > numpy.array(float('inf')) // 1 inf
AFAIK this and http://bugs.python.org/issue22198 are the only differences from Python floats, at least on my machine.
That's an interesting bug report and it's significantly different (mathematically speaking) from the discussion here. That aside, I have to wonder if numpy has its own way of representing infinity and how that behaves. I still maintain that it's least surprising for float('inf') // 1 to be NaN. You're trying to satisfy float('inf') = mod + 1 * y and in this case mod and y are both indeterminate (because this is basically a nonsensical equation).
Well, in `x = y // a`, as y tends towards infinity, x will also tend towards infinity, though in discrete steps. Yes, you get an indeterminate value, but one that's larger than any real number.
Sorry? If you've studied mathematics you'd know there's no discrete value that is the same as infinity. [snip] He didn't say that infinity was a discrete value, he said that x will tend towards infinity in discrete steps.
On Thu, Sep 18, 2014 at 11:20 AM, Ian Cordasco <graffatcolmingov@gmail.com> wrote:
I understand that intuitively float('inf') // 1 being equal to infinity is nice, but it is inherently undefined. We don't really have the concept of undefined so NaN seems most acceptable.
The most acceptable would be to have x // 1 do the same as math.floor(x) for any float x. Note that math.floor() behavior changed from 2.x to 3.x: Python 2.7.7:
math.floor(float('inf')) inf
Python 3.4.1:
math.floor(float('inf')) Traceback (most recent call last): File "<stdin>", line 1, in <module> OverflowError: cannot convert float infinity to integer
It looks like float // float case was overlooked when it was decided that math.floor() should return int.
On Thu, Sep 18, 2014 at 11:48 AM, Alexander Belopolsky < alexander.belopolsky@gmail.com> wrote:
It looks like float // float case was overlooked when it was decided that math.floor() should return int.
Note that PEP 3141 specifies that Real.__floordiv__ should return an integer. http://legacy.python.org/dev/peps/pep-3141/
On Thu, Sep 18, 2014 at 5:20 PM, Ian Cordasco <graffatcolmingov@gmail.com> wrote:
On Thu, Sep 18, 2014 at 9:09 AM, Petr Viktorin <encukou@gmail.com> wrote:
On Thu, Sep 18, 2014 at 3:38 PM, Ian Cordasco <graffatcolmingov@gmail.com> wrote:
On Sep 18, 2014 2:31 AM, "Petr Viktorin" <encukou@gmail.com> wrote:
For the record, this gives inf in Numpy.
> import numpy > numpy.array(float('inf')) // 1 inf
AFAIK this and http://bugs.python.org/issue22198 are the only differences from Python floats, at least on my machine.
That's an interesting bug report and it's significantly different (mathematically speaking) from the discussion here. That aside, I have to wonder if numpy has its own way of representing infinity and how that behaves. I still maintain that it's least surprising for float('inf') // 1 to be NaN. You're trying to satisfy float('inf') = mod + 1 * y and in this case mod and y are both indeterminate (because this is basically a nonsensical equation).
Well, in `x = y // a`, as y tends towards infinity, x will also tend towards infinity, though in discrete steps. Yes, you get an indeterminate value, but one that's larger than any real number.
Sorry? If you've studied mathematics you'd know there's no discrete value that is the same as infinity. I'm not even sure how anyone could begin define floor(infinity). Infinity is not present in any discrete set. Yes float('inf') / 1 should be float('inf'), no one is arguing that. That's easily shown through limits. floor(float('inf') / 1) has no intrinsic meaning. Discrete sets such as the naturals, integers, and rationals are all "countably infinite" but there's no bijective mapping between them and the real numbers (and therefore, no such mapping to the complex numbers) because the are uncountably infinite real numbers.
There is even no *real* number that is the same as infinity. The result of // on floats is a float; discrete sets don't come into play. Practically, floor(f) is f minus a value between 0 and 1. If you have (x1 = y1 // a) and (x2 = y2 // a) and (y1 < y2 - a), then (x1 < x2); as y grows without bound, x will also grow without bound. Correct me if I'm wrong, I did study math but it is rusty.
I understand that intuitively float('inf') // 1 being equal to infinity is nice, but it is inherently undefined. We don't really have the concept of undefined so NaN seems most acceptable.
I disagree with is the conclusion that NaN is the most appropriate. But the discussion is starting to go in circles here, and I actually don't much care for the actual result.
Are any Numpy developers around? Is there a reason it has different behavior from Python?
I expect because of np.array semantics it is different. I'm not sure if it's intentional or if it's a bug, but I'm curious as well.
What I do care about is that Python and Numpy should give the same result. It would be nice to see this changed in either Python or Numpy, whatever the "correct" result is.
On Thu, Sep 18, 2014 at 05:59:02PM +0200, Petr Viktorin wrote: [...]
Sorry? If you've studied mathematics you'd know there's no discrete value that is the same as infinity. I'm not even sure how anyone could begin define floor(infinity). Infinity is not present in any discrete set. Yes float('inf') / 1 should be float('inf'), no one is arguing that. That's easily shown through limits. floor(float('inf') / 1) has no intrinsic meaning. Discrete sets such as the naturals, integers, and rationals are all "countably infinite" but there's no bijective mapping between them and the real numbers (and therefore, no such mapping to the complex numbers) because the are uncountably infinite real numbers.
There is even no *real* number that is the same as infinity.
Correct. Once we start talking about a value representing infinity, we're being impure and mathematically dubious, regardless of whether we have ints or floats. But more than that, an IEEE-754 infinity doesn't just represent mathematical infinity, but also finite numbers which overflowed. Hence: py> 1.7976931348623157e+308 * 1.1 inf I don't think it is clear what inf//1 should return, which suggests to me that returning a NAN is perhaps less wrong than returning inf. (If we really don't know how to interpret inf//1, then a NAN, or an exception, is the right answer.) [...]
What I do care about is that Python and Numpy should give the same result. It would be nice to see this changed in either Python or Numpy, whatever the "correct" result is.
That is reasonable. -- Steven
On Thu, Sep 18, 2014 at 12:17 PM, Steven D'Aprano <steve@pearwood.info> wrote:
What I do care about is that Python and Numpy should give the same result. It would be nice to see this changed in either Python or Numpy, whatever the "correct" result is.
That is reasonable.
Consistency with NumPy cannot aways be achieved. Note that numpy.floor returns floats while math.floor returns ints. (NumPy cannot follow stdlib here because it does not have arbitrary precision integers.)
On Thu, Sep 18, 2014 at 7:04 PM, Alexander Belopolsky <alexander.belopolsky@gmail.com> wrote:
On Thu, Sep 18, 2014 at 12:17 PM, Steven D'Aprano <steve@pearwood.info> wrote:
What I do care about is that Python and Numpy should give the same result. It would be nice to see this changed in either Python or Numpy, whatever the "correct" result is.
That is reasonable.
Consistency with NumPy cannot aways be achieved. Note that numpy.floor returns floats while math.floor returns ints. (NumPy cannot follow stdlib here because it does not have arbitrary precision integers.)
Right. That particular difference has a reason behind it, however. There is no reason to differ here, except perhaps backwards compatibility. And if backwards compatibility is the reason for Python not changing, it should be documented (as an unfortunate mistake) so other implementations do the same thing. And it should have a test (which I'm happy to write once a decision is reached -- wanting to write a test for floor floatdiv is largely why I'm here debating this).
On Thu, Sep 18, 2014 at 8:20 AM, Ian Cordasco <graffatcolmingov@gmail.com> wrote:
On Thu, Sep 18, 2014 at 9:09 AM, Petr Viktorin <encukou@gmail.com> wrote:
On Thu, Sep 18, 2014 at 3:38 PM, Ian Cordasco <graffatcolmingov@gmail.com> wrote:
On Sep 18, 2014 2:31 AM, "Petr Viktorin" <encukou@gmail.com> wrote:
For the record, this gives inf in Numpy.
> import numpy > numpy.array(float('inf')) // 1 inf
AFAIK this and http://bugs.python.org/issue22198 are the only differences from Python floats, at least on my machine.
That's an interesting bug report and it's significantly different (mathematically speaking) from the discussion here. That aside, I have to wonder if numpy has its own way of representing infinity and how that behaves. I still maintain that it's least surprising for float('inf') // 1 to be NaN. You're trying to satisfy float('inf') = mod + 1 * y and in this case mod and y are both indeterminate (because this is basically a nonsensical equation).
Well, in `x = y // a`, as y tends towards infinity, x will also tend towards infinity, though in discrete steps. Yes, you get an indeterminate value, but one that's larger than any real number.
Sorry? If you've studied mathematics you'd know there's no discrete value that is the same as infinity. I'm not even sure how anyone could begin define floor(infinity). Infinity is not present in any discrete set. Yes float('inf') / 1 should be float('inf'), no one is arguing that. That's easily shown through limits. floor(float('inf') / 1) has no intrinsic meaning. Discrete sets such as the naturals, integers, and rationals are all "countably infinite" but there's no bijective mapping between them and the real numbers (and therefore, no such mapping to the complex numbers) because the are uncountably infinite real numbers.
I understand that intuitively float('inf') // 1 being equal to infinity is nice, but it is inherently undefined. We don't really have the concept of undefined so NaN seems most acceptable.
Are any Numpy developers around? Is there a reason it has different behavior from Python?
I expect because of np.array semantics it is different. I'm not sure if it's intentional or if it's a bug, but I'm curious as well.
The ISO C99/C11 (Annex F) (and POSIX and IEEE-754) standards define a function called "roundToIntegralTowardsNegative". For the special value +Inf, it specifies a return value of +Inf. However, the integral value returned is still an IEEE-754 formatted value and can return +Inf. PEP-3141 changed the behavior of math.floor() (and __floor__ in general) to return an actual integer. That makes it impossible to comply with ISO etc. standards.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Thu, Sep 18, 2014 at 1:27 PM, Case Van Horsen <casevh@gmail.com> wrote:
The ISO C99/C11 (Annex F) (and POSIX and IEEE-754) standards define a function called "roundToIntegralTowardsNegative". For the special value +Inf, it specifies a return value of +Inf.
However, the integral value returned is still an IEEE-754 formatted value and can return +Inf. PEP-3141 changed the behavior of math.floor() (and __floor__ in general) to return an actual integer. That makes it impossible to comply with ISO etc. standards.
I don't think there is any dispute over what math.floor(inf) should return. POSIX, C99, IEEE and probably many other standards agree that inf should be returned as long as the resulting type can represent it. Note that before math.floor() was changed to return int in 3.x, we had
math.floor(float('inf')) inf
(Python 2.7.8) The question here is not about floor, but about floor_division. NumPy implements it as simple-minded floor(x/y), while Python attempts to be more precise by doing floor((x - fmod(x, y))/y). $ hg blame -d -u -w Objects/floatobject.c nascheme Thu Jan 04 01:44:34 2001 +0000: float_divmod(PyObject *v, PyObject *w) .. guido Sun Oct 20 20:16:45 1991 +0000: mod = fmod(vx, wx); tim Sat Sep 16 03:54:24 2000 +0000: /* fmod is typically exact, so vx-mod is *mathematically* an guido Thu May 06 14:26:34 1999 +0000: exact multiple of wx. But this is fp arithmetic, and fp guido Thu May 06 14:26:34 1999 +0000: vx - mod is an approximation; the result is that div may guido Thu May 06 14:26:34 1999 +0000: not be an exact integral value after the division, although guido Thu May 06 14:26:34 1999 +0000: it will always be very close to one. guido Thu May 06 14:26:34 1999 +0000: */ guido Sun Oct 20 20:16:45 1991 +0000: div = (vx - mod) / wx; .. Given that this logic dates back to 1991, I doubt not-finite case was seriously considered. In light of PEP 3141, if anything should be done about float // float it would be to make it return and int and as a consequence inf // 1 should raise an OverflowError.
On Sep 18, 2014 12:31 PM, "Alexander Belopolsky" < alexander.belopolsky@gmail.com> wrote:
On Thu, Sep 18, 2014 at 1:27 PM, Case Van Horsen <casevh@gmail.com> wrote:
The ISO C99/C11 (Annex F) (and POSIX and IEEE-754) standards define a function called "roundToIntegralTowardsNegative". For the special value +Inf, it specifies a return value of +Inf.
However, the integral value returned is still an IEEE-754 formatted value and can return +Inf. PEP-3141 changed the behavior of math.floor() (and __floor__ in general) to return an actual integer. That makes it
to comply with ISO etc. standards.
I don't think there is any dispute over what math.floor(inf) should return. POSIX, C99, IEEE and probably many other standards agree that inf should be returned as long as the resulting type can represent it.
Note that before math.floor() was changed to return int in 3.x, we had
math.floor(float('inf')) inf
(Python 2.7.8)
The question here is not about floor, but about floor_division. NumPy implements it as simple-minded floor(x/y), while Python attempts to be more
impossible precise by doing floor((x - fmod(x, y))/y).
$ hg blame -d -u -w Objects/floatobject.c nascheme Thu Jan 04 01:44:34 2001 +0000: float_divmod(PyObject *v,
PyObject *w)
.. guido Sun Oct 20 20:16:45 1991 +0000: mod = fmod(vx, wx); tim Sat Sep 16 03:54:24 2000 +0000: /* fmod is typically exact, so vx-mod is *mathematically* an guido Thu May 06 14:26:34 1999 +0000: exact multiple of wx. But this is fp arithmetic, and fp guido Thu May 06 14:26:34 1999 +0000: vx - mod is an approximation; the result is that div may guido Thu May 06 14:26:34 1999 +0000: not be an exact integral value after the division, although guido Thu May 06 14:26:34 1999 +0000: it will always be very close to one. guido Thu May 06 14:26:34 1999 +0000: */ guido Sun Oct 20 20:16:45 1991 +0000: div = (vx - mod) / wx; ..
Given that this logic dates back to 1991, I doubt not-finite case was seriously considered.
Right.
In light of PEP 3141, if anything should be done about float // float it would be to make it return and int and as a consequence inf // 1 should raise an OverflowError.
+1
On Thu, Sep 18, 2014 at 9:35 PM, Guido van Rossum <guido@python.org> wrote:
On Sep 18, 2014 12:31 PM, "Alexander Belopolsky" <alexander.belopolsky@gmail.com> wrote:
Right.
In light of PEP 3141, if anything should be done about float // float it would be to make it return and int and as a consequence inf // 1 should raise an OverflowError.
+1
But, is this a good change to make in 3.5? I assume this would apply do __divmod__[0] as well. Should there be a float-only math.divmod?
On Thu, Sep 18, 2014 at 3:35 PM, Guido van Rossum <guido@python.org> wrote:
In light of PEP 3141, if anything should be done about float // float it would be to make it return an int and as a consequence inf // 1 should raise an OverflowError.
+1
I opened http://bugs.python.org/issue22444 for this.
On Thu, Sep 18, 2014 at 12:31 PM, Alexander Belopolsky <alexander.belopolsky@gmail.com> wrote:
On Thu, Sep 18, 2014 at 1:27 PM, Case Van Horsen <casevh@gmail.com> wrote:
The ISO C99/C11 (Annex F) (and POSIX and IEEE-754) standards define a function called "roundToIntegralTowardsNegative". For the special value +Inf, it specifies a return value of +Inf.
However, the integral value returned is still an IEEE-754 formatted value and can return +Inf. PEP-3141 changed the behavior of math.floor() (and __floor__ in general) to return an actual integer. That makes it impossible to comply with ISO etc. standards.
I don't think there is any dispute over what math.floor(inf) should return. POSIX, C99, IEEE and probably many other standards agree that inf should be returned as long as the resulting type can represent it.
I dispute that there is no dispute over what math.floot(inf) should return. ;-) All the standards specify a result type can represent +-Inf and +-0. A standards compliant version should return +-Inf and +-0. lrint() and llrint() are defined to return long or long long, respectively. It would be fine if they raised an exception. The current math.floor() actually behaves more like llrint() than floor(). I accpet that having math.floor() return an integer (and raise an exception for +-Inf) may be useful in many cases but it is different from the standard. Other floating-point libraries still return a floating-point value.
numpy.floor(numpy.float64('Inf')) inf
mpmath.floor(mpmath.mpf('inf')) mpf('+inf')
gmpy2.floor(gmpy2.mpfr('inf')) mpfr('inf')
bigfloat.floor(bigfloat.BigFloat('inf')) BigFloat.exact('Infinity', precision=53)
Disclaimer: I maintain gmpy2.
Note that before math.floor() was changed to return int in 3.x, we had
math.floor(float('inf')) inf
(Python 2.7.8)
The question here is not about floor, but about floor_division. NumPy implements it as simple-minded floor(x/y), while Python attempts to be more precise by doing floor((x - fmod(x, y))/y).
$ hg blame -d -u -w Objects/floatobject.c nascheme Thu Jan 04 01:44:34 2001 +0000: float_divmod(PyObject *v, PyObject *w) .. guido Sun Oct 20 20:16:45 1991 +0000: mod = fmod(vx, wx); tim Sat Sep 16 03:54:24 2000 +0000: /* fmod is typically exact, so vx-mod is *mathematically* an guido Thu May 06 14:26:34 1999 +0000: exact multiple of wx. But this is fp arithmetic, and fp guido Thu May 06 14:26:34 1999 +0000: vx - mod is an approximation; the result is that div may guido Thu May 06 14:26:34 1999 +0000: not be an exact integral value after the division, although guido Thu May 06 14:26:34 1999 +0000: it will always be very close to one. guido Thu May 06 14:26:34 1999 +0000: */ guido Sun Oct 20 20:16:45 1991 +0000: div = (vx - mod) / wx; ..
Given that this logic dates back to 1991, I doubt not-finite case was seriously considered.
In light of PEP 3141, if anything should be done about float // float it would be to make it return and int and as a consequence inf // 1 should raise an OverflowError.
Since divmod() and floor_division aren't defined by a standard, Python can define its own standard. But each time Python changes behavior, external libraries will need to change, or not; and another difference between Python versions is introduced.
Case Van Horsen <casevh@gmail.com> wrote:
I don't think there is any dispute over what math.floor(inf) should return. POSIX, C99, IEEE and probably many other standards agree that inf should be returned as long as the resulting type can represent it.
I dispute that there is no dispute over what math.floot(inf) should return. ;-)
All the standards specify a result type can represent +-Inf and +-0. A standards compliant version should return +-Inf and +-0. lrint() and llrint() are defined to return long or long long, respectively. It would be fine if they raised an exception. The current math.floor() actually behaves more like llrint() than floor().
I've always found the behavior of math.floor() a bit surprising, especially since most functions in the module are thin wrappers around the C functions from math.h.
math.modf(float("inf")) (0.0, inf)
So (if we can change it) I'd prefer that floor() behaves according to the C standard. Stefan Krah
On Thu, Sep 18, 2014 at 03:31:05PM -0400, Alexander Belopolsky wrote:
I don't think there is any dispute over what math.floor(inf) should return. POSIX, C99, IEEE and probably many other standards agree that inf should be returned as long as the resulting type can represent it.
Why don't we add an integer infinity? Python int is not a low-level primitive type, it's an object, and can support as rich a set of behaviour as we like. We could subclass int, give it a pair of singletons Infinity and -Infinity (say), and have math.floor(float('inf')) return one of them as needed. - The subclass need not be a builtin public class, like bool, it could be a private implementation detail. The only promise made is that isinstance(Infinity, int) returns True. - The Infinity and -Infinity instances need not be built-in. - For that matter, they may not even be singletons. - We could, but don't necessarily need to, support int('inf'). - But int(float('inf')) and int(Decimal('inf')) should return the int Infinity. -- Steven
On Sep 19, 2014, at 2:52, Steven D'Aprano <steve@pearwood.info> wrote:
On Thu, Sep 18, 2014 at 03:31:05PM -0400, Alexander Belopolsky wrote:
I don't think there is any dispute over what math.floor(inf) should return. POSIX, C99, IEEE and probably many other standards agree that inf should be returned as long as the resulting type can represent it.
Why don't we add an integer infinity?
I was thinking the same thing. In addition to your points, while it's not _useful_ as often, there's nothing inherently any more strange or unmathematical about an affine extended integral line than an extended real line. (In fact, if anything, not having a "largest int" akin to the largest float makes it more sensible.) And it would mean people wouldn't have to use the float -inf as a starting value for finding a maximum, they could use an actual integer. That does raise the question of whether there should be an int NaN...
Python int is not a low-level primitive type, it's an object, and can support as rich a set of behaviour as we like. We could subclass int, give it a pair of singletons Infinity and -Infinity (say), and have math.floor(float('inf')) return one of them as needed.
- The subclass need not be a builtin public class, like bool, it could be a private implementation detail. The only promise made is that isinstance(Infinity, int) returns True.
- The Infinity and -Infinity instances need not be built-in.
- For that matter, they may not even be singletons.
- We could, but don't necessarily need to, support int('inf').
- But int(float('inf')) and int(Decimal('inf')) should return the int Infinity.
-- Steven _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Fri, Sep 19, 2014 at 03:13:13AM -0700, Andrew Barnert wrote:
On Sep 19, 2014, at 2:52, Steven D'Aprano <steve@pearwood.info> wrote:
On Thu, Sep 18, 2014 at 03:31:05PM -0400, Alexander Belopolsky wrote:
I don't think there is any dispute over what math.floor(inf) should return. POSIX, C99, IEEE and probably many other standards agree that inf should be returned as long as the resulting type can represent it.
Why don't we add an integer infinity?
I was thinking the same thing. [...] That does raise the question of whether there should be an int NaN...
Ah, you had to raise that issue! Now it's sure to be rejected! *wink* An int NAN can and should be considered only when there is a clear need for it. Since Python tends to prefer raising exceptions than returning NANs, e.g. 0/0 raises, I'm not sure that there are any operations that return ints which would benefit from an int NAN. (Personally, I'd rather get NANs than exceptions, but apparently I'm in the minority.) -- Steven
participants (10)
-
Alexander Belopolsky
-
Andrew Barnert
-
Case Van Horsen
-
Guido van Rossum
-
Ian Cordasco
-
MRAB
-
Nick Coghlan
-
Petr Viktorin
-
Stefan Krah
-
Steven D'Aprano