Как распределить сумму 40 рублей пропорционально количеству с точностью до рубля в таблице значений?
Распределение суммы (например, 40 рублей) пропорционально количеству с точностью до рубля — это типичная задача, возникающая при расчёте долей в 1С, когда результат должен быть целым числом (без копеек) и при этом сумма всех долей строго равна исходной.
1. Пример исходных данных
Предположим, у нас есть следующая таблица значений:
№ | Количество |
---|---|
1 | 2 |
--- | --- |
2 | 3 |
--- | --- |
3 | 5 |
--- | --- |
Общая сумма: 40 рублей
Общая база распределения (сумма количеств): 2 + 3 + 5 = 10
2. Расчёт коэффициента
Сначала определим коэффициент распределения:
Коэффициент = ОбщаяСумма / ОбщаяБаза
Коэффициент = 40 / 10 = 4
Теперь каждая строка получит:
-
Строка 1: 2 × 4 = 8
-
Строка 2: 3 × 4 = 12
-
Строка 3: 5 × 4 = 20
Итог: 8 + 12 + 20 = 40 — всё корректно, сумма распределена.
3. Что делать при дробных результатах
Если бы база была не делится нацело, например:
№ | Количество |
---|---|
1 | 1 |
--- | --- |
2 | 2 |
--- | --- |
3 | 3 |
--- | --- |
База = 6
Коэффициент = 40 / 6 ≈ 6.666...
Результаты до округления:
-
1 × 6.666... = 6.666...
-
2 × 6.666... = 13.333...
-
3 × 6.666... = 20
Сумма: 6.666... + 13.333... + 20 = 40
Если мы округлим каждое значение:
- 6.666 → **7
** - 13.333 → **13
** - 20 → **20
**
Итог: 7 + 13 + 20 = 40 — совпадает.
Но бывают случаи, когда после округления сумма не совпадает. Тогда нужно использовать алгоритм корректировки.
4. Алгоритм с корректировкой
Шаг 1: Расчёт долей и округление вниз
Для каждой строки:
-
вычисляется точное значение: Количество * Коэффициент
-
округляется вниз: ЦелаяСумма = Цел(ТочноеЗначение)
-
сохраняется остаток: Остаток = ТочноеЗначение - ЦелаяСумма
Считаем сумму всех округленных значений: ТекущаяСумма
Шаг 2: Корректировка
Если ТекущаяСумма < ИсходнаяСумма:
-
разницу Недостача = ИсходнаяСумма - ТекущаяСумма
-
отсортировать строки по убыванию остатка (чем больше остаток, тем ближе значение к следующему целому)
-
распределить недостачу по этим строкам — прибавить по 1 рублю в строки с наибольшими остатками, пока не будет достигнута нужная сумма
5. Пример с округлением и корректировкой
Имеем:
№ | Количество |
---|---|
1 | 2 |
--- | --- |
2 | 1 |
--- | --- |
3 | 3 |
--- | --- |
Сумма: 40
База: 6
Коэффициент: 40 / 6 = 6.666...
Точное распределение:
-
2 × 6.666... = 13.333 → Цел = 13 → Остаток = 0.333
-
1 × 6.666... = 6.666 → Цел = 6 → Остаток = 0.666
-
3 × 6.666... = 20 → Цел = 20 → Остаток = 0
Целые суммы: 13 + 6 + 20 = 39
Осталась 1 рубль недостачи
Сортировка по остаткам:
-
строка 2 (остаток 0.666)
-
строка 1 (остаток 0.333)
-
строка 3 (остаток 0)
Прибавляем 1 рубль строке 2 (у которой самый большой остаток)
Итоговое распределение:
-
строка 1: 13
-
строка 2: 7 (6 + 1)
-
строка 3: 20
Сумма: 40 рублей
6. Реализация в 1С
На языке 1С можно реализовать алгоритм так:
ОбщаяСумма = 40;
База = 0;
Для каждого Стр Из ТаблицаЦикл Цикл
База = База + Стр.Количество;
КонецЦикла;
Коэффициент = ОбщаяСумма / База;
// Расчёт точных значений, округление вниз и вычисление остатков
Для каждого Стр Из ТаблицаЦикл Цикл
ТочноеЗначение = Стр.Количество \* Коэффициент;
Стр.Сумма = Цел(ТочноеЗначение);
Стр.Остаток = ТочноеЗначение - Стр.Сумма;
КонецЦикла;
// Суммируем округлённые суммы
СуммаВсего = 0;
Для каждого Стр Из ТаблицаЦикл Цикл
СуммаВсего = СуммаВсего + Стр.Сумма;
КонецЦикла;
// Распределение недостающих рублей
Недостача = ОбщаяСумма - СуммаВсего;
Если Недостача > 0 Тогда
Отсортированная = ТаблицаЦикл.Скопировать();
Отсортированная.СортироватьПоУбыванию("Остаток");
Для каждого Стр Из Отсортированная Цикл
Если Недостача = 0 Тогда
Прервать;
КонецЕсли;
Стр.Сумма = Стр.Сумма + 1;
Недостача = Недостача - 1;
КонецЦикла;
КонецЕсли;
7. Применение в реальных задачах
Такой подход нужен при:
-
распределении оплаты между позициями
-
учёте пропорциональных налогов
-
разбиении бонусов/скидок между строками
-
расчёте себестоимости по количеству
Он обеспечивает корректную арифметику и точную итоговую сумму, соответствующую исходной, несмотря на округления.