Untitled
unknown
plain_text
4 months ago
15 kB
9
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