# How to get sign of a number?

5.2k Views

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)

• @Orbling: Good question, maybe because it's already installed? Let me try :)
• @Tomalak Geret'kal: Sometimes you're looking for feedback, right? ;)

Here's a cool one-liner that will do it for you efficiently and reliably:

``````function sign(\$n) {
return (\$n > 0) - (\$n < 0);
}
``````
• 1
• Well, 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 of `0`. Finally, both `-0` and `0` are treated as equal to zero by IEEE specs, so will both return false under both conditions, yielding a sign of `0`. It's going to work for all numeric inputs. Feeding `NAN` into the function yields `1 - 1 = 0` which is as good an answer as any I suppose.

In PHP 7 you should use the combined comparison operator (`<=>`):

``````\$sign = \$i <=> 0;
``````
• This 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.
• AFAIK, 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 `<=>`.

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))
``````
• 1
• this is ok for integers, but if somebody pastes this solution for floats he will get into trouble.
• 2
• @rocksportrocker: Especially for NAN and INF values. And for integers there is overflow as well.
• don't works for `0.3` (or all numbers from `-1` to `1`)
• 1
• @hakre: in this case, all number from -1 to 1 return 0, not their sign
• 2
• @Yukulélé: Edited the post. Hope this is more helpful. Keep in mind that the question asks for integer numbers, not floating point numbers.

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.

• @Gordon Could you provide a link for that?
• 1
• It'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.

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 );`

• The expression should represent a value of: `(-1, 0, 1)`.
• 1
• @hakre, i'm not sure what you mean by that.
• 2
• @hakre, forgot about that part, added a zero check.

I think that gmp_sign is not very efficient because it expects a GMP or string. (\$n ? abs(\$n)/\$n : 0) is mathematically correct, but the division costs time. The min/max solutions seem to get unnecessary complex for floats.

(\$n > 0) - (\$n < 0) always does 2 tests and one subtraction (\$n < 0 ? -1 : (\$n > 0 ? 1 : 0) does one or two tests and no arithmetic, it should be most efficient. But I don't believe that the difference will be relevant for most use cases.

I know this is late but what about simply dividing the number by the abs() of itself?

Something like:

``````function sign(\$n) {
return \$n/(abs(\$n));
}
``````

Put whatever error handling you want for div by zero.

• 2
• good 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.
``````echo \$number, ': ', strcmp(\$number, 0), "\n";
``````
• 1
• this is elegant, but not very efficient. Converting an int to a string needs much longer than comparisons to 0.
• I 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 value `0` 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.
• Does 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.
• 2
• Yes it does. Have a try with it.
• Cool! The docs is a little unprecise if it's always `-1, 0 or 1`, however, I will try it in the code. Thanks!

Here's one without loop:

``````function sign(\$number){
echo \$number, ': ', \$number ? abs(\$number) / \$number : 0, "\n";
}

\$numbers = array(-100, 0, 100);

array_walk(\$numbers, 'sign');
``````