math.inf and math.nan constants
The current way to get infinite and nan floats are to do float("inf") and float("nan"), respectively. For many applications, this is sufficient. However, for scientific and mathematical computing, using inf and nan values is very common, and the current approach is very verbose. So for those applications, I think it would be useful if the math standard library module provided "math.nan" and "math.inf", which would return the same thing as float("nan") and float("inf"), respectively.
So with the proposal, you'd likely do something like from math import nan, inf Couldn't you just instead put nan, inf = float("nan"), float("inf") at the top of your script? I don't really think this is any more verbose than an import from the math module. (Unless you're already doing an import star from math)
Yes, this would be a shortcut for that. math.nan and math.inf are less
verbose than float("nan") and float("inf"), even if you aren't already
using the math module (fewer characters total, and in particular fewer
special characters). It would also, at least in my opinion, be more
readable. Plus there is already the math.isnan and math.isinf, so I don't
think it would be totally out-of-place.
On Wed, Jan 7, 2015 at 2:49 PM, Mark Young
So with the proposal, you'd likely do something like
from math import nan, inf
Couldn't you just instead put
nan, inf = float("nan"), float("inf")
at the top of your script? I don't really think this is any more verbose than an import from the math module. (Unless you're already doing an import star from math)
On 07/01/2015 15:58, Todd wrote:
Yes, this would be a shortcut for that. math.nan and math.inf are less verbose than float("nan") and float("inf"), even if you aren't already using the math module (fewer characters total, and in particular fewer special characters). It would also, at least in my opinion, be more readable. Plus there is already the math.isnan and math.isinf, so I don't think it would be totally out-of-place.
I totally agree. +1 -- Marco Buttu INAF-Osservatorio Astronomico di Cagliari Via della Scienza n. 5, 09047 Selargius (CA) Phone: 070 711 80 217 Email: mbuttu@oa-cagliari.inaf.it
On Wed, Jan 7, 2015 at 10:23 AM, Marco Buttu
On 07/01/2015 15:58, Todd wrote:
Yes, this would be a shortcut for that. math.nan and math.inf are less
verbose than float("nan") and float("inf"), even if you aren't already using the math module (fewer characters total, and in particular fewer special characters). It would also, at least in my opinion, be more readable. Plus there is already the math.isnan and math.isinf, so I don't think it would be totally out-of-place.
I totally agree. +1
Another +1. Two points: 1. The current ways to create inf and nan are not obvious and hard to discover. It will be nice to have these constants discoverable in tab completion from math. 2. The repr()s of nan and inf are simply 'nan' and 'inf', not 'float("nan")' and 'float("inf")', so it is natural to expect nan and inf constants in some namespace.
Also +1. I sometimes import numpy just for this because I find float("inf") so ugly. Best, Neil On Wednesday, January 7, 2015 at 11:08:23 AM UTC-5, Alexander Belopolsky wrote:
On Wed, Jan 7, 2015 at 10:23 AM, Marco Buttu
javascript:> wrote: On 07/01/2015 15:58, Todd wrote:
Yes, this would be a shortcut for that. math.nan and math.inf are less
verbose than float("nan") and float("inf"), even if you aren't already using the math module (fewer characters total, and in particular fewer special characters). It would also, at least in my opinion, be more readable. Plus there is already the math.isnan and math.isinf, so I don't think it would be totally out-of-place.
I totally agree. +1
Another +1.
Two points:
1. The current ways to create inf and nan are not obvious and hard to discover. It will be nice to have these constants discoverable in tab completion from math.
2. The repr()s of nan and inf are simply 'nan' and 'inf', not 'float("nan")' and 'float("inf")', so it is natural to expect nan and inf constants in some namespace.
Both good points…
On 8 January 2015 at 02:07, Alexander Belopolsky
On Wed, Jan 7, 2015 at 10:23 AM, Marco Buttu
wrote: On 07/01/2015 15:58, Todd wrote:
Yes, this would be a shortcut for that. math.nan and math.inf are less verbose than float("nan") and float("inf"), even if you aren't already using the math module (fewer characters total, and in particular fewer special characters). It would also, at least in my opinion, be more readable. Plus there is already the math.isnan and math.isinf, so I don't think it would be totally out-of-place.
I totally agree. +1
Another +1.
Two points:
1. The current ways to create inf and nan are not obvious and hard to discover. It will be nice to have these constants discoverable in tab completion from math.
2. The repr()s of nan and inf are simply 'nan' and 'inf', not 'float("nan")' and 'float("inf")', so it is natural to expect nan and inf constants in some namespace.
3. Having these as documented constants provides a natural home for documentation of some of the standard assumptions about the behaviour of containers and comparisons that they can break (this is mostly NaN related - off the top of my head, I don't recall any particularly weird inf-induced behaviour) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
+1. Let's do it.
On Wed, Jan 7, 2015 at 7:23 AM, Marco Buttu
On 07/01/2015 15:58, Todd wrote:
Yes, this would be a shortcut for that. math.nan and math.inf are less
verbose than float("nan") and float("inf"), even if you aren't already using the math module (fewer characters total, and in particular fewer special characters). It would also, at least in my opinion, be more readable. Plus there is already the math.isnan and math.isinf, so I don't think it would be totally out-of-place.
I totally agree. +1
-- Marco Buttu
INAF-Osservatorio Astronomico di Cagliari Via della Scienza n. 5, 09047 Selargius (CA) Phone: 070 711 80 217 Email: mbuttu@oa-cagliari.inaf.it
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido)
On 01/07/2015 08:07 AM, Guido van Rossum wrote:
On Wed, Jan 7, 2015 at 7:23 AM, Marco Buttu wrote:
On 07/01/2015 15:58, Todd wrote:
Yes, this would be a shortcut for that. math.nan and math.inf are less verbose than float("nan") and float("inf"), even if you aren't already using the math module (fewer characters total, and in particular fewer special characters). It would also, at least in my opinion, be more readable. Plus there is already the math.isnan and math.isinf, so I don't think it would be totally out-of-place.
I totally agree. +1
+1. Let's do it.
Anything special for float('-inf') ? -- ~Ethan~
On Wed, Jan 7, 2015 at 10:55 AM, Ethan Furman
On 01/07/2015 08:07 AM, Guido van Rossum wrote:
On Wed, Jan 7, 2015 at 7:23 AM, Marco Buttu wrote:
On 07/01/2015 15:58, Todd wrote:
Yes, this would be a shortcut for that. math.nan and math.inf are less verbose than float("nan") and float("inf"), even if you aren't already using the math module (fewer characters total, and in particular fewer special characters). It would also, at least in my opinion, be more readable. Plus there is already the math.isnan and math.isinf, so I don't think it would be totally out-of-place.
I totally agree. +1
+1. Let's do it.
Anything special for float('-inf') ?
There is no constant name as short and obvious as -math.inf. -- Devin
2015-01-07 14:33 GMT+01:00 Todd
The current way to get infinite and nan floats are to do float("inf") and float("nan"), respectively. For many applications, this is sufficient. However, for scientific and mathematical computing, using inf and nan values is very common, and the current approach is very verbose. So for those applications, I think it would be useful if the math standard library module provided "math.nan" and "math.inf", which would return the same thing as float("nan") and float("inf"), respectively.
Do you expect singletons? I mean that float("nan") is math.nan would be True. Request of float("0.0") singleton: http://bugs.python.org/issue4024 I dislike the idea of adding math.<float constant>. I agree with Mark Young, you are already create you own symbols in a module. Victor
On Wed, Jan 7, 2015 at 8:29 AM, Victor Stinner
2015-01-07 14:33 GMT+01:00 Todd
: The current way to get infinite and nan floats are to do float("inf") and float("nan"), respectively. For many applications, this is sufficient. However, for scientific and mathematical computing, using inf and nan values is very common, and the current approach is very verbose. So for those applications, I think it would be useful if the math standard library module provided "math.nan" and "math.inf", which would return the same thing as float("nan") and float("inf"), respectively.
Do you expect singletons? I mean that float("nan") is math.nan would be True.
That seems like a bad idea. There are millions of different NaNs, so xxx is math.nan would only work sometimes. (math.isnan is the way to deal with this.) -- Devin
On Wed, 7 Jan 2015 15:29:14 +0100
Victor Stinner
2015-01-07 14:33 GMT+01:00 Todd
: The current way to get infinite and nan floats are to do float("inf") and float("nan"), respectively. For many applications, this is sufficient. However, for scientific and mathematical computing, using inf and nan values is very common, and the current approach is very verbose. So for those applications, I think it would be useful if the math standard library module provided "math.nan" and "math.inf", which would return the same thing as float("nan") and float("inf"), respectively.
Do you expect singletons? I mean that float("nan") is math.nan would be True.
Request of float("0.0") singleton: http://bugs.python.org/issue4024
I dislike the idea of adding math.<float constant>.
You mean like math.pi and math.e? :)
On Wed, 7 Jan 2015 14:33:54 +0100
Todd
The current way to get infinite and nan floats are to do float("inf") and float("nan"), respectively. For many applications, this is sufficient. However, for scientific and mathematical computing, using inf and nan values is very common, and the current approach is very verbose. So for those applications, I think it would be useful if the math standard library module provided "math.nan" and "math.inf", which would return the same thing as float("nan") and float("inf"), respectively.
Note if you are using Numpy, you already have np.nan and np.inf. Regards Antoine.
On Wed, Jan 07, 2015 at 02:33:54PM +0100, Todd wrote:
The current way to get infinite and nan floats are to do float("inf") and float("nan"), respectively. For many applications, this is sufficient. However, for scientific and mathematical computing, using inf and nan values is very common, and the current approach is very verbose. So for those applications, I think it would be useful if the math standard library module provided "math.nan" and "math.inf", which would return the same thing as float("nan") and float("inf"), respectively.
Compare: inf = float('inf') func(inf) versus: from math import inf func(inf) Defining your module's own constant actually takes two characters fewer than importing it from the math module. In any case, we're talking about an utterly trivial micro-optimization. This is Python, not Unix shell scripting. We don't use names like "umount" to save one character over "unmount", we encouraging writing for clarity and correctness over brevity. The math module has constants pi and e because it would be truly an inconvenience to have to create them yourself: pi = 3.14159265389793 I can remember the first six digits of pi, 3.1415, anything more than that I have to look up, and of course there is the considerable risk of getting it wrong, as I did above. But the same does not apply to creating your own inf constant. There is no long series of digits to remember, just three letters, and it's hard to get it wrong. Whether you write import math process(math.inf) or inf = float('inf') process(inf) is much the same effort. At worst, we might say that it is a matter of personal taste which you prefer. But frankly, the difference is trivial. Of course, writing float('inf') every single time you want an infinity is wasteful and silly, but that's a matter of education. If you can't teach people to write inf = float('inf') you won't be able to teach them to use math.inf either. Up to now, I have only discussed inf, not nan, because there is only one inf value in floats. (Two if you count -inf.) But the IEEE 754 standard provides many different NAN values, and offers a possible interpretion of them: the extra "payload" on each NAN can be used to carry diagnostic information on which numeric operation failed. Back in the 1980s, I was a user of the Apple Standard Numerics Environment (SANE), which provided easy access to NAN payloads and a standard interpretation for them. It is a system which can work well and help in debugging. Python today doesn't give us any simple way to access all those different float NANs, or offer any interpretation of what they might mean, but it might some day. I am strongly opposed to anything which might pre-empt that or discourage future advances. In summary: - offering a math.inf is harmless but not especially useful; - offering a single math.nan is harmful and I strongly oppose it. -- Steve
On Thu, Jan 8, 2015 at 3:09 AM, Steven D'Aprano
I can remember the first six digits of pi, 3.1415...
Aside: That's technically an incorrect approximation. Since the next digit is a 9, you ought to round that up... or just use 3.14159, stopping before the 2 and thus correctly rounding down. ChrisA
On Thu, Jan 08, 2015 at 03:14:17AM +1100, Chris Angelico wrote:
On Thu, Jan 8, 2015 at 3:09 AM, Steven D'Aprano
wrote: I can remember the first six digits of pi, 3.1415...
Aside: That's technically an incorrect approximation.
I know. I didn't say it was a good approximation, I said I could remember those digits. -- Steve
On Wed, Jan 7, 2015 at 8:09 AM, Steven D'Aprano
On Wed, Jan 07, 2015 at 02:33:54PM +0100, Todd wrote:
The current way to get infinite and nan floats are to do float("inf") and float("nan"), respectively. For many applications, this is sufficient. However, for scientific and mathematical computing, using inf and nan values is very common, and the current approach is very verbose. So for those applications, I think it would be useful if the math standard library module provided "math.nan" and "math.inf", which would return the same thing as float("nan") and float("inf"), respectively.
Compare:
inf = float('inf') func(inf)
versus:
from math import inf func(inf)
But using a more common style, you already have math imported anyway, and you can just write math.inf rather than having to interrupt your coding flow, see if you already have an inf variable defined, if not define it, etc.
Defining your module's own constant actually takes two characters fewer than importing it from the math module.
But that's not the (whole) point. The existing idioms are commonly used and unintuitive. I suppose you would also be in favor of defining e = math.exp(1) in favor of math.e?
In any case, we're talking about an utterly trivial micro-optimization. This is Python, not Unix shell scripting. We don't use names like "umount" to save one character over "unmount", we encouraging writing for clarity and correctness over brevity.
The math module has constants pi and e because it would be truly an inconvenience to have to create them yourself:
pi = 3.14159265389793
I can remember the first six digits of pi, 3.1415, anything more than that I have to look up, and of course there is the considerable risk of getting it wrong, as I did above.
But the same does not apply to creating your own inf constant. There is no long series of digits to remember, just three letters, and it's hard to get it wrong. Whether you write
import math process(math.inf)
or
inf = float('inf') process(inf)
is much the same effort. At worst, we might say that it is a matter of personal taste which you prefer. But frankly, the difference is trivial.
I say bah to that long-winded diatribe.
Of course, writing float('inf') every single time you want an infinity is wasteful and silly, but that's a matter of education. If you can't teach people to write inf = float('inf') you won't be able to teach them to use math.inf either.
Up to now, I have only discussed inf, not nan, because there is only one inf value in floats. (Two if you count -inf.) But the IEEE 754 standard provides many different NAN values, and offers a possible interpretion of them: the extra "payload" on each NAN can be used to carry diagnostic information on which numeric operation failed. Back in the 1980s, I was a user of the Apple Standard Numerics Environment (SANE), which provided easy access to NAN payloads and a standard interpretation for them. It is a system which can work well and help in debugging.
Python today doesn't give us any simple way to access all those different float NANs, or offer any interpretation of what they might mean, but it might some day. I am strongly opposed to anything which might pre-empt that or discourage future advances.
I don't see how the existence of a nan constant pre-empts anything. Your imagined new mechanism will have to co-exist with float("nan") anyway.
In summary:
- offering a math.inf is harmless but not especially useful;
- offering a single math.nan is harmful and I strongly oppose it.
That's your opinion and you're entitled to it. -- --Guido van Rossum (python.org/~guido)
On Wed, Jan 07, 2015 at 08:16:18AM -0800, Guido van Rossum wrote:
I suppose you would also be in favor of defining e = math.exp(1) in favor of math.e?
Euler's Number e is an important mathematical constant, but I'm not sure that it is a useful *programming* constant, more useful than (say) γ, the Euler-Mascheroni constant which is also ubiquitous in mathematics. I can't think of any reason to use e on its own, apart from exponentials and logs, where we have functions which are more accurate than calling e**x directly. If e wasn't already in the math module, I don't think there are enough use-cases to justify adding it. Plenty of other languages don't (e.g. Haskell and Lua). I think math.tau would be much more useful and important than e :-) http://bugs.python.org/issue12345
I say bah to that long-winded diatribe.
Long-winded, perhaps, but a diatribe? (Definition on WordNet: "thunderous verbal attack".) -- Steve
On Wed, Jan 7, 2015 at 8:09 AM, Steven D'Aprano
import math process(math.inf)
or
inf = float('inf') process(inf)
is much the same effort. At worst, we might say that it is a matter of personal taste which you prefer. But frankly, the difference is trivial.
exactly -- but the cost is trivial too. Note that numpy provides np.inf and np.nan for a reason, and it s a nice thing to have.
- offering a math.inf is harmless but not especially useful;
but nice. - offering a single math.nan is harmful and I strongly oppose it. defining math.nan as a singleton could be considered harmful, but I don't see any harm at all in offering it as a pre-defined constant. We NEED to have a way to create a NaN-valued float in any case (and do with float('nan')) -- this would be no different. And as nan (and inf, and -inf) can result from computation, rather than python-level object creation, they are different than None anyway (they are also particular values or a float, rather than a particular type). +1 -Chris -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
On Wed, Jan 7, 2015 at 10:25 AM, Chris Barker
On Wed, Jan 7, 2015 at 8:09 AM, Steven D'Aprano
wrote: - offering a single math.nan is harmful and I strongly oppose it.
defining math.nan as a singleton could be considered harmful, but I don't see any harm at all in offering it as a pre-defined constant. We NEED to have a way to create a NaN-valued float in any case (and do with float('nan')) -- this would be no different.
Maybe this would justify a note in the documentation, that this is one NaN, but there are many others that are different. As long as people know not to rely on math.nan being the same object or having the same bits as every nan, then there's no harm. -- Devin
On 2015-01-07 16:57, Devin Jeanpierre wrote:
On Wed, Jan 7, 2015 at 10:25 AM, Chris Barker
wrote: On Wed, Jan 7, 2015 at 8:09 AM, Steven D'Aprano
wrote: - offering a single math.nan is harmful and I strongly oppose it.
defining math.nan as a singleton could be considered harmful, but I don't see any harm at all in offering it as a pre-defined constant. We NEED to have a way to create a NaN-valued float in any case (and do with float('nan')) -- this would be no different.
Maybe this would justify a note in the documentation, that this is one NaN, but there are many others that are different.
As long as people know not to rely on math.nan being the same object or having the same bits as every nan, then there's no harm.
Does that mean it should be a function that returns a NaN, i.e. math.nan()?
On 01/07/2015 10:23 AM, MRAB wrote:
On 2015-01-07 16:57, Devin Jeanpierre wrote:
Maybe this would justify a note in the documentation, that this is one NaN, but there are many others that are different.
As long as people know not to rely on math.nan being the same object or having the same bits as every nan, then there's no harm.
Does that mean it should be a function that returns a NaN, i.e. math.nan()?
No, it should be similar to math.e and math.pi -- that is, a constant value (which NaN is bound to math.nan is subject to change without notice, but it will be a NaN). -- ~Ethan~
On Wed, 07 Jan 2015 18:23:37 +0000
MRAB
On 2015-01-07 16:57, Devin Jeanpierre wrote:
On Wed, Jan 7, 2015 at 10:25 AM, Chris Barker
wrote: On Wed, Jan 7, 2015 at 8:09 AM, Steven D'Aprano
wrote: - offering a single math.nan is harmful and I strongly oppose it.
defining math.nan as a singleton could be considered harmful, but I don't see any harm at all in offering it as a pre-defined constant. We NEED to have a way to create a NaN-valued float in any case (and do with float('nan')) -- this would be no different.
Maybe this would justify a note in the documentation, that this is one NaN, but there are many others that are different.
As long as people know not to rely on math.nan being the same object or having the same bits as every nan, then there's no harm.
Does that mean it should be a function that returns a NaN, i.e. math.nan()?
If it returns always the same NaN it won't make a difference. However we could have a random.nan() function to get random NaNs (perhaps with different distributions). Regards Antoine.
On Wed, Jan 07, 2015 at 07:31:00PM +0100, Antoine Pitrou wrote:
However we could have a random.nan() function to get random NaNs (perhaps with different distributions).
Do you have a use case for random NANs? I'd rather have the float constructor allow you to specify the payload, as decimal already does: py> decimal.Decimal('nan123') Decimal('NaN123') or possible a class method: float.nan(123) -- Steve
Maybe this would justify a note in the documentation, that this is one NaN, but there are many others that are different.
As long as people know not to rely on math.nan being the same object or having the same bits as every nan, then there's no harm.
comparison with NaNs should be tough and can only be done with the maths.isnan functions. IEEE754 requires that all comparisons with NaN give false, i.e., nan == 0: False nan != 0: False (I use in FORTRAN codes to find NaNs in old code) Same for comparing nan to itself.
x = float('nan') x is x True x == x False
Unless math.nan was a singleton, the "is" operator would also fail, and even that would not compare to a nan generated in computation in general. But I agree, having *a* nan constant in math would be good, as long as users know what they can do with it and what not. It should not be a function. -Alexander
here another odd issue related to NaN arithmetics: (1)
nan = float('nan') nan is nan True nan == nan False
this is what we want. Good. But (2)
x = (nan,) x is x True x == x True
... hmm ... apparently the comparison uses ID before using == ? for tuple elements? on the other hand (3)
(nan,) is (nan,) False (nan,) == (nan,) True
I guess we see from (4)
float('nan') is float('nan') False (float('nan'),) == (float('nan'),) False
I understand why they all give the results they do, however, I think the second comparison in (2) should give False and, more importantly, the first comparison of (4) should be True - maths.nan should be a singleton - even if we allow to float.make_nan() to produce NaNs with different payloads - but maths.nan could be just one thing, one instance, the numerical counterpart to None. -Alexander
On Fri, Jan 9, 2015 at 10:58 PM, Alexander Heger
here another odd issue related to NaN arithmetics:
(1)
nan = float('nan') nan is nan True nan == nan False
this is what we want. Good. But
(2)
x = (nan,) x is x True x == x True
... hmm ... apparently the comparison uses ID before using == ? for tuple elements?
It doesn't even compare them. Consider:
class Different: ... def __eq__(self, other): ... print("Comparing",id(self),"with",id(other)) ... return False ... x = Different() x == x Comparing 139945362930712 with 139945362930712 False tup = x, tup == tup True
A tuple is equal to itself, for efficiency's sake, and doesn't go in and check that all its elements are equal to themselves.
on the other hand
(3)
(nan,) is (nan,) False (nan,) == (nan,) True
This, however, shows your point better. Likewise, using my Different class shows that the comparison isn't made:
(x,) is (x,) False (x,) == (x,) True
I guess we see from
(4)
float('nan') is float('nan') False (float('nan'),) == (float('nan'),) False
Right; they're different objects, so the short-cut isn't taken. It's a shortcut that works safely for every sane object except NaN. You won't find many non-buggy objects that aren't equal to themselves.
I understand why they all give the results they do, however, I think the second comparison in (2) should give False and, more importantly, the first comparison of (4) should be True - maths.nan should be a singleton - even if we allow to float.make_nan() to produce NaNs with different payloads - but maths.nan could be just one thing, one instance, the numerical counterpart to None.
Why should math.nan be a singleton? Consider:
float("1.0") is float("1.0") False (float("1.0"),) == (float("1.0"),) True
Even with integers, although CPython caches some small ones:
int("12345") is int("12345") False (int("12345"),) == (int("12345"),) True
(And CPython also caches literals, so both these tests have to use explicit constructor calls.) I think we can all agree that the number 12345 is unique - there aren't two such numbers. So if we're allowed to have two int objects representing the exact same number, why should NaN (which represents the vastly infinite space of non-numbers) be unique? ChrisA
Dear Chris, thanks for answering my questions.
I understand why they all give the results they do, however, I think the second comparison in (2) should give False and, more importantly, the first comparison of (4) should be True - maths.nan should be a singleton - even if we allow to float.make_nan() to produce NaNs with different payloads - but maths.nan could be just one thing, one instance, the numerical counterpart to None.
Why should math.nan be a singleton? Consider:
float("1.0") is float("1.0") False (float("1.0"),) == (float("1.0"),) True
Even with integers, although CPython caches some small ones:
int("12345") is int("12345") False (int("12345"),) == (int("12345"),) True
(And CPython also caches literals, so both these tests have to use explicit constructor calls.)
I think we can all agree that the number 12345 is unique - there aren't two such numbers. So if we're allowed to have two int objects representing the exact same number, why should NaN (which represents the vastly infinite space of non-numbers) be unique?
I think I was not thinking clearly. Here, if float('nan') would return math.nan it would it would, by definition, always be the same object instead of creating new ones (with different payloads). An issue may be if the value comes from elsewhere, e.g., was pickled. I am now wondering what about float("-nan")? Do you want to introduce a syntax for signaling nans and such with payload and signs float("-nans123")? -Alexander
On 9 January 2015 at 21:58, Alexander Heger
here another odd issue related to NaN arithmetics: (2)
x = (nan,) x is x True x == x True
... hmm ... apparently the comparison uses ID before using == ? for tuple elements?
I understand why they all give the results they do, however, I think the second comparison in (2) should give False
There's an inherent conflict between the mathematical notion of NaN and the software engineering notion of object identity. For containers in Python, it's the latter that prevails, in order to preserve the invariant that "x is y" implies "x in (y,)" for arbitrary containers and objects, even if x and y happen to be distinct references to the exact same NaN object. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
There's an inherent conflict between the mathematical notion of NaN and the software engineering notion of object identity. For containers in Python, it's the latter that prevails, in order to preserve the invariant that "x is y" implies "x in (y,)" for arbitrary containers and objects, even if x and y happen to be distinct references to the exact same NaN object.
I suppose in the end it is not advisable to use "is" to compare numerical variables in the first place as you can run into the cached values,
x = 256 y = 256 x is y True x = 257 y = 257 x is y False
In most cases of numerical applications people will use numpy and that behaves the expected way, the issue is if a python list behaves different from a numpy array.
import numpy as np x = np.tile(np.nan, 3) x == x array([False, False, False], dtype=bool) x is x True
x = [float('nan')] * 3 x == x True x is x True
-Alexander
On Fri, Jan 9, 2015 at 5:03 AM, Alexander Heger
I suppose in the end it is not advisable to use "is" to compare numerical variables in the first place
AFAIU, you only want to use "is" for singletons (None) or if you really want to know if two names reference the same object, which is very unlikely need at runtime, but handy for debugging. Making math.nan a singleton is a bad idea for many reasons already mentioned. Though it would be pretty cool if you could override "is" to make: x is math.nan be: math.isnan(x) and maybe the same thing for any arbitrary floats that may have nan values: x is y becomes: True if math.isnan(x) and math.isnan(y) else (id(x) == id(y)) (or something like that...) Is that even possible to override is that way? -Chris -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
On Mon, Jan 12, 2015 at 10:55 AM, Chris Barker
Though it would be pretty cool if you could override "is" to make:
x is math.nan
be:
math.isnan(x)
No, it wouldn't! It'd be cute, it'd read really nicely the first time, but breaking the definition of object identity is a Bad Thing. For instance, imagine this: x = 0*1e400 y = 1e400-1e400 z = math.nan print(x is y, y is z, x is z) If you hide the first three lines and look only at the last one, you would expect that "False True True" is an impossible result. But that's exactly what redefining "is" could do. ChrisA
Chris Barker writes:
Making math.nan a singleton is a bad idea for many reasons already mentioned.
But it's not a singleton, not even in the class of NaNs. It's a named constant, like zero or pi. True, the name is ambiguous in the sense that it's easy to forget that (unlike zero and pi) this NaN-with-a-name is not otherwise special in any NaN-y way you can depend on, and that's slightly dangerous. I dislike it -- AFAICS math.nan is pretty useless: if you need a particular NaN repeatedly, I still don't see why "nan = float('nan')" is unsatisfactory, and I worry that multiple package writers might use it as "the NaN to return for undefined operations", competing for the role of "my NaN" (cf the idea suggested that NaN payload could be used to track the module that produced it). That's different from math.inf, which seems like a reasonable addition with no real downside (although similarly little upside AFAICS). But I have to give the advocates this point: I think it's much less likely that people will write "x is math.nan" with poor results than that they will write "x == math.pi",and it's the same group that would likely fall prey to both.
Though it would be pretty cool if you could override "is" to make:
x is math.nan
be:
math.isnan(x)
In Python we spell that "isinstance", not "is".
But it's not a singleton, not even in the class of NaNs. It's a named constant, like zero or pi.
Right, it's a particular value of a float -- more that that, it's a bunch if values, so even less a singleton than pi, even.
math.isnan(x)
In Python we spell that "isinstance", not "is".
Except that nan is not a type. In way, it's like how there are two bit patterns for the value 0.0 in floats (-0.0 and 0.0). But in that case, -0.0 == 0.0 is True. Whereas NaN == NaN is false. hence the need for math.isnan. Honestly, I wasn't really thinking it would be a good idea, but it did seem like it could make it a pseudo-singleton, and be a, as Chris A. puts it, "cute" way to express it. Not cute enough to create a weird exception to an otherwise clearly defined operator, however. -CHB
Chris Barker - NOAA Federal writes:
But it's not a singleton, not even in the class of NaNs. It's a named constant, like zero or pi.
Right, it's a particular value of a float -- more that that, it's a bunch if values, so even less a singleton than pi, even.
AFAIK, the proposed math.nan is *not* a bunch of values. It's a particular float value that happens to be a NaN, just as math.pi is a particular float value that happens not to be a NaN. The use cases are very different, however. math.pi is used when you want a value that is a close IEEE 754 float approximation to mathematical pi in concrete computations, while math.nan is used when you want a value that "takes you out" of the world of concrete computation and can be interpreted as an "error value". IEEE 754 provides a huge number of NaN values but only defines that "error value" role for them (AIUI, actually four such roles, the combinations of positive vs negative and signaling vs quiet).
math.isnan(x)
In Python we spell [the operator form of] that "isinstance", not "is".
Except that nan is not a type.
True, "NaN" is not a type currently implemented in Python, but it could be a subtype of float. I imagine getting the Python class definition right would be a bit fiddly and not at all useful, though. Compare the "bool" type as a subtype of "int".
In way, it's like how there are two bit patterns for the value 0.0 in floats (-0.0 and 0.0).
As far as "typeness" goes, that analogy is exact. Both "Zero" and "NaN" are (non-singleton) subtypes of (IEEE 754) float. You could say that "Pi" is a singleton containing only math.pi, too, but that's not very useful as a description.
On 12/01/2015 16:05, Stephen J. Turnbull wrote:
Chris Barker - NOAA Federal writes:
But it's not a singleton, not even in the class of NaNs. It's a named constant, like zero or pi.
Right, it's a particular value of a float -- more that that, it's a bunch if values, so even less a singleton than pi, even.
AFAIK, the proposed math.nan is *not* a bunch of values. It's a particular float value that happens to be a NaN, just as math.pi is a particular float value that happens not to be a NaN.
The implementation is here https://hg.python.org/cpython/rev/cf4bf577749c so as "Although practicality beats purity." can we move on now please? -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence
TL;DR: Mark Lawrence wrote:
as "Although practicality beats purity." can we move on now please?
Absolutely.
Adding math.nan and math.inf is great, nothing else to do.
Feel free to read more below, if you're as obsessed by this as I am.....
On Mon, Jan 12, 2015 at 8:05 AM, Stephen J. Turnbull
AFAIK, the proposed math.nan is *not* a bunch of values.
correct -- math.nan is a particular one of those values. The thing is, in common usage, one often needs to know if a given float is one of the nan values -- it is very rare that anyone knows or cares which one. So you need a good way to ask that question, and: x == math.nan does not work, due to how IEEE defined NaN. So we have math.isnan(x), which is the right thing to do, and the most common question people would ask. Being able to do x is math.nan, and have that give the answer most commonly wanted would be a nice way to spell, but, again, not worth breaking the now clear definition of "is". So -- sorry to bring it up -- I was just enjoying the what if game (and genuinely curious about whether it was possible in the current python implementation to overload is like that. I take it the answer is: "no, and that's a good thing."
particular float value that happens to be a NaN, just as math.pi is a particular float value that happens not to be a NaN. The use cases are very different, however. math.pi is used when you want a value that is a close IEEE 754 float approximation to mathematical pi in concrete computations, while math.nan is used when you want a value that "takes you out" of the world of concrete computation and can be interpreted as an "error value".
sure, but the bigger difference is that math.pi == math.pi returns True and x == math.pi returns True is x has the exact same values as math.pi math.isnan(x) is, in more analogous to a < x < b i.e., a specific range of values. Anyway, I'm done. -Chris -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
On Mon, Jan 12, 2015 at 8:54 AM, Chris Barker
Being able to do x is math.nan, and have that give the answer most commonly wanted would be a nice way to spell, but, again, not worth breaking the now clear definition of "is".
While this discussion about what the meaning of "is" is is a funny in-joke for those who remember the Clinton impeachment trials, that you even considered it (and posted about it!) makes me shudder -- Python's "is" operator is so closely tied to object identity that to propose overriding it as a kind of "category" test makes me wonder if you understand Python at all. Proposing to change "==" to make all NaNs appear equal would be less earth-shattering -- that might go against all IEEE fp standards, but at least Python's "==" operator is intended for that purpose. -- --Guido van Rossum (python.org/~guido)
On 2015-01-12 18:05, Guido van Rossum wrote:
On Mon, Jan 12, 2015 at 8:54 AM, Chris Barker
mailto:chris.barker@noaa.gov> wrote: Being able to do x is math.nan, and have that give the answer most commonly wanted would be a nice way to spell, but, again, not worth breaking the now clear definition of "is".
While this discussion about what the meaning of "is" is is a funny in-joke for those who remember the Clinton impeachment trials, that you even considered it (and posted about it!) makes me shudder -- Python's "is" operator is so closely tied to object identity that to propose overriding it as a kind of "category" test makes me wonder if you understand Python at all. Proposing to change "==" to make all NaNs appear equal would be less earth-shattering -- that might go against all IEEE fp standards, but at least Python's "==" operator is intended for that purpose.
I was going to say that calling it "isnan" is in keeping with "isdigit", etc, but those are instance methods! So, why is it "math.isnan(x)" and not "x.isnan()"?
On Mon, Jan 12, 2015 at 1:33 PM, MRAB
I was going to say that calling it "isnan" is in keeping with "isdigit", etc, but those are instance methods!
So, why is it "math.isnan(x)" and not "x.isnan()"?
I'm a little curious about this myself, since float.is_nan(), float.is_inf(), and float.is_finite() are all implemented, but #if 0'd out. -- Zach
On Mon, Jan 12, 2015 at 11:40 AM, Zachary Ware < zachary.ware+pyideas@gmail.com> wrote:
On Mon, Jan 12, 2015 at 1:33 PM, MRAB
wrote: I was going to say that calling it "isnan" is in keeping with "isdigit", etc, but those are instance methods!
So, why is it "math.isnan(x)" and not "x.isnan()"?
I'm a little curious about this myself, since float.is_nan(), float.is_inf(), and float.is_finite() are all implemented, but #if 0'd out.
Heh. I don't recall how that was decided. If you really want to know, try tracking down the author (hg blame gives me unhelpfully that it was some svn merge in 2008). -- --Guido van Rossum (python.org/~guido)
On Mon, Jan 12, 2015 at 7:55 PM, Guido van Rossum
Heh. I don't recall how that was decided. If you really want to know, try tracking down the author (hg blame gives me unhelpfully that it was some svn merge in 2008).
My memory tells me that it was Christian Heimes. I'm not sure how much I trust it, though. Mark
Christian is the author of the merges for sure. Christian, do you remember
why float.is_finite and friends are commented out, in favor of math.isnan()?
On Mon, Jan 12, 2015 at 11:59 AM, Mark Dickinson
On Mon, Jan 12, 2015 at 7:55 PM, Guido van Rossum
wrote: Heh. I don't recall how that was decided. If you really want to know, try tracking down the author (hg blame gives me unhelpfully that it was some svn merge in 2008).
My memory tells me that it was Christian Heimes. I'm not sure how much I trust it, though.
Mark
-- --Guido van Rossum (python.org/~guido)
On Mon, Jan 12, 2015 at 2:05 PM, Guido van Rossum
Christian is the author of the merges for sure. Christian, do you remember why float.is_finite and friends are commented out, in favor of math.isnan()?
Here's the actual commit that added float.is_{nan,inf,finite}, already commented out: http://svn.python.org/view?view=revision&revision=62380 """ Author: christian.heimes Date: Fri Apr 18 23:13:07 2008 UTC (6 years, 8 months ago) Changed paths: 25 Log Message: I finally got the time to update and merge Mark's and my trunk-math branch. The patch is collaborated work of Mark Dickinson and me. It was mostly done a few months ago. The patch fixes a lot of loose ends and edge cases related to operations with NaN, INF, very small values and complex math. The patch also adds acosh, asinh, atanh, log1p and copysign to all platforms. Finally it fixes differences between platforms like different results or exceptions for edge cases. Have fun :) """ -- Zach
On Mon, Jan 12, 2015 at 11:40 AM, Zachary Ware
On Mon, Jan 12, 2015 at 1:33 PM, MRAB
wrote: I was going to say that calling it "isnan" is in keeping with "isdigit", etc, but those are instance methods!
So, why is it "math.isnan(x)" and not "x.isnan()"?
I'm a little curious about this myself, since float.is_nan(), float.is_inf(), and float.is_finite() are all implemented, but #if 0'd out.
I'm not Christian, but adding methods to numbers can be annoying because you may also have to add it to ints, rationals, decimals, the numeric ABCs... At the very least, to ints, anyway. -- Devin
On Mon, Jan 12, 2015 at 3:39 PM, Devin Jeanpierre
So, why is it "math.isnan(x)" and not "x.isnan()"?
I'm a little curious about this myself, since float.is_nan(), float.is_inf(), and float.is_finite() are all implemented, but #if 0'd out.
I'm not Christian, but adding methods to numbers can be annoying because you may also have to add it to ints, rationals, decimals, the numeric ABCs... At the very least, to ints, anyway.
and there are any number of other things in math that _could_ be methods.... -Chris -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
On Mon, Jan 12, 2015 at 01:40:20PM -0600, Zachary Ware wrote:
On Mon, Jan 12, 2015 at 1:33 PM, MRAB
wrote: I was going to say that calling it "isnan" is in keeping with "isdigit", etc, but those are instance methods!
So, why is it "math.isnan(x)" and not "x.isnan()"?
I'm a little curious about this myself, since float.is_nan(), float.is_inf(), and float.is_finite() are all implemented, but #if 0'd out.
Can we re-start this issue? http://bugs.python.org/issue18842 I have a lot of code that takes either a decimal or a float, and I currently have to write things like: if isinstance(x, Decimal): isnan = x.is_nan() else: isnan = math.isnan(x) which is just ick. If you're wondering why I don't just unconditionally call math.isnan, consider this: py> from decimal import Decimal py> x = Decimal('snan') py> float(x) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: cannot convert signaling NaN to float -- Steve
But what other methods from Decimal would we have to add to float (and to
int, etc.)?
IIRC there are just too many differences between Decimal and float to ever
hope for equivalence. (How do you spell sin() of a Decimal?)
On Mon, Jan 12, 2015 at 5:49 PM, Steven D'Aprano
On Mon, Jan 12, 2015 at 01:40:20PM -0600, Zachary Ware wrote:
On Mon, Jan 12, 2015 at 1:33 PM, MRAB
wrote: I was going to say that calling it "isnan" is in keeping with "isdigit", etc, but those are instance methods!
So, why is it "math.isnan(x)" and not "x.isnan()"?
I'm a little curious about this myself, since float.is_nan(), float.is_inf(), and float.is_finite() are all implemented, but #if 0'd out.
Can we re-start this issue?
http://bugs.python.org/issue18842
I have a lot of code that takes either a decimal or a float, and I currently have to write things like:
if isinstance(x, Decimal): isnan = x.is_nan() else: isnan = math.isnan(x)
which is just ick.
If you're wondering why I don't just unconditionally call math.isnan, consider this:
py> from decimal import Decimal py> x = Decimal('snan') py> float(x) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: cannot convert signaling NaN to float
-- Steve _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido)
On Tue, Jan 13, 2015 at 1:12 PM, Guido van Rossum
But what other methods from Decimal would we have to add to float (and to int, etc.)?
IIRC there are just too many differences between Decimal and float to ever hope for equivalence. (How do you spell sin() of a Decimal?)
These kinds of features should be modular (in the Mark Rosewater sense of the word). Adding float.is_nan is useful whether or not you can calculate the sine of a Decimal (and vice versa). It's currently possible to ask the question "Are you NaN?" of both floats and Decimals, and this simply adds compatible spellings for it. I'm +0 on it, but only because I don't use Decimal NaN in my code. If I did, I'd probably be a strong +1. ChrisA
On Mon, Jan 12, 2015 at 06:12:05PM -0800, Guido van Rossum wrote:
But what other methods from Decimal would we have to add to float (and to int, etc.)?
IIRC there are just too many differences between Decimal and float to ever hope for equivalence. (How do you spell sin() of a Decimal?)
Ideally you would spell it num.sin(), if anyone ever gets around to writing a sin routine for Decimals that doesn't go through conversion of floats first. But I'm not asking for Decimal to support every function and method that floats do. I'm asking that where Decimal and float both support the same function, that be a method rather than a function for one and a method for the other. I'm very glad that Python doesn't *require* object-oriented code for all things, as Java does, but there are cases where mixing procedural and OO interfaces is a nuisance. Now that Python has a full numeric tower, having the same function be a method for some numbers and a function for others makes it difficult to write type-agnostic code. As an alternative to float methods, perhaps the math module could be more polymorphic, so we could write things like (say): math.sqrt(some_decimal) and get a Decimal result instead of a float. I don't particularly care whether I call a function or a method, so long as I don't have to call isinstance() first. Steve
On Mon, Jan 12, 2015 at 5:49 PM, Steven D'Aprano
wrote: On Mon, Jan 12, 2015 at 01:40:20PM -0600, Zachary Ware wrote:
On Mon, Jan 12, 2015 at 1:33 PM, MRAB
wrote: I was going to say that calling it "isnan" is in keeping with "isdigit", etc, but those are instance methods!
So, why is it "math.isnan(x)" and not "x.isnan()"?
I'm a little curious about this myself, since float.is_nan(), float.is_inf(), and float.is_finite() are all implemented, but #if 0'd out.
Can we re-start this issue?
http://bugs.python.org/issue18842
I have a lot of code that takes either a decimal or a float, and I currently have to write things like:
if isinstance(x, Decimal): isnan = x.is_nan() else: isnan = math.isnan(x)
which is just ick.
If you're wondering why I don't just unconditionally call math.isnan, consider this:
py> from decimal import Decimal py> x = Decimal('snan') py> float(x) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: cannot convert signaling NaN to float
-- Steve _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido)
On Mon, Jan 12, 2015 at 6:39 PM, Steven D'Aprano
I'm very glad that Python doesn't *require* object-oriented code for all things, as Java does, but there are cases where mixing procedural and OO interfaces is a nuisance. Now that Python has a full numeric tower, having the same function be a method for some numbers and a function for others makes it difficult to write type-agnostic code.
As an alternative to float methods, perhaps the math module could be more polymorphic, so we could write things like (say):
math.sqrt(some_decimal)
and get a Decimal result instead of a float. I don't particularly care whether I call a function or a method, so long as I don't have to call isinstance() first.
I proposed something similar in https://mail.python.org/pipermail/python-ideas/2011-November/012844.html Summary: math.trunc, math.ceil, and math.floor currently look for __trunc__, __ceil__, and __floor__ methods on the argument. This could extended to add a check for __sqrt__, __is_nan__, __sin__, etc. special methods. casevh
On Mon, Jan 12, 2015 at 9:39 PM, Steven D'Aprano
As an alternative to float methods, perhaps the math module could be more polymorphic, so we could write things like (say):
math.sqrt(some_decimal)
Something like this is trivial to implement using the singledispatch module, but when you are faced with the functions of two arguments such as pow, things get hairier. What type should pow(2.5, Decimal(2)) return?
On Mon, Jan 12, 2015 at 7:02 PM, Alexander Belopolsky
On Mon, Jan 12, 2015 at 9:39 PM, Steven D'Aprano
wrote: As an alternative to float methods, perhaps the math module could be more polymorphic, so we could write things like (say):
math.sqrt(some_decimal)
Something like this is trivial to implement using the singledispatch module, but when you are faced with the functions of two arguments such as pow, things get hairier. What type should pow(2.5, Decimal(2)) return?
I've thought about about the following for pow(x,y), but it would break too much existing code (i.e. when x and y are integers). if isinstance(x, float) and isinstance(y, float): return the float x**y try: return x.__pow__(x,y): except TypeError: pass try: return y.__pow__(x,y) except TypeError: pass return float(x)**float(y) It would be nice we could distinguish "real" numbers where a real number uses a radix, a significand, and an exponent to represent a number. A float uses a radix of 2, a significant of 53 bits, and limited exponent range. A Decimal uses a radix of 10, a significand of arbitrary precision, and a (usually) wide exponent range. Both float and Decimal would be instances of real numbers. Then the following might work: if isinstance(x, real) and isinstance(y, real): try: return x.__pow__(x,y): except TypeError: pass try: return y.__pow__(x,y) except TypeError: pass return float(x)**float(y) casevh
_______________________________________________ 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 Sun, Jan 11, 2015 at 3:55 PM, Chris Barker
Though it would be pretty cool if you could override "is" to make:
x is math.nan
be:
math.isnan(x)
and maybe the same thing for any arbitrary floats that may have nan values:
x is y
becomes:
True if math.isnan(x) and math.isnan(y) else (id(x) == id(y))
(or something like that...)
Is that even possible to override is that way?
Not in Python. Anyway, a huge motivation for "is" is to know that if x is y, then foo(x) is exactly equivalent to foo(y). That would no longer be the if all nans were "identical", since struct.pack can give different values for different nans. -- Devin
On Wed, Jan 7, 2015 at 8:09 AM, Steven D'Aprano
In any case, we're talking about an utterly trivial micro-optimization. This is Python, not Unix shell scripting. We don't use names like "umount" to save one character over "unmount", we encouraging writing for clarity and correctness over brevity.
The math module has constants pi and e because it would be truly an
inconvenience to have to create them yourself:
pi = 3.14159265389793
You're missing one key detail. If I see math.nan or math.inf in code, I
know what those values are. If I see a bare nan or inf in the code I don't. That's an inconvenience too.
Up to now, I have only discussed inf, not nan, because there is only one inf value in floats. (Two if you count -inf.) But the IEEE 754 standard provides many different NAN values, and offers a possible interpretion of them: the extra "payload" on each NAN can be used to carry diagnostic information on which numeric operation failed.
This is a red herring as any future change to support this won't automatically touch code that uses float("nan") just as it won't touch code that uses float.nan. There is a problem here but that's not it. The problem is that float("nan") is float("nan") => False math.nan is math.nan => True So is this an attractive nuisance that will make people think they can should use x is math.nan instead of math.isnan(x)? Hopefully not but something to consider. Pylint should flag this usage. --- Bruce Check out my new puzzle book: http://Ju.mp/ingToConclusions Get it free here: http://Ju.mp/ingToConclusionsFree (available on iOS)
On 01/07/2015 11:02 AM, Bruce Leban wrote:
There is a problem here but that's not it. The problem is that
float("nan") is float("nan") => False math.nan is math.nan => True
This is not a new problem: --> nan = float('nan') --> nan is nan True
So is this an attractive nuisance that will make people think they can should use x is math.nan instead of math.isnan(x)? Hopefully not but something to consider. Pylint should flag this usage.
Agreed, for all linters. -- ~Ethan~
On Thu, Jan 8, 2015 at 6:02 AM, Bruce Leban
There is a problem here but that's not it. The problem is that
float("nan") is float("nan") => False math.nan is math.nan => True
So is this an attractive nuisance that will make people think they can should use x is math.nan instead of math.isnan(x)? Hopefully not but something to consider. Pylint should flag this usage.
I don't think that's a problem. Using 'is' to test floating-point values is already broken:
math.acos(-1) is math.pi False math.atan(1)*4 is math.pi False 1.0 + 2.0 is 3.0 False
There are plenty of calculations that will result in infinity or NaN, and the correct thing to do will be either an equality check or the math.is* functions. Or, as everyone keeps spouting, some kind of epsilon-based "almost equal" check. Or something. But not object identity. ChrisA
On Wed, Jan 7, 2015 at 2:13 PM, Chris Angelico
On Thu, Jan 8, 2015 at 6:02 AM, Bruce Leban
wrote: There is a problem here but that's not it. The problem is that
float("nan") is float("nan") => False math.nan is math.nan => True
So is this an attractive nuisance that will make people think they can should use x is math.nan instead of math.isnan(x)? Hopefully not but something to consider. Pylint should flag this usage.
I don't think that's a problem. Using 'is' to test floating-point values is already broken:
[...]
Correct. And the first half of the thread was comparing the convenience of defining a nan constant at the top of your module using "nan = float('nan')" with "from math import nan". That would have the exact same 'is' problem. There is no attractive nuisance here except that this thread itself is wasting everybody's time. :-) -- --Guido van Rossum (python.org/~guido)
On Wed Jan 07 2015 at 5:20:04 PM Guido van Rossum
On Wed, Jan 7, 2015 at 2:13 PM, Chris Angelico
wrote: On Thu, Jan 8, 2015 at 6:02 AM, Bruce Leban
wrote: There is a problem here but that's not it. The problem is that
float("nan") is float("nan") => False math.nan is math.nan => True
So is this an attractive nuisance that will make people think they can should use x is math.nan instead of math.isnan(x)? Hopefully not but something to consider. Pylint should flag this usage.
I don't think that's a problem. Using 'is' to test floating-point values is already broken:
[...]
Correct. And the first half of the thread was comparing the convenience of defining a nan constant at the top of your module using "nan = float('nan')" with "from math import nan". That would have the exact same 'is' problem.
There is no attractive nuisance here except that this thread itself is wasting everybody's time. :- )
Exactly. Someone should file a bug to track this and then nosy mark.dickinson, rhettinger, stutzbach as specified in the experts index. Then the work can be tracked and be seen done.
On 01/10/2015 12:56 PM, Brett Cannon wrote:
Exactly. Someone should file a bug to track this and then nosy mark.dickinson, rhettinger, stutzbach as specified in the experts index. Then the work can be tracked and be seen done.
http://bugs.python.org/issue23185 Was already filed, but other appropriate parties added. -- ~Ethan~
On Wed, Jan 7, 2015 at 11:02 AM, Bruce Leban
There is a problem here but that's not it. The problem is that
float("nan") is float("nan") => False math.nan is math.nan => True
So is this an attractive nuisance that will make people think they can should use x is math.nan instead of math.isnan(x)?
This "attractive nuisance" exists for ALL python objects, and is especially attractive for interned ints and strings. I have a much harder time getting students to use "is None" than getting them to not use "is" elsewhere. My summary: there isn't a huge reason to add math.nan, but there is essentially zero cost -- what's the problem? -Chris -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
On Wednesday, January 7, 2015 8:10 AM, Steven D'Aprano
Up to now, I have only discussed inf, not nan, because there is only one inf value in floats. (Two if you count -inf.) But the IEEE 754 standard provides many different NAN values, and offers a possible interpretion of them: the extra "payload" on each NAN can be used to carry diagnostic information on which numeric operation failed. Back in the 1980s, I was a user of the Apple Standard Numerics Environment (SANE), which provided easy access to NAN payloads and a standard interpretation for them. It is a system which can work well and help in debugging.
Python today doesn't give us any simple way to access all those different float NANs, or offer any interpretation of what they might mean, but it might some day. I am strongly opposed to anything which might pre-empt that or discourage future advances.
I don't think there's really an issue here; the only thing this preempts is using the plain name `float.nan` for such future advances. What's wrong with, say, `float.make_nan(payload=30, quiet=False, sign=True)`? Given that the former is almost certainly going to be used far more often than the latter, the extra characters to type and read for the uncommon case don't seem like a serious problem. Since you brought up SANE, from what I remember (I tried to dig up the Apple Numerics Manual or the semi-public SANE 68k assembly source, but I give up…), this is roughly equivalent to what SANE did. There was a function to return a NaN with a code from 0-255, with meanings like "square root of a negative" or "division by zero" or "invalid NaN code"—the last being used if you tried to call it with 0 as the code. If you wanted the all-zeros NaN, that was a separate function. Meanwhile, if you only care about platforms that use x86/68k-style representations for IEEE-754 (unfortunately, pre-2008 the bits weren't standardized, so at least MIPS did things differently), `make_nan` is pretty easy. Something like: def make_nan(payload=0, sign=False, quiet=True): payload |= (0x7ff0000000000000 | (sign * 0x8000000000000000) | (quiet * 0x0008000000000000)) return struct.unpack('d', struct.pack('Q', payload))[0] And likewise, you could write a `parse_nan` that returns `payload, sign, quiet`. And you'd probably want to add some parameter validation (and don't forget that payload 0 and quiet-bit 0 means it's not a NaN, it's an inf).
On Thu, Jan 8, 2015 at 9:38 PM, Andrew Barnert
On Wednesday, January 7, 2015 8:10 AM, Steven D'Aprano
wrote: Python today doesn't give us any simple way to access all those different float NANs, or offer any interpretation of what they might mean, but it might some day. I am strongly opposed to anything which might pre-empt that or discourage future advances.
I don't think there's really an issue here; the only thing this preempts is using the plain name `float.nan` for such future advances. What's wrong with, say, `float.make_nan(payload=30, quiet=False, sign=True)`? Given that the former is almost certainly going to be used far more often than the latter, the extra characters to type and read for the uncommon case don't seem like a serious problem.
+1, a classmethod is the right place for this. -- Devin
def make_nan(payload=0, sign=False, quiet=True): payload |= (0x7ff0000000000000 | (sign * 0x8000000000000000) | (quiet * 0x0008000000000000))
return struct.unpack('d', struct.pack('Q', payload))[0]
And likewise, you could write a `parse_nan` that returns `payload, sign, quiet`. And you'd probably want to add some parameter validation (and don't forget that payload 0 and quiet-bit 0 means it's not a NaN, it's an inf).
so, payload default should not be 0 but, e.g., 1.
On Jan 9, 2015, at 4:25, Alexander Heger
def make_nan(payload=0, sign=False, quiet=True): payload |= (0x7ff0000000000000 | (sign * 0x8000000000000000) | (quiet * 0x0008000000000000))
return struct.unpack('d', struct.pack('Q', payload))[0]
And likewise, you could write a `parse_nan` that returns `payload, sign, quiet`. And you'd probably want to add some parameter validation (and don't forget that payload 0 and quiet-bit 0 means it's not a NaN, it's an inf).
so, payload default should not be 0 but, e.g., 1.
I don't think so. The NaN you get from float("nan") on most platforms is positive, quiet, payload 0 (matching the defaults above). The NaN you get from np.nan is usually either the same, or the negative version of it. Also, any library that defines meanings for NaN payloads is presumably going to define one for 1 (I'm pretty sure SANE did), and it's unlikely to be anything generic. And on platforms where the native C lib displays detailed NaN information, quiet 0 will just be NaN or qNaN or similar, but quiet 1 will be NaN1 or qNaN(1) or similar. So, 1 is not a good default. Maybe the obvious answer is to not provide a default value at all; if you want quiet 0 you have to make_nan(0), not just make_nan, and that will raise if you happen to be on an old reversed-quiet-bit platform, while if you want default NaN you just use float.nan instead of float.make_nan. You could even to do as SANE did (or at least as I remember it) and not allow 0 at all; if you want quiet 0 you use float.nan. Or, alternatively, make the default None, which uses the right default payload for your platform. Speaking of which, IIRC, the default payload on MIPS machines (which had reversed quiet bit) was -1. Which implies that it might be handy to take negative payloads and complement off 1<<51, because if anyone has any use for such payloads they may be thinking of them as negatives, not as huge positives. But anyway, I think all of this shows why we probably don't want to add make_nan today, but how easily we (or even a third-party lib) can add it later, once someone has a platform/library that they need it for so we can paint the bikeshed to match the house. And my original point: adding float.nan to 3.5 doesn't prevent a more detailed NaN API in the future.
On Fri, Jan 09, 2015 at 05:38:14AM +0000, Andrew Barnert wrote:
On Wednesday, January 7, 2015 8:10 AM, Steven D'Aprano
wrote: Python today doesn't give us any simple way to access all those different float NANs, or offer any interpretation of what they might mean, but it might some day. I am strongly opposed to anything which might pre-empt that or discourage future advances.
I don't think there's really an issue here; the only thing this preempts is using the plain name `float.nan` for such future advances.
Okay, okay, I admit defeat :-) I must say, compared to some years ago when the prevailing attitude about NANs was closer to "if Python supports them at all you're lucky", I am glad to see better support for NANs. If that means baking in the idea that there is "a NAN", I can live with that.
What's wrong with, say, `float.make_nan(payload=30, quiet=False, sign=True)`? Given that the former is almost certainly going to be used far more often than the latter, the extra characters to type and read for the uncommon case don't seem like a serious problem.
Or float('-snan30').
Since you brought up SANE, from what I remember (I tried to dig up the Apple Numerics Manual or the semi-public SANE 68k assembly source, but I give up…), this is roughly equivalent to what SANE did. There was a function to return a NaN with a code from 0-255, with meanings like "square root of a negative" or "division by zero" or "invalid NaN code"—the last being used if you tried to call it with 0 as the code.
The payloads SANE used (adjusted to Python syntax where appropriate): Name Payload Example ============= ======= ========= NANSQRT 1 sqrt(-1) NANADD 2 +INF + (-INF) NANDIV 4 0/0 NANMUL 8 0*INF NANREM 9 x % 0 NANASCBIN 17 float("foo") NANCOMP 20 convert COMP NAN to float NANZERO 21 create NAN with 0 payload NANTRIG 33 invalid arg to trig functions NANINVTRIG 34 asin(2.0) NANLOG 36 log(-1) NANPOWER 37 invalid arg to x**y NANFINAN 38 invalid arg to finance funcs
If you wanted the all-zeros NaN, that was a separate function.
I don't think there is an all-zeroes NAN for single and double format. I believe they would be +INF or -INF depending on the sign bit. There was a 64-bit "comp" data type which had a single NAN value, perhaps that is what you are thinking of. comp was integer valued, and had no INFs.
Meanwhile, if you only care about platforms that use x86/68k-style representations for IEEE-754 (unfortunately, pre-2008 the bits weren't standardized, so at least MIPS did things differently), `make_nan` is pretty easy. Something like:
def make_nan(payload=0, sign=False, quiet=True): payload |= (0x7ff0000000000000 | (sign * 0x8000000000000000) | (quiet * 0x0008000000000000))
return struct.unpack('d', struct.pack('Q', payload))[0]
Nice!
And likewise, you could write a `parse_nan` that returns `payload, sign, quiet`. And you'd probably want to add some parameter validation (and don't forget that payload 0 and quiet-bit 0 means it's not a NaN, it's an inf).
-- Steve
On Jan 10, 2015, at 0:33, Steven D'Aprano
On Fri, Jan 09, 2015 at 05:38:14AM +0000, Andrew Barnert wrote:
On Wednesday, January 7, 2015 8:10 AM, Steven D'Aprano
wrote: Python today doesn't give us any simple way to access all those different float NANs, or offer any interpretation of what they might mean, but it might some day. I am strongly opposed to anything which might pre-empt that or discourage future advances.
I don't think there's really an issue here; the only thing this preempts is using the plain name `float.nan` for such future advances.
Okay, okay, I admit defeat :-)
I must say, compared to some years ago when the prevailing attitude about NANs was closer to "if Python supports them at all you're lucky", I am glad to see better support for NANs. If that means baking in the idea that there is "a NAN", I can live with that.
What's wrong with, say, `float.make_nan(payload=30, quiet=False, sign=True)`? Given that the former is almost certainly going to be used far more often than the latter, the extra characters to type and read for the uncommon case don't seem like a serious problem.
Or float('-snan30').
Since you brought up SANE, from what I remember (I tried to dig up the Apple Numerics Manual or the semi-public SANE 68k assembly source, but I give up…), this is roughly equivalent to what SANE did. There was a function to return a NaN with a code from 0-255, with meanings like "square root of a negative" or "division by zero" or "invalid NaN code"—the last being used if you tried to call it with 0 as the code.
The payloads SANE used (adjusted to Python syntax where appropriate):
Name Payload Example ============= ======= ========= NANSQRT 1 sqrt(-1) NANADD 2 +INF + (-INF) NANDIV 4 0/0 NANMUL 8 0*INF NANREM 9 x % 0 NANASCBIN 17 float("foo") NANCOMP 20 convert COMP NAN to float NANZERO 21 create NAN with 0 payload NANTRIG 33 invalid arg to trig functions NANINVTRIG 34 asin(2.0) NANLOG 36 log(-1) NANPOWER 37 invalid arg to x**y NANFINAN 38 invalid arg to finance funcs
Out of curiosity, where did you find this? Do you still have the Apple Numerics Manual in a box with all the Inside Mac and HIG books, or is it online somewhere and I just couldn't find it?
If you wanted the all-zeros NaN, that was a separate function.
I don't think there is an all-zeroes NAN for single and double format. I believe they would be +INF or -INF depending on the sign bit.
According to the 2008 standard, the quiet bit is part of the bits that distinguish nan from inf, and that bit is set for quiet; therefore, a qnan with payload 0 exists, and is not an inf. Pre-2008, that was already the way most platforms worked, but not all. I remember some code I had to deal with that had "ifdef MIPS 1s-complement the payload" all over the place (in fact, too all over the place; when reading a float out of storage it would flip the payload twice, giving you -inf where you should have has nan, which was the bug I has to fix that forced me to learn all this stuff in the first place…). From what I remember, the original spec didn't even require that the quiet/signaling bit has to count as part of the bits that separate nan from inf, allowed platforms to reserve any bits for internal use as long as 9 contiguous bits were available for library payloads, and all kinds of other craziness, but I never dealt with anything more deviant than MIPS doing the quiet/signaling bit backward.
On Sat, Jan 10, 2015 at 01:35:36AM -0800, Andrew Barnert wrote:
On Jan 10, 2015, at 0:33, Steven D'Aprano
wrote: The payloads SANE used (adjusted to Python syntax where appropriate):
Name Payload Example ============= ======= ========= NANSQRT 1 sqrt(-1) NANADD 2 +INF + (-INF) [...]
Out of curiosity, where did you find this? Do you still have the Apple Numerics Manual in a box with all the Inside Mac and HIG books, or is it online somewhere and I just couldn't find it?
I have the Numerics Manual on my book shelf, not quite in arms reach but close. I came across a PDF version on Apple's website a long time ago, but lost it, and it no longer appears to be available.
If you wanted the all-zeros NaN, that was a separate function.
I don't think there is an all-zeroes NAN for single and double format. I believe they would be +INF or -INF depending on the sign bit.
According to the 2008 standard, the quiet bit is part of the bits that distinguish nan from inf, and that bit is set for quiet; therefore, a qnan with payload 0 exists, and is not an inf.
Ah, well if you count the quiet bit as separate from the payload, that makes sense. I'm used to thinking of the flag that distinguishes quiet from signalling as part of the payload. The Apple Numerics Manual gives the following three fields for 64-bit doubles: Bit 1: sign bit s Bits 2-12: biased exponent e Bit2 13-64: fraction f 0 < e < 2047, any f: normalised e = 0, f!= 0: denormalised e = 0, f = 0: zero e = 2047, f = 0: infinity e = 2047, f != 0: NAN so I'm used to thinking of the whole 52 bits of f as the payload. For the longest time, I assumed that the sign bit distinguished signalling from quiet NANs, which would leave all 52 bits of f for payload, rather than the most significant bit of f. As it stands now, there are two of each NAN, one with the sign bit set and one without, and the standard doesn't specify any meaning to that.
Pre-2008, that was already the way most platforms worked, but not all. I remember some code I had to deal with that had "ifdef MIPS 1s-complement the payload" all over the place (in fact, too all over the place; when reading a float out of storage it would flip the payload twice, giving you -inf where you should have has nan, which was the bug I has to fix that forced me to learn all this stuff in the first place…). From what I remember, the original spec didn't even require that the quiet/signaling bit has to count as part of the bits that separate nan from inf, allowed platforms to reserve any bits for internal use as long as 9 contiguous bits were available for library payloads, and all kinds of other craziness, but I never dealt with anything more deviant than MIPS doing the quiet/signaling bit backward.
Thanks for that bit of history. Are there now any restrictions or standards for what the NAN payloads mean? -- Steve
On Jan 10, 2015, at 2:23, Steven D'Aprano
As it stands now, there are two of each NAN, one with the sign bit set and one without, and the standard doesn't specify any meaning to that.
Yeah, I think the current version says that implementations must ignore the sign bit, and users should ignore it. (I don't have the spec in front of me right now, so I'm going by memory here.)
Are there now any restrictions or standards for what the NAN payloads mean?
IIRC, the short version is as few restrictions as possible on the user, and whatever restrictions are needed on implementations to make that true. Something like: * Implementations shouldn't assign any meaning to the payload beyond the quiet bit. * NaN-on-number ops should preserve the entire NaN payload. (I forget what NaN-on-NaN ops do, but I assume it's preserving one or the other.) * If quiet bit is used, it must be x86/etc.-style (set means quiet). * Signaling-to-quiet conversions should leave the other bits alone.
According to the 2008 standard, the quiet bit is part of the bits that distinguish nan from inf, and that bit is set for quiet; therefore, a qnan with payload 0 exists, and is not an inf.
yes, the default payload is 0 for the quiet NaNs. I suppose the routine can throw an exception if one tries to make a signaling NaN with payload 0. Maybe setting default payload to 1 was not a good suggestion. On could set it to 1 if someone creates a signaling NaN w/o specifying payload (instead)...but, then, if someone goes all the way specifying a signaling NaN, they should know what they are doing ... I also have not been able to find any documentation on specific NaN payload values/constants online so far. ... I find it somewhat a surprise this is not well documented ... -Alexander
On Jan 10, 2015, at 15:22, Alexander Heger
According to the 2008 standard, the quiet bit is part of the bits that distinguish nan from inf, and that bit is set for quiet; therefore, a qnan with payload 0 exists, and is not an inf.
yes, the default payload is 0 for the quiet NaNs. I suppose the routine can throw an exception if one tries to make a signaling NaN with payload 0. Maybe setting default payload to 1 was not a good suggestion. On could set it to 1 if someone creates a signaling NaN w/o specifying payload (instead)...but, then, if someone goes all the way specifying a signaling NaN, they should know what they are doing
Well, my code wasn't intended as a stdlib proposal; if you copy it into your app, hopefully it's because you have a need for it and therefore know what you're doing. :)
I also have not been able to find any documentation on specific NaN payload values/constants online so far. ... I find it somewhat a surprise this is not well documented ...
I don't know if anyone ever tried to standardize a set of meanings for the payload (I can imagine Apple pushing for SANE's codes, or NASA/JPL trying to get vendors to agree on something), but if so, they apparently never succeeded, because the latest standard (2008) leaves all the bits to user/library code and says the implementation should just preserve and ignore them. There seem to be a lot more blogs and such by committee members and participants nowadays, so there's a good chance that you can find some of the history if you're interested. If you're just looking for something to use as a guide for how to assign payloads in your own project, the list of SANE codes earlier in this thread is probably not a bad place to start. (And you've still got 44 bits left if you want to track the module or something else along with the reason code.)
participants (25)
-
Alexander Belopolsky
-
Alexander Heger
-
Andrew Barnert
-
Antoine Pitrou
-
Brett Cannon
-
Bruce Leban
-
Case Van Horsen
-
Chris Angelico
-
Chris Barker
-
Chris Barker - NOAA Federal
-
Devin Jeanpierre
-
Ethan Furman
-
Guido van Rossum
-
Marco Buttu
-
Mark Dickinson
-
Mark Lawrence
-
Mark Young
-
MRAB
-
Neil Girdhar
-
Nick Coghlan
-
Stephen J. Turnbull
-
Steven D'Aprano
-
Todd
-
Victor Stinner
-
Zachary Ware