Генерация двух случайных чисел, квадратная сумма которых == 1 - PullRequest
3 голосов
/ 08 мая 2019

Привет, я хотел бы сгенерировать два случайных числа, чтобы сумма их квадратов равнялась 1.

Я написал этот код. Сумма их квадрата не может быть идеально равна 1, но она должна быть около 0,999. Я также использовал if(math.isclose(abs(gene_value_1)**2 + abs(gene_value_2)**2, 1)), но он не работает.

gene_value_1 = random.uniform(0, 1)
gene_value_2 = random.uniform(0, 1)
if(abs(gene_value_1)**2 + abs(gene_value_2)**2) == 1:
    print(added)

Я хочу сгенерировать два случайных числа, где сумма их квадратов почти равна 1.

Ответы [ 5 ]

8 голосов
/ 08 мая 2019

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

Если x**2 + y**2 = 1, то y полностью определяется как x: y = sqrt(1 - x**2):

gene_value_1 = random.uniform(0, 1)
gene_value_2 = math.sqrt(1.0 - gene_value_1**2)

Как упоминалось в комментариях как к вопросу, так и к этому ответу, распределение, полученное таким образом, является неоднородным по отношению к двум числам. Поскольку gene_value_1 и gene_value_2 описывают единичную окружность в декартовом пространстве в равномерном случае, вы можете сделать

angle = random.uniform(0, 2 * math.pi)
gene_value_1 = math.cos(angle)
gene_value_2 = math.sin(angle)
2 голосов
/ 08 мая 2019

Я полностью доверяю предложению Марка Дикинсона об использовании тригонометрии для генерации двух случайных чисел, квадраты которых равны 1. Это одна из самых важных тригонометрических идентификаций, которую иногда называют пифагорейской формулойдля синусов и косинусов

синус ^ 2 (тета) + cos ^ 2 (тета) = 1

Таким образом, мы выбираем theta случайным образом винтервал [-pi, pi] и возьмите sine и cosine этого.Это дает нам два числа, которые при квадрате независимо, а затем суммируются, будут равны 1.

Итак, реализация будет выглядеть примерно так:

def squared_unity():
    r = np.random.uniform(-np.pi, np.pi)
    r1, r2 = np.cos(r), np.sin(r)
    # sanity check
    sq_sum = np.sum(np.square([r1, r2]))
    print("the two random numbers are: {}, {}".format(round(r1, 4), round(r2, 4)))
    print("sum of the squares of them is: {}".format(round(sq_sum, 4)))

In [172]: for i in range(10): 
     ...:     squared_unity() 

the two random numbers are: -0.4232, 0.906
sum of the squares of them is: 1.0
the two random numbers are: -0.6432, 0.7657
sum of the squares of them is: 1.0
the two random numbers are: -0.9854, 0.1701
sum of the squares of them is: 1.0
the two random numbers are: 0.6192, -0.7852
sum of the squares of them is: 1.0
the two random numbers are: 0.613, 0.7901
sum of the squares of them is: 1.0
the two random numbers are: 0.3289, -0.9444
sum of the squares of them is: 1.0
the two random numbers are: -0.6289, -0.7775
sum of the squares of them is: 1.0
the two random numbers are: 0.5851, 0.811
sum of the squares of them is: 1.0
the two random numbers are: -0.9515, 0.3076
sum of the squares of them is: 1.0
the two random numbers are: 0.992, -0.1258
sum of the squares of them is: 1.0
1 голос
/ 08 мая 2019

генерирует два случайных числа, где сумма их квадратов почти равна равно 1.

Предполагая, что почти равное подразумевает небольшую дельту

delta = 0.00000000001
gene_value_1 = random.uniform(0,1)
gene_value_2 = math.sqrt(1.0 - gene_value_1**2)
gene_value_2 = random.uniform(gene_value_2-delta,gene_value_2+delta)
0 голосов
/ 09 мая 2019

Если вам нужны два значения, квадратные суммы которых равны 1, геометрически обоснованные предложения уже сделаны превосходно, то есть генерируют угол & theta; равномерно по [0,2 & pi;) и используют синус (& theta;) и ​​косинус (& theta;). Однако, если вы хотите расширить область до более высоких измерений, этот подход довольно быстро становится неприятным.

Хорошей альтернативой, которая обобщает произвольное число измерений, является генерация независимых гауссианов и их нормализация. N независимых многомерных гауссианов можно представить как N-мерный вектор, который с одинаковой вероятностью будет указывать в любом направлении в N-пространстве. Сгенерируйте вектор, нормализуйте его длину до 1,0 и вуаля !, мгновенная сумма квадратов == 1. Если вы хотите, чтобы сумма квадратов была близка к единице, но не равнялась, вы можете рандомизировать нормализующий масштабный коэффициент.

from functools import reduce
from math import sqrt
from random import gauss, uniform

def sum_of_squares_is_one(n = 2):
    if ((n < 2) or (int(n) != n)) is True:
        raise Exception("Invalid argument for n")
    l = [gauss(0.0, 1.0) for _ in range(n)]
    norm = sqrt(reduce(lambda sum,x: sum + x*x, l, 0.0)) # / uniform(0.95, 1.05)
    return [x / norm for x in l]

print(sum_of_squares_is_one())
# => [-0.5507487065788466, -0.8346711101995371]
print(sum_of_squares_is_one(5))
# => [-0.5985784458250389, 0.3741123562198886, -0.2600006068118713, -0.5415988718467569, 0.37525209604886034]

Передайте явный аргумент для n, чтобы получить N-мерный результат. Раскомментируйте деление на униформу, если вы хотите получить значения, сумма квадратов которых находится в [0,95, 1,05], или скорректируйте диапазон в соответствии с вашими потребностями.

0 голосов
/ 08 мая 2019

isclose имеет допуск по умолчанию 10 ^ -9;это может быть слишком жестким для ваших целей.Поскольку вы не смогли указать проблему, я попробую версию, не используя функцию вообще:

import random

tol = 0.01    # Tolerance: how close to 1.0 do we have to be?

# For illustration, try 1000 times; only a few will get close enough.
for _ in range(1000):
    gene_value_1 = random.uniform(0, 1)
    gene_value_2 = random.uniform(0, 1)
    if abs((gene_value_1**2 + gene_value_2**2) - 1.0) < tol:
        print(gene_value_1, gene_value_2)

Вывод:

0.494788483232363 0.8684265825591323
0.2534457849885592 0.9641226120957478
0.7203139196461331 0.6907040618050416
0.5209764827501758 0.8494629588837268
0.35131722626502326 0.9326863439646066
0.9090058297727053 0.41193607685541955
0.38668550268554913 0.9211652839586227
0.4981396919166827 0.8716609641505723
0.32335194126436084 0.9515174500031403
0.8975054159419422 0.4338981696304519
0.9055370877201422 0.4174842572890476
0.6174536739530609 0.789563981024344
0.8238168460048567 0.564248521210536
0.8086540730748032 0.5877591346132056
0.9483222364877975 0.3290608007951834
0.7610944343401178 0.6448728614809394
0.9909209668202087 0.1333222757510487
0.985161966125415 0.16537725793380365
0.39363133060821665 0.9232464739964449
...