Математики и программисты, мне нужна ваша помощь!
Я начал недавно изучать язык Python и решил сделать проект, на который у меня не хватает знаний и опыта. Я столкнулся с несколькими проблемами, связанными с математикой и удобной реализацией на Python.
В общем, я создаю программу, которая генерирует значения для «генов». Пример: есть ген скорости, и среднее значение равно 1, что означает 1 клетка в секунду, но мне нужно, чтобы у каждого существа генерилось своё рандомное значение в диапазоне от 0.666 до 1.5, и при этом, чтобы шанс выпадения значения ниже среднего был таким же, как шанс выпадения значения выше среднего. Ниже распишу всё более математически(?).
Y = Это выпавшее число, которое < 1.
X = Это выпавшее число, которое > 1.
Yобщ = Это сумма всех потенциально возможных выпавших чисел < 1 без повторений.
Xобщ = Это сумма всех потенциально возможных выпавших чисел > 1 без повторений.
Y% = Шанс выпадения числа которое < 1.
X% = Шанс выпадения числа которое > 1.
Мне нужно, чтобы генерировалось рациональное число с не более чем 3 числами после запятой, в диапазоне от 0,666 до 1,5, и при этом Yобщ = Xобщ⁻¹, а Xобщ = Yобщ⁻¹. А также нужно, чтобы X%=Y%. Вот снизу напишу 2 неправильных способа решения и один технически правильный, но ОЧЕНЬ муторный.
Первый не правильный способ.
Рандомить рациональное число с не более чем 3 числами после запятой от 0.5 и до 1.5, и тогда условие «X% = Y%» верно, но при этом условие «Yобщ = Xобщ⁻¹, а Xобщ = Yобщ⁻¹» неверно. И это условие невероятно важно, ведь если оно не выполняется, то тогда в среднем каждое существо передвигается медленее, чем 1 клетка в секунду, ведь максимальная возможная скорость в 1.5 раза больше, чем средняя, а минимальная скорость в 2 раза меньше средней, а по-хорошему должна быть в 1.5 меньше.
Второй не правильный способ.
Рандомить рациональное число с не более чем 3 числами после запятой от 0,666 и до 1,5, и тогда условие «Yобщ = Xобщ⁻¹, а Xобщ = Yобщ⁻¹» верно, но при этом условие «X% = Y%» неверно. А это условие очень важно, ведь в таких условиях существ с большой скоростью будет появляться больше, чем тех, у кого скорость меньше.
Муторный способ.
Лично отобрать, какие числа могут упасть, и чтобы каждое число имело аналог в минус первой степени. Но это очень долго, ведь нужно будет отобрать сотни, если не тысячи чисел.
Дополнительный вопрос
Как можно «обрезать» число, не округлять, а именно обрезать лишние цифры после какого-то количества.
Буду очень признателен если вы мне поможете, ведь сам я точно не справлюсь.
Сгенерируй (неслучайно) нужное количество нужных циферок, а потом распредели их (случайно) по нужным ячейкам.
До математического описания задачи вы ещё не дошли.
Обрезать число можно функцией double(math.floor(x*10 **вНужнойСтепени))/10 **вНужнойСтепени
Вам следует задуматься о законе распределения (как уже вам посоветовал jepz) Да и вообще, о постановке задачи. Писать надо о проблеме, а не о том, сколько лет вы уже программируете, это-то как раз никому не интересно и отбивает охоту читать дальше.
Либо сгенерировать целое случайное в заданном диапазоне и поделить на нужную степень 10.
Либо используйте другой тип, decimal например. decimal — Десятичная арифметика с фиксированной и плавающей точкой | Документация Python 3
На жалость давить не следует: вы не на паперти.
Слишком много деталей, перечитывать и вникать впадлу, прочитает от силы человек 5. Конкретную проблему назови
Она и так конкретно названа.
Привет! Это отличная задача. Она затрагивает фундаментальную проблему в геймдизайне и биологическом моделировании: аддитивность против мультипликативности.
Твоя проблема в том, что ты пытаешься использовать линейную случайность (равномерное распределение) там, где по логике вещей числа должны изменяться кратно. В математике для этого идеально подходит Логнормальное распределение, но для твоей задачи (с четким диапазоном и 3 знаками) есть способ проще.
Решение задачи через логарифмическое пространство
Чтобы условия
X%=Y%
𝑋%=𝑌%
и
Xобщ=Yобщ-1
𝑋общ=𝑌−1общ
соблюдались, нужно генерировать случайное число не в диапазоне скоростей, а в диапазоне коэффициентов изменения.
Возьмем твой максимум:
1.5
1.5
.
Найдем его логарифм (по любому основанию, возьмем натуральный
ln
𝑙𝑛
):
ln(1.5)≈0.40546
𝑙𝑛(1.5)≈0.40546
.
Твой минимум
0.666
0.666
(что есть
1/1.5
1/1.5
) в логарифмическом пространстве будет тем же числом, но с минусом:
ln(1/1.5)≈-0.40546
𝑙𝑛(1/1.5)≈−0.40546
.
Алгоритм для Python:
Мы генерируем случайное число между
-0.40546
−0.40546
и
0.40546
0.40546
, а затем возводим
e
𝑒
(экспоненту) в эту степень.
python
import random
import math
def generate_gene():
# 1. Задаем максимальное отклонение (1.5)
max_val = 1.5
# 2. Переходим в логарифмическое пространство
log_limit = math.log(max_val)
# 3. Генерируем равномерное число от -log_limit до +log_limit
# Это гарантирует X% = Y%
random_log = random.uniform(-log_limit, log_limit)
# 4. Возвращаем обратно через экспоненту
# Это гарантирует, что 1.5 и 0.666 равновероятны по модулю влияния
gene_value = math.exp(random_log)
# 5. Применяем "обрезку" до 3 знаков
return truncate(gene_value, 3)
Используйте код с осторожностью.
Как «обрезать» (не округлять) число
Стандартный round() округляет 0.6666 до 0.667. Чтобы именно отсечь лишнее, можно использовать математический трюк: умножаем на 1000, отбрасываем дробную часть и делим обратно на 1000.
Функция обрезки:
python
def truncate(number, digits):
stepper = 10.0 ** digits
return math.trunc(stepper * number) / stepper
# Пример: truncate(1.4569, 3) -> 1.456
Используйте код с осторожностью.
Почему это работает:
Симметрия: Если ты выберешь в логарифмах число
0.2
0.2
, то при обратном переводе получишь
1.22
1.22
. Если выберешь
-0.2
−0.2
, получишь
0.819
0.819
(
1/1.22
1/1.22
). Шанс попасть в «плюс» или «минус» ровно 50/50.
Среднее значение: При таком подходе «средним» (медианой) всегда будет ровно
1.0
1.0
.
Маленький совет по Python:
Если тебе нужно, чтобы значения были распределены не равномерно (где каждое число от 0.66 до 1.5 встречается одинаково часто), а «кучковались» вокруг единицы (что более естественно для генов), используй random.gauss(0, sigma) вместо random.uniform(), но это уже следующий уровень сложности.
Как планируешь использовать эти гены дальше — будет ли наследование с небольшими мутациями?
Спасибо хоть и за неиросетевой, но весьма информативный ответ, я не очень понял, как оно работает, но с таким кодом оно работает великолепно! Ещё раз спасибо.
import random
import math
gene_value=1
stepper=0
def generate_gene():
max_val=1.5
log_limit=math.log(max_val)
random_log=random.uniform(-log_limit, log_limit)
gene_value=math.exp(random_log)
stepper=10.0**3
return math.trunc(stepper*gene_value)/stepper
gene_value=generate_gene()
print(gene_value)
Ну я вообще математик и программист аж 3 по всем этим придметам