Как получить знак числа?

есть ли (простой) способ получить "знак" числа (целого числа) в PHP, сопоставимого с gmp_signDocs:

  • -1 отрицательный
  • 0 ноль
  • 1 положительный

Я помню, что есть какая-то функция сравнения, которая может это сделать, но я не могу найти ее на данный момент.

я быстро собрал эту (демо), который делает работу, но, возможно, есть что-то более изящное (например, вызов одной функции?), Я хотел бы отобразить результат на массив:

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

foreach($numbers as $number)
{
   echo $number, ': ', $number ? abs($number) / $number : 0, "n";
}

(этот код может столкнуться с проблемами точности с плавающей запятой, вероятно)

по теме: запрос #19621 Math нуждается в функции " sign ()"

9 ответов


вот классный One-liner, который сделает это для вас эффективно и надежно:

function sign($n) {
    return ($n > 0) - ($n < 0);
}

в PHP 7 Вы должны использовать комбинированный оператор сравнения (<=>):

$sign = $i <=> 0;

вариант выше в моем вопросе, который я тестировал и который также работает и не имеет проблемы с плавающей запятой:

min(1, max(-1, $number))

Edit: код выше имеет недостаток для чисел float (вопрос был о целых числах) в диапазоне, большем, чем -1 и меньше 1 который может быть исправлен со следующим коротышкой:

min(1, max(-1, $number == 0 ? 0 : $number * INF))

у этого все еще есть недостаток для поплавка NAN возвращение -1 всегда. Что может быть правильный. Вместо этого можно захотеть вернуться 0 а также:

min(1, max(-1, (is_nan($number) or $number == 0) ? 0 : $number * INF))

вы можете вложить троичные операторы:

echo $number, ': ',  ($number >= 0 ? ($number == 0 ? 0 : 1) : -1 )

Это не имеет проблем с точностью с плавающей запятой и позволяет избежать деления с плавающей запятой.


что не так с этой формой?

if ( $num < 0 )
{
  //negative
}
else if ( $num == 0 )
{
  //zero
}
else
{
  //positive
}

или тройной:

$sign = $num < 0 ? -1 : ( $num > 0 ? 1 : 0 );

Не уверен в производительности abs vs сравнение значений, но вы можете использовать:

$sign = $num ? $num / abs($num) : 0;

и вы можете превратить любой из них в функцию:

function valueSign($num)
{
  return $sign = $num < 0 ? -1 : ( $num > 0 ? 1 : 0 );
  //or
  return $sign = $num ? $num / abs($num) : 0;
}

Я полагаю, вы могли бы говорить о gmp_cmp, который вы могли бы назвать gmp_cmp( $num, 0 );


Я думаю, что gmp_sign не очень эффективен, потому что он ожидает GMP или строку. ($n ? abs ($n)/$n : 0) математически корректен, но деление стоит времени. Решения min/max, похоже, становятся ненужными для поплавков.

($n > 0) - ($n 0 ? 1: 0) делает один или два теста и никакой арифметики, он должен быть наиболее эффективным. Но я не верю, что разница будет актуальна для большинства случаев использования.


Я знаю, что это поздно, но как насчет простого деления числа на abs () самого по себе?

что-то типа:

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

поместите любую обработку ошибок, которую вы хотите для div, на ноль.


вот один без цикла:

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

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

array_walk($numbers, 'sign');

использовать strcmpDocs:

echo $number, ': ', strcmp($number, 0), "\n";