[flame][holywar]a & (a - 1)

bleyman

Как известно некоторым людям, для целого положительного а выражение a & (a - 1) равно нулю в том и только том случае, если а является целой степенью двойки. Все остальные люди могут это проверить руками.
Внимание, вопрос: считаете ли вы допустимым (и, более того, необходимым) писать код именно такого вида

if (0 != (rcvBufferSize & (rcvBufferSize - 1 || rcvBufferSize <= 0)
{
throw new InvalidOperationException("Buffer size must be nonnegative power of 2");
}

в случае, если возникает необходимость проверить то, что необходимо проверить вот в этом конкретном случае?
Или призрак неграмотного сан-техника, тупо хлопающего глазами на такой код, вызывает в вас непреодолимое желание написать цикл, рекурсивную функцию, привести к даблу и взять логарифм наконец? Тогда, кстати, второй вопрос - тернарный оператор вы тоже не используете по той же причине (сложность для чтения неопытным программистом)?

Chupa

цикл и рекурсивную функцию наверное не надо,
а заменить выражение на inline функцию с камментом было бы неплохо

bobby

Вот да, я предложил это в аську, но он сказал "это не тру, имхо".

bleyman

"Читатель должен узнавать из каждой страницы что-то новое,
Совершенствоваться с каждой строкой,
Иначе чтение будет пустой забавою" (с) Oscar Wilde.

hoha32

Тернарный оператор рулит!
<это единственное, что я тут понял ^-^ >

Chupa

Угу, it was hard to write, it should be hard to understand.
Человек, читающий код, будет постоянно спотыкаться об этот &, даже если он знает, как это работает. В случае с inline функцией, код будет читаться нормально всегда, но работать точно так же.

bleyman

О тернарный оператор я тоже поначалу спотыкался взглядом, а потом вдруг привык, и он стал казаться мне намного более читабельным способом представления некоторых вещей (чем условный оператор).
Возможно, после длительного чтения/писания кода, насыщенного такими изящными вещицами, я тоже перестану спотыкаться о них взглядом? Я уже почти перестаю!

Chupa

Если ты хочешь, чтобы в дальнейшем этот код был неразрывно связан с тобой, то ты всё делаешь правильно. Потом сможешь шантажировать начальство, как единственный специалист.
Но иногда люди хотят потом спихнуть код на негров и наслаждаться результатами под звуки классической музыки, а не под стук клавиш. В этом случае лучше хоть иногда заботиться о меньших братьях.

Ivan8209

Только для машин с дополнением до двух и пропуском переполнения.
"0 !=" убрать (заменить на "!") и будет порядок.
По возможности, при прочих равных использую тернарный оператор.
Но для простоты чтения.
---
...Я работаю антинаучным аферистом...

bleyman

Ну да, я о них и забочусь.
Они будут читать мой код, периодически испытвать сатори, и, соответственно, будет расти их зарплата.

bobby

"0 !=" убрать (заменить на "!") и будет порядок.
Есть языки, в которых это некорректно.

Ivan8209

"x & (x-1)" --- это идиоматическое выражение, которому уже тыща лет.
Опытный программист его знает, а неопытный должен выучить его наизусть
точно так же, как и смысл операторов "&&" и "||".
---
...Я работаю антинаучным аферистом...

Ivan8209

Это не тот язык.
---
...Я работаю антинаучным аферистом...

bleyman

>> Только для машин с дополнением до двух и пропуском переполнения.
У моей Виртуальной Машины вполне чёткие спецификации, в которых даже указан размер инта, так что я вполне спокоен на этот счёт =)
>> "0 !=" убрать (заменить на "!") и будет порядок
Создатели моего Любимого Языка весьма радикально поборолись с "if (a = b)", запретив автоматический каст инта к булу в условии ифа. В общем, это довольно удобно.

bobby

Да вот как раз тот, раз на нем пишет .

Ivan8209

> Создатели моего Любимого Языка весьма радикально поборолись
Вот чёрт!
Уже и здесь наследили.
Александры македоцковы.
---
"...Надо учиться --- не напрягаясь!.."

bleyman

>> смысл операторов "&&" и "||".
Смысл этих операторов, кстати, радикально поменялся где-то лет двадцать назад, когда автор одного с-подобного языка разрешил оператор оверлоадинг. Как это ни удивительно, многие программисты и преподаватели программирования это изменение не заметили, и используют предыдущий смысл

Ivan8209


: * over 2 = over 2 = and abs >r * r> + ;

Не очень удачное решение.
Лучше было оставить как есть и сделать приведение к логическому типу.
А для логического типа правильно определить "&" и "|".

bleyman

Вообще ничего не понял.
Все слова понятны.
Все действия в коде вроде тоже.
Но ни то, ни другое, ни то и другое вместе никак не желает складываться во что-нибудь осмысленное.
Я ещё у Мадкроза по аське спросил - он тоже вообще ничего не понял.

enochka1145

Разумеется. Просто поставь в начале
/* if rcvBufferSize is a power of 2  */
или что-нибудь в этом духе.

bleyman

Там это в тексте эксепшена написано =)

enochka1145

Ну можешь не писать. Будешь немеренно крут. Только за твою крутизну кому-то придётся платить. Точнее, не кому, а всем тем, кто будет иметь несчастье иметь дело с твоим кодом.
Потом, принцип "не рой яму другому - сам в неё попадёшь" ещё не отменили.
Я бы всё-таки поставил комментий.

Ivan8209

Люди, делавшие "алгол", нарочно сделали знак присваивания таким,
чтобы он заметно отличался от сравнения.
Я понимаю, что насильникам было не до рассуждений,
им лишь бы работу сделать, я понимаю, что потом потребовалась
совместимость, но начерта городить чёрт знает что при создании
совершенно нового языка --- вот что мне непонятно.
Если делается логический тип, ведущий себя как один двоичный разряд,
то более имеет смысл оставить для него поразрядные действия,
а старые логические действия, когда от целого числа
бралось его логическое значение, оставить как есть
или расширить так, чтобы если от какого объекта
определить логическое значение, то бралось бы последнее.
Вроде того, список не пуст, ссылка не ведёт в никуда,
что-то ещё создано, непусто, отрисовано, отработало и т. п.
---
...Я работаю антинаучным аферистом...

Ivan8209

А зачем менять прозрачный и работающий код?
---
...Я работаю антинаучным аферистом...

bleyman

Про знак присваивания ты прав, наверное. Хотя, в общем, правильней было бы просто напрячься и сделать его statement-ом, а не expression-ом. Заодно и действий с сайд-эффектом стало бы меньше =)
А про разницу & и && ты, кажется, не понял.
В языке С семантика была такая: & - побитовый, && - логический, к логическому в качестве бесплатного дополнения даются ленивые вычисления (и то я не уверен, что в раннем стандарте эта опция была по дефолту включена).
Начиная с С++ семантика в корне поменялась: & - неленивый, && - ленивый, для логических и целочисленных типов добавляется дополнительная семантика, уже вытекающая из этого.

Ivan8209

В "алголе" он был тоже "expression".
Ты зря, на самом деле, это надо ценить.
Я не помню, как там в раннем стандарте.
Поразрядность сама собой влечёт жадность.
Если логический тип представлять одним разрядом
или равносильно таковому, то на целых и логических типах
плюсы ничего не поменяли, кроме исключения приведения
целого к логическому.
---
...Я работаю антинаучным аферистом...
P. S. Загляни в соседнее обсуждение.

bleyman

Нееее, нифига подобного.
Подумай ещё раз внимательно.
Плюсы подходят к делу с совершенно другой стороны. Правда, таким образом, что любой сишный код сохраняет свою семантику.
Разница такая же существенная (правда, немного в другой плоскости как между [] в С и оператором [] в С#: первое - это сокращённая запись dereference со сложением, второе - это сокращённая запись вызова метода Item(...)
Типа, код в большинстве случаев вроде выглядит одинаково, и компилится приблизительно в одинаковые вещи, но на самом деле - небо и земля, и это становится понятно, когда в С кто-нибудь пишет 3[a], а на шарпе - а["zzz", 13, true].
>> плюсы ничего не поменяли, кроме исключения приведения целого к логическому.
Ты о плюсах или о шарпе?

Ivan8209

> Ты о плюсах или о шарпе?
"x" --- это "##", по определению.
Типа, знаки альтерации, 1-й год обучения муз. школы.
Не вижу разницы, кроме как той, что (недо)приплюснутые разбивают
предыдущую семантику начисто.
В сях
0ead & 0xbeef --> 0x9ead
0ead && 0xbeef --> 0xbeef (с ленивостью вычислений)
0 && a/0 --> 0
1 && a/0 --> undefined
В (недо)приплюснутых, как ты утверждаешь, целые не приведутся к логическим.
Как я понял.
Или

if(0ead && 0xbeef) puts("Ha!");

всё-таки работает?
---
...Я работаю антинаучным аферистом...

Marinavo_0507

> Внимание, вопрос: считаете ли вы допустимым (и, более того, необходимым)
> писать код именно такого вида
Только если нравится писать всё по три раза по три раза по три раза, как в яве.

bleyman

Я почитал микрософтовский хелп.
1) В языке С нет типа bool, вообще ни одного. Поэтому
The logical-AND operator produces the value 1 if both operands have nonzero values. If either operand is equal to 0, the result is 0. If the first operand of a logical-AND operation is equal to 0, the second operand is not evaluated.
2) В языке С++ есть тип bool, поэтому
The logical AND operator (&&) returns the boolean value true if both operands are true and returns false otherwise. The operands are implicitly converted to type bool prior to evaluation, and the result is of type bool. Logical AND has left-to-right associativity.
На первый взгляд разницы не видно, поскольку C++ bool умеет имплицитно конвертиться в 0/1. "if", соответственно, в сишном случае требует ненулёвости аргумента, в плюсовом - эвальюэейтит аргумент в bool и требует истинности, те же яйца, вид сбоку, пока мы рассматриваем переход от С к С++.
Но в языке С++ вообще-то операторы можно перегружать произвольным образом, поэтому для произвольных сущностей a и b сам язык фиксирует едининственное ограничение по семантике, в котором & отличается от &&: один ленивый, второй неленивый. Ну и precedence у них немножко разный. А вот из этого и из общего смысла (что действие должно иметь нечто общее с конъюнкцией) уже следуют разные следствия, что типа побитовое сложение никак не может быть ленивым, например.
Более того, вот эти все тонкости на тему того, в каком порядке что во что преобразуется тоже внезапно получают некоторый смысл, так как в плюсах операторы преобразования типов тоже можно переопределять.

enochka1145

Я никогда не пишу в Java по три раза. Строчка
Object object = new Object;
набирается так:
ne
<Ctrl+Space>
<Enter>
O
<Ctrl+Space>
<Enter>
<Tab>
<Ctrl+Space>
<Enter>
<Tab>
<Del>

Marinavo_0507

> Я никогда не пишу в Java по три раза.
Молодец. Только такой сгенерированный хитроумным редактором код читать таки приходится в виде простого текста.

Ivan8209

Мне всегда казалось, что плюсы перегоняют истину в -1.
Надо будет проверить.
Если всё так, как ты говоришь, то да, код ломаться не должен.
Перегрузка операторов, да ещё и правила умолчательного преобразования типов --- это кошмар.
Оно хотя бы предупреждения даёт, что куда преобразовало?
Или это только по особой просьбе?
---
...Я работаю антинаучным аферистом...

Marinavo_0507

> Оно хотя бы предупреждения даёт, что куда преобразовало?
А ты не сдохнешь, как та корова, если на каждую строчку получишь по предупреждению?

enochka1145

Ну ведь загибаешь же, а?
Можешь не повторяться, а давать переменным дурацкие имена.
Можно было бы не называть конструктор именем класса, а оставить как в виртуальной машине - <init>.
Так было бы удобнее?
Прочитать 3 похожих слова - не такая уж и тяжёлая работа. ИМХО, тяжелее было бы гадать: "что общего между этими тремя разными названиями?"

Marinavo_0507

> Можешь не повторяться, а давать переменным дурацкие имена.
К счастью, сразу же было предложено решение получше - inline функция. Ну или #define.

enochka1145

// Мне всегда казалось, что плюсы перегоняют истину в -1.

А почему не в -666? Лечись, пока есть надежда, пока диагноз опять не изменился.
Типы, кстати, не обязательно преобразовывать неявно. Есть ключевое слово explicit.

Ivan8209

Не знаю, я уже отвык от ECLRL, у меня REPL
и то, что понравилось, записывается в блокнотик.
---
...Я работаю антинаучным аферистом...

enochka1145

// К счастью, сразу же было предложено решение получше - inline функция. Ну или #define.
Не понимаю. Можно пример?

Elina74

Поддерживаю. -666 было бы логичнее.
___
Ибо так завещал великий Ленин.

Ivan8209

Кофеинщикам не понять.
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."

Elina74

А если приплюснутые?
___
я в вашу

Ivan8209

static inline int _ispow2(int n) { return (n&(n-1; }
#define _ispow2(n) n)&n)-1
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."

enochka1145

Нет, ну это просто жемчужина C++-творчества, не считая static, int (вместо bool подчёркивания, лишних скобок после return, макроса со всеми присущими ему недостатками (навскидку, отсутствие пространства имён и проверки типов, а также дословное упоминание аргумента дважды) и отсутствия проверки на положительность.
Только я вообще-то не тот вопрос задавал.
Ещё раз говорю, лечись пока не поздно. Сам себе потом ещё не раз спасибо скажешь.

Ivan8209

На плюсы мне покласть, они большие и тормознутые,
под интересующую меня платформу их нет, только кросс.
Да и код будет слишком громоздким.
Подчёркивание для того, что не WFF.
---
"Люди недалёкие обычно осуждают всё, что выходит за пределы их понимания."

Anturag

Нет, ну это просто жемчужина C++-творчества, не считая static, int (вместо bool подчёркивания, лишних скобок после return, макроса со всеми присущими ему недостатками (навскидку, отсутствие пространства имён и проверки типов, а также дословное упоминание аргумента дважды) и отсутствия проверки на положительность.

Ты прогнал, начиная со слов "С++-творчества" и далее. Подумай почему (подсказку уже дал даже )
Оставить комментарий
Имя или ник:
Комментарий: