Что делать, если после округления сумма распределения не совпадает с исходной?
Если после округления дробных значений сумма распределения не совпадает с исходной, необходимо использовать специальный алгоритм, позволяющий устранить разницу и добиться строгого соответствия итоговой суммы. Эта проблема характерна при распределении денежных средств с округлением до целых рублей. Ниже подробно описаны причины, принципы устранения и реализация корректного распределения с компенсацией расхождений.
1. Почему возникает расхождение после округления
Когда значения распределяются пропорционально и округляются до рублей, результат становится неточным. Пример:
- Исходная сумма: **40 руб.**
- Пропорции: \[4.4, 3.3, 2.3\]
- После округления: \[4, 3, 2\] → всего **9**, а нужно **10**
- Разница = ±1 или более, если множество строк.
Причина — округление каждой строки по отдельности, без учёта накопленного эффекта округлений.
2. Общая идея решения
Алгоритм состоит из трёх этапов:
-
Распределить сумму пропорционально и запомнить дробные значения.
-
Округлить все значения вниз до рублей и посчитать их сумму.
-
Вычислить, сколько рублей не хватает до исходной суммы.
-
Раздать недостающие рубли тем строкам, где остаток после округления был наибольшим.
Такой метод используется в банках, при расчетах с налогами и заработной платой, а также в 1С при точном распределении бюджетов, скидок и других сумм.
3. Подробный пример алгоритма
Исходные данные:
- Строки таблицы значений с колонками:
- Количество (база распределения),
- Доля = (Количество / ОбщаяБаза),
- Сумма = Доля \* ОбщаяСумма,
- СуммаЦелая — округлённая часть вниз (целое),
- Остаток — дробная часть (остаток до полного числа).
#### **Пошагово:**
**Шаг 1. Рассчитать пропорции:**
ОбщаяБаза = 0;
Для каждого Стр из Таблица Цикл
ОбщаяБаза = ОбщаяБаза + Стр.Количество;
КонецЦикла;
**Шаг 2. Вычислить долю и дробную сумму:**
Для каждого Стр из Таблица Цикл
Стр.Доля = Стр.Количество / ОбщаяБаза;
Стр.Сумма = Стр.Доля \* ОбщаяСумма;
Стр.СуммаЦелая = Цел(Стр.Сумма);
Стр.Остаток = Стр.Сумма - Стр.СуммаЦелая;
КонецЦикла;
**Шаг 3. Подсчитать сумму округлённых значений и разницу:**
ИтоговаяСумма = 0;
Для каждого Стр из Таблица Цикл
ИтоговаяСумма = ИтоговаяСумма + Стр.СуммаЦелая;
КонецЦикла;
НеХватает = ОбщаяСумма - ИтоговаяСумма;
**Шаг 4. Раздать недостающие рубли строкам с наибольшими остатками:**
Таблица.Сортировать("Остаток Убыв");
Для Индекс = 0 По НеХватает - 1 Цикл
Таблица\[Индекс\].СуммаЦелая = Таблица\[Индекс\].СуммаЦелая + 1;
КонецЦикла;
После этого сумма СуммаЦелая по всем строкам будет точно равна исходной сумме.
4. Варианты обработки при отрицательной разнице
Если результат превышает исходную сумму (например, округляли вверх), можно аналогично:
- Сортировать по остаткам по возрастанию.
- Вычитать 1 рубль из строк с наименьшими остатками.
Такой случай бывает, если изначально округляли математически (Окр), а не вниз.
5. Где применяется в 1С
-
Распределение скидок по строкам документа.
-
Пропорциональное распределение суммы налога или расходов.
-
Финансовое планирование.
-
Закрытие затрат по базам распределения.
6. Встроенные механизмы платформы
1С:Предприятие не предлагает встроенной функции точного распределения с компенсацией округлений. Поэтому такой алгоритм разрабатывается вручную в модулях обработки или объектах (например, документ, внешний отчёт, обработка).
Дополнительные функции:
-
Окр(Число, 0) — математическое округление.
-
Цел() — округление вниз.
-
Окр(Число, 0, РежимОкругления.ОтБольшеКМеньшему) — контроль за направлением округления.
7. Проверка корректности результата
После завершения алгоритма обязательно проверяется:
КонтрольСумма = 0;
Для каждого Стр из Таблица Цикл
КонтрольСумма = КонтрольСумма + Стр.СуммаЦелая;
КонецЦикла;
Если КонтрольСумма <> ОбщаяСумма Тогда
ВызватьИсключение("Ошибка распределения: сумма не совпадает!");
КонецЕсли;
Это гарантирует точность и предотвращает логические ошибки в учёте.