В практике разработчика 1С часто возникает задача не просто округлить число по правилам математики, а именно «отсечь» лишние знаки. Например, когда из числа 7 167,127 нам нужно получить строго 7 167,12. Стандартная функция Окр() в большинстве своих режимов при значении 7 в третьем знаке округлит число в большую сторону до 13 копеек. В этой статье мы подробно разберем, как реализовать «округление вниз» (или отбрасывание разрядов) различными способами, проанализируем нюансы работы с отрицательными числами и особенности вычислений в запросах.
Самый популярный и простой способ, предложенный в обсуждении, — это использование функции Цел() (получение целой части числа). Поскольку нам нужно сохранить два знака после запятой, мы сначала «поднимаем» эти знаки в целую часть, а затем возвращаем их обратно.
Разберем этот алгоритм по шагам:
Цел(), которая просто отбрасывает всю дробную часть.Посмотрим на пример кода:
ИсходноеЧисло = 7167.127;
Результат = Цел(ИсходноеЧисло * 100) / 100;
// Результат будет равен 7167.12
Удобно тестировать подобные математические алгоритмы в режиме предприятия, используя встраиваемую консоль кода на основе Monaco-editor.
Важный нюанс: Этот метод отлично работает для положительных чисел, выполняя так называемое «округление к нулю» (Truncate). Однако, если мы столкнемся с отрицательным числом, например -7 167,127, результат будет -7 167,12. С точки зрения строгой математики (функция Floor), округление вниз для отрицательного числа должно давать -7 167,13, так как это число меньше. Если ваша задача требует именно математического «вниз», этот код придется дополнить проверкой знака.
Некоторые разработчики предпочитают использовать стандартную функцию Окр(), но со специальным «сдвигом». Идея заключается в том, чтобы вычесть из числа половину значения разряда, до которого происходит округление. Для округления до двух знаков это 0.005.
Проанализируем ситуацию: если мы вычтем 0.005 из 7 167,127, мы получим 7 167,122. При обычном математическом округлении до двух знаков это число превратится в 7 167,12. Если же на входе будет 7 167,124, после вычитания получится 7 167,119, что округлится до 7 167,12 (здесь нужно быть осторожным с логикой отсечения).
Рассмотрим пример реализации:
ИсходноеЧисло = 7167.127;
Результат = Окр(ИсходноеЧисло - 0.005, 2, РежимОкругления.Окр15как20);
// Результат: 7167.12
Этот метод часто называют «хаком», и он требует обязательного комментирования в коде.
В системе 1С функция Окр() имеет третий параметр — РежимОкругления. Существует два системных режима:
Окр15как10 — если на границе стоит 5, округляем в меньшую сторону.Окр15как20 — если на границе стоит 5, округляем в большую сторону (стандарт).Выясним причину, по которой это не решает задачу автора. Параметр РежимОкругления влияет только на ситуацию, когда следующая цифра после округляемого разряда — ровно 5. Если же там стоит 7 (как в примере 7.127), то при любом режиме система округлит число вверх до 7.13. Именно поэтому прямое использование Окр() без математических манипуляций здесь бесполезно.
При использовании метода Цел(Число * 100) / 100 мы можем столкнуться с неприятной особенностью представления чисел в памяти компьютера. Хотя в 1С тип Число достаточно точный, при сложных вычислениях может возникнуть эффект «плавающей точки».
Представим, что в результате каких-то расчетов число 1.13 в памяти выглядит как 1.129999999999. При умножении на 100 мы получим 112.9999999999. Функция Цел() отбросит дробь и вернет 112. После деления получится 1.12 вместо ожидаемого 1.13. Чтобы избежать таких ошибок, профессиональные разработчики иногда добавляют «микро-смещение»:
Точность = 100;
МикроСмещение = 0.000000001;
Результат = Цел(МоеЧисло * Точность + МикроСмещение) / Точность;
В языке запросов 1С функционал ограничен: там нет функции Цел(). Если вам нужно отбросить знаки прямо в запросе, придется использовать конструкцию ВЫРАЗИТЬ(Число КАК ЧИСЛО(15, 0)). Однако ВЫРАЗИТЬ работает по правилам математического округления.
Чтобы имитировать «отбрасывание» дробной части в запросе, мы можем использовать операцию получения остатка от деления %, а Быстрый анализ данных поможет оперативно проверить корректность работы формул:
ВЫБРАТЬ
Продажи.Сумма - (Продажи.Сумма % 1) КАК ЦелаяЧасть
ИЗ
РегистрНакопления.Продажи КАК Продажи
Подобные конструкции удобно тестировать, используя расширение Управляемая консоль запросов, отчетов.
Для получения двух знаков логика усложняется: нужно умножить поле на 100, вычесть остаток от деления на 1 и разделить результат на 100.
Проанализировав ситуацию, можно сделать следующие выводы:
Цел(Число * 100) / 100. Это самый читаемый и понятный вариант.Формат() не меняет само число. Если вы напишете Формат(7.127, "ЧДЦ=2"), пользователь увидит 7.13, хотя в переменной останется 7.127. Подготавливайте данные до их вывода в отчет или записи в базу.Надеемся, эти примеры помогут вам избежать ошибок при работе с дробными числами в 1С!