Когда написанный на С++ с использованием С и Ассемблера кусок кода в 12 тысяч строк внезапно компилируется с первого раза, это как минимум подозрительно. Я боюсь его запускать.
Рубрика: Блог
Судебные издержки
Проходил в здание суда. Звеню на металлоискателе. Охранники делают стойку, я выкладываю всё из карманов. Продолжаю звенеть. Снимаю очки, ручку, bluetooth-гарнитуру. Продолжаю звенеть. В задумчивости показываю охранникам пряжку ремня и чехол для телефона с магнитными застёжками. Охранники придирчиво осматривают ремень и позволяют мне пройти.
В лифте, рассовывая добро по карманам, обнаруживаю на ремне, за чехлом для телефона, складной нож калибра «на динозавра», который я забыл оставить дома…
Back to the Future
Что же ещё смотреть в день перевода часов на зимнее время, как не великую, непревзойдённую классику «Назад в будущее», — хотя бы ради вступительных кадров? 🙂

Программистский юмор
В Фортране переменные, начинающиеся с букв от I до N, имеют по умолчанию тип «целое число» (integer), а со всех остальных — «вещественное», сиречь любое на числовой прямой (real). Можно было вручную преодолеть это ограничение, явно переопределив тип переменной при её создании. Отсюда пошла шутка:
In Fortran, God is real (unless declared integer).
Восхищения пост
Вот за что я люблю IKEA — это за веру в людей.
Держатель крышек для кастрюль Variera. Во всей инструкции по сборке — один пункт: «Навинтить 14 шпеньков на фиговинки». И сверху заботливый комикс: «Запутался в инструкции? Позвони нам, мы поможем!»


Ребята, вы правда верите в то, что если человек сумел запутаться в такой инструкции, то он сможет вам позвонить?..
Как перевернуть 32-битное число?
Предположим, у вас есть 32-битное число, и вы хотите перевернуть его побитово, независимо от знака: 0x00000001 станет 0x80000000, а 0x71643257, или 01110001 01100100 00110010 01010111 в двоичной записи, станет 11101010 01001100 00100110 10001110, или 0xEA4C268E.
Как сделать это наиболее эффективно?
Простейший способ — выполнить итерацию в цикле по всем 32 битам и на каждой итерации брать последний бит с одной из сторон, создавая новое число бит за битом:
unsigned reverseBits(unsigned n) {
unsigned result = 0;
for (int i = 0; i < 32; ++i) {
// Extract the least significant bit of `n` and shift it to the correct position
result = (result << 1) | (n & 1);
// Shift `n` to process the next bit
n >>= 1;
}
return result;
}И это работает, но неэффективно, главным образом из-за самого цикла, который добавляет ветвления. Мы можем немного поиграть с циклом, заменив for на do { … } while, но это мало что изменит. Можно ли вообще избавиться от цикла?
Вообще-то, можно!
Смотреть и восхищаться:
unsigned reverse(unsigned x) {
x = ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555);
x = ((x & 0x33333333) << 2) | ((x >> 2) & 0x33333333);
x = ((x & 0x0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F);
x = (x << 24) | ((x & 0xFF00) << 8) |
((x >> 8) & 0xFF00) | (x >> 24);
return x;
}Никаких ветвлений, никаких циклов, только сдвиги и логические операции.
Разве это не гениально? Какая жалость, что это не мой код! 🙂 Я бы тоже решал эту задачу с помощью цикла.