How to get sign of a number?

31,757

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

Share:
31,757
hakre
Author by

hakre

print_r converter (Github)

Updated on February 23, 2020

Comments

  • hakre
    hakre about 4 years

    Is there a (simple) way to get the "sign" of a number (integer) in PHP comparable to gmp_signDocs:

    • -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)

    Related: Request #19621 Math needs a "sign()" function

  • hakre
    hakre over 12 years
    The expression should represent a value of: (-1, 0, 1).
  • hakre
    hakre over 12 years
    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.
  • Toto
    Toto over 12 years
    Yes it does. Have a try with it.
  • zzzzBov
    zzzzBov over 12 years
    @hakre, i'm not sure what you mean by that.
  • zzzzBov
    zzzzBov over 12 years
    @hakre, forgot about that part, added a zero check.
  • hakre
    hakre over 12 years
    Cool! The docs is a little unprecise if it's always -1, 0 or 1, however, I will try it in the code. Thanks!
  • rocksportrocker
    rocksportrocker over 12 years
    this is ok for integers, but if somebody pastes this solution for floats he will get into trouble.
  • rocksportrocker
    rocksportrocker over 12 years
    this is elegant, but not very efficient. Converting an int to a string needs much longer than comparisons to 0.
  • hakre
    hakre over 12 years
    @rocksportrocker: Especially for NAN and INF values. And for integers there is overflow as well.
  • hakre
    hakre over 12 years
    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.
  • Toto
    Toto over 12 years
    @hakre: Thanks for the note. That's true when comparing string ( != '' ) and number.
  • Yukulélé
    Yukulélé about 11 years
    don't works for 0.3 (or all numbers from -1 to 1)
  • Yukulélé
    Yukulélé about 11 years
    strcmp("110","12") say 12 biger than 110 (this function compare strings char by char)
  • Yukulélé
    Yukulélé about 11 years
    @hakre: in this case, all number from -1 to 1 return 0, not their sign
  • hakre
    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
    Milosz about 10 years
    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.
  • flu
    flu over 9 years
    @Gordon Could you provide a link for that?
  • Rolf
    Rolf almost 9 years
    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.
  • hakre
    hakre about 8 years
    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.
  • asiby
    asiby almost 5 years
    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.
  • Sasha
    Sasha almost 4 years
    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 <=>.