Привет, я хотел бы сгенерировать два случайных числа так, чтобы сумма их квадратов была равна 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.
Ваша формулировка проблемы противоречива. Если у вас есть условие, что их сумма квадратов равна 1,0, то у вас нет двух случайных чисел: у вас есть одно случайное число, а второе получено из первого. Вы пытаетесь сделать случайные снимки и узнать, попали ли вы близко в единичный круг?
Возьмите 1 случайное число от 0 до 1, возведите его в квадрат, вычтите квадратное значение из 1 и найдите из него квадратный корень... вам повезет, если вы сгенерируете два случайных числа и надеетесь, что их квадраты в сумме дадут 1.
См.: mathworld.wolfram.com/CirclePointPicking.html






Ваше требование на самом деле не для двух разных чисел. Это для одной пары чисел, сумма квадратов которых равна единице.
Если 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)
Хотя это решает проблему, как и требовалось, стоит отметить, что полученное распределение является асимметричным между x и y. ген_значение_2 будет больше, чем ген_значение_1 большую часть времени (1/sqrt(2) ~ 0,71)
Полярный метод, предложенный @MarkDickinson в комментариях выше, лучше. Он генерирует точки x, y, равномерно распределенные по единичной окружности, чего не делает этот метод.
В обоих приведенных выше комментариях упоминается справедливое замечание, я думаю, что это следует включить в ответ в качестве примечания.
@кмарио. Добавлено дополнительное дополнение.
Теперь выглядит хорошо ? спасибо за обновление! Причина, по которой я предложил, заключается в том, что не все читают раздел комментариев, особенно когда ответ принимается OP. + 1
generate two random numbers where the sum of their squares is nearly equal to 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)
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
Я отдаю должное Предложение Марка Дикинсона за использование тригонометрии для генерации двух случайных чисел, сумма квадратов которых равна 1. Это одно из наиболее важных тригонометрических тождеств, которое иногда называют Формула Пифагора для синусов и косинусов.
sine^2 (theta) + cos^2(theta) = 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, уже сделанные геометрически обоснованные предложения превосходны, т. Е. Сгенерируйте угол θ равномерно на [0,2π) и используйте синус (θ) и косинус (θ). Однако, если вы хотите расшириться до более высоких измерений, этот подход довольно быстро становится неприятным.
Хорошая альтернатива, которая обобщается на произвольное число измерений, состоит в том, чтобы генерировать независимые гауссианы и нормализовать их. 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], или измените диапазон в соответствии с вашими потребностями.
Как насчет
cos(angle)иsin(angle)для случайно выбранного угла в[-pi, pi]?