Знаковая проблема

Давно ничего не писал. А тут вдруг решил проблему, которая периодически занимала меня последний месяц. Речь про задачу про знаки из первой лабораторной работы курсеровского курса Hardware/Software Interface. Из-за этой задачи, я собственно и дропнул этот курс – не сумел решить с наскоку и расстроился.

Суть задачи в том, что используя только операции сложения, вычитания, умножения, битового сдвига влево и вправо, побитовых И, ИЛИ, НЕ, исключающего ИЛИ и оператора логического отрицания решить задачу нахождения знака 32-битного числа со знаком. На вход функции подаётся число, на выходе должны быть:

  • 1 – если число положительное
  • -1 – если число отрицательное
  • 0 – если число – это ноль

Использовать какие-либо операторы сравнения запрещено.

Задача решается элементарно благодаря оператору логического отрицания. Суть этого оператора в том, что он возвращает единицу, если ему на вход дали ноль и возвращает ноль, если на вход ему дали не ноль.

Фишка в том, что знак хранится в 31-ом бите и сам по себе выделяется очень просто. Засада на месяц состояла в том, чтобы отделить положительные числа от нуля – в обоих случаях в 31-ом бите сидит ноль. А решение состоит в том, чтобы умножить выделенный знак на двойное логическое отрицание исходного числа. Вот и весь фокус. Весьма тривиальный и простой, но непривычный для меня.

out = (1-2*((unsigned)in>>31))*!!in;