В стандартном встроенном языке 1С функция Окр() выполняет математическое округление до ближайшего целого или заданной разрядности (десятые, сотые и т.д.). Однако в торговых операциях и при формировании прайс-листов часто возникает задача округлять цену строго в большую сторону (в пользу предприятия) с кратным шагом — например, до 0.05 или 0.10 денежных единиц.
Рассмотрим детально, как решить эту задачу с помощью различных алгоритмов, математических формул, универсальных функций, а также средствами языка запросов и типовых конфигураций 1С.
Сформулируем исходные условия. Если установлен шаг округления 0.05, математическое округление для значения 37.22 даст результат 37.20. В то же время бизнес-логика требует получить 37.25.
Проанализируем требуемую логику на примерах:
37.21 должно округляться до 37.25.37.22 должно округляться до 37.25.37.25 уже кратно шагу и должно оставаться 37.25.37.26 переходит на следующий шаг и округляется до 37.30.Наиболее лаконичный способ решения задачи — использование вычисления целой части с помощью функции Цел() и проверка остатка через условие. Для шага 0.05 коэффициентом масштабирования выступает число 20 (так как 1 / 0.05 = 20).
Разберем математическую формулу для шага 0.05:
// Округление в большую сторону до 0.05
Результат = ?(Цел(Цена * 20) / 20 = Цена, Цел(Цена * 20) / 20, (Цел(Цена * 20) + 1) / 20);
Посмотрим, как работает данное выражение:
20. Например, 37.22 * 20 = 744.4.Цел(744.4) = 744.20: 744 / 20 = 37.20.0.05. Если не равны, прибавляем к целой части 1 и делим на 20: (744 + 1) / 20 = 37.25.Аналогично, если требуется округлять в большую сторону до шага 0.10, используется коэффициент 10 (так как 1 / 0.10 = 10):
// Округление в большую сторону до 0.10
Результат = ?(Цел(Цена * 10) / 10 = Цена, Цел(Цена * 10) / 10, (Цел(Цена * 10) + 1) / 10);
Если необходимо сделать код более наглядным для отладки или включить дополнительные проверки, создадим отдельную функцию с ветвлением по условиям Если ... ИначеЕсли.
Рассмотрим пример функции для шага 0.05:
Функция ОкруглитьДо0_05_ВБольшуюСторону(Цена) Экспорт
Дельта = Окр(Цена, 1) - Цена;
Если Дельта = 0 Тогда
// Число уже кратно 0.10
Результат = Цена;
ИначеЕсли Дельта < 0 Тогда
// Дробные значения 0.01, 0.02, 0.03, 0.04 подтягиваем до 0.05
Результат = Цена + (0.05 - (Цена - Окр(Цена, 1)));
ИначеЕсли Дельта = 0.05 Тогда
// Уже кратно 0.05
Результат = Цена;
Иначе
// Для значений выше 0.05 подтягиваем до следующего десятичного разряда
Результат = Окр(Цена, 1);
КонецЕсли;
Возврат Результат;
КонецФункции
В реальных проектах шаг округления может меняться (например, 0.05, 0.10, 0.50, 5.00 или 10.00). Для таких задач целесообразно написать универсальную функцию, принимающую два параметра: исходную сумму и желаемый шаг.
Проанализируем следующий универсальный алгоритм:
Функция ОкруглитьВБольшуюСторону(Значение, Шаг) Экспорт
Если Шаг = 0 Тогда
Возврат Значение;
КонецЕсли;
// Рассчитываем частное и ограничиваем точность для предотвращения ошибок с плавающей точкой
Частное = Окр(Значение / Шаг, 6);
ЦелоеЧастное = Цел(Частное);
// Если остатка нет — значение уже кратно шагу, иначе добавляем 1 шаг
Если ЦелоеЧастное = Частное Тогда
Возврат Значение;
Иначе
Возврат (ЦелоеЧастное + 1) * Шаг;
КонецЕсли;
КонецФункции
Для быстрой однострочной записи без условий также применяют математическое смещение с прибавлением коэффициента, близкого к единице:
Результат = Цел(Цена / Шаг + 0.999999) * Шаг;
В языке запросов 1С функция Окр() отсутствует, а конструкция ВЫРАЗИТЬ() выполняют только математическое округление. Чтобы выполнить округление вверх непосредственно в запросе, используют комбинацию функций ВЫРАЗИТЬ() и вычитание 0.5 для получения целой части числа.
Рассмотрим пример запроса с округлением цены вверх до 0.05 (умножаем на 20, округляем вверх, затем делим на 20):
ВЫБРАТЬ
НоменклатураСЦены.Номенклатура КАК Номенклатура,
НоменклатураСЦены.Цена ИсходнаяЦена,
ВЫБОР
КОГДА (НоменклатураСЦены.Цена * 20) - ВЫРАЗИТЬ((НоменклатураСЦены.Цена * 20) - 0.5 КАК ЧИСЛО(15, 0)) > 0
ТОГДА (ВЫРАЗИТЬ((НоменклатураСЦены.Цена * 20) - 0.5 КАК ЧИСЛО(15, 0)) + 1) / 20
ИНАЧЕ ВЫРАЗИТЬ((НоменклатураСЦены.Цена * 20) - 0.5 КАК ЧИСЛО(15, 0)) / 20
КОНЕЦ КАК ЦенаСШагом005
ИЗ
Справочник.Номенклатура КАК НоменклатураСЦены
Если задача связана с формированием прайс-листов и расчетных цен в типовых решениях (1С:Управление торговлей, 1С:ERP, 1С:Комплексная автоматизация), доработка кода часто не требуется.
Разберем порядок настройки в пользовательском режиме:
0.05 или 0.10).При расчете цен по формулам или при загрузке новых цен система применит указанное правило автоматически.
При реализации собственных алгоритмов округления в 1С обратите внимание на следующие нюансы:
1. Погрешность вычислений с плавающей точкой: Из-за особенностей представления двоичных чисел в памяти результат деления 37.25 / 0.05 может составить 745.0000000000001. В результате прямое сравнение ЦелоеЧастное = Частное может вернуть Ложь. Чтобы избежать этой проблемы, всегда предварительно ограничивайте точность деления через Окр(Значение / Шаг, 6).
2. Округление цен и сумм весовых товаров: Округление цены до 0.05 не гарантирует, что итоговая сумма строки документа будет кратна 0.05, если количество товара выражено дробным числом (например, 1.337 кг). В таких случаях алгоритм округления необходимо применять не только к цене номенклатуры, но и пересчитывать итоговую сумму строки или документа.