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

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

Введение

Начиная с версии платформы 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 не будет опубликован. Обязательные поля помечены *