Top.Mail.Ru
Ответы

Математики и программисты, мне нужна ваша помощь!

Я начал недавно изучать язык 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%» неверно. А это условие очень важно, ведь в таких условиях существ с большой скоростью будет появляться больше, чем тех, у кого скорость меньше.

Муторный способ.

Лично отобрать, какие числа могут упасть, и чтобы каждое число имело аналог в минус первой степени. Но это очень долго, ведь нужно будет отобрать сотни, если не тысячи чисел.

Дополнительный вопрос

Как можно «обрезать» число, не округлять, а именно обрезать лишние цифры после какого-то количества.


Буду очень признателен если вы мне поможете, ведь сам я точно не справлюсь.

По дате
По рейтингу
Аватар пользователя
jurijus_zaksasИскусственный интеллект
7мес

Сгенерируй (неслучайно) нужное количество нужных циферок, а потом распредели их (случайно) по нужным ячейкам.

Аватар пользователя
iurii_semykinОракул
7мес
Изменено

До математического описания задачи вы ещё не дошли.

Обрезать число можно функцией double(math.floor(x*10 **вНужнойСтепени))/10 **вНужнойСтепени

Вам следует задуматься о законе распределения (как уже вам посоветовал jepz) Да и вообще, о постановке задачи. Писать надо о проблеме, а не о том, сколько лет вы уже программируете, это-то как раз никому не интересно и отбивает охоту читать дальше.

Либо сгенерировать целое случайное в заданном диапазоне и поделить на нужную степень 10.

Либо используйте другой тип, decimal например. decimal — Десятичная арифметика с фиксированной и плавающей точкой | Документация Python 3

На жалость давить не следует: вы не на паперти.

Аватар пользователя
mozambik1487Мыслитель
7мес

Слишком много деталей, перечитывать и вникать впадлу, прочитает от силы человек 5. Конкретную проблему назови

Аватар пользователя
spichka_xvostУченик
7мес

Она и так конкретно названа.

Аватар пользователя
jepzМыслитель
7мес

Привет! Это отличная задача. Она затрагивает фундаментальную проблему в геймдизайне и биологическом моделировании: аддитивность против мультипликативности.

Твоя проблема в том, что ты пытаешься использовать линейную случайность (равномерное распределение) там, где по логике вещей числа должны изменяться кратно. В математике для этого идеально подходит Логнормальное распределение, но для твоей задачи (с четким диапазоном и 3 знаками) есть способ проще.

Решение задачи через логарифмическое пространство

Чтобы условия

X%=Y%

𝑋%=𝑌%

и

Xобщ=Yобщ-1

𝑋общ=𝑌−1общ

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

  1. Возьмем твой максимум:

    1.5

    1.5

    .

  2. Найдем его логарифм (по любому основанию, возьмем натуральный

    ln

    𝑙𝑛

    ):

    ln(1.5)≈0.40546

    𝑙𝑛(1.5)≈0.40546

    .

  3. Твой минимум

    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

123456789101112131415161718192021
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

123456
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(), но это уже следующий уровень сложности.

Как планируешь использовать эти гены дальше — будет ли наследование с небольшими мутациями?

Аватар пользователя
spichka_xvostУченик
7мес

Спасибо хоть и за неиросетевой, но весьма информативный ответ, я не очень понял, как оно работает, но с таким кодом оно работает великолепно! Ещё раз спасибо.

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)

Аватар пользователя
fgctfvv_12344gУченик
7мес

Ну я вообще математик и программист аж 3 по всем этим придметам



Видео по теме