Что делать, если после округления сумма распределения не совпадает с исходной?


Если после округления дробных значений сумма распределения не совпадает с исходной, необходимо использовать специальный алгоритм, позволяющий устранить разницу и добиться строгого соответствия итоговой суммы. Эта проблема характерна при распределении денежных средств с округлением до целых рублей. Ниже подробно описаны причины, принципы устранения и реализация корректного распределения с компенсацией расхождений.

1. Почему возникает расхождение после округления

Когда значения распределяются пропорционально и округляются до рублей, результат становится неточным. Пример:

- Исходная сумма: **40 руб.**
- Пропорции: \[4.4, 3.3, 2.3\]  
- После округления: \[4, 3, 2\]  всего **9**, а нужно **10**
- Разница = ±1 или более, если множество строк.    

Причина — округление каждой строки по отдельности, без учёта накопленного эффекта округлений.

2. Общая идея решения

Алгоритм состоит из трёх этапов:

  1. Распределить сумму пропорционально и запомнить дробные значения.

  2. Округлить все значения вниз до рублей и посчитать их сумму.

  3. Вычислить, сколько рублей не хватает до исходной суммы.

  4. Раздать недостающие рубли тем строкам, где остаток после округления был наибольшим.

Такой метод используется в банках, при расчетах с налогами и заработной платой, а также в 1С при точном распределении бюджетов, скидок и других сумм.

3. Подробный пример алгоритма

Исходные данные:
- Строки таблицы значений с колонками:
    - Количество (база распределения),
    - Доля = (Количество / ОбщаяБаза),
    - Сумма = Доля \* ОбщаяСумма,
    - СуммаЦелая  округлённая часть вниз (целое),
    - Остаток  дробная часть (остаток до полного числа).
#### **Пошагово:**
**Шаг 1. Рассчитать пропорции:**
ОбщаяБаза = 0;
Для каждого Стр из Таблица Цикл
ОбщаяБаза = ОбщаяБаза + Стр.Количество;
КонецЦикла;
**Шаг 2. Вычислить долю и дробную сумму:**
Для каждого Стр из Таблица Цикл
Стр.Доля = Стр.Количество / ОбщаяБаза;
Стр.Сумма = Стр.Доля \* ОбщаяСумма;
Стр.СуммаЦелая = Цел(Стр.Сумма);
Стр.Остаток = Стр.Сумма - Стр.СуммаЦелая;
КонецЦикла;
**Шаг 3. Подсчитать сумму округлённых значений и разницу:**
ИтоговаяСумма = 0;
Для каждого Стр из Таблица Цикл
ИтоговаяСумма = ИтоговаяСумма + Стр.СуммаЦелая;
КонецЦикла;
НеХватает = ОбщаяСумма - ИтоговаяСумма;
**Шаг 4. Раздать недостающие рубли строкам с наибольшими остатками:**
Таблица.Сортировать("Остаток Убыв");
Для Индекс = 0 По НеХватает - 1 Цикл
Таблица\[Индекс\].СуммаЦелая = Таблица\[Индекс\].СуммаЦелая + 1;
КонецЦикла;

После этого сумма СуммаЦелая по всем строкам будет точно равна исходной сумме.

4. Варианты обработки при отрицательной разнице

Если результат превышает исходную сумму (например, округляли вверх), можно аналогично:
- Сортировать по остаткам по возрастанию.
- Вычитать 1 рубль из строк с наименьшими остатками.
Такой случай бывает, если изначально округляли математически (Окр), а не вниз.

5. Где применяется в 1С

  • Распределение скидок по строкам документа.

  • Пропорциональное распределение суммы налога или расходов.

  • Финансовое планирование.

  • Закрытие затрат по базам распределения.

6. Встроенные механизмы платформы

1С:Предприятие не предлагает встроенной функции точного распределения с компенсацией округлений. Поэтому такой алгоритм разрабатывается вручную в модулях обработки или объектах (например, документ, внешний отчёт, обработка).

Дополнительные функции:

  • Окр(Число, 0) — математическое округление.

  • Цел() — округление вниз.

  • Окр(Число, 0, РежимОкругления.ОтБольшеКМеньшему) — контроль за направлением округления.

7. Проверка корректности результата

После завершения алгоритма обязательно проверяется:

КонтрольСумма = 0;
Для каждого Стр из Таблица Цикл
КонтрольСумма = КонтрольСумма + Стр.СуммаЦелая;
КонецЦикла;
Если КонтрольСумма <> ОбщаяСумма Тогда
ВызватьИсключение("Ошибка распределения: сумма не совпадает!");
КонецЕсли;

Это гарантирует точность и предотвращает логические ошибки в учёте.