В практике разработчика 1С задачи по манипуляции с системами счисления встречаются при интеграции с торговым оборудованием, работе с низкоуровневыми протоколами передачи данных или при реализации специфических алгоритмов шифрования и хэширования. В этой статье мы подробно разберем, как написать собственные функции для конвертации чисел из десятичной системы в двоичную и обратно, проанализируем типичные ошибки новичков и рассмотрим современные возможности платформы 1С.
Самый распространенный способ перевода числа из десятичной системы в любую другую — это метод последовательного деления на основание искомой системы (в нашем случае на 2). Разберем этот процесс по шагам. Мы делим число на 2, записываем остаток, а полученное частное снова делим на 2, пока оно не станет равным нулю.
Важный нюанс: при делении в 1С переменная типа Число может содержать дробную часть. Чтобы алгоритм работал корректно, нам необходимо использовать функцию Цел() для получения целой части от деления, иначе цикл может стать бесконечным или вернуть неверный результат.
Рассмотрим пример реализации функции перевода:
Функция ДесятичноеВДвоичное(Знач ЧислоДесятичное) Экспорт
Если ЧислоДесятичное = 0 Тогда
Возврат "0";
КонецЕсли;
Результат = "";
ТекущееЧисло = ЧислоДесятичное;
Пока ТекущееЧисло > 0 Цикл
Остаток = ТекущееЧисло % 2; // Получаем 0 или 1
Результат = Строка(Остаток) + Результат; // Добавляем в начало строки
ТекущееЧисло = Цел(ТекущееЧисло / 2); // Важно использовать Цел()
КонецЦикла;
Возврат Результат;
КонецФункции
Обратите внимание на строку Результат = Строка(Остаток) + Результат;. Поскольку остатки при делении мы получаем в обратном порядке (от младшего разряда к старшему), добавляя новый символ в начало строки, мы автоматически "разворачиваем" число в правильном направлении. Это избавляет нас от необходимости писать отдельную функцию для переворота строки.
Для обратного перевода из двоичной системы (представленной в виде строки) в десятичное число можно использовать классическую формулу суммы степеней двойки. Однако программно гораздо эффективнее и элегантнее использовать схему Горнера. Вместо того чтобы вычислять возведение в степень для каждого разряда, мы будем двигаться по строке слева направо.
Проанализируем алгоритм: мы берем текущий накопленный результат, умножаем его на 2 (основание системы) и прибавляем значение текущего разряда. Рассмотрим, как это выглядит в коде:
Функция ДвоичноеВДесятичное(Знач ДвоичнаяСтрока) Экспорт
Результат = 0;
Для Позиция = 1 По СтрДлина(ДвоичнаяСтрока) Цикл
Символ = Сред(ДвоичнаяСтрока, Позиция, 1);
// Проверяем, что в строке только 0 и 1
Если Символ <> "0" И Символ <> "1" Тогда
Продолжить;
КонецЕсли;
Результат = Результат * 2 + Число(Символ);
КонецЦикла;
Возврат Результат;
КонецФункции
Этот метод хорош тем, что он универсален. Если вам потребуется переводить числа из восьмеричной или шестнадцатеричной системы, достаточно будет заменить множитель 2 на соответствующее основание системы счисления.
Разберем основные ошибки, которые часто допускают разработчики при написании подобных алгоритмов, на основе обсуждений на форумах:
b = b / 2 в 1С не выполняет целочисленное деление автоматически. Если b было равно 5, результатом станет 2.5, что приведет к ошибкам в следующем цикле вычислений. Всегда используйте Цел() или конструкцию (b - b % 2) / 2.Результат = Результат + Остаток), не забудьте инвертировать итоговую строку перед выводом пользователю.Число в 1С имеет ограничение по разрядности. При работе с очень длинными двоичными последовательностями (например, более 64 бит), результат может не поместиться в стандартную числовую переменную.Начиная с версии платформы 8.3.12, в распоряжении разработчиков появились встроенные функции для работы с битами. Хотя они не переводят число в строку напрямую, они позволяют эффективно манипулировать двоичными данными без использования циклов деления.
Рассмотрим функции, которые могут быть полезны:
ПобитовоеИ(Число1, Число2) — позволяет проверить, установлен ли конкретный бит в числе.ПобитовыйСдвигЛ(Число, Количество) и ПобитовыйСдвигП(Число, Количество) — позволяют сдвигать биты числа влево или вправо.Например, проверить значение конкретного бита (0 или 1) можно следующим образом:
// Проверим 3-й бит числа (отсчет с 0)
ЗначениеБида = ?(ПобитовоеИ(ИсходноеЧисло, 8) > 0, 1, 0); // 2^3 = 8
Если в процессе разработки вы все же столкнулись с необходимостью развернуть строку задом наперед (например, после формирования остатков в цикле), выясним наиболее быстрый способ сделать это. Поскольку встроенной функции Reverse() в языке 1С нет, мы реализуем простой цикл:
Функция РазвернутьСтроку(ИсходнаяСтрока)
Результат = "";
Для Сч = СтрДлина(ИсходнаяСтрока) По 1 Цикл
Результат = Результат + Сред(ИсходнаяСтрока, Сч, 1);
КонецЦикла;
Возврат Результат;
КонецФункции
Мы проанализировали основные подходы к работе с системами счисления в 1С. Для простых задач вполне достаточно реализовать функции деления и умножения (схема Горнера). Если же ваша задача требует высокой производительности или работы с битовыми масками, рекомендуем обратить внимание на встроенные побитовые функции платформы 8.3.12 и старше. Помните о специфике типа Число и всегда контролируйте целочисленность операций при делении.