How to get sign of a number?
Solution 1
Here's a cool one-liner that will do it for you efficiently and reliably:
function sign($n) {
return ($n > 0) - ($n < 0);
}
Solution 2
In PHP 7 you should use the combined comparison operator (<=>
):
$sign = $i <=> 0;
Solution 3
A variant to the above in my question I tested and which works as well and has not the floating point problem:
min(1, max(-1, $number))
Edit: The code above has a flaw for float numbers (question was about integer numbers) in the range greater than -1
and smaller than 1
which can be fixed with the following shorty:
min(1, max(-1, $number == 0 ? 0 : $number * INF))
That one still has a flaw for the float NAN
making it return -1
always. That might not be correct. Instead one might want to return 0
as well:
min(1, max(-1, (is_nan($number) or $number == 0) ? 0 : $number * INF))
Solution 4
You can nest ternary operators:
echo $number, ': ', ($number >= 0 ? ($number == 0 ? 0 : 1) : -1 )
This has no problem with floating point precision and avoids an floating point division.
Solution 5
What's wrong with this form?
if ( $num < 0 )
{
//negative
}
else if ( $num == 0 )
{
//zero
}
else
{
//positive
}
or ternary:
$sign = $num < 0 ? -1 : ( $num > 0 ? 1 : 0 );
Not sure of the performance of abs
vs value comparison, but you could use:
$sign = $num ? $num / abs($num) : 0;
and you could turn any of them into a function:
function valueSign($num)
{
return $sign = $num < 0 ? -1 : ( $num > 0 ? 1 : 0 );
//or
return $sign = $num ? $num / abs($num) : 0;
}
I suppose you could be talking about gmp_cmp
, which you could call as gmp_cmp( $num, 0 );
Comments
-
hakre about 4 years
Is there a (simple) way to get the "sign" of a number (integer) in PHP comparable to
gmp_sign
Docs:- -1 negative
- 0 zero
- 1 positive
I remember there is some sort of compare function that can do this but I'm not able to find it at the moment.
I quickly compiled this (Demo) which does the job, but maybe there is something more nifty (like a single function call?), I would like to map the result onto an array:
$numbers = array(-100, 0, 100); foreach($numbers as $number) { echo $number, ': ', $number ? abs($number) / $number : 0, "\n"; }
(this code might run into floating point precision problems probably)
-
hakre over 12 yearsThe expression should represent a value of:
(-1, 0, 1)
. -
hakre over 12 yearsDoes this work for numbers (as strings)? I think that's the function I was thinking about, but I'm unsure if it's really doing the job.
-
Toto over 12 yearsYes it does. Have a try with it.
-
zzzzBov over 12 years@hakre, i'm not sure what you mean by that.
-
zzzzBov over 12 years@hakre, forgot about that part, added a zero check.
-
hakre over 12 yearsCool! The docs is a little unprecise if it's always
-1, 0 or 1
, however, I will try it in the code. Thanks! -
rocksportrocker over 12 yearsthis is ok for integers, but if somebody pastes this solution for floats he will get into trouble.
-
rocksportrocker over 12 yearsthis is elegant, but not very efficient. Converting an int to a string needs much longer than comparisons to 0.
-
hakre over 12 years@rocksportrocker: Especially for NAN and INF values. And for integers there is overflow as well.
-
hakre over 12 yearsI now have tested this for some hours. If the
$number
actually is a string (and representing zero, like"n/a"
), this won't work (min(max) works here). Just noting, it's a side-case, just leaving this for the note. It generally worked pretty well, but not for string variables representing the numerical value0
as we know it in PHP. @rocksportrocker: There are not really actual types like string or intever in PHP, so the conversion argument seems bogus in my eyes. Would be micro-optimizing for nothing anyway to that closely watch at it. -
Toto over 12 years@hakre: Thanks for the note. That's true when comparing string ( != '' ) and number.
-
Yukulélé about 11 yearsdon't works for
0.3
(or all numbers from-1
to1
) -
Yukulélé about 11 years
strcmp("110","12")
say12
biger than110
(this function compare strings char by char) -
Yukulélé about 11 years@hakre: in this case, all number from -1 to 1 return 0, not their sign
-
hakre about 11 years@Yukulélé: Edited the post. Hope this is more helpful. Keep in mind that the question asks for integer numbers, not floating point numbers.
-
Milosz about 10 yearsWell, you won't run into integer overflow issues or float precision issues since no arithmetic is performed on
$n
. Moreover, IEEE floats do follow the law of excluded middle (¬(A > B) ⇒ A ≤ B
,¬(A < B) ⇒ A ≥ B
), so you won't get a nonzero number satisfying both conditions and yielding an incorrect sign of0
. Finally, both-0
and0
are treated as equal to zero by IEEE specs, so will both return false under both conditions, yielding a sign of0
. It's going to work for all numeric inputs. FeedingNAN
into the function yields1 - 1 = 0
which is as good an answer as any I suppose. -
flu over 9 years@Gordon Could you provide a link for that?
-
Rolf almost 9 yearsIt's here: php.net/manual/en/language.operators.comparison.php and the reason is that it's not obvious what (true?'true':false?'t':'f') will return (it's 't', not 'true'). rocksportrocker used parentheses to ensure the order of evaluation, and that's okay.
-
hakre about 8 yearsgood point, perhaps a bit rough at the edges (not saying other answers are complete, my old one also has rough edges IIRC), it's not only division by zero but also INF which needs handling for the division operator.
-
asiby almost 5 yearsThis is good, I love it. The spaceship operator. But it will break servers that have not yet been upgraded to PHP 7.0. Sadly those still exist.
-
Sasha almost 4 yearsAFAIK, in PHP result of
<=>
isn't guaranteed to be+1
,0
or-1
, it can be any positive integer instead of+1
and any negative integer instead if-1
(see discussion in comments here). So, the TS may need some function to process the result of<=>
.