Целая часть числа во встроенном языке и запросах 1С 8.3
Содержание
Целую часть числа в 1С берут функцией Цел(Число): Цел(17.85) вернёт 17, а Цел(-17.85) вернёт -17. Функция просто отбрасывает дробную часть, без всякого округления. Если нужно округлить по правилам, используют Окр(), а если нужно именно «вниз» для отрицательных чисел — пишут пару строк поверх Цел().
В запросе всё сложнее. Классический приём — ВЫРАЗИТЬ(Поле КАК ЧИСЛО(15, 0)), но он округляет, а не отбрасывает дробь. Ниже — код для встроенного языка, для запросов и для задач, где целая часть нужна на практике: упаковки, страницы, рубли и копейки.
Функция Цел(): как получить целую часть числа
Цел() — встроенная функция платформы 1С:Предприятие 8.3. Она работает одинаково в любой конфигурации: БП 3.0, ЗУП 3.1, УТ 11, ERP или своей разработке. Доступна на клиенте и на сервере, директивы компиляции не нужны.
Что делает функция:
- ✂️ отбрасывает всё, что стоит после запятой;
- ➡️ двигается к нулю, а не вниз по числовой оси;
- 🔢 возвращает значение типа
Число, а не строку; - 🚫 ничего не округляет:
Цел(9.9999)даст9.
Последний пункт — главная причина, по которой функцию выбирают. Округление «по-бухгалтерски» тут не нужно: если в коробку входит 12 штук, а на складе 35, полных коробок 2, а не 3.
| Выражение | Результат |
|---|---|
Цел(5.2) | 5 |
Цел(5.8) | 5 |
Цел(5) | 5 |
Цел(0.99) | 0 |
Цел(-5.2) | -5 |
Цел(-5.8) | -5 |
Синтаксис Цел() и примеры кода
Синтаксис короткий: один параметр, тип Число.
Результат = Цел(Число);
Простой пример в процедуре:
Количество = 35;
ВКоробке = 12;
ПолныхКоробок = Цел(Количество / ВКоробке); // 2
Остаток = Количество - ПолныхКоробок * ВКоробке; // 11
Сообщить("Коробок: " + Формат(ПолныхКоробок, "ЧГ=0")
+ ", штук россыпью: " + Формат(Остаток, "ЧГ=0"));
Проверим арифметику: 35 / 12 = 2,916…; целая часть 2; 2 × 12 = 24; 35 − 24 = 11.
Дробная часть числа
Дробную часть получают вычитанием:
Число = 128.47;
ЦелаяЧасть = Цел(Число); // 128
ДробнаяЧасть = Число - Цел(Число); // 0.47
Для отрицательного числа дробная часть тоже будет отрицательной: -3.25 - Цел(-3.25) = -3.25 - (-3) = -0.25.
Проверка, что число целое
Частая задача — убедиться, что пользователь ввёл целое количество, а не 2,5 штуки.
Функция ЭтоЦелоеЧисло(Значение) Экспорт
Если ТипЗнч(Значение) <> Тип("Число") Тогда
Возврат Ложь;
КонецЕсли;
Возврат Значение = Цел(Значение);
КонецФункции
Сравнение Значение = Цел(Значение) надёжно: числа в 1С десятичные, поэтому 0.1 + 0.2 в 1С даёт ровно 0.3, без «хвостов», привычных по другим языкам.
Чем Цел() отличается от Окр() и округления вниз
Путают эти функции постоянно. Разница в том, что делать с дробью.
| Число | Цел() | Окр(Ч, 0) | Вниз (floor) | Вверх (ceil) |
|---|---|---|---|---|
7.3 | 7 | 7 | 7 | 8 |
7.5 | 7 | 8 | 7 | 8 |
7.8 | 7 | 8 | 7 | 8 |
-7.3 | -7 | -7 | -8 | -7 |
-7.8 | -7 | -8 | -8 | -7 |
Для положительных чисел Цел() совпадает с округлением вниз. Для отрицательных — нет: Цел(-7.3) = -7, а математическое округление вниз даёт -8.
Как работает Окр()
Полный синтаксис: Окр(Число, Разрядность, РежимОкругления).
- 🎯
Разрядность— сколько знаков оставить после запятой. Ноль — до целого. - ↩️ Отрицательная разрядность округляет до десятков, сотен:
Окр(1234.5, -2)=1200. - ⚖️
РежимОкругления.Окр15как20— пятёрка округляется вверх по модулю:Окр(2.5, 0)=3. Это режим по умолчанию. - ⚖️
РежимОкругления.Окр15как10— пятёрка отбрасывается:Окр(2.5, 0, РежимОкругления.Окр15как10)=2.
А = Окр(2.5, 0); // 3
Б = Окр(2.5, 0, РежимОкругления.Окр15как10); // 2
В = Окр(2.4999, 0, РежимОкругления.Окр15как20); // 2
Г = Окр(1234.5, -2); // 1200
Окр(Ч, 0, РежимОкругления.Окр15как10) — не аналог Цел(). Число 7.8 так округлится до 8. Режим влияет только на ровную пятёрку.
Формат() тоже округляет
Формат(7.8, "ЧДЦ=0") вернёт строку 8, а не 7. Форматная строка округляет число для показа. Если на печатной форме нужна именно целая часть, сначала Цел(), потом Формат():
Строка = Формат(Цел(7.8), "ЧДЦ=0; ЧГ=0"); // "7"
Целая часть в языке запросов 1С
В запросе вызвать Цел() из встроенного языка нельзя. Есть три пути.
Способ 1. ВЫРАЗИТЬ с поправкой
ВЫРАЗИТЬ(Х КАК ЧИСЛО(15, 0)) приводит число к типу без знаков после запятой. При этом СУБД округляет значение: 7,8 станет 8. Чтобы получить округление вниз, сравниваем результат с исходным числом:
ВЫБРАТЬ
Товары.Номенклатура КАК Номенклатура,
Товары.Количество КАК Количество,
ВЫБОР
КОГДА ВЫРАЗИТЬ(Товары.Количество / 12 КАК ЧИСЛО(15, 0)) > Товары.Количество / 12
ТОГДА ВЫРАЗИТЬ(Товары.Количество / 12 КАК ЧИСЛО(15, 0)) - 1
ИНАЧЕ ВЫРАЗИТЬ(Товары.Количество / 12 КАК ЧИСЛО(15, 0))
КОНЕЦ КАК ПолныхКоробок
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Товары
Логика простая: если после приведения число стало больше исходного, значит, его округлило вверх — вычитаем единицу. Приём не зависит от того, как конкретная СУБД обрабатывает ровную пятёрку, поэтому одинаково работает в файловой базе, на MS SQL и PostgreSQL.
Для отрицательных значений этот код даёт округление вниз (−7,3 → −8). Если нужно поведение как у Цел() (к нулю), добавьте ветку: для отрицательных чисел вычитать единицу не надо, а прибавлять, когда результат приведения оказался меньше исходного.
Деление на поле в запросе защищайте: ВЫБОР КОГДА Т.ВКоробке = 0 ТОГДА 0 ИНАЧЕ … КОНЕЦ. Деление на ноль в запросе прерывает его выполнение.
Способ 2. Функция ЦЕЛ в запросе (новые версии платформы)
Начиная с платформы 8.3.20 в язык запросов добавлены математические функции, среди них ЦЕЛ() и ОКР(). Они работают, если режим совместимости конфигурации не ниже 8.3.20. В типовых конфигурациях режим совместимости часто стоит ниже, поэтому проверьте его в свойствах конфигурации, прежде чем писать такой код. Если режим ниже — используйте способ 1.
Способ 3. Посчитать после запроса
Если записей немного, проще выгрузить результат и досчитать в коде:
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ПолныхКоробок = Цел(Выборка.Количество / 12);
// ...
КонецЦикла;
Для отчёта на СКД есть вариант без кода в модуле: вычисляемое поле, в выражении которого вызывается экспортная функция общего модуля с Цел() внутри. Общий модуль должен быть доступен на сервере.
Альтернативные способы и математические приёмы
Когда Цел() сам по себе не подходит, его дополняют. Ниже — готовые функции для общего модуля.
Округление вниз (floor) для любого знака
Функция ОкруглитьВниз(Число) Экспорт
ЦелаяЧасть = Цел(Число);
Если Число < ЦелаяЧасть Тогда
Возврат ЦелаяЧасть - 1;
КонецЕсли;
Возврат ЦелаяЧасть;
КонецФункции
Проверка: для -7.3 целая часть -7; -7.3 < -7 — истина; результат -8. Для 7.3 условие ложно, ответ 7.
Округление вверх (ceil)
Функция ОкруглитьВверх(Число) Экспорт
ЦелаяЧасть = Цел(Число);
Если Число > ЦелаяЧасть Тогда
Возврат ЦелаяЧасть + 1;
КонецЕсли;
Возврат ЦелаяЧасть;
КонецФункции
Проверка: 7.3 → 8; -7.3 → целая часть -7, условие -7.3 > -7 ложно, ответ -7. Ровное число 7 не меняется.
Остаток от деления: оператор %
Во встроенном языке 1С есть оператор остатка %. Вместе с Цел() он закрывает целочисленное деление:
Частное = Цел(35 / 12); // 2
Остаток = 35 % 12; // 11
Для чётности: Число % 2 = 0. Для «каждой третьей строки»: НомерСтроки % 3 = 0.
Округление до кратного
Цены до 10 рублей вниз, количество до кратности упаковки:
ЦенаВниз = Цел(Цена / 10) * 10; // 1287 → 1280
Кратно6 = Цел(Количество / 6) * 6; // 40 → 36
Ошибки при получении целой части и как их исправить
Ещё две ловушки, о которых не скажет сообщение об ошибке:
- Строка с запятой.
Число("3,7")иЧисло("3.7")в разных региональных настройках ведут себя по-разному. Если значение пришло из файла или внешней системы, замените разделитель черезСтрЗаменить()до преобразования. - Неопределено в реквизите. У пустого составного реквизита значение
Неопределено, иЦел()на нём упадёт. Проверка:Если ЗначениеЗаполнено(Значение) И ТипЗнч(Значение) = Тип("Число").
Практические задачи: где нужна целая часть числа
Несколько сценариев, которые встречаются в доработках учётных конфигураций.
Рубли и копейки
Сумма = 15420.37;
Рубли = Цел(Сумма); // 15420
Копейки = Окр((Сумма - Рубли) * 100); // 37
Копейки округляем через Окр(), чтобы не потерять одну копейку на суммах, которые пришли с лишними знаками после расчётов.
Количество страниц или пачек
Нужно разбить 103 строки по 25 на страницу. Полных страниц Цел(103 / 25) = 4, но всего страниц 5. Здесь нужна функция ОкруглитьВверх(103 / 25): 4,12 → 5.
Полные годы и месяцы между датами
Разность дат в 1С — число секунд. Полные дни:
ДнейМежду = Цел((ДатаОкончания - ДатаНачала) / 86400);
86 400 — секунд в сутках. Для полных лет точнее не делить на 365, а сравнивать даты через ДобавитьМесяц(ДатаНачала, 12 * Лет): високосные годы иначе дадут сбой на границе.
Разбивка суммы на равные части
Разделить 1 000 рублей на 3 платежа:
Всего = 1000;
Частей = 3;
Платёж = Цел(Всего / Частей * 100) / 100; // 333.33
Последний = Всего - Платёж * (Частей - 1); // 333.34
Проверка: 333,33 × 2 = 666,66; 1000 − 666,66 = 333,34. Сумма платежей сходится до копейки — остаток уходит в последний платёж.
Номер квартала по дате
Квартал удобно получить из номера месяца целочисленным делением:
Квартал = Цел((Месяц(Дата) - 1) / 3) + 1;
Проверка: январь — Цел(0 / 3) + 1 = 1; март — Цел(2 / 3) + 1 = 1; апрель — Цел(3 / 3) + 1 = 2; декабрь — Цел(11 / 3) + 1 = 4. Для самих границ квартала в платформе есть НачалоКвартала() и КонецКвартала(), а номер нужен для группировок и подписей в отчётах.