Случайная неслучайная скидка

24.01.19

Разработка - Математика и алгоритмы

Найти случайное число, но сделать так, чтобы чем меньше значение, тем чаще выпадало это число (с обратной экспоненциальной зависимостью).

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Демонстрация нахождения случайной скидки.
.erf 10,49Kb
0
0 Скачать (1 SM) Купить за 1 850 руб.

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

Но потом в задаче появилось уточнение - скидки должны выпадать по обратной экспоненциальной зависимости. Т.е. к примеру скидка 5% должна выпадать гораздо чаще скидки 95%.

Желание клиента для меня вполне понятно, нечего постоянно раскидываться большими скидками, но пусть они иногда выпадают.  Почему экспоненциально - будем считать что для красоты (я не знаю откуда взялась эта идея).

Опишу тут два варианта решения, которые я нашел для себя.

1. Создать массив скидок, где некоторые скидки повторяются N раз ( N это "вес" числа ).


// Для примера создадим массив чисел (скидок) от 1 до 99
МассивЧисел = Новый Массив(); 
Счетчик = 1;
Пока Счетчик <= 100 Цикл
	Массив.Добавить(Счетчик);
	Счетчик = Счетчик + 1;
КонецЦикла; 
 

// На основе массива значений скидок сделаем новый массив, где скидки будут повторятся пропорционально весу значения скидки 
МассивПоВесу = СоздатьМассивПоВесу(МассивЧисел); 

// Выберем случайное число в диапазоне от 0 до количества элементов массива
ГСЧ = Новый ГенераторСлучайныхЧисел();
СлучайноеЧисло = ГСЧ.СлучайноеЧисло(0, МассивПоВесу.Количество()-1);

// Нашли случайную скидку
СлучайнаяСкидка = МассивПоВесу[СлучайноеЧисло];



Функция СоздатьМассивПоВесу(МассивЧисел)
	
	МассивПоВесу = Новый Массив;
	
	// коэффициент, который показывает во сколько раз скидка 0% больше скидки 100% , можно выбрать по своему желанию
	Коэффициент = 20;

	Для каждого Элемент Из МассивЧисел Цикл
			
		Вес = Exp( (100 - Элемент) / (100 / Log(Коэффициент)) );
		Вес = Окр( Вес * 10, 0); // 10 - в данном случае подобрано эмпирически, для округления до удобного целого числа

		Для Счетчик = 1 По Вес Цикл
			МассивПоВесу.Добавить(Элемент);
		КонецЦикла; 
		
	КонецЦикла; 
	
	Возврат МассивПоВесу;
	
КонецФункции

 

2. Получение скидки сложением весов чисел в цикле.

Для получения случайной скидки суммируем веса скидок, пока эта сумма не превысит случайное число, умноженное на сумму всех весов.

 

// Для примера создадим массив чисел (скидок) от 1 до 99
МассивЧисел = Новый Массив(); 
Счетчик = 1;
Пока Счетчик <= 100 Цикл
	МассивЧисел .Добавить(Счетчик);
	Счетчик = Счетчик + 1;
КонецЦикла; 

// Для каждой скидки определим вес и поместим всё в таблицу значений
ТаблицаСкидок = СоздатьТаблицуВесовСкидок(МассивЧисел);

СуммаВесов = 0;
Для каждого СтрокаТЗ Из ТаблицаСкидок Цикл
	СуммаВесов = СуммаВесов + СтрокаТЗ.Вес;
КонецЦикла; 

// Случайное число 0 .. 1
ГСЧ = Новый ГенераторСлучайныхЧисел();
СлучайноеЧисло = ГСЧ.СлучайноеЧисло(0, 100) / 100;

Лямбда = СуммаВесов * СлучайноеЧисло;

// В цикле накапливаем вес, пока не сработает условие. Текущая строка при этом и будет найденная скидка
Накопление = 0;
Для Каждого СтрокаТЗ Из ТаблицаСкидок Цикл
	Накопление = Накопление + СтрокаТЗ.Вес;
	Если Накопление >= Лямбда Тогда
		СлучайнаяСкидка = СтрокаТЗ.Скидка; // Нашли скидку
		Прервать;
	КонецЕсли;
КонецЦикла;


Функция СоздатьТаблицуВесовСкидок(Массив)

	ТаблицаСкидок = Новый ТаблицаЗначений;
	ТаблицаСкидок.Колонки.Добавить("Скидка");
	ТаблицаСкидок.Колонки.Добавить("Вес");
	
	Для каждого Элемент Из Массив Цикл
		
		НоваяСтрока = ТаблицаСкидок.Добавить();
		НоваяСтрока.Скидка = Элемент;

		// коэффициент, который показывает во сколько раз скидка 0% больше скидки 100% , можно выбрать по своему желанию
		Коэффициент = 20;
		
		Коэф = 100 / Log(Коэффициент);
		НоваяСтрока.Вес = Exp( (100 - Элемент) / Коэф);
		
	КонецЦикла;  
	
	// На случай не отсортированного массива на входе
	ТаблицаСкидок.Сортировать("Скидка");

	Возврат ТаблицаСкидок;
	
КонецФункции

 

Ключевые моменты описаны в коде выше.

В обработке есть демонстрация работы обоих алгоритмов и отрисовка графика для метода сложения сумм весов. Кроме этого добавил еще вариант линейной зависимости.

Тестировалось в BAS ERP 2.1.6.3

См. также

Математика и алгоритмы Программист Платформа 1C v8.2 Конфигурации 1cv8 Россия Абонемент ($m)

На написание данной работы меня вдохновила работа @glassman «Переход на ClickHouse для анализа метрик». Автор анализирует большой объем данных, много миллионов строк, и убедительно доказывает, что ClickHouse справляется лучше PostgreSQL. Я же покажу как можно сократить объем данных в 49.9 раз при этом: 1. Сохранить значения локальных экстремумов 2. Отклонения от реальных значений имеют наперед заданную допустимую погрешность.

1 стартмани

30.01.2024    3162    stopa85    12    

38

Математика и алгоритмы Бесплатно (free)

Разработка алгоритма, построенного на модели симплекс-метода, для нахождения оптимального раскроя.

19.10.2023    7550    user1959478    51    

36

Математика и алгоритмы Разное Платформа 1С v8.3 Конфигурации 1cv8 Россия Абонемент ($m)

Расширение (+ обработка) представляют собою математический тренажер. Ваш ребенок сможет проверить свои знание на математические вычисление до 100.

2 стартмани

29.09.2023    3107    maksa2005    8    

26

Математика и алгоритмы Инструментарий разработчика Программист Платформа 1С v8.3 Мобильная платформа Россия Абонемент ($m)

Что ж... лучше поздно, чем никогда. Подсистема 1С для работы с регулярными выражениями: разбор выражения, проверка на соответствие шаблону, поиск вхождений в тексте.

1 стартмани

09.06.2023    10902    7    SpaceOfMyHead    18    

61

Математика и алгоритмы Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Три задачи - три идеи - три решения. Мало кода, много смысла. Мини-статья.

03.04.2023    4357    RustIG    9    

25

Механизмы платформы 1С Математика и алгоритмы Программист Платформа 1С v8.3 Россия Бесплатно (free)

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

23.11.2022    3527    gzharkoj    14    

25

Математика и алгоритмы Программист Платформа 1С v8.3 Россия Абонемент ($m)

Обычно под распределением понимают определение сумм пропорционально коэффициентам. Предлагаю включить сюда также распределение по порядку (FIFO, LIFO) и повысить уровень размерности до 2-х. 1-ое означает, что распределение может быть не только пропорциональным, но и по порядку, а 2-ое - это вариант реализации матричного распределения: по строкам и столбцам. Возможно вас заинтересует также необычное решение этой задачи через создание DSL на базе реализации текучего интерфейса

1 стартмани

21.03.2022    9041    7    kalyaka    11    

44
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. scientes 295 25.01.19 14:47 Сейчас в теме
Могу предложить вот такой вариант.
Функция СкидкаДляInfostart(сигма) экспорт
	перем скидка;
	ГСЧ = Новый ГенераторСлучайныхЧисел(ТекущаяУниверсальнаяДатаВМиллисекундах());
	пока истина цикл
		u=-1+2*ГСЧ.СлучайноеЧисло(0,100)/100;
		v=-1+2*ГСЧ.СлучайноеЧисло(0,100)/100;
		s=u*u+v*v;
		if s<1 then
			r=sqrt(-2*Log(s)/s);
			z=цел(max(u,-u)*r*сигма);
			скидка=мин(z,99);
			прервать;
		endif	   
	конеццикла;	 
	возврат скидка;
КонецФункции	
Показать
Оставьте свое сообщение