classification
Title: math.signum(int)
Type: enhancement Stage:
Components: Library (Lib) Versions: Python 3.3
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: Nosy List: fkbreitl, gekonntde, georg.brandl, rhettinger, valhallasw
Priority: normal Keywords:

Created on 2003-10-24 02:44 by gekonntde, last changed 2012-03-15 19:48 by mark.dickinson. This issue is now closed.

Messages (17)
msg54050 - (view) Author: Konrad Voelkel (gekonntde) Date: 2003-10-24 02:44
python needs a signum function,

def signum(self, int):
 if(int < 0): return -1;
 elif(int > 0): return 1;
 else: return int;
msg54051 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2003-11-28 17:56
Logged In: YES 
user_id=80475

With the use cases being infrequent and the pure python
version being so easy, I think we ought to pass on this one.
msg54052 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2004-01-01 06:35
Logged In: YES 
user_id=80475

Closed due to lack of further interest or development.
msg155647 - (view) Author: Frank Breitling (fkbreitl) Date: 2012-03-13 19:24
Its true.
Python needs it as every scientific programming language needs it.
Its a matter of completeness.
This is a deficit.
msg155648 - (view) Author: Merlijn van Deen (valhallasw) * Date: 2012-03-13 19:31
numpy.sign does this: http://docs.scipy.org/doc/numpy/reference/generated/numpy.sign.html
msg155652 - (view) Author: Frank Breitling (fkbreitl) Date: 2012-03-13 19:41
That's too much for too little.

The math module should cover the basics.
msg155653 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2012-03-13 19:44
I disagree that this is useful enough to make it worth adding to the standard library.  Between math.copysign and simple comparisons, I think all the common cases are well covered.  And it's a simple one-line function:

def signum(x):
    return (x > 0) - (x < 0)

Frank, do you have any convincing use-cases that aren't already covered by math.copysign or simple two-way comparisons (e.g., x >= 0)?
msg155657 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2012-03-13 19:57
See also the (fairly) recent python-ideas discussion starting here:

http://mail.python.org/pipermail/python-ideas/2010-April/007136.html
msg155662 - (view) Author: Frank Breitling (fkbreitl) Date: 2012-03-13 20:43
Mark, the convincing use-cases apear already on this page.

People suggest the usage of numpy or the definition of all kinds of functions to accomplish this trivial task. But the users don't want to worry about this. They just want to use this function and not lose time figuring out how to best implement it in python.

Copysign is not very intuitive e.g. because command completion on math.si_ fails and because it will not be a first result by search engines.

The discussion is another example for the user request. And I have the feeling that with the time spend on it all different variations of signum functions could have been implemented including their documentation - although the implementation of your two line solution should have been satisfying for almost everybody...
msg155686 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2012-03-13 22:42
> Mark, the convincing use-cases apear already on this page.

I meant that I'd be interested to see examples of real code (e.g., specific numeric algorithms, etc.) where signum would be useful, and where existing functionality doesn't really do the job neatly.  In most examples I can think of, I'm either creating a sign only to multiply some quantity by it later, or I'm making some decision based on the sign.  In the first case, math.copysign usually fits the needs very well;  in the second, I only need a two-way choice anyway (until Python gets three-way if statements).

For example, a case that *seems* like it would be a good candidate for a sign function at first glance is computing the roots of a quadratic polynomial a*x**2 + b*x + c in a numerically safe manner.  There what you want to do is find the auxiliary quantity

  q = -(b + sign(b)*sqrt(b**2 - 4*a*c))

and compute the roots as q / (2*a) and (2*c) / q.  [The point of doing it this way is to avoid loss of significant digits from a subtraction of nearly-equal quantities in the case where b is large compared to a and c.]

But that's a perfect use-case for copysign:  instead of first computing the sign of b and then multiplying by the sqrt, you'd just compute

  q = -(b + copysign(sqrt(b**2 - 4*a*c), b))

Moreover, in this case you don't want the sign function described in this issue anyway, since it gives wrong results when b == 0;  you want a two-valued sign function that always gives -1 or 1, even for an argument of 0.

So, do you have better examples than the one above?
msg155733 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2012-03-14 07:22
Can we add a comment to that effect to the math docs?
msg155737 - (view) Author: Frank Breitling (fkbreitl) Date: 2012-03-14 09:23
Mark, https://en.wikipedia.org/wiki/Signum_function or elementary math books tell us that this function is called signum, sign or sgn.
A library should adopt this standard for the same reason we don't want a ComputeTheSine or calcsin, which would be very confusing.

As we learn from repeated discussions people want to use this signum function, no matter we can imagine this or not and no matter whether that functionality is hidden somewhere else.

Since we are talking about not more than 5 lines of code, I don't see any reason not to have it. If there are some please let us know.
msg155885 - (view) Author: Frank Breitling (fkbreitl) Date: 2012-03-15 14:17
Here an example where the signum function provides an elegant way to calculate the Julian date:

def julian_date(YY,MM,DD,HR,Min,Sec,UTcor):
     return 367*YY - (7*(YY+((MM+9)/12))/4) + (275*MM/9)+ DD + 1721013.5 + UTcor/24 - 0.5*sign((100*YY)+MM-190002.5) + 0.5 + HR/24.0 + Min/(60.0*24.0) + Sec/(3600.0*24.0)

http://aa.usno.navy.mil/faq/docs/JD_Formula.php
http://www.krioma.net/blog/2011/09/python_julian_date.php

By the way Julian date should be part of the time or datetime module.
msg155890 - (view) Author: Merlijn van Deen (valhallasw) * Date: 2012-03-15 14:31
I'm not quite sure why that formula would be "elegant" in the first place, and I most certainly don't understand why

0.5*sign((100*YY)+MM-190002.5) + 0.5

is more elegant than

((100*YY)+MM > 190002.5)

or

(((YY = 1900) and (MM > 2.5)) or (YY > 1900))

or rather: implementing leap years correctly in the first place, so the formula also works outside of the 1800-2099 range.


And, in general, I don't understand the problem. Everyone who does scientific computing has numpy *anyway*, so there is no gain for them.

As a last note, the C math.h also doesn't have a sign() function, and only a copysign() function: http://en.wikipedia.org/wiki/C_mathematical_functions
msg155891 - (view) Author: Merlijn van Deen (valhallasw) * Date: 2012-03-15 15:01
Although there is one use case which I now realise due to your post: easier 1-on-1 implementation of existing algorithms.

Another possible reason to implement it is that it's not that hard to implement the sign() function wrongly, if it also has to work with nans. This implementation:

def signum(x):
    return (x > 0) - (x < 0)

returns 0 for nan, which is wrong (it should return nan). Another naive implementation

def signum(x):
    return math.copysign(1, x)

also fails for nan, and gives a result for +/- 0 that could be right or wrong, depending on context.
msg155896 - (view) Author: Frank Breitling (fkbreitl) Date: 2012-03-15 15:45
Because its short.

Because the former is a proper mathematical expression, while the latter 
is python jargon with limited use elsewhere.

Exactly, why is there no correct implementation of Julian date in python 
time or datetime?
For most practical purposes I can understand why most people would 
consider the above formula most useful and most elegant.

Then what's the math module good for?

So what? Is this the law of Moses? Or should we fall back to Assebmly?
Python is supposed to be a high-level language not a stone age tool.

However, I am glad you found at least another reason convincing to have 
this function.

Cheers!
msg155897 - (view) Author: Frank Breitling (fkbreitl) Date: 2012-03-15 15:56
Unfortunately my reply to the list lost all quotes, so I try to answer again through the web interface:
---

> I'm not quite sure why that formula would be "elegant" in the first place,

Because its short.

> and I most certainly don't understand why 0.5*sign((100*YY)+MM-190002.5) + 0.5 is more elegant ...

Because the former is a proper mathematical expression, while the latter is python jargon with limited use elsewhere.

> or rather: implementing leap years correctly in the first place, so the formula also works outside of the 1800-2099 range.

Exactly, why is there no correct implementation of Julian date in python time or datetime?
For most practical purposes I can understand why most people would consider the above formula most useful and most elegant.

> And, in general, I don't understand the problem. Everyone who does scientific computing has numpy *anyway*, so there is no gain for them.

Then what's the math module good for?

> As a last note, the C math.h also doesn't have a sign() function, and only a copysign() function: http://en.wikipedia.org/wiki/C_mathematical_functions

So what? Is this the law of Moses? Or should we fall back to Assebmly?
Python is supposed to be a high-level language not a stone age tool.

However, I am glad you found at least another reason convincing to have this function.

Cheers!
History
Date User Action Args
2016-08-11 19:55:10r.david.murraylinkissue27739 superseder
2012-03-15 19:48:33mark.dickinsonsetnosy: - mark.dickinson
2012-03-15 15:56:27fkbreitlsetmessages: + msg155897
2012-03-15 15:45:11fkbreitlsetmessages: + msg155896
2012-03-15 15:01:32valhallaswsetmessages: + msg155891
2012-03-15 14:31:28valhallaswsetmessages: + msg155890
2012-03-15 14:17:16fkbreitlsetmessages: + msg155885
2012-03-14 09:23:30fkbreitlsetmessages: + msg155737
2012-03-14 07:22:57georg.brandlsetnosy: + georg.brandl
messages: + msg155733
2012-03-13 22:42:00mark.dickinsonsetmessages: + msg155686
2012-03-13 20:43:28fkbreitlsetmessages: + msg155662
2012-03-13 20:06:56mark.dickinsonsetversions: - Python 2.6, Python 3.1, Python 2.7, Python 3.2, Python 3.4
2012-03-13 19:57:06mark.dickinsonsetmessages: + msg155657
2012-03-13 19:44:35mark.dickinsonsetnosy: + mark.dickinson
messages: + msg155653
2012-03-13 19:41:40fkbreitlsetmessages: + msg155652
2012-03-13 19:31:39valhallaswsetnosy: + valhallasw
messages: + msg155648
2012-03-13 19:24:04fkbreitlsetnosy: + fkbreitl

messages: + msg155647
versions: + Python 2.6, Python 3.1, Python 2.7, Python 3.2, Python 3.3, Python 3.4
2003-10-24 02:44:04gekonntdecreate