Пытаясь программировать ...иногда даже получается

Combined Comparison (Spaceship) Operator для чисел на PHP < 7 без операций сравнения

А вы знаете, что такое Combined Comparison (Spaceship) Operator? Еще нет? Тогда вам сюда, а пока я расскажу свой вариант реализации данного оператора для чисел на PHP < 7 без использования операторов сравнения.

Первый вопрос, который вы можете задать, зачем все это нужно? Не знаю, но я столкнулся с такой задачей на одном из собеседований, причем ответа мне так и не дали, но пытливый ум не позволил оставить вопрос без внимания.

Первое, что я решил для себя, знак результата определяется через разность входных параметров. Действительно, по такой схеме все получается как нужно:

  • $a < $b — результат отрицательный;
  • $a = $b — результат 0;
  • $a > $b — результат положительный.

Но на этом закончить нельзя, потому что вариантов может быть всего 3: -1, 0 и 1. Тогда я решил, что неплохо было бы делить результат разности - пусть это будет $c - на модуль разности, что даст в итоге единицу с нужным знаком и, действительно, получилось неплохо. Почти неплохо...:

  • -$c / $c — результат -1;
  • 0 / 0 — а вот здесь и кроется то самое "почти";
  • $c / $c — результат 1.

Все, чего можно добиться в PHP (< 7, по крайней мере) при делении на 0 — предупреждение:

E_WARNING : type 2 -- Division by zero

Это означает, что отловить ошибку через try нельзя, а по условию задачи использование операций сравнения запрещено.

Тогда мне в голову пришла идея сделать так, чтобы делитель никогда не мог быть равен 0. Сделать это я решил через сумму делителя с каким-нибудь маленьким числом, например, 0.0001. Как же так, спросите вы, ведь теперь на выходе ни при каком условии не получится 0 или 1? И будете правы.

На помощь приходит фунция round c $precision = 0 и в режиме PHP_ROUND_HALF_UP (в документации указано, что эти значения являются значениями по умолчанию, но я рекомендую указывать их явно, чтобы точно получить нужный результат). Согласно документации:

PHP_ROUND_HALF_UP — округляет val в большую сторону от нуля до precision десятичных знаков, если следующий знак находится посередине. Т.е. округляет 1.5 в 2 и -1.5 в -2.

В результате я получил следующую функцию:

function num_combined_comparsion($a, $b)
{
  $diff = $a - $b;
  $result = $diff / ( 0.0001 + abs($diff) );
  $result = round( $result, 0, PHP_ROUND_HALF_UP );

  return $result;
}

В PHP 7 функционал Combined Comparison (Spaceship) Operator будет реализован в ядре, поэтому ответ на вопрос станет проще, а пока (как минимум для PHP 5.4.38), как вариант, можно использовать такое решение. Если у кого-то есть более изящный и лаконичный ответ на поставленный вопрос, то присылайте, с радостью его рассмотрю, а пока до новых встреч и удачи!