Untitled
unknown
plain_text
8 months ago
15 kB
10
Indexable
// Объявления функций
Далее Функция РазбитьПозициюПеребором(Цена, Количество, ОбщаяСумма);
Далее Функция ПеребратьКоличества(Цена, Количество, ОбщаяСумма, Шаг, ИзменятьКоличество);
// Функция разбивает позицию на две части методом перебора по количеству.
// Сохраняет исходную цену для первой позиции и подбирает цену для второй позиции.
//
// Параметры:
// Цена - Число - Цена с точностью до 2 знаков после запятой
// Количество - Число - Количество с точностью до 3 знаков после запятой
// ОбщаяСумма - Число - Общая сумма с точностью до 2 знаков после запятой
//
// Возвращаемое значение:
// ТаблицаЗначений - Содержит две строки с колонками: Цена, Количество, Сумма
// или 0, если разбиение невозможно
Функция РазбитьПозициюПеребором(Цена, Количество, ОбщаяСумма)
// Округляем входные данные до нужной точности
Цена = Окр(Цена, 2);
Количество = Окр(Количество, 3);
ОбщаяСумма = Окр(ОбщаяСумма, 2);
// Проверяем, нужно ли разбиение
ТеоретическаяСумма = Окр(Цена * Количество, 2);
Если ТеоретическаяСумма = ОбщаяСумма Тогда
Результат = СоздатьОбъект("ТаблицаЗначений");
Результат.ИзменитьСтруктуру();
Результат.ДобавитьКолонку("Цена");
Результат.ДобавитьКолонку("Количество");
Результат.ДобавитьКолонку("Сумма");
Результат.ДобавитьСтроку();
Результат.Цена.Значение = Цена;
Результат.Количество.Значение = Количество;
Результат.Сумма.Значение = ОбщаяСумма;
Результат.ДобавитьСтроку();
Результат.Цена.Значение = 0;
Результат.Количество.Значение = 0;
Результат.Сумма.Значение = 0;
Возврат Результат;
КонецЕсли;
// Определяем шаг перебора в зависимости от дробной части количества
Если Количество = Цел(Количество) Тогда
// Если количество целое число
Шаг = 1;
ИначеЕсли Окр(Количество * 10, 0) = Цел(Количество * 10) Тогда
// Если количество имеет только один десятичный знак
Шаг = 0.001;
ИначеЕсли Окр(Количество * 100, 0) = Цел(Количество * 100) Тогда
// Если количество имеет два десятичных знака
Шаг = 0.001;
Иначе
// Если количество имеет три десятичных знака
Шаг = 0.001;
КонецЕсли;
// Вызываем функцию перебора
Результат = ПеребратьКоличества(Цена, Количество, ОбщаяСумма, Шаг, 0);
Если Результат = 0 Тогда
Результат = ПеребратьКоличества(Цена, Количество, ОбщаяСумма, Шаг, 1);
КонецЕсли;
Возврат Результат;
КонецФункции
// Функция перебирает возможные разбиения позиции по количеству.
//
// Параметры:
// Цена - Число - Цена с точностью до 2 знаков после запятой
// Количество - Число - Количество с точностью до 3 знаков после запятой
// ОбщаяСумма - Число - Общая сумма с точностью до 2 знаков после запятой
// Шаг - Число - Шаг перебора количества
// ИзменятьКоличество - Число - Флаг, указывающий, нужно ли изменять количество (0 - нет, 1 - да)
//
// Возвращаемое значение:
// ТаблицаЗначений - Содержит две строки с колонками: Цена, Количество, Сумма
// или 0, если разбиение невозможно
Функция ПеребратьКоличества(Цена, Количество, ОбщаяСумма, Шаг, ИзменятьКоличество)
// Перебираем все возможные значения Количество2
Для И = 1 По Цел(Количество / Шаг) + 1 Цикл
Количество2 = Окр(И * Шаг, 3);
Количество1 = Окр(Количество - Количество2, 3);
// Если Количество1 <= 0, дальше нет смысла
Если Количество1 <= 0 Тогда
Прервать;
КонецЕсли;
// Считаем сумму первой позиции
Сумма1 = Окр(Цена * Количество1, 2);
Цена1 = Окр(Сумма1 / Количество1, 8);
Если Цена1 <> Цена Тогда
Продолжить;
КонецЕсли;
// Считаем остаток по сумме
Сумма2 = Окр(ОбщаяСумма - Сумма1, 2);
// Вычисляем цену для второй позиции
Цена2Исх = Сумма2 / Количество2;
Цена2 = Окр(Цена2Исх, 2);
// Проверяем, "бьётся" ли вторая позиция по сумме
Сумма2Проверка = Окр(Цена2 * Количество2, 2);
Если (Сумма2Проверка <> Сумма2) И (ИзменятьКоличество = 1) Тогда
Количество2 = 1;
Цена2Исх = Сумма2;
Цена2 = Цена2Исх;
Сумма2Проверка = Окр(Цена2 * Количество2, 2);
КонецЕсли;
Если Сумма2Проверка = Сумма2 Тогда
// Нашли подходящее разбиение
Результат = СоздатьОбъект("ТаблицаЗначений");
Результат.ИзменитьСтруктуру();
Результат.ДобавитьКолонку("Цена");
Результат.ДобавитьКолонку("Количество");
Результат.ДобавитьКолонку("Сумма");
// Добавляем первую позицию
Результат.ДобавитьСтроку();
Результат.Цена.Значение = Цена1;
Результат.Количество.Значение = Количество1;
Результат.Сумма.Значение = Сумма1;
// Добавляем вторую позицию
Результат.ДобавитьСтроку();
Результат.Цена.Значение = Цена2;
Результат.Количество.Значение = Количество2;
Результат.Сумма.Значение = Сумма2;
Возврат Результат;
КонецЕсли;
КонецЦикла;
// Если не нашли подходящего разбиения
Возврат 0;
КонецФункции
// Процедура для тестирования алгоритма на нескольких примерах
Процедура ТестАлгоритмаПеребора()
// Создаем таблицу тестовых случаев (Количество, Сумма)
ТестовыеСлучаи = СоздатьОбъект("ТаблицаЗначений");
ТестовыеСлучаи.ИзменитьСтруктуру();
ТестовыеСлучаи.ДобавитьКолонку("Количество");
ТестовыеСлучаи.ДобавитьКолонку("Сумма");
// Добавляем тестовые случаи
ТестовыеСлучаи.ДобавитьСтроку();
ТестовыеСлучаи.Количество.Значение = 3.500;
ТестовыеСлучаи.Сумма.Значение = 35.00;
ТестовыеСлучаи.ДобавитьСтроку();
ТестовыеСлучаи.Количество.Значение = 5.678;
ТестовыеСлучаи.Сумма.Значение = 70.06;
ТестовыеСлучаи.ДобавитьСтроку();
ТестовыеСлучаи.Количество.Значение = 2.500;
ТестовыеСлучаи.Сумма.Значение = 24.98;
ТестовыеСлучаи.ДобавитьСтроку();
ТестовыеСлучаи.Количество.Значение = 2.000;
ТестовыеСлучаи.Сумма.Значение = 30.00;
ТестовыеСлучаи.ДобавитьСтроку();
ТестовыеСлучаи.Количество.Значение = 12.5;
ТестовыеСлучаи.Сумма.Значение = 653.13;
// Выполняем тесты
ТестовыеСлучаи.ВыбратьСтроки();
Индекс = 1;
Пока ТестовыеСлучаи.ПолучитьСтроку() = 1 Цикл
Сообщить("");
Сообщить("Тест #" + Индекс + ":");
Количество = ТестовыеСлучаи.Количество.Значение;
ОбщаяСумма = ТестовыеСлучаи.Сумма.Значение;
Цена = Окр(ОбщаяСумма / Количество, 2);
Сообщить("Исходные данные: Цена = " + Цена + ", Количество = " + Количество + ", Сумма = " + ОбщаяСумма);
Сообщить("Теоретическая сумма: " + Окр(Цена * Количество, 3));
Результат = РазбитьПозициюПеребором(Цена, Количество, ОбщаяСумма);
Если Результат = 0 Тогда
Сообщить("Разбиение невозможно");
Иначе
// Получаем первую позицию
Результат.ВыбратьСтроки();
Результат.ПолучитьСтроку();
Цена1 = Результат.Цена.Значение;
Количество1 = Результат.Количество.Значение;
Сумма1 = Результат.Сумма.Значение;
// Получаем вторую позицию
Результат.ПолучитьСтроку();
Цена2 = Результат.Цена.Значение;
Количество2 = Результат.Количество.Значение;
Сумма2 = Результат.Сумма.Значение;
Если Количество2 = 0 Тогда
Сообщить("Разбиение не требуется, исходные данные корректны");
Иначе
Сообщить("");
Сообщить("Результат разбиения:");
Сообщить("Позиция 1: Цена = " + Цена1 + ", Количество = " + Количество1 + ", Сумма = " + Сумма1);
Сообщить("Проверка: " + Цена1 + " * " + Количество1 + " = " + Окр(Цена1 * Количество1, 2));
Сообщить("Позиция 2: Цена = " + Цена2 + ", Количество = " + Количество2 + ", Сумма = " + Сумма2);
Сообщить("Проверка: " + Цена2 + " * " + Количество2 + " = " + Окр(Цена2 * Количество2, 2));
Сообщить("Общая сумма после разбиения: " + Окр(Сумма1 + Сумма2, 2));
Сообщить("Общее количество после разбиения: " + Окр(Количество1 + Количество2, 3));
// Проверяем условия корректности разбиения
СуммаПроверка = (Окр(Сумма1 + Сумма2, 2) - ОбщаяСумма) < 0.01;
КоличествоПроверка = (Окр(Количество1 + Количество2, 3) - Количество) < 0.001;
КоличествоПроверка = 1;
Цена1Проверка = (Окр(Цена1 * Количество1, 2) - Сумма1) < 0.01;
Цена2Проверка = (Окр(Цена2 * Количество2, 2) - Сумма2) < 0.01;
Если СуммаПроверка И КоличествоПроверка И Цена1Проверка И Цена2Проверка Тогда
Сообщить("✅ Разбиение корректно");
Иначе
Сообщить("❌ Разбиение некорректно");
КонецЕсли;
КонецЕсли;
КонецЕсли;
Индекс = Индекс + 1;
КонецЦикла;
КонецПроцедуры
// Запуск тестирования
// ТестАлгоритмаПеребора();
Editor is loading...
Leave a Comment