1с8 Распределение суммы по базе

В данном алгоритме ошибка прибавляется к сумме, у которой максимальный коэффициент. При достаточном большом количестве сторк можкт накопиться погрешность, которая прибавится к этой строке.

Функция РаспределитьПропорционально(Знач ИсхСумма, МассивКоэф, Знач Точность = 2) Экспорт
	
	Если МассивКоэф.Количество() = 0 Или ИсхСумма = 0 Или ИсхСумма = Null Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ИндексМакс = 0;
	МаксЗнач   = 0;
	РаспрСумма = 0;
	СуммаКоэф  = 0;
	
	Для К = 0 По МассивКоэф.Количество() - 1 Цикл
		
		МодульЧисла = ?(МассивКоэф[К] > 0, МассивКоэф[К], - МассивКоэф[К]);
		
		Если МаксЗнач < МодульЧисла Тогда
			МаксЗнач = МодульЧисла;
			ИндексМакс = К;
		КонецЕсли;
		
		СуммаКоэф = СуммаКоэф + МассивКоэф[К];
		
	КонецЦикла;
	
	Если СуммаКоэф = 0 Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	МассивСумм = Новый Массив(МассивКоэф.Количество());
	
	Для К = 0 По МассивКоэф.Количество() - 1 Цикл
		МассивСумм[К] = Окр(ИсхСумма * МассивКоэф[К] / СуммаКоэф, Точность, 1);
		РаспрСумма = РаспрСумма + МассивСумм[К];
	КонецЦикла;
	
	// Погрешности округления отнесем на коэффиецент с максимальным весом
	Если Не РаспрСумма = ИсхСумма Тогда
		МассивСумм[ИндексМакс] = МассивСумм[ИндексМакс] + ИсхСумма - РаспрСумма;
	КонецЕсли;
	
	Возврат МассивСумм;
	
КонецФункции

Из Розницы 2.2

// Выполняет пропорциональное распределение суммы в соответствии
// с заданными коэффициентами распределения.
//
// Параметры:
//  РаспределяемаяСумма - Число  - сумма, которую надо распределить, если сумма равна 0 - то возвращается Неопределено;
//                                 Если передана отрицательная - расчет по модулю и после инверсия знаков результата.
//  Коэффициенты        - Массив - коэффициенты распределения, должны быть положительны или отрицательными одновременно
//  Точность            - Число  - точность округления при распределении. Необязателен.
//
// Возвращаемое значение:
//  Массив - массив размерностью равный массиву коэффициентов, содержит
//           суммы в соответствии с весом коэффициента (из массива коэффициентов).
//           В случае, если распределить невозможно (кол-во коэффициентов = 0,
//           есть коэффициенты с отрицательным значением или суммарный вес коэффициентов = 0),
//           тогда будет возвращено Неопределено.
//
// Пример:
//
//	Коэффициенты = Новый Массив;
//	Коэффициенты.Добавить(1);
//	Коэффициенты.Добавить(2);
//	Результат = ОбщегоНазначенияКлиентСервер.РаспределитьСуммуПропорциональноКоэффициентам(1, Коэффициенты);
//	// Результат = [0.33, 0.67]
//
Функция РаспределитьСуммуПропорциональноКоэффициентам(Знач РаспределяемаяСумма, Знач Коэффициенты, Знач Точность = 2) Экспорт
	
	КоэффициентыАбсолютные = Новый Массив(Новый ФиксированныйМассив(Коэффициенты)); // cpy
	
	// Старое поведение при неуказанной сумме - для обратной совместимости.
	Если Не ЗначениеЗаполнено(РаспределяемаяСумма) Тогда 
		Возврат Неопределено;
	КонецЕсли;
	
	Если КоэффициентыАбсолютные.Количество() = 0 Тогда 
		// Недопустимо значение параметра Коэффициенты
		// Ожидалось: хотя бы один коэффициент будет задан.
		Возврат Неопределено;
	КонецЕсли;
	
	ИндексМаксимальногоКоэффициента = 0;
	МаксимальныйКоэффициент = 0;
	СуммаКоэффициентов = 0;
	КоэффициентыОтрицательны = (КоэффициентыАбсолютные[0] < 0);
	
	Для Индекс = 0 По КоэффициентыАбсолютные.Количество() - 1 Цикл
		Коэффициент = КоэффициентыАбсолютные[Индекс];
		
		Если КоэффициентыОтрицательны И Коэффициент > 0 Тогда 
			// Недопустимо значение параметра Коэффициенты
			// Ожидалось: все коэффициенты положительны или все отрицательны одновременно.
			Возврат Неопределено;
		КонецЕсли;
		
		Если Коэффициент < 0 Тогда 
			Коэффициент = -Коэффициент; // Abs(Коэффициент)
			КоэффициентыАбсолютные[Индекс] = Коэффициент; // move
		КонецЕсли;
		
		Если МаксимальныйКоэффициент < Коэффициент Тогда
			МаксимальныйКоэффициент = Коэффициент;
			ИндексМаксимальногоКоэффициента = Индекс;
		КонецЕсли;
		
		СуммаКоэффициентов = СуммаКоэффициентов + Коэффициент;
	КонецЦикла;
	
	Если СуммаКоэффициентов = 0 Тогда
		// Недопустимо значение параметра Коэффициенты
		// Ожидалось: хотя бы один коэффициент будет отличен от нуля.
		Возврат Неопределено;
	КонецЕсли;
	
	Результат = Новый Массив(КоэффициентыАбсолютные.Количество());
	
	ВыполнятьИнверсию = (РаспределяемаяСумма < 0);
	Если ВыполнятьИнверсию Тогда 
		РаспределяемаяСумма = -РаспределяемаяСумма; // Abs(РаспределяемаяСумма).
	КонецЕсли;
	
	РаспределеннаяСумма = 0;
	
	Для Индекс = 0 По КоэффициентыАбсолютные.Количество() - 1 Цикл
		Результат[Индекс] = Окр(РаспределяемаяСумма * КоэффициентыАбсолютные[Индекс] / СуммаКоэффициентов, Точность, 1);
		РаспределеннаяСумма = РаспределеннаяСумма + Результат[Индекс];
	КонецЦикла;
	
	СуммарнаяПогрешность = РаспределяемаяСумма - РаспределеннаяСумма;
	
	Если СуммарнаяПогрешность > 0 Тогда 
		
		// Погрешности округления отнесем на коэффициент с максимальным весом.
		Если Не РаспределеннаяСумма = РаспределяемаяСумма Тогда
			Результат[ИндексМаксимальногоКоэффициента] = Результат[ИндексМаксимальногоКоэффициента] + СуммарнаяПогрешность;
		КонецЕсли;
		
	ИначеЕсли СуммарнаяПогрешность < 0 Тогда 
		
		// Если распределили больше чем положено, размазываем погрешность по ближайшим максимальным весам.
		ЗначениеПогрешности = 1 / Pow(10, Точность);
		КоличествоЭлементовПогрешности = -СуммарнаяПогрешность / ЗначениеПогрешности;
		
		Для Сч = 1 По КоличествоЭлементовПогрешности Цикл 
			МаксимальныйКоэффициент = МаксимальноеЗначениеВМассиве(КоэффициентыАбсолютные);
			Индекс = КоэффициентыАбсолютные.Найти(МаксимальныйКоэффициент);
			Результат[Индекс] = Результат[Индекс] - ЗначениеПогрешности;
			КоэффициентыАбсолютные[Индекс] = 0;
		КонецЦикла;
		
	Иначе 
		// Если СуммарнаяПогрешность = 0, то все идеально.
	КонецЕсли;
	
	Если ВыполнятьИнверсию Тогда 
		Для Индекс = 0 По КоэффициентыАбсолютные.Количество() - 1 Цикл
			Результат[Индекс] = -Результат[Индекс];
		КонецЦикла;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции