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

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

31 голосов
/ 26 сентября 2011

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

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

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

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

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

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

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

Related: Request # 19621 Math needsфункция sign ()

Ответы [ 9 ]

52 голосов
/ 09 декабря 2013

Вот крутой однострочник, который сделает это для вас эффективно и надежно:

function sign($n) {
    return ($n > 0) - ($n < 0);
}
28 голосов
/ 27 августа 2015

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

$sign = $i <=> 0;
17 голосов
/ 26 сентября 2011

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

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

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

* * 1010

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

min(1, max(-1, (is_nan($number) or $number == 0) ? 0 : $number * INF))
9 голосов
/ 26 сентября 2011

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

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

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

6 голосов
/ 26 сентября 2011

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

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

или троичный:

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

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

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

4 голосов
/ 16 августа 2015

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

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

3 голосов
/ 21 февраля 2016

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

Что-то вроде:

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

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

2 голосов
/ 26 сентября 2011

Использование strcmp Документы :

echo $number, ': ', strcmp($number, 0), "\n";
1 голос
/ 26 сентября 2011

Вот один без петли:

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

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

array_walk($numbers, 'sign');
...