Разработка механизмов расчета стоимости, налогов или распределения количеств в 1С неизбежно сталкивает программиста с необходимостью округления дробных чисел. Зачастую поведение стандартной функции Окр() кажется неочевидным или даже ошибочным. В этой статье мы подробно разберем, по каким правилам работает платформа «1С:Предприятие», почему «школьный» метод округления может подвести и как реализовать специфические алгоритмы округления, принятые в Excel.
Рассмотрим ситуацию, которая часто вызывает вопросы: почему Окр(6.3448, 2) возвращает 6.34, хотя интуитивно кажется, что должно получиться 6.35? Ошибка кроется в попытке применить так называемое «каскадное» округление (справа налево по разрядам).
Проанализируем ситуацию: при каскадном подходе мы сначала округляем 8 до 5 (в предыдущем разряде), получаем 6.345, а затем округляем 5 в большую сторону и получаем 6.35. Однако математическое округление работает иначе. Его главная цель — минимизация абсолютной погрешности.
Выясним причину выбора системой значения 6.34, рассчитав разницу между исходным числом и возможными вариантами округления:
abs(6.3448 - 6.34) = 0.0048abs(6.3448 - 6.35) = 0.0052Как мы видим, число 6.3448 физически находится ближе к 6.34. Погрешность в первом случае меньше, поэтому система абсолютно корректно выбирает этот результат. Математика не учитывает «историю» знаков после целевого разряда, она оценивает все число целиком относительно границ округления.
Для управления процессом в 1С предусмотрена встроенная функция Окр(). Разберем ее параметры более детально, чтобы понимать, на что мы можем влиять.
Синтаксис функции выглядит следующим образом: Окр(Число, Разрядность, РежимОкругления).
Посмотрим на пример работы с третьим параметром:
// Стандартное округление (1.5 превращается в 2)
Результат1 = Окр(1.5, 0, РежимОкругления.Окр15как20); // Вернет 2
// Округление в меньшую сторону (1.5 превращается в 1)
Результат2 = Окр(1.5, 0, РежимОкругления.Окр15как10); // Вернет 1
Важный момент: третий параметр влияет только на ситуацию, когда число находится ровно посередине между двумя вариантами. Если число хотя бы на ничтожную долю ближе к одной из границ (как в примере 6.3448), режим округления не изменит результат.
Иногда бизнес-логика требует от нас отойти от математических правил. Например, при расчете количества упаковок нам всегда нужно округлять вверх (даже если осталось 1.1 штуки, нам нужна целая коробка), или при расчете скидок — всегда вниз в пользу клиента. В 1С нет прямых аналогов функций Excel ОКРУГЛВВЕРХ и ОКРУГЛВНИЗ, но мы можем легко их сконструировать.
Для того чтобы просто отсечь лишние знаки, не анализируя их величину, воспользуемся функцией Цел(). Рассмотрим алгоритм: умножаем число на 10 в степени нужной разрядности, берем целую часть и делим обратно.
Пример реализации функции для отсечения до 2 знаков:
Функция ОкруглитьВниз(Знач Число, Знач Разрядов)
Множитель = Pow(10, Разрядов);
Возврат Цел(Число * Множитель) / Множитель;
КонецФункции
// Пример: ОкруглитьВниз(6.3499, 2) даст 6.34
Округление вверх реализуется похожим образом, но с небольшой математической хитростью — добавлением значения, которое «вытолкнет» число к следующему целому при использовании Цел().
Функция ОкруглитьВверх(Знач Число, Знач Разрядов)
Множитель = Pow(10, Разрядов);
// Добавляем минимально возможное смещение для перехода разряда
Возврат Цел(Число * Множитель + 0.9999999999) / Множитель;
КонецФункции
// Пример: ОкруглитьВверх(6.3401, 2) даст 6.35
Иногда программисты сталкиваются с тем, что Окр(0.35, 1) внезапно выдает 0.3 вместо 0.4, хотя режим установлен в Окр15как20. Проанализируем ситуацию: это происходит из-за того, что компьютеры хранят числа в двоичном виде. Число 0.35 в памяти может быть представлено как 0.3499999999999998.
Чтобы избежать подобных «сюрпризов» при сравнении или округлении критически важных данных (например, валютных сумм), рекомендуется добавлять крайне малое число («эпсилон») перед округлением:
// Безопасное округление суммы
ТочнаяСумма = Сумма + 0.0000000001;
Результат = Окр(ТочнаяСумма, 2);
Важно помнить, что функция Окр() недоступна внутри текста запроса. Для округления в запросах используется конструкция ВЫРАЗИТЬ(). Рассмотрим ее особенности:
ВЫБРАТЬ
ВЫРАЗИТЬ(Таблица.Цена КАК ЧИСЛО(15, 2)) КАК ЦенаОкругленно
ИЗ
Справочник.Номенклатура КАК Таблица
Будьте внимательны: ВЫРАЗИТЬ в запросах может вести себя по-разному в зависимости от типа используемой СУБД (SQL Server, PostgreSQL). В некоторых версиях SQL используется «банковское округление» (округление до ближайшего четного), что может привести к расхождениям между результатами отчета и результатами обработки этих же данных в коде 1С.
Подведем итог: платформа 1С работает строго в рамках математических правил. Если вы получаете результат, отличный от ожидаемого, проверьте расстояние от исходного числа до ближайших границ округления и убедитесь, что вы не используете «каскадную» логику. Для специфических задач всегда можно использовать комбинацию функций Цел() и арифметических операций.