В практике разработки на платформе 1С иногда возникают олимпиадные или алгоритмические задачи, в которых требуется разобрать число на разряды в условиях жестких системных ограничений. Рассмотрим задачу: на вход поступает целое число X (значение до пяти разрядов, где каждая цифра равна 0 или 1) и порядковый номер разряда Y (от 1 до 5, нумерация слева направо, то есть от старшего разряда к младшему). Если число содержит меньше пяти разрядов, недостающие старшие разряды считаются равными нулю — например, для числа 1001 первая цифра равна 0.
При этом накладываются строгие ограничения: запрещено использовать преобразование в строку (функцию Строка()), побитовые операторы (которые во встроенном языке 1С применимы только к типу Булево), а также функции округления и взятия целой части (Окр(), Цел()). Разберем по шагам, какими алгоритмическими приемами можно решить эту задачу средствами языка 1С.
Прежде чем перейти к коду, проанализируем доступный инструментарий платформы:
/ всегда возвращает точный дробный результат, а отдельного оператора целочисленного деления нет.% поддерживается в качестве стандартной арифметической операции над числами.(X - (X % 10)) / 10 всегда дает точный целый результат без дробного остатка и без вызова системной функции Цел().0 + (X > 9999) возвращает 1 при истинности условия и 0 при ложности.Рассмотрим первый подход, основанный на вычислении остатка от деления на 10. Так как нумерация разрядов идет слева направо (1 — десятки тысяч, 5 — единицы), то цифра с номером Y находится на позиции 5 - Y справа. Если мы сдвинем число вправо на нужное количество шагов, искомая цифра окажется в разряде единиц, откуда ее легко забрать через оператор остатка от деления % 10.
Посмотрим на пример реализации алгоритма:
&НаКлиенте
Функция F_СдвигВправо(Знач Х, Знач У)
Шагов = 5 - У;
Для Счетчик = 0 По Шагов Цикл
Остаток = Х % 10;
Х = (Х - Остаток) / 10;
КонецЦикла;
Возврат Остаток;
КонецФункции
Разберем логику работы этого метода:
5 - У.Х % 10.Цел().Остаток оказывается искомая цифра.Рассмотрим альтернативное решение, в котором число обрабатывается от старших разрядов к младшим. Поскольку разряды могут принимать только значения 0 или 1, мы можем проверить наличие единицы в текущем разряде путем простого сравнения или вычитания веса этого разряда (10000, 1000, 100, 10, 1).
Так как стандартный оператор возведения в степень (вроде ^ или **) во встроенном языке не поддерживается, вес разряда вычисляется вложенным циклом умножения на 10:
Функция F_ПоразрядноеВычитание(Знач Х, Знач У)
Перем Цифра;
Для НЦ = 1 По У Цикл
Множитель = 1;
Для Степень = 1 По 5 - НЦ Цикл
Множитель = Множитель * 10;
КонецЦикла;
Х = Х - Множитель;
Если Х >= 0 Тогда
Цифра = 1;
Иначе
Цифра = 0;
Х = Х + Множитель;
КонецЕсли;
КонецЦикла;
Возврат Цифра;
КонецФункции
Проанализируем этот алгоритм:
У раз — от первого (старшего) разряда до целевого.Множитель (например, для первой итерации при пятизначном числе это 10000).Х.У цикл завершается, и переменная Цифра содержит корректный ответ.Выясним, как решить задачу максимально компактно без явных циклов. Для этого используем рекурсию и сдвиг числа влево (умножение на 10). На каждом шаге рекурсии мы проверяем, превышает ли число порог в 9999 (что означает наличие единицы в старшем разряде), после чего «срезаем» старшую единицу и сдвигаем число влево, уменьшая счетчик У.
Посмотрим на пример рекурсивной функции:
Функция F_Рекурсия(Х, У)
Возврат ?(У < 2, 0 + (Х > 9999), F_Рекурсия((Х - 10000 * (Х > 9999)) * 10, У - 1));
КонецФункции
Разберем по шагам, как работает данная конструкция:
У < 2 (то есть мы дошли до искомого разряда), проверяется условие Х > 9999. Выражение 0 + (Х > 9999) преобразует булево значение в число 1 или 0.10000 * (Х > 9999)) и умножаем остаток на 10, продвигая следующий разряд на позицию десятков тысяч.У уменьшается на единицу, приближая завершение рекурсии.Если задача допускает прямое вычисление без перебора, можно применить формулу позиционной системы счисления. Чтобы изолировать цифру разряда $10^k$ (где $k = 5 - Y$), берется остаток от деления на $10^{k+1}$ для отсечения старших разрядов, затем вычитается остаток от деления на $10^k$ для обнуления младших разрядов, после чего результат делится на $10^k$:
Цифра = ((X % 10^(k + 1)) - (X % 10^k)) / 10^k
Так как вычитаемое кратно $10^k$, деление всегда выполняется нацело, что строго удовлетворяет условию отсутствия функций округления.