При разработке алгоритмов заказа товаров часто возникает задача округления расчетного количества до целых упаковок (тарности). В языке запросов 1С нет встроенных функций ОКРВВЕРХ или CEIL, что заставляет разработчиков прибегать к использованию конструкции ВЫБОР или математических хитростей с оператором ВЫРАЗИТЬ. В этой статье мы подробно разберем, как работает округление в запросах, почему стандартные условия могут не срабатывать и как написать надежный код для расчета заказов.
Прежде всего, нам необходимо прояснить, как именно система 1С обрабатывает числа при использовании оператора ВЫРАЗИТЬ. В отличие от некоторых заблуждений, этот оператор не просто отсекает дробную часть, а выполняет полноценное арифметическое округление.
Рассмотрим по шагам правила округления в запросе:
Окр() во встроенном языке, где по умолчанию используется «бухгалтерское» округление (до ближайшего четного). В запросах же 0.5 всегда превращается в 1.Посмотрим на пример, подтверждающий это поведение в консоли запросов:
ВЫБРАТЬ
ВЫРАЗИТЬ(0.5 КАК ЧИСЛО(10, 0)) КАК Поле1,
ВЫРАЗИТЬ(0.49 КАК ЧИСЛО(10, 0)) КАК Поле2,
ВЫРАЗИТЬ(20 / 3 КАК ЧИСЛО(10, 0)) КАК Поле3
Результатом выполнения такого запроса будут значения: 1, 0 и 7 соответственно. Это фундаментальное знание, которое поможет нам строить дальнейшую логику.
Часто программисты сталкиваются с ситуацией, когда конструкция ВЫБОР работает некорректно. Проанализируем типичный пример: нам нужно заказать товар так, чтобы общее количество было кратно Тарность. Мы пытаемся сравнить результат деления с его округленным вариантом.
Выясним причину возможной ошибки. Если переменная Рекомендовано (количество к заказу) или Тарность сами по себе являются дробными числами (например, вес в кг), то простое сравнение может не сработать. Если Рекомендовано равно 10.1, а Тарность равна 1, то результат деления будет 10.1. Оператор ВЫРАЗИТЬ(10.1 КАК ЧИСЛО(15, 0)) даст 10. Условие 10 >= 10.1 вернет Ложь, и мы уйдем в ветку ИНАЧЕ, прибавляя лишнюю единицу там, где это не планировалось, или наоборот.
Для корректной работы условий всегда проверяйте типы данных в исходных таблицах. Если вы работаете с результатами предыдущих пакетов запроса, убедитесь, что значения были правильно типизированы через ВЫРАЗИТЬ еще на этапе формирования временной таблицы.
Рассмотрим наиболее надежный способ реализации округления вверх (до целого количества упаковок) в запросе. Нам нужно получить такое число Заказать, которое будет кратно Тарность и будет не меньше, чем Рекомендовано.
Проанализируем универсальную конструкцию:
ВЫБОР
КОГДА ТаблицаСЗаказом.Тарность > 0
ТОГДА ВЫБОР
// Проверяем, является ли число уже кратным тарности
КОГДА ВЫРАЗИТЬ(ТаблицаСЗаказом.Рекомендовано / ТаблицаСЗаказом.Тарность КАК ЧИСЛО(15, 0))
>= ТаблицаСЗаказом.Рекомендовано / ТаблицаСЗаказом.Тарность
// Если округленное значение больше или равно исходному, значит арифметическое округление сработало вверх или в ноль
ТОГДА ТаблицаСЗаказом.Тарность * (ВЫРАЗИТЬ(ТаблицаСЗаказом.Рекомендовано / ТаблицаСЗаказом.Тарность КАК ЧИСЛО(15, 0)))
ИНАЧЕ
// Если арифметическое округление сработало вниз, принудительно прибавляем единицу
ТаблицаСЗаказом.Тарность * (ВЫРАЗИТЬ(ТаблицаСЗаказом.Рекомендовано / ТаблицаСЗаказом.Тарность КАК ЧИСЛО(15, 0)) + 1)
КОНЕЦ
ИНАЧЕ ТаблицаСЗаказом.Рекомендовано
КОНЕЦ КАК Заказать
Существует и более лаконичный «математический» способ округления вверх для положительных чисел. Мы можем прибавить к числу 0.4999999999 перед выполнением ВЫРАЗИТЬ. Это заставит любое число с минимальной дробной частью перейти порог 0.5 и округлиться вверх.
Пример лаконичного кода:
ВЫРАЗИТЬ(Таблица.Значение + 0.4999999999 КАК ЧИСЛО(15, 0))
Однако будьте осторожны: количество девяток после запятой определяет точность, с которой система будет считать число «почти целым». Если в ваших данных возможны значения с 6 знаками после запятой (например, 1.000001), такой метод может потребовать еще большей точности.
При расчетах в запросах мы всегда должны помнить о безопасности вычислений. Разберем основные риски:
Тарность или Рекомендовано содержит NULL, результатом всего арифметического выражения будет NULL. Обязательно используйте функцию ЕСТЬNULL(Поле, 0).ЕСТЬNULL в поле Тарность оказался ноль, запрос завершится аварийно. Всегда оборачивайте деление в конструкцию ВЫБОР КОГДА Тарность > 0.ВЫРАЗИТЬ(... КАК ЧИСЛО(15, 3)).Мы выяснили, что основной причиной ошибок при округлении в запросах является неучтенная дробная часть исходных данных или непонимание принципа работы ВЫРАЗИТЬ. Для создания стабильного отчета или обработки заказов рекомендуем придерживаться следующих правил:
ВЫРАЗИТЬ.0.5 — это всегда 1.0.499....Соблюдение этих простых правил позволит вам создавать надежные механизмы расчета в любых конфигурациях на платформе 1С:Предприятие 8.3.