Почему функция Окр с режимом Окр15как10 не округляет число вниз и как правильно отсекать дробную часть в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке алгоритмов расчета, формировании печатных форм или подготовке данных часто возникает задача округлить число строго в меньшую сторону (отсечь лишние знаки). Разработчики нередко пытаются использовать встроенную функцию Окр() со специальным режимом округления, например:

Результат = Окр(1.15511, 2, РежимОкругления.Окр15как10);

Однако на практике такой вызов возвращает значение 1.16 вместо ожидаемого 1.15. Проанализируем причину такого поведения платформы 1С:Предприятие и разберем правильные способы округления и усечения чисел.

Причина поведения функции Окр и режима Окр15как10

Выясним причину, почему платформа выдает 1.16. Параметр РежимОкругления.Окр15как10 (или его числовой аналог 0) не выполняет операцию усечения (truncation / floor). Он предназначен строго для разрешения неоднозначности («правило половины»), когда отбрасываемая часть числа в точности равна половине единицы младшего разряда.

Рассмотрим подробнее логику математического округления:

  1. Если после округляемого разряда идут цифры от 0 до 4 (например, 1.154), число всегда округляется вниз (до 1.15).
  2. Если после округляемого разряда идет число строго больше половины (например, 511 в числе 1.15511), число по законам математики округляется вверх независимо от указанного режима.
  3. Режим РежимОкругления.Окр15как10 вступает в силу только тогда, когда отбрасываемая часть точно равна 5 (например, 1.155000...). Только в этом случае 1.155 округлится до 1.15, тогда как при стандартном режиме РежимОкругления.Окр15как20 результат был бы 1.16.

Таким образом, функция Окр() не предназначена для простого отбрасывания знаков (усечения). Для решения этой задачи используются другие подходы.

Способ 1. Использование функции Цел() для усечения положительных чисел

Наиболее надежным и производительным способом отбросить лишние знаки дробной части для положительных чисел является предварительное умножение на коэффициент разрядности, взятие целой части и обратное деление.

Посмотрим на пример кода для округления до 2 знаков после запятой:


ИсходноеЧисло = 1.15511;
Коэффициент = 100; // Для 2 знаков после запятой (10^2)
Результат = Цел(ИсходноеЧисло * Коэффициент) / Коэффициент;
// Результат равен 1.15

Разберем по шагам, что происходит в данном алгоритме:

  1. Число 1.15511 умножается на 100 и превращается в 115.511.
  2. Функция Цел() отбрасывает дробную часть, оставляя 115.
  3. Значение 115 делится на 100, в результате получается точное значение 1.15.

Способ 2. Коррекция числа перед математическим округлением

Если требуется продолжить использование функции Окр(), можно сместить число на величину половины младшего разряда минус дельта погрешности. Рассмотрим пример:


ИсходноеЧисло = 1.15511;
Результат = Окр(ИсходноеЧисло - 0.0049999999, 2);
// Результат равен 1.15

Такой подход искусственно занижает дробную часть, заставляя стандартное математическое округление работать в сторону уменьшения. Однако данный метод менее прозрачен и требует аккуратности с подбором дельты при разной разрядности.

Способ 3. Универсальная функция округления вниз (Floor) с учетом отрицательных чисел

Следует помнить, что функция Цел() в 1С всегда усекает число в сторону нуля (для -1.155 выражение Цел(-1.155 * 100) / 100 вернет -1.15, что математически больше исходного числа). Если требуется строгое округление к минус бесконечности, напишем универсальную функцию:


Функция ОкруглитьВниз(ИсходноеЧисло, Точность = 2) Экспорт
    Коэффициент = Pow(10, Точность);
    СдвинутоеЧисло = ИсходноеЧисло * Коэффициент;
    РезультатЦел = Цел(СдвинутоеЧисло);
    
    Если ИсходноеЧисло < 0 И СдвинутоеЧисло <> РезультатЦел Тогда
        РезультатЦел = РезультатЦел - 1;
    КонецЕсли;
    
    Возврат РезультатЦел / Коэффициент;
КонецФункции

Способ 4. Отсечение знаков в запросах 1С

Функция языка запросов ВЫРАЗИТЬ(Поле КАК ЧИСЛО(Длина, Точность)) также использует стандартное округление. Если требуется выполнить отсечение знаков непосредственно в запросе, применим вычисление остатка от деления:


ВЫБРАТЬ
    ВЫБОР
        КОГДА Таблица.Сумма >= 0 
            ТОГДА (Таблица.Сумма * 100 - (Таблица.Сумма * 100) % 1) / 100
        ИНАЧЕ ...
    КОНЕЦ КАК СуммаОкругленнаяВниз
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК Таблица
← На главную