Смотрел я как то, не так давно, почти что только что, код своего преподавателя, набирался уму - разуму, да попивал чай зеленый с коньячком, и вдруг встречаю я странную штуку:
k=k+!(k%2);
Углубился я в раздумья - "встречал то раньше я знак восхищения только в логически
выражениях, а тут вот на тебе"... И как бы я часто клавишу F10 не нажимал так понят
и не смог, зачем оно и что делает. Помню, как то, человек хороший, сказал мне мудрость вот такую, что напиши ты int a=0; a следом сразу a=~a; то а в мгновенья станет -1, так вот, возможноль, что и этот случай, который был описан выше, причастен к фокусам из этих серий?
Ответы
Ответ 1
Да, это из той же серии, что и ~a.
На самом деле !a эквивалентно (a == 0) и имеет тип bool. Но когда вы интерпретирует
это значение как int (а у вас так и происходит, из-за сложения с целым), bool превращаетс
в 0 или 1. Таким образом, как целое число наше выражение эквивалентно a == 0 ? 1 : 0. В частности, если известно, что a -- 0 или 1, то это просто меняет значение на противоположное: если был ноль, станет 1, иначе станет 0.
Таким образом, выражение k+!(k%2) следует понимать так:
если k было чётным, k%2 == 0, ! обращает значение в 1, и в результате получается k+1.
если k было нечётным, k%2 != 0, ! обращает значение в 0, и в результате получается просто k.
То есть результат -- ближайшее (сверху) нечётное число. Makes sense?
Такая техника, как в вашем примере -- один из примеров кода, за который одни обожают
а другие ненавидят язык С++ (и С). Специалисты, тяготеющие к С, обычно больше любя
такую лаконичную запись, а те, кто видит в языке скорее высокоуровневые конструкции, чем биты и байты, часто морщатся от такого кода. Я отношу себя к любителям высокоуровневых языков, но мне такие лаконичные конструкции нравятся.
Вот тут собрано много примеров подобного кода. Почитайте! Ещё несколько мозгоразрывающих примеров на SO: здесь и здесь.
(Вынес из комментариев) Кстати, обратите внимание, что более коротким (и возможно более эффективным) кодом, выполняющим ту же задачу, является
k |= 1;
Он, кстати, работает и для отрицательных значений k (это не вполне очевидно).
Ответ 2
Знак ! обозначает отрицание. !0 равен 1, !все_остальное равно 0.
Смысл k=k+!(k%2); Если k четное, оно увеличивается на единицу. Более короткая запись k|=1;
Если разложить по шагам:
X=k%2
if(X) X=0; else X=1;
k=k+X;
Ответ 3
Вот @Rules, возможно, пытался сказать что-то более-менее правильное. Но до конц
он так вам все и не объяснил. Дело в том, что логический тип в С++ - это алиас целочисленног
типа, но, в отличие от целых чисел типа int, например, тип bool имеет целочисленные значения в диапазоне от [0;1]. Короче говоря, логический тип может принимать только два значения - 0(false), 1(true).
Сказанное мною вы можете сами проверить, приведя "логику" к числам так, например:
int a=(int)true; // 1
int b=(int)false // 0
И приводить, кстати говоря, явным образом не обязательно. Обратный пример:
bool a=48555; // 1
bool b=0; // 0
bool b=-948; // 1( из этого следует, что false`ом может быть только нуль )
Из всего этого следует, что эта "конструкция":
k=k+!(k%2);
будет либо инкрементировать K, либо оставлять неизменным. Если (k%2)>0, то прибавляется нуль ( т.к !(true) - это false ), иначе - единица( т.к !(false) - это true).
И никаких величин более единицы, как это вам показал @Rules !
P.S И вам, и пользователю @Rules было бы неплохо ознакомиться с булевой алгеброй.
Ответ 4
k=k+!(k%2);
Значит: k равно k плюс не(остаток от деления k на 2);
не(1) = 0; не(0) = 1;
5%2 = остаток от деления 5 на 2 = 1 (т.е (4/2)+1);
23%7 = остаток от деления 23 на 7 = 2 (т.е (21/7)+2);
24%2 = остаток от деления 24 на 2 = 0 (т.е (24/2)+0);
итак: если k = 4 то k = 4 + !0 => k = 4 + 1 => k = 5;
если k = 17 то k = 17 + !1 => k = 17 + 0 => k = 17
то есть k увеличивается на единицу если оно изначально делилось на 2
PS: забыл упомянуть: !(любое число кроме 0) = 0
Комментариев нет:
Отправить комментарий