Wonder if there are any nontrivial ways of finding number\'s sign (signum function)?
May be shorter / faster / more elegant solutions than the obvious one
Math.sign is not supported on IE 11. I am combining the best answer with Math.sign answer :
Math.sign = Math.sign || function(number){
var sign = number ? ( (number <0) ? -1 : 1) : 0;
return sign;
};
Now, one can use Math.sign directly.
The function you're looking for is called signum, and the best way to implement it is:
function sgn(x) {
return (x > 0) - (x < 0);
}
Should this not support JavaScript’s (ECMAScript’s) signed zeroes? It seems to work when returning x rather than 0 in the “megafast” function:
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? x : NaN : NaN;
}
This makes it compatible with a draft of ECMAScript’s Math.sign (MDN):
Returns the sign of the x, indicating whether x is positive, negative or zero.
- If x is NaN, the result is NaN.
- If x is −0, the result is −0.
- If x is +0, the result is +0.
- If x is negative and not −0, the result is −1.
- If x is positive and not +0, the result is +1.
A solution that works on all numbers, as well as 0
and -0
, as well as Infinity
and -Infinity
, is:
function sign( number ) {
return 1 / number > 0 ? 1 : -1;
}
See the question "Are +0 and -0 the same?" for more information.
Warning: None of these answers, including the now standard Math.sign will work on the case 0
vs -0
. This may not be an issue for you, but in certain physics implementations it may matter.
The methods I know of are as follows:
Math.sign(n)
var s = Math.sign(n)
This is the native function, but is slowest of all because of the overhead of a function call. It does however handle 'NaN' where the others below may just assume 0 (i.e. Math.sign('abc') is NaN).
((n>0) - (n<0))
var s = ((n>0) - (n<0));
In this case only the left or right side can be a 1 based on the sign. This results in either 1-0
(1), 0-1
(-1), or 0-0
(0).
The speed of this one seems neck and neck with the next one below in Chrome.
(n>>31)|(!!n)
var s = (n>>31)|(!!n);
Uses the "Sign-propagating right shift". Basically shifting by 31 drops all bits except the sign. If the sign was set, this results in -1, otherwise it is 0. Right of |
it tests for positive by converting the value to boolean (0 or 1 [BTW: non-numeric strings, like !!'abc'
, become 0 in this case, and not NaN]) then uses a bitwise OR operation to combine the bits.
This seems the best average performance across the browsers (best in Chrome and Firefox at least), but not the fastest in ALL of them. For some reason, the ternary operator is faster in IE.
n?n<0?-1:1:0
var s = n?n<0?-1:1:0;
Fastest in IE for some reason.
jsPerf
Tests performed: https://jsperf.com/get-sign-from-value
I don't see any practical sence of returning -0 and 0 from Math.sign
so my version is:
function sign(x) {
x = Number(x);
if (isNaN(x)) {
return NaN;
}
if (x === -Infinity || 1 / x < 0) {
return -1;
}
return 1;
};
sign(100); // 1
sign(-100); // -1
sign(0); // 1
sign(-0); // -1