Давно ничего не писал. А тут вдруг решил проблему, которая периодически занимала меня последний месяц. Речь про задачу про знаки из первой лабораторной работы курсеровского курса Hardware/Software Interface. Из-за этой задачи, я собственно и дропнул этот курс – не сумел решить с наскоку и расстроился.
Суть задачи в том, что используя только операции сложения, вычитания, умножения, битового сдвига влево и вправо, побитовых И, ИЛИ, НЕ, исключающего ИЛИ и оператора логического отрицания решить задачу нахождения знака 32-битного числа со знаком. На вход функции подаётся число, на выходе должны быть:
- 1 – если число положительное
- -1 – если число отрицательное
- 0 – если число – это ноль
Использовать какие-либо операторы сравнения запрещено.
Задача решается элементарно благодаря оператору логического отрицания. Суть этого оператора в том, что он возвращает единицу, если ему на вход дали ноль и возвращает ноль, если на вход ему дали не ноль.
Фишка в том, что знак хранится в 31-ом бите и сам по себе выделяется очень просто. Засада на месяц состояла в том, чтобы отделить положительные числа от нуля – в обоих случаях в 31-ом бите сидит ноль. А решение состоит в том, чтобы умножить выделенный знак на двойное логическое отрицание исходного числа. Вот и весь фокус. Весьма тривиальный и простой, но непривычный для меня.
out = (1-2*((unsigned)in>>31))*!!in;