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), как вариант, можно использовать такое решение. Если у кого-то есть более изящный и лаконичный ответ на поставленный вопрос, то присылайте, с радостью его рассмотрю, а пока до новых встреч и удачи!