Побитовые операции "на пальцах"

Простой пример для понимания того, как это работает.

Введение

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

Теория

Под каждое число ОС выделяет определенный участок в памяти. Его размер зависит от типа числа. Платформа 1С сама заботится о типах — это называется динамической типизацией. Но если открыть синтакс-помощник и найти там например функцию ПобитовоеИ, то в описании сказано, что в качестве параметра может быть указано число в диапазоне 0 – 2#k8SjZc9Dxk32-1 (4.294.967.295), что соответствует типу unsigned long int. Максимальный размер такого числа будет 32 бита (4 байта). Каждый бит в памяти может быть представлен 1 или 0. Число начинает формироваться начиная с самого правого бита (00000000000000000000000000000001 — 1 с типом unsigned long int в двоичной системе).

Практика

В качестве практики реализуем функцию, которая будет преобразовывать число из десятичной системы в двоичную, используя побитовые операции. Идея такого алгоритма в следующем — нужно проверить каждый бит числа на наличие в нем 0 или 1. Из полученных таким образом чисел, можно составить представление исходного числа в двоичной системе. Другими словами, каждый бит числа типа unsigned long int нужно сравнить с 1. Таких битов в числе этого типа 32, то есть можно использовать цикл. Ранее я привел пример того, как выглядит 1 в двоичной системе. То есть если в цикле передвигать первый бит начиная с самого старшего, то получится, что за время цикла 1 "побывает" в каждом из битов. Это можно назвать маской. В виде таблицы можно представить вот так:

Номер итерации Десятичное представление (1*2#k8SjZc9DxkНомерИтерации) Двоичное представление
31 2,147,483,648 10000000000000000000000000000000
3 8 00000000000000000000000000001000
2 4 00000000000000000000000000000100
1 2 00000000000000000000000000000010
0 1 00000000000000000000000000000001

Теперь на каждой итерации можно "сравнивать" биты исходного числа с десятичным числом из средней колонки таблицы. В случае полного совпадения битов (1-1 или 0-0) результат должен быть также 1 или 0, в противном случае всегда 0. В полученном таким образом числе, текущий бит (номер итерации) нужно сдвинуть вправо на количество битов, равное номеру итерации.

Описанный алгоритм реализуется средствами языка платформы 1С следующим образом:

Result = "";
Size = 32;
Counter = Size - 1;
While Counter >= 0 Do
// ПобитовыйСдвигВлево
Mask = BitwiseShiftLeft(1, Counter);
// ПобитовоеИ
NumberAfterCompare = BitwiseAnd(Mask, LongToBinary);
// ПобитовыйСдвигВправо
OneOrZero = BitwiseShiftRight(NumberAfterCompare, Counter);
Result = Result + String(OneOrZero);
EndDo;
Message(Result);

Но, разработчики платформы сделали пару функций, которые облегчат решение данной задачи. В данном случае переменную OneOrZero можно получить следующим образом:

// ПроверитьПоБитовойМаске
OneOrZero = ?(CheckByBitMask(LongToBinary, Mask), 1, 0);

Но и это не все. В следующем примере даже нет необходимости вычислять маску:

// ПроверитьБит
OneOrZero = ?(CheckBit(IntToBinary, Counter), 1, 0);

Вместо заключения приведу еще один простой пример. Эта операция известна как swap. Кто не знает что это такое — обязательно запустите, будете удивлены.

a = BitwiseXor(a, b);
b = BitwiseXor(a, b);
a = BitwiseXor(a, b);

P.s. Есть еще несколько функций платформы для работы с битами. Краткое их описание на зазеркалье.

14 Comments

  1. CyberCerber

    Недавно писал генерацию QR, DataMatrix и других ШК на чистом 1С, поэтому с такими операциями повозился.

    Понял, насколько 1С все же медленный. Чтобы добиться скорости генерации хотя бы 10 ШК в секунду, пришлось поизвращаться.

    Например, операция BitwiseXor или ПобитовоеИсключительноеИли (Кстати, почему Исключительное, а не Исключающее? Странно…). Так вот, она используется в алгоритме очень часто для создания байтов коррекции. Оказалось самой дорогой частью кода, в итоге, т.к. вычисления идут в рамках байта, заранее загнал все варианты сумм в соответствие, брал результат оттуда, стало быстрее.

    Reply
  2. fr13

    (1) отличный пример применения данного функционала платформы

    Reply
  3. for_sale

    Ничего не понял, но очень интересно)

    Reply
  4. lic_avenger

    Кто в теме. Где, когда, и т.д. и т.п это применяется? и главное для чего? можете объяснить?

    Reply
  5. ltfriend

    А почему комментарии а коде на русском?

    Reply
  6. bulpi

    То ли я тупой, то ли автор объясняет плохо. Непонятно ни фига.

    Reply
  7. bulpi

    И я запустил «swap» и совершенно не удивлен. Все очевидно.

    Reply
  8. Xershi

    (1) на джава скрипте 8к строк было кажись.

    Все перевел?

    Reply
  9. fr13

    (5) это названия функций на русском как их можно найти в синтакс-помощнике.

    Reply
  10. fr13

    (7) а Вы часто хотите удивиться, делая знакомые вещи?

    Reply
  11. CyberCerber

    (8) Хм, не знаю, что там на 8К… У меня 700 — 800 где-то. Но я не переводил с другого языка, с нуля писал.

    Reply
  12. CyberCerber

    (4) Ну, функционал необычный, в создании печатной формы, наверное, не поможет… 🙂

    Я применял для генерации различных низкоуровневых вещей на чистом 1С: штрихкодов, ключей шифрования, файлов, например, картинок.

    Reply
  13. FesenkoA

    (6) не хочу вас обидеть, но вы упускаете третий вариант

    Ложь = истина и ложь;

    Ложь = ложь и истина;

    Ложь = ложь и ложь;

    Reply
  14. lic_avenger

    (12) Спасибо! Теперь понятно (штрихкод, ключ,прочее)

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *