math.copysign not to introduce float
The math.copysign(x, y) function always returns a float, even when the given x is an int, i.e. math.copysign(3, -1) gives -3.0. This is documented behaviour, but I find it somewhat surprising given that the name suggests that it only copies a sign, and it's also annoying in situations when an int is strictly needed (i.e. as the step argument to range), requiring an additional cast. I'm interested to hear whether it might be a good idea to preserve the int/float type of the argument in math.copysign.
In Python 2, returning an int where a float was expected could break existing code (since in Python 2 int and float behave differently under division), but in Python 3 int is virtually a subclass of float (see PEP 3141). So it's not a crazy idea. However, it's a bit of a slippery slope. Pretty much everything in the math module always returns a float. Or do you propose that math.sin(0) also return 1 instead of 1.0? Also, how important is it to use this? I suspect the only reason it exists as a builtin is that it handles -0.0 correctly. But that's really only of interest to people doing serious floating point stuff. For everyone else, it's pretty much this one-liner: def copysign(x, y): return abs(x) if y >= 0 else -abs(x) On Thu, Nov 28, 2019 at 4:20 PM Marein <python-ideas@marein.net> wrote:
The math.copysign(x, y) function always returns a float, even when the given x is an int, i.e. math.copysign(3, -1) gives -3.0. This is documented behaviour, but I find it somewhat surprising given that the name suggests that it only copies a sign, and it's also annoying in situations when an int is strictly needed (i.e. as the step argument to range), requiring an additional cast.
I'm interested to hear whether it might be a good idea to preserve the int/float type of the argument in math.copysign. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/OD5EVP... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
Yep. It’s also the only way that I know of to get the sign of a NaN. We can’t even parse the repr for that! Brandt
On Nov 28, 2019, at 21:36, Guido van Rossum <guido@python.org> wrote: I suspect the only reason it exists as a builtin is that it handles -0.0 correctly. But that's really only of interest to people doing serious floating point stuff.
On Fri, Nov 29, 2019 at 8:30 AM Brandt Bucher <brandtbucher@gmail.com> wrote:
Yep. It’s also the only way that I know of to get the sign of a NaN. We can’t even parse the repr for that!
Exactly -- while a tiny bit handy for ints, floats are where it is really *needed*. And back to Guido's point -- while called "math", the math module really is a "float_math" module. It began as a wrapper around the C math library, and while it has grown a number of Python specific functions, I'm pretty sure all the ones that reflect C math functions are essentially unchanged, and it should probably stay that way. -CHB -- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
Thanks for all the input! I don't know if I agree that it's a slippery slope, since copysign seems to me of a different nature compared to e.g. sin. How important to use this: Many languages do feature a sign function, if that's of any worth. copysign is python's closest built-in equivalent. I did realise this is probably a bit of an X/Y problem. I gave the example of range, where int values are required. I was using it like this: range(start, end, sign(end-start)), to automatically have a range going up or down. But that's really the only concrete case I know. So then it might really come down to range not accepting floats, which I think is an old topic. On Fri, 29 Nov 2019 at 17:58, Christopher Barker <pythonchb@gmail.com> wrote:
On Fri, Nov 29, 2019 at 8:30 AM Brandt Bucher <brandtbucher@gmail.com> wrote:
Yep. It’s also the only way that I know of to get the sign of a NaN. We can’t even parse the repr for that!
Exactly -- while a tiny bit handy for ints, floats are where it is really *needed*.
And back to Guido's point -- while called "math", the math module really is a "float_math" module. It began as a wrapper around the C math library, and while it has grown a number of Python specific functions, I'm pretty sure all the ones that reflect C math functions are essentially unchanged, and it should probably stay that way.
-CHB
-- Christopher Barker, PhD
Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/HGRTJR... Code of Conduct: http://python.org/psf/codeofconduct/
On Dec 4, 2019, at 06:57, Marein <python-ideas@marein.net> wrote:
I was using it like this: range(start, end, sign(end-start)), to automatically have a range going up or down. But that's really the only concrete case I know.
If your only use for non-float-specific copysign would be implementing sign, why not ask for sign instead? It seems much more directly useful here, and potentially more widely useful as well. But I don’t think that’s needed either. It still doesn’t come up that often, and when it does, anyone can implement it trivially yourself (unlike float copysign). Plus, if your only use for sign is for this range, why not just wrap that whole thing in a function and put it in your toolkit? def birange(start, stop): return range(start, stop, 1 if stop>=start else -1) Unlike using either sign or copysign, this doesn’t force the reader to stop and think about whether start==stop is safe, it will obviously safely give you an empty range. (You can extend this to be more flexible (take just stop, or start and stop, or start and stop and abs(step) arguments) if you need it.)
I suspect Tim Peters had a good reason to include copysign() rather than sign(). On Wed, Dec 4, 2019 at 10:28 AM Andrew Barnert via Python-ideas < python-ideas@python.org> wrote:
On Dec 4, 2019, at 06:57, Marein <python-ideas@marein.net> wrote:
I was using it like this: range(start, end, sign(end-start)), to
automatically have a range going up or down. But that's really the only concrete case I know.
If your only use for non-float-specific copysign would be implementing sign, why not ask for sign instead? It seems much more directly useful here, and potentially more widely useful as well.
But I don’t think that’s needed either. It still doesn’t come up that often, and when it does, anyone can implement it trivially yourself (unlike float copysign).
Plus, if your only use for sign is for this range, why not just wrap that whole thing in a function and put it in your toolkit?
def birange(start, stop): return range(start, stop, 1 if stop>=start else -1)
Unlike using either sign or copysign, this doesn’t force the reader to stop and think about whether start==stop is safe, it will obviously safely give you an empty range.
(You can extend this to be more flexible (take just stop, or start and stop, or start and stop and abs(step) arguments) if you need it.)
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/3NXOYL... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
[Guido]
I suspect Tim Peters had a good reason to include copysign() rather than sign().
Tim wasn't involved in this one :-) But copysign is a "recommended" function in IEEE-754, and was eventually added to the C standard (for libm). So supplying it in `math` was really a no-brainer for whoever did it (guessing it was Mark Dickinson, but don't really know).
On 11/28/19 2:51 PM, Marein wrote:
The math.copysign(x, y) function always returns a float, even when the given x is an int, i.e. math.copysign(3, -1) gives -3.0. This is documented behaviour, but I find it somewhat surprising given that the name suggests that it only copies a sign, and it's also annoying in situations when an int is strictly needed (i.e. as the step argument to range), requiring an additional cast.
I'm interested to hear whether it might be a good idea to preserve the int/float type of the argument in math.copysign.
In my experience, copysign is really only needed for floating point numbers, and where it is used, efficiency is often at least somewhat important so adding code to make it work to produce an int result would slow things down. For a range step, I find using a ternary operation to be clearer than using copysign. -- Richard Damon
participants (7)
-
Andrew Barnert
-
Brandt Bucher
-
Christopher Barker
-
Guido van Rossum
-
Marein
-
Richard Damon
-
Tim Peters