Как получить дробную часть числа во встроенном языке 1С
Содержание
Дробную часть числа в 1С выделяют одной строкой: ДробнаяЧасть = Число - Цел(Число);. Функция Цел() отбрасывает всё после запятой, а разница с исходным значением и есть дробная часть: для 12.75 получится 0.75.
Этот приём работает во всех конфигурациях на платформе 1С:Предприятие 8.3, потому что Цел() — функция самого встроенного языка, а не типового решения. Сложности начинаются на краях: отрицательные числа, результат деления с длинным хвостом, суммы с тремя знаками после запятой, расчёт прямо в запросе. Для каждого случая есть свой приём, и ошибка в нём обычно всплывает уже в печатной форме или в сверке сумм.
Функция Цел(): основной способ отделить целую и дробную часть
Цел(Число) возвращает целую часть, просто отрезая дробную. Она не округляет: Цел(9.99) вернёт 9, а не 10.
Число = 12.75;
ЦелаяЧасть = Цел(Число); // 12
ДробнаяЧасть = Число - ЦелаяЧасть; // 0.75
Почему это надёжно:
- 🔹 тип
Числов 1С хранит значения в десятичной форме, поэтому12.75 - 12даёт ровно0.75, без «хвостов» вида0.7500000001, привычных по другим языкам; - 🔹 функция есть и на клиенте, и на сервере, директивы компиляции не мешают;
- 🔹 результат имеет тот же знак, что и исходное число (подробнее — в разделе про отрицательные значения).
Если дробную часть нужно получить как целое число (например, 75 из 12.75), умножьте её на степень десятки:
ДробнаяЧасть = Число - Цел(Число); // 0.75
ДвеЦифры = ДробнаяЧасть * 100; // 75
Проверка «число целое?» — частный случай той же операции: Если Число = Цел(Число) Тогда. Это короче и понятнее, чем сравнивать дробную часть с нулём.
Округл(): когда дробную часть надо округлить, а не отрезать
Округл(Число, Разрядность, РежимОкругления) не выделяет дробную часть сам по себе. Но без него не обойтись, когда дробная часть нужна с заданной точностью или когда исходное значение «грязное».
Параметры функции:
| Параметр | Что задаёт | Пример |
|---|---|---|
| Число | исходное значение | 12.756 |
| Разрядность | сколько знаков после запятой оставить; может быть отрицательной | 2 → 12.76, -1 → 10 |
| РежимОкругления | как округлять половину | РежимОкругленияЧисла.Окр15как20 |
По умолчанию действует Окр15как20: половина округляется от нуля, 2.5 → 3. Режим Окр15как10 округляет половину к нулю: 2.5 → 2.
Типовая связка «округлить, потом выделить»:
Число = 12.756;
Число = Округл(Число, 2); // 12.76
ДробнаяЧасть = Число - Цел(Число); // 0.76
Почему порядок важен. Если сначала отрезать, а потом округлять дробную часть отдельно, на числах вроде 12.997 получите 0.997 → 1.00. Дробная часть «переполнится» и станет равна единице, а целая останется 12. Округляйте исходное число, а не кусок.
Через Округл() можно получить и целую часть с округлением, если отбрасывание не подходит:
ЦелаяОкругленная = Округл(12.6); // 13
ЦелаяОтрезанная = Цел(12.6); // 12
Остаток от деления на единицу: оператор %
Во встроенном языке 1С есть оператор остатка от деления %. Он работает и с дробными операндами, поэтому остаток от деления на 1 — это дробная часть:
ДробнаяЧасть = 12.75 % 1; // 0.75
Результат совпадает с Число - Цел(Число), включая знак: у -12.75 % 1 тоже будет -0.75.
Где % удобнее, чем Цел():
- 🔸 дробная часть относительно шага.
Число % 0.05показывает, насколько цена отклоняется от кратности пяти копейкам; - 🔸 отдельная цифра после запятой. Вторая цифра числа
12.75:Цел(12.75 * 100) % 10→5; - 🔸 проверка кратности.
Количество % 1 = 0— количество целое,Количество % 6 = 0— делится на упаковки по 6 штук.
Цифры дробной части по отдельности
Иногда нужна не вся дробь, а конкретная цифра — например, для контрольного разряда или проверки, что в количестве нет третьего знака. Сдвиньте нужную цифру в позицию единиц и возьмите остаток от деления на 10:
Функция ЦифраПослеЗапятой(Число, Позиция)
Сдвинуто = Цел(Число * Pow(10, Позиция));
Возврат Сдвинуто % 10;
КонецФункции
ЦифраПослеЗапятой(12.758, 1) // 7
ЦифраПослеЗапятой(12.758, 3) // 8
Проверка: 12.758 * 1000 = 12758, остаток от деления на 10 — 8. Для отрицательных чисел результат тоже будет отрицательным, поэтому передавайте в функцию модуль.
Шаг цены
Округление цены до шага строится на той же идее, но через Округл():
Шаг = 0.05;
Цена = 103.27;
ЦенаКратная = Округл(Цена / Шаг) * Шаг; // 103.25
Отклонение = Цена % Шаг; // 0.02
Проверим арифметику: 103.27 / 0.05 = 2065.4, округление даёт 2065, умножение на 0.05 — 103.25. Разница с исходной ценой — 0.02.
Сравнение методов
| Метод | Код | Когда брать | Риски |
|---|---|---|---|
| Вычитание целой части | Ч - Цел(Ч) | почти всегда | длинный хвост после деления |
| Остаток от деления | Ч % 1 | шаг, кратность, отдельные цифры | непривычен для читающих код |
| Округлить, затем вычесть | Ч - Цел(Ч) после Округл(Ч, 2) | суммы и цены | забыть, что округлено исходное число |
| Через строку | СтрРазделить(Строка(Ч), ",") | никогда | разделитель и пробелы зависят от локали |
Последняя строка таблицы — частая ошибка новичков. Строка(1234.5) вернёт 1 234,5: с неразрывным пробелом между разрядами и запятой, которая на другой локали может стать точкой. Разбор такой строки ломается при первом же переносе базы на другой сервер.
Отрицательные числа и граничные случаи
Знак дробной части
Цел() отбрасывает дробь в сторону нуля, а не вниз:
Цел(-3.7) // -3, а не -4
-3.7 - Цел(-3.7) // -0.7
Если вам нужна «математическая» дробная часть, всегда неотрицательная (-3.7 → 0.3), считайте целую часть с округлением вниз:
Функция ЦелаяЧастьВниз(Число)
Результат = Цел(Число);
Если Число < 0 И Число <> Результат Тогда
Результат = Результат - 1;
КонецЕсли;
Возврат Результат;
КонецФункции
ЦелаяЧасть = ЦелаяЧастьВниз(-3.7); // -4
ДробнаяЧасть = -3.7 - ЦелаяЧасть; // 0.3
Если нужен только модуль дробной части без знака, достаточно ?(ДробнаяЧасть < 0, -ДробнаяЧасть, ДробнаяЧасть).
Результат деления
10 / 3 даёт 3.333… с десятками троек. Дробная часть такого числа тоже бесконечная, и сравнивать её с 0.33 бессмысленно. Больше того, 1 / 3 * 3 может дать не ровно 1, а число на хвостик меньше — и Цел() вернёт 0.
Перед Цел() от результата деления округляйте его до нужной точности.
Результат = Округл(Сумма / Количество, 2);
Значения не числового типа
Цел() от Неопределено, Null или строки вызовет ошибку преобразования типа. Так бывает с пустыми реквизитами составного типа и с полями запроса после левого соединения.
Если ТипЗнч(Значение) = Тип("Число") Тогда
ДробнаяЧасть = Значение - Цел(Значение);
Иначе
ДробнаяЧасть = 0;
КонецЕсли;
Строку из файла сначала превратите в число: Число(СтрЗаменить(Текст, ",", ".")). Конструкцию оберните в Попытка … Исключение, если в данных может встретиться мусор.
Точность реквизита
Реквизит с типом Число(15, 2) хранит только два знака после запятой. Записали туда 12.756 — в базе окажется значение с двумя знаками. Не полагайтесь на это неявное приведение: округлите сами через Округл(), тогда результат будет одинаковым в коде и в базе.
Рубли и копейки: практический пример
Самая частая прикладная задача — разложить сумму на рубли и копейки для печатной формы, сверки с банком или текстового поля «сумма прописью».
Функция РазложитьСумму(Знач Сумма)
Сумма = Округл(Сумма, 2);
Рубли = Цел(Сумма);
Копейки = (Сумма - Рубли) * 100;
Результат = Новый Структура;
Результат.Вставить("Рубли", Рубли);
Результат.Вставить("Копейки", Копейки);
Возврат Результат;
КонецФункции
Части = РазложитьСумму(1234.56);
// Части.Рубли = 1234, Части.Копейки = 56
Разберём ловушки по шагам:
- Округление в начале. Без него сумма
10.999дала бы10рублей и99.9копейки. С округлением получается11.00→11рублей0копеек. - Копейки после округления — целые.
(1234.56 - 1234) * 100 = 56, дополнительныйЦел()не нужен. - Вывод с ведущим нулём. Пять копеек должны печататься как
05, а не5:
ТекстКопеек = Формат(Части.Копейки, "ЧЦ=2; ЧВН=; ЧН=00");
ТекстРублей = Формат(Части.Рубли, "ЧГ=0; ЧН=0");
Текст = ТекстРублей + " руб. " + ТекстКопеек + " коп.";
// 1234 руб. 56 коп.
Параметр ЧВН включает ведущие нули, ЧН задаёт текст для нуля, ЧГ=0 убирает разделитель разрядов.
- Возвраты и сторно. Для
-15.30функция вернёт-15рублей и-30копеек. В печатной форме знак обычно выводят один раз перед суммой, поэтому раскладывайте модуль суммы, а знак добавляйте отдельно.
Если нужна сумма прописью целиком, не собирайте её из частей: функция ЧислоПрописью() с параметрами предмета исчисления уже выводит и рубли, и копейки в правильных падежах.
Массовые расчёты: где считать и как не тормозить
Сама операция Число - Цел(Число) дешёвая. Медленно становится из-за того, что её окружает.
В запросе вместо цикла
Если дробную часть нужно посчитать для тысяч строк регистра, считайте её в запросе, а не в цикле по выборке. Классический приём — приведение к числу без знаков после запятой через ВЫРАЗИТЬ, которое округляет значение:
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.КоличествоОстаток КАК Количество,
Остатки.КоличествоОстаток
- ВЫРАЗИТЬ(Остатки.КоличествоОстаток - 0.5 КАК ЧИСЛО(15, 0)) КАК ДробнаяЧасть
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
Сдвиг на 0.5 превращает округление в отбрасывание вниз: 7.3 - 0.5 = 6.8 → 7, 7.0 - 0.5 = 6.5 → 7. Приём рассчитан на неотрицательные значения. Для отрицательного целого числа -3 - 0.5 = -3.5, и результат зависит от того, как округляется половина, — такие строки отфильтруйте условием или посчитайте в коде.
В свежих версиях платформы в язык запросов добавлены математические функции, включая ЦЕЛ и ОКР. Откройте синтакс-помощник своей версии: если они там есть, используйте их вместо трюка с ВЫРАЗИТЬ.
В коде
- ⚡ не делайте серверный вызов на каждую строку. Передайте таблицу на сервер одним вызовом и посчитайте там;
- ⚡ уберите строковые преобразования из цикла.
Формат()иСтрока()создают новые строки и заметно дороже арифметики — форматируйте только то, что выводите; - ⚡ не пересчитывайте одно и то же. Если
Округл(Сумма, 2)нужен в трёх местах, сохраните в переменную; - ⚡ меряйте, а не гадайте. Замер через
ТекущаяУниверсальнаяДатаВМиллисекундах()до и после цикла покажет, стоит ли оптимизация усилий.
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
Для Каждого Строка Из ТаблицаТоваров Цикл
Строка.ДробнаяЧасть = Строка.Количество - Цел(Строка.Количество);
КонецЦикла;
Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - Начало;
Частые вопросы
Есть ли в 1С отдельная функция для дробной части?
Число - Цел(Число) или Число % 1, результат одинаковый.Как узнать количество знаков после запятой?
Можно ли получить дробную часть в выражении СКД?
Цел() и Окр(), поэтому работает то же вычитание. Для больших объёмов надёжнее посчитать поле прямо в запросе набора данных.Как округлить до десятков или сотен рублей?
Округл(1234.56, -2) вернёт 1200, Округл(1250, -2) — 1300.Почему дробная часть получилась отрицательной?
Цел() отбрасывает дробь в сторону нуля, поэтому у отрицательного числа дробная часть тоже отрицательная. Нужна неотрицательная — считайте целую часть с округлением вниз.