При разработке алгоритмов расчета, формировании печатных форм или подготовке данных часто возникает задача округлить число строго в меньшую сторону (отсечь лишние знаки). Разработчики нередко пытаются использовать встроенную функцию Окр() со специальным режимом округления, например:
Результат = Окр(1.15511, 2, РежимОкругления.Окр15как10);
Однако на практике такой вызов возвращает значение 1.16 вместо ожидаемого 1.15. Проанализируем причину такого поведения платформы 1С:Предприятие и разберем правильные способы округления и усечения чисел.
Выясним причину, почему платформа выдает 1.16. Параметр РежимОкругления.Окр15как10 (или его числовой аналог 0) не выполняет операцию усечения (truncation / floor). Он предназначен строго для разрешения неоднозначности («правило половины»), когда отбрасываемая часть числа в точности равна половине единицы младшего разряда.
Рассмотрим подробнее логику математического округления:
1.154), число всегда округляется вниз (до 1.15).511 в числе 1.15511), число по законам математики округляется вверх независимо от указанного режима.РежимОкругления.Окр15как10 вступает в силу только тогда, когда отбрасываемая часть точно равна 5 (например, 1.155000...). Только в этом случае 1.155 округлится до 1.15, тогда как при стандартном режиме РежимОкругления.Окр15как20 результат был бы 1.16.Таким образом, функция Окр() не предназначена для простого отбрасывания знаков (усечения). Для решения этой задачи используются другие подходы.
Наиболее надежным и производительным способом отбросить лишние знаки дробной части для положительных чисел является предварительное умножение на коэффициент разрядности, взятие целой части и обратное деление.
Посмотрим на пример кода для округления до 2 знаков после запятой:
ИсходноеЧисло = 1.15511;
Коэффициент = 100; // Для 2 знаков после запятой (10^2)
Результат = Цел(ИсходноеЧисло * Коэффициент) / Коэффициент;
// Результат равен 1.15
Разберем по шагам, что происходит в данном алгоритме:
1.15511 умножается на 100 и превращается в 115.511.Цел() отбрасывает дробную часть, оставляя 115.115 делится на 100, в результате получается точное значение 1.15.Если требуется продолжить использование функции Окр(), можно сместить число на величину половины младшего разряда минус дельта погрешности. Рассмотрим пример:
ИсходноеЧисло = 1.15511;
Результат = Окр(ИсходноеЧисло - 0.0049999999, 2);
// Результат равен 1.15
Такой подход искусственно занижает дробную часть, заставляя стандартное математическое округление работать в сторону уменьшения. Однако данный метод менее прозрачен и требует аккуратности с подбором дельты при разной разрядности.
Следует помнить, что функция Цел() в 1С всегда усекает число в сторону нуля (для -1.155 выражение Цел(-1.155 * 100) / 100 вернет -1.15, что математически больше исходного числа). Если требуется строгое округление к минус бесконечности, напишем универсальную функцию:
Функция ОкруглитьВниз(ИсходноеЧисло, Точность = 2) Экспорт
Коэффициент = Pow(10, Точность);
СдвинутоеЧисло = ИсходноеЧисло * Коэффициент;
РезультатЦел = Цел(СдвинутоеЧисло);
Если ИсходноеЧисло < 0 И СдвинутоеЧисло <> РезультатЦел Тогда
РезультатЦел = РезультатЦел - 1;
КонецЕсли;
Возврат РезультатЦел / Коэффициент;
КонецФункции
Функция языка запросов ВЫРАЗИТЬ(Поле КАК ЧИСЛО(Длина, Точность)) также использует стандартное округление. Если требуется выполнить отсечение знаков непосредственно в запросе, применим вычисление остатка от деления:
ВЫБРАТЬ
ВЫБОР
КОГДА Таблица.Сумма >= 0
ТОГДА (Таблица.Сумма * 100 - (Таблица.Сумма * 100) % 1) / 100
ИНАЧЕ ...
КОНЕЦ КАК СуммаОкругленнаяВниз
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Таблица