Author Topic: Битовые и логические операции  (Read 26651 times)

0 Members and 1 Guest are viewing this topic.

Johnny

  • Создатель
  • Герой форума
  • *
  • Posts: 593
    • View Profile
Битовые и логические операции
« on: March 26, 2014, 09:11:51 AM »
Приведенная информация актуальна только для версии 4.10, находящейся на тестировании

В версии 4.10 была изменена логика работы условий и наравне с этим появилась возможность использовать в вычислениях наравне с привычной арифметикой битовые операции.

[Spoiler="Информация для тех кто уже использовал в условиях and,or,xor"]
На самом деле отчасти вы уже знакомы с битовыми операциями. Это уже знакомые нам И, ИЛИ и ИСКЛЮЧАЮЩЕЕ ИЛИ (далее and, or, xor). Несмотря на то, что эти операторы мы использовали лишь в логических условиях, на самом деле с помощью них так же можно производить операции над величинами, как это делается на самом низком уровне – уровне железа ПК.
Ранее, подразумевалось что операндами могут быть лишь 0 и 1. Ну вы помните, 0 and 1 = 0, 0 or 1 = 1 и все такое. И даже когда писалось выражение типа (5 > 3) and (4 < 2), это в конечном итоге после вычисления отношений в скобках превращалось в тоже (1) and (0)
Теперь, начиная с версии 4.10 вместе с изменением работы логики появилась возможность производить битовые операции ВЕЗДЕ. Как в условиях, так и в вычислениях.
[/spoiler]

Перед началом я напомню, что в компьютере все – в двоичном виде, потому что это исключительно удобно в плане электроники. В математике же любое число может быть представлено в любом виде, в десятичном, в двоичном, в шестнадцатеричном. В каком бы виде число не было представлено, это по прежнему то же число. Несмотря на то, что мы с детства привыкли работать в десятеричной системе счисления, а компьютер понимает лишь нули и единицы.
Так же, говоря "истина" я имею ввиду "1",а говоря "1" я имею ввиду "истина". "0" это "ложь". Такой подход обусловлен тем, что битовые операции неотделимы от логических высказываний.
Битовые операции возможны лишь с целыми положительными числами. И нулем.
Так же я напоминаю что "and", "or" и "xor" являются синонимами операций "&","|" и "^" соответственно. При этом с точки зрения кликера, "роднее" ему именно знаковые обознаения операций и поэтому я рекомендовал бы использовать именно их (меньше шанс что парсер "споткнется" в каком либо "особом случае"). Однако поскольку это учебная статья, в примерах я буду использовать первый набор, потому что для новичков он нагляднее.

Итак приступим. Бросаемся в бой сразу с готовым скриптом. Я напоминаю что версия должна быть не ниже 4.10
Code: (Clickermann) [Select]
$var = 15 and 6
print($var)
Выполнив этот код, вы получите в результате 6. То есть ничего не изменится. Рассмотрим как получается данный результат.
"15" это десятичное представление числа. Это же число представленное в двоичном виде будет выглядеть как 00001111 (для соблюдения стандарта будет оперировать одним байтом, т.е. восьми битами; незначащие разряды забьем нулями). Вы можете убедиться что это так, включив калькулятор в Win7 и переведя его в режим "Программист" (этот удобный калькулятор одна из причин моего окончательного перехода на семерку). "6" в двоичном виде это 00000110.
Выполняем операцию. Для удобства восприятия запишет одно число под другим.
Code: [Select]
00001111
00000110
И теперь просто вертикально (сверху вниз, по столбцам) проверяем привычное нам условие. Если вверху и внизу 1, то и в результате будет 1. В другом случае будет 0. Так работает операция AND и вы об этом уже знаете, если хоть раз писали комплексное условие.
Code: [Select]
00001111  // 15
          // and
00000110  // 6
00000110  // Результат 6
Повторим опыт с другими числами. Возьмем 51 и 60. Результатом будет 48. Смотрим как получилось.
Code: [Select]
76543210  // Биты, No
--------
00110011  // 51
00111100  // 60
00110000  // 48
Таким образом истину образует только пара битов 4 и 5 (биты считаются справа налево, первый бит имеет индекс 0), в которых в обоих числах единицы.
Стоит отметить, что правило про "перемену мест" справедливо для всех битовых операций. Вы легко можете проверить это простым примером на основе предыдущей задачи
Code: (Clickermann) [Select]
$var = 51 and 60
print($var)
$var = 60 and 51
print($var)
Имея эти базовые знания быстро освоим операции OR и XOR
Если для операции AND нужно для истины чтобы оба бита были 1, то для OR хватит и одного из них. Перепишем пример с 51 и 60.
Code: [Select]
00110011  // 51
00111100  // 60
00111111  // 63
Как вы видите «единички спустились» почти во все разряды кроме последних двух (6-ого и 7-ого). Для тех кто не понял почему, я напомню что и 1 or 0 = 1 и 1 or 1 = 1. Лишь 0 or 0 = 0
И завершим нашу лекцию наиболее интересной (и по этому редко используемой) операцией XOR. Это нечто среднее между AND и OR. Для того что бы XOR вернул истину, нужно что бы ЛИШЬ ОДИН из пары был истиной. Таким образом 1 xor 1 = 0 и 0 xor 0 = 0. А вот 1 xor 0 = 1.
Снова вернемся к нашим крайне удачным числам 51 и 60.
Code: [Select]
00110011  // 51
00111100  // 60
00001111  // 15
Как вы видите "разномастными" являются первые четыре пары бит (0..3). Все остальные являются одинаковыми и несмотря на 0 или 1, для xor важно лишь различие.
У операции xor есть еще одно свойство если два раза подрояд произвести операцию xor при помощи одного и того же числа, то вы получите исходное число. Иллюстрирует это простой пример
Code: (Clickermann) [Select]
$var = 51
$key = 60

$var = $var xor $key
print("xor: ", $var)

$var = $var xor $key
print("xor again: ", $var)
Поэтому XOR является самым простым (и одновременно быстрым) алгоритмом шифрования. Не знаю как вам это пригодится для написания скриптов на линейку…
Поздравляю. Вы освоили битовые операции.

Теперь, не отрываясь от чтения, рассмотрим специфику работы логических высказываний.
В версии 4.10 считается, что операции отношения  >, <, = (если речь не идет о присваивании значения) являются такими же операциями как сложение или вычитание (или битовые операции). Однако в зависимости от истинности результатом будет 0 или 1.
Рассмотрим пример.

Code: [Select]
$var = 5 > 3
При этом $var = 1, потому что 5 очевидно больше 3. Если бы было меньше, то результат был бы 0.
Более сложный случай
Code: [Select]
$var = (5 > 3) and (2 > 3)
Результат $var = 0, потому что получается (1) and (0), ведь 2 не больше 3. Ну а 1 and 0, как вы уже знаете дадут 0. Если бы это было в условии if
Code: (Clickermann) [Select]
if ((5 > 3) and (2 > 3) )
  print("ok")
end_if
То условие бы не выполнилось, потому что результат логического высказывания (состоящего из сравнений и их битового произведения – and) будет 0. Для того что бы "if выполнился" он должен быть больше нуля. Стоит заметить что не обязательно "1" а именно больше нуля.

Простые примеры для понимания
Code: (Clickermann) [Select]
// высказывание истинно ( > 0 ), условие выполняется
if(100)
  print("ok")
end_if
// высказывание ложно ( < 0 ), условие не выполняется
if(-100)
  print("ok")
end_if
// высказывание ложно (= 0), условие не выполняется
if ( 1 and 0 )
  print("ok")
end_if
// высказывание истинно (> 0, помните же пример из битовых операций?), условие выполняется
if ( 51 and 60 )
  print("ok")
end_if
// высказывание истинно, условие выполняется, приоритетные скобки поддерживаются
if ( (51 and 60) or 1 )
  print("ok")
end_if
Важно отметить важность приоритетных скобок. Дело в том что и у битовых операций есть свои приоритеты: операция AND (ее еще называют битовым произведением) выполняется первой. Если порядок действий не обозначен скобками. Пример
Code: (Clickermann) [Select]
// пример 1
$var = 3 or 15 and 12
print($var) // 15

// пример 2
$var = (3 or 15) and 12
print($var) // 12
Разберем пример 1
3 or 15 and 12 // первым по приоритету выполняется операция and получаем
3 or 12 // так как 15 and 12 = 12
И в результате будет 15, так как 3 or 12 = 15
Разберем пример 2
(3 or 15) and 12 // первым как и везде идет операция в скобках получаем
(15) and 12 // и в результате 12

Напоследок приведем совершенно дикий для новичка пример
Code: (Clickermann) [Select]
if( ((10 + (2 > 1)) and 8 + 2) or 3 )
  print("true")
else
  print("nope")
end_if
Выполнится ли условие? Да, потому что результат высказывания будет 11, а это явно больше 0, чего достаточно для выполнения блока условия, соответствующего истине. Если вы сможете самостоятельно просчитать это выражение (и запомнить что условия считаются истинными когда они больше 0) то вы способный программист.

Cartman

  • Зашел в гости
  • *
  • Posts: 6
    • View Profile
Re: Битовые и логические операции
« Reply #1 on: July 06, 2014, 04:53:20 PM »
Что то я не понял на счет условия, скобки что, наоборот раскрываются?

Johnny

  • Создатель
  • Герой форума
  • *
  • Posts: 593
    • View Profile
Re: Битовые и логические операции
« Reply #2 on: August 19, 2014, 08:43:52 AM »
Больше примеров
Я больше чем уверен, что многие не оценили (не вникли в) битовые операции, поэтому решил привести несколько примеров, показывающих сферы их применения. Возможно примеры будут дополняться.


Проверка равенства нескольких переменных в шапке одного условия
Code: (clickermann) [Select]
// изменение хотя бы одной из переменных ведет к "порче" всего условия
$var1 = 333
$var2 = 333
$var3 = 333
$var4 = 333
$var5 = 333

if ( ($var1 & $var2 & $var3 & $var4 & $var5) = 333  )
  print("true")
else
  print("false")
end_if

halt



Простой переключатель флага с 0 на 1 и обратно
Code: (clickermann) [Select]
$swch = 1

// бесконечный цикл
while(1)
  print($swch)
  $swch = $swch xor 1 // вся суть
  wait(1)
end_cyc

halt


Проверка четности значения
Стоит заметить что 0 данным кодом тоже будет считаться четным
Code: (clickermann) [Select]
// бесконечный цикл
while(1)
   $value = rnd(1,99) // генерация случайного числа
   
   if ( $value and 1 ) // проверка первого бита $value
      print($value ," - нечет")
   else
      print($value, " - чет")
   end_if
   
   wait(1)
end_cyc

halt