Необычное использование побитового XOR в Javascript?
Привет.
Отлаживая недавно очередной кусок чужого кода наткнулся на такой цикл:
while (--i ^ -1) /* тело цикла */;
при этом, изначально i равно некоторому положительному числу. То есть, побитовый оператор используется здесь для целых чисел. Немного подумав, я понял, что результат побитового XOR обратится в нуль единственно в случае, когда числа равны. Тогда условие кастуется в true. В противном случае, будет не-ноль, что кастуется в false.
Получается, можно использовать побитовый XOR вместо оператора != (если мы заранее знаем, что сравниваемые величины суть числа).
Отсюда у меня возник вопрос, который я хочу поставить перед аудиторией.
Почему автор использует XOR?
Вчера весь вечер я размышлял над этим и наиболее правдоподобной причиной мне показалось желание написать «крутой непонятный код». Сразу вспомнилось, как я, когда начинал постигать азы программирования, вдруг обнаружил, что могу писать «лаконичный код, который сложен для понимания и который работает». Мне казалось, что это свидетельствует о каких-то скиллах. На самом деле, понятно, что это свидетельствует об обратном. В пользу этой гипотезы было ещё то, что весь остальной код в окрестности приведённого фрагмента был написан подобным образом.
Правда, мне не давала покоя ещё одна мысль. Я представил себе, что если бы я хотел усложнить код, мне бы почему-то не пришло в голову использовать XOR, даже если бы я и знал о такой возможности.
В результате (безуспешно пытаясь заснуть на протяжение двух часов :) ), я встал, подошёл к компу и написал скриптик, который делал много сравнений тем и иным способом и мерял время.
Оказалось, что если использовать побитовый XOR вместо !=, появляется прирост в производительности (по крайней мере на Firefox), этот прирост стабильный (то есть он есть всегда, то больше, то меньше), но составляет всего лишь около 1%.
Может быть, есть ещё какие-нибудь особенности, дающие преимущество побитовому XOR?
Время я мерял так: написал два одинаковых цикла которые проверяли это условие одинаковое «большое число» раз. «Большое число» было достаточно большим, чтобы условие проверялось несколько секунд, но достаточно малым, чтобы броузер не успел пожаловаться на зависший скрипт.
Затем я прогнал скрипт несколько раз и смотрел результаты.
После этого для симметричности я поменял циклы местами. И всегда оказывалось что XOR считает чуть-чуть быстрее. Так что, это не похоже на «выброс в пределах погрешности».
Код, который был в окрестности манипулирует элементами нескольких массивов побитово. Мы обсуждали вчера с коллегами, появилась гипотеза, что писать этот код посадили какого-нибудь олдскульного сишника или ассемблерщика. Вроде как, такие выкрутасы для них являются нормальными и не требуют дополнительных комментариев.
Возможно, побитовый XOR в этом случае всегда приводит к экономии памяти и времени, и чувак написал его не задумываясь безо всякой задней мысли. А мы тут гадаем :)
Как вариант код писал фанат оллимпиадного программирования. Там главное задачу решить, уложившись в нормативы, а уж насколько будет непонятным решение неважно.