Как в 1С определить, чётное число или нечётное
Содержание
Чётность числа во встроенном языке 1С проверяют одной строкой: Цел(Число / 2) * 2 = Число. Если выражение истинно — число чётное, если ложно — нечётное. Готового оператора %, как в Python или C, и отдельной функции остатка в языке 1С нет, поэтому опытные разработчики определяют чётное число через целую часть от деления.
Разберём рабочую функцию, вариант с вычислением самого остатка, поведение на дробных и отрицательных значениях, обработку массива чисел и типичные промахи. Все примеры рассчитаны на 1С:Предприятие 8.3 — встроенный язык одинаков в любой конфигурации на этой платформе, будь то Бухгалтерия, ЗУП, Управление торговлей или собственная разработка. Поэтому код ниже переносится без изменений.
Базовая функция проверки чётности
Самый надёжный и короткий способ определить чётность — оформить его отдельной функцией и вызывать её там, где нужно.
Функция ЭтоЧётное(Число)
Возврат Цел(Число / 2) * 2 = Число;
КонецФункции
Логика простая. Цел() возвращает целую часть числа, отбрасывая дробь. Для чётного числа деление на 2 даёт ровно целое значение, и после обратного умножения на 2 мы получаем исходное число. Для нечётного — дробь теряется, и равенство не выполняется.
Проверим вручную:
Цел(8 / 2) * 2=Цел(4) * 2=8→ равно 8, число чётное.Цел(7 / 2) * 2=Цел(3.5) * 2=3 * 2=6→ не равно 7, число нечётное.
Вызов в коде:
Если ЭтоЧётное(Количество) Тогда
Сообщить("Количество чётное");
Иначе
Сообщить("Количество нечётное");
КонецЕсли;
Цел() именно отбрасывает дробную часть, а не округляет. Это и нужно для проверки чётности — округление дало бы неверный результат на значениях вроде 4,5.
Почему во встроенном языке нет оператора %
Разработчики, пришедшие из других языков, первым делом пробуют написать Число % 2 = 0. Во встроенном языке 1С такого оператора нет: арифметика ограничена сложением, вычитанием, умножением и делением. Поэтому остаток от деления здесь вычисляют вручную.
Формула остатка выводится из той же целой части:
Остаток = Число - Цел(Число / Делитель) * Делитель;
Для проверки чётности делитель равен 2:
Остаток = Число - Цел(Число / 2) * 2;
Если Остаток = 0 Тогда
// число чётное
КонецЕсли;
Вариант с остатком удобен, когда само значение остатка нужно дальше — например, при распределении номеров по группам или при проверке кратности не только двум, но и трём, пяти, десяти. Если же нужен только ответ «да/нет», короче сравнивать напрямую через Цел(Число / 2) * 2 = Число.
Коротко о том, какой приём когда брать:
| Приём | Выражение | Когда применять |
|---|---|---|
| Прямое сравнение | Цел(Число / 2) * 2 = Число | нужен только ответ «чётное/нечётное» |
| Через остаток | Число - Цел(Число / 2) * 2 | нужно само значение остатка |
| Отдельная функция | ЭтоЧётное(Число) | проверка встречается в коде много раз |
Все три основаны на одной и той же целой части от деления, поэтому дают одинаковый результат. Разница только в удобстве: отдельную функцию проще читать и править, прямое сравнение короче, а формула остатка пригодится, если дальше по коду нужно именно числовое значение.
Не ищите в синтаксис-помощнике функцию «Остаток» — её во встроенном языке нет, остаток всегда считается выражением через Цел().
Дробные числа: сначала приводим к целому
Понятие чётности определено только для целых чисел. Вопрос «чётное ли 4,7» смысла не имеет, поэтому дробное значение сначала надо привести к целому — и только потом проверять.
Здесь важно осознанно выбрать, как именно отбросить дробь:
Цел(Число)— отбрасывает дробную часть (4,7 → 4; 4,2 → 4).Окр(Число, 0)— округляет по правилам арифметики (4,7 → 5; 4,2 → 4).
Разные способы дают разную чётность для одного исходного значения, поэтому решение зависит от задачи. Если число получено делением или расчётом и по смыслу должно быть целым, обычно его округляют:
ЦелоеЗначение = Окр(Число, 0);
Если Цел(ЦелоеЗначение / 2) * 2 = ЦелоеЗначение Тогда
Сообщить("После округления число чётное");
КонецЕсли;
Если число пришло из расчёта с делением, возможна погрешность вычислений с плавающей точкой. Перед проверкой чётности приведите значение к нужной разрядности через Окр(), иначе «целое на вид» число может оказаться 7,0000001.
Отрицательные числа и ноль
Формула через Цел() корректно работает и для отрицательных значений, потому что Цел() отбрасывает дробь в сторону нуля одинаково для обоих знаков.
Проверим:
Цел(-4 / 2) * 2=Цел(-2) * 2=-4→ равно -4, чётное.Цел(-3 / 2) * 2=Цел(-1.5) * 2=-1 * 2=-2→ не равно -3, нечётное.
Ноль по математическому определению чётный, и формула это подтверждает: Цел(0 / 2) * 2 = 0. Отдельной обработки нуля не требуется — та же функция ЭтоЧётное() вернёт для него Истина.
Результат функции — значение типа Булево, поэтому его сразу подставляют в условие или присваивают реквизиту: Если ЭтоЧётное(Номер) Тогда …. Дополнительно сравнивать с Истина не нужно — это лишняя запись.
Проверка чётности в запросе
В языке запросов 1С отдельной функции остатка от деления тоже нет. Поэтому для списков удобнее поступать одним из двух способов.
Первый — получить данные запросом, а признак чётности вычислить в модуле после выборки:
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Если Цел(Выборка.Номер / 2) * 2 = Выборка.Номер Тогда
// строка с чётным номером
КонецЕсли;
КонецЦикла;
Второй — если чередование нужно прямо в результате запроса, выразите тот же остаток в вычисляемом поле через целую часть (Цел() доступна и в запросе). Но на практике проверку чётности почти всегда проще и нагляднее делать в коде после выборки — там её легко изменить и отладить.
Если же результат формируется системой компоновки данных, признак чётности удобнее вынести в вычисляемое поле набора данных или в пользовательское поле компоновки, а не считать его в каждом месте вывода. Выражение остаётся тем же — целая часть от деления номера на два. Главное правило одно: саму формулу держите в одном месте, чтобы при правке не искать её по всему коду.
Обработка массива чисел
Когда чисел много, функцию чётности применяют в цикле. Типовая задача — посчитать, сколько в массиве чётных элементов, или разложить их по двум коллекциям.
ЧётныеЧисла = Новый Массив;
НечётныеЧисла = Новый Массив;
Для Каждого Элемент Из ИсходныйМассив Цикл
Если Цел(Элемент / 2) * 2 = Элемент Тогда
ЧётныеЧисла.Добавить(Элемент);
Иначе
НечётныеЧисла.Добавить(Элемент);
КонецЕсли;
КонецЦикла;
Сообщить("Чётных: " + ЧётныеЧисла.Количество());
Для таблицы значений схема та же — перебор Для Каждого Строка Из ТаблицаЗначений Цикл и проверка нужной колонки:
Для Каждого Строка Из ТаблицаДокументов Цикл
Строка.ЧётныйНомер = ЭтоЧётное(Строка.Номер);
КонецЦикла;
Выносите саму проверку в функцию ЭтоЧётное() и вызывайте её внутри цикла: так код читается лучше и правка формулы делается в одном месте. Если по массиву нужно не разложить элементы, а, например, обнулить каждый второй или сложить только чётные — меняется только тело условия, а сама проверка остаётся прежней.
О «побитовой оптимизации» и проверке младшего бита, как в C, на платформе 1С думать не стоит. Арифметика здесь не узкое место — время съедают запросы к базе и чтение объектов, а не сравнение Цел(Число / 2) * 2. Выигрыш от микротрюков незаметен, а читаемость падает.
Типичные ошибки
Ошибки в проверке чётности почти всегда сводятся к нескольким повторяющимся ситуациям.
- 🔸 Попытка применить оператор
%. КодЧисло % 2просто не скомпилируется — такого оператора во встроенном языке нет. - 🔸 Проверка дробного числа напрямую.
Цел(4.7 / 2) * 2даст 4, что не равно 4,7, и любое дробное число будет «нечётным». Сначала приведите значение к целому. - 🔸 Путаница
Цел()иОкр(). Для отбрасывания дроби нуженЦел().Окр()без второго аргумента тоже округляет, и результат проверки может измениться. - 🔸 Сравнение с погрешностью. После деления значение бывает не ровно целым из-за вычислений с плавающей точкой. Приводите к разрядности через
Окр(Число, 0)до проверки. - 🔸 Строка вместо числа. Если значение пришло из реквизита типа «Строка», деление вызовет ошибку. Приведите его к числу функцией
Число(). - 🔸 Хранение признака чётности в базе. Чётность — вычисляемое свойство. Не заводите под него отдельный реквизит: при изменении номера сохранённое значение разойдётся с реальным. Считайте чётность в момент вывода, а не держите в данных.
Где это пригодится на практике
Проверка чётности редко бывает самоцелью — обычно она часть более крупной задачи.
Чередование строк в выводе. Чтобы подсветить каждую вторую строку таблицы или отчёта, заводят счётчик строк и по его чётности меняют оформление:
Счётчик = 0;
Для Каждого Строка Из Данные Цикл
Счётчик = Счётчик + 1;
ЧётнаяСтрока = ЭтоЧётное(Счётчик);
// по ЧётнаяСтрока выбираем цвет/стиль строки
КонецЦикла;
Счётчик увеличивают вручную в цикле вывода, а не берут из данных — так чередование остаётся ровным даже при фильтрах и сортировке, когда исходные номера идут не подряд.
Разнесение по двум потокам. Пакетную обработку иногда делят на два набора — например, чётные и нечётные номера документов обрабатывают разными процедурами. Схема — та же, что в примере с массивом выше.
Контроль ввода. Если по регламенту некоторый реквизит должен быть кратен двум (количество в упаковке, парные позиции), проверку чётности ставят в обработчик проверки заполнения и не дают провести документ с нечётным значением.
Разметка периодов и нумерация. Чередование «чёт/нечёт» используют для разметки недель, смен, мест — везде, где две группы должны идти через одну.
Во всех случаях ядро одно — функция ЭтоЧётное() из первого раздела.
Тот же приём работает и для проверки кратности любому другому числу — достаточно заменить двойку на нужный делитель. Например, кратность трём или десяти:
Функция КратноЛи(Число, Делитель)
Возврат Цел(Число / Делитель) * Делитель = Число;
КонецФункции
Вызов КратноЛи(Сумма, 10) ответит, кратна ли сумма десяти, КратноЛи(Количество, 3) — делится ли количество на три без остатка. Это удобно для контроля комплектов, фасовки по упаковкам и округления партий. Написав одну универсальную функцию, вы закрываете и проверку чётности (делитель 2), и любую другую кратность.
Частые вопросы
Чем заменить оператор `%` из других языков?
Число - Цел(Число / Делитель) * Делитель — оно возвращает остаток от деления. Для проверки чётности делитель равен 2, а для признака «да/нет» короче сравнивать Цел(Число / 2) * 2 = Число.Почему для отбрасывания дроби берут `Цел()`, а не `Окр()`?
Цел() отбрасывает дробную часть, а Окр() округляет. В проверке чётности нужно именно отбрасывание: при округлении, например, 4,5 превратилось бы в 5 и результат проверки был бы неверным.Как вывести из списка только чётные позиции?
Цел(Поле / 2) * 2 = Поле. Отбирать чётность прямо в условии запроса неудобно — проще сделать это в модуле.Правильно ли формула работает с отрицательными числами?
Цел() отбрасывает дробь в сторону нуля одинаково для плюса и минуса, поэтому -4 определяется как чётное, -3 — как нечётное, а 0 — как чётное.Есть ли разница по скорости между способами?
Цел() выполняется мгновенно; реальное время в обработке занимают запросы и чтение объектов, а не арифметика. Оптимизировать саму проверку чётности смысла нет.