Если вам нужны два значения, квадратные суммы которых равны 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], или скорректируйте диапазон в соответствии с вашими потребностями.