Случайная точка на сфере

31

Соревнование

Напишите программу или функцию, которая не требует ввода и выводит вектор длины в теоретически однородном случайном направлении.1

Это эквивалентно случайной точке на сфере, описываемой

x2+y2+z2=1

в результате чего такое распределение

Случайное распределение точек на сфере с радиусом 1.

Выход

Три числа с плавающей точкой из теоретически однородного случайного распределения, для которого уравнение выполняется в пределах точности.x2+y2+z2=1

Вызов замечания

  • Случайное распределение должно быть теоретически однородным . То есть, если генератор псевдослучайных чисел заменить истинным ГСЧ из действительных чисел, это приведет к равномерному случайному распределению точек на сфере.
  • Генерирование трех случайных чисел из равномерного распределения и их нормализация недопустимы: будет смещение в сторону углов трехмерного пространства.
  • Аналогично, создание двух случайных чисел из равномерного распределения и использование их в качестве сферических координат недопустимо: будет иметь место смещение к полюсам сферы.
  • Надлежащее единообразие может быть достигнуто с помощью алгоритмов, включая, но не ограничиваясь:
    • Генерация трех случайных чисел , и из нормального (гауссовского) распределения около и нормализация их. xyz0
    • Генерация трех случайных чисел , и из равномерного распределения в диапазоне . Вычислить длину вектора с помощью . Затем, если , отбросим вектор и сгенерируем новый набор чисел. Иначе, если , нормализовать вектор и вернуть результат. xyz(1,1)l=x2+y2+z2l>1l1
    • Генерация двух случайных чиселi и j из равномерного распределения в диапазоне (0,1) и преобразование их в сферические координаты, например, так:
      θ=2×π×iϕ=cos1(2×j1)
      так чтоx,yиzмогут быть вычислены как
      x=cos(θ)×sin(ϕ)y=sin(θ)×sin(ϕ)z=cos(ϕ)
  • Предоставьте в своем ответе краткое описание используемого вами алгоритма.
  • Узнайте больше о выборе точек на MathWorld .

Примеры вывода

[ 0.72422852 -0.58643067  0.36275628]
[-0.79158628 -0.17595886  0.58517488]
[-0.16428481 -0.90804027  0.38532243]
[ 0.61238768  0.75123833 -0.24621596]
[-0.81111161 -0.46269121  0.35779156]

Основные пометки

  • Это , поэтому ответ, использующий наименьшее количество байтов на каждом языке, выигрывает.
  • Применяются стандартные правила , правила ввода / вывода и лазейки .
  • Пожалуйста, включите ссылку Try it Online или эквивалентную, чтобы продемонстрировать, как работает ваш код.
  • Пожалуйста, мотивируйте ваш ответ объяснением вашего кода.
Jitse
источник
Можно ли подобрать 3 реала равномерно в [-1, 1], а затем отклонить их (и повторить), если сумма их квадратов не равна 1?
Grimmy
6
@ Грими, мне нравится эта лазейка. Нет, это не разрешено, потому что теоретически нулевой шанс любого выхода.
Джитс
Разве предложение @ Grimy не похоже на реализацию второго примера, упомянутую вами? Это решение также теоретически не имеет шансов на получение какого-либо результата
Сасват Падхи,
2
@SaswatPadhi Нет, у этого есть шанс pi/6 ≈ 0.5236произвести вывод. Это площадь сферы, вписанная в единичный куб
Луис Мендо,
1
@ LuisMendo Понятно. В этом случае вероятность составляет ~ 0,5, как вы упомянули. Для предложения Грими, это ~ 0.
Сасват Падхи

Ответы:

24

R , 23 байта

x=rnorm(3)
x/(x%*%x)^.5

Попробуйте онлайн!

Генерирует 3 реализации распределения N(0,1) и нормализует результирующий вектор.

Участок 1000 реализаций:

enter image description here

Робин Райдер
источник
2
Можете ли вы обосновать, что 3 оси распределены нормально, что приводит к равномерному распределению по сфере? (Я не вижу этого)
Джеффри поддерживает Монику
4
@Jeffrey Это довольно хорошо известно по вероятности / статистике; но доказательство для 2D (которое простирается аккуратно до 3-х измерений) примерно: пусть и независимо. Тогда f X ( x ) = K e - 1X,YN(0,1)иfY(y)=Ke-1fX(x)=Ke12x2, поэтому по независимостиfXY(x,y)=K2e-1fY(y)=Ke12y2гдеz=(x,y), поэтому ясно, что распределениеzзависит исключительно от величиныz, и, следовательно, направление распределяется равномерно. fXY(x,y)=K2e12(x2+y2)=fZ(z)=K2e12z2z=(x,y)zz
Джузеппе
1
Таким образом, нормальное распределение дает нам равномерно распределенные точки вокруг круга, а деление на величину гарантирует, что точки лежат на круге
Джузеппе
23

Машинный код x86-64 - 63 62 55 49 байт

6A 4F                push        4Fh  
68 00 00 80 3F       push        3F800000h  
C4 E2 79 18 4C 24 05 vbroadcastss xmm1,dword ptr [rsp+5]  
rand:
0F C7 F0             rdrand      eax  
73 FB                jnc         rand  
66 0F 6E C0          movd        xmm0,eax  
greaterThanOne:
66 0F 38 DC C0       aesenc      xmm0,xmm0  
0F 5B C0             cvtdq2ps    xmm0,xmm0  
0F 5E C1             divps       xmm0,xmm1  
C4 E3 79 40 D0 7F    vdpps       xmm2,xmm0,xmm0,7Fh  
0F 2F 14 24          comiss      xmm2,dword ptr [rsp]  
75 E9                jne         greaterThanOne
58                   pop         rax  
58                   pop         rax  
C3                   ret  

Использует второй алгоритм, модифицированный. Возвращает вектор [x, y, z, 0]в формате xmm0.

Объяснение:

push 4Fh
push 3f800000h

Выдвигает значение для 1 и 2 ^ 31 как число с плавающей точкой в ​​стек. Данные перекрываются из-за расширения знака, сохраняя несколько байтов.

vbroadcastss xmm1,dword ptr [rsp+5] Загружает значение для 2 ^ 31 в 4 позиции xmm1.

rdrand      eax  
jnc         rand  
movd        xmm0,eax

Генерирует случайное 32-разрядное целое число и загружает его в конец xmm0.

aesenc      xmm0,xmm0  
cvtdq2ps    xmm0,xmm0  
divps       xmm0,xmm1 

Создает случайное 32-разрядное целое число, преобразует его в число с плавающей точкой (со знаком) и делит на 2 ^ 31, чтобы получить числа от -1 до 1.

vdpps xmm2,xmm0,xmm0,7Fhдобавляет квадраты нижних 3 поплавков, используя сам точечный продукт, маскируя верхний поплавок. Это дает длину

comiss      xmm2,dword ptr [rsp]  
jne          rand+9h (07FF7A1DE1C9Eh)

Сравнивает длину в квадрате с 1 и отклоняет значения, если она не равна 1. Если длина в квадрате равна единице, то длина также равна единице. Это означает, что вектор уже нормализован и сохраняет квадратный корень и делит.

pop         rax  
pop         rax 

Восстановите стек.

ret возвращает значение в xmm0

Попробуйте онлайн .

меня'
источник
7
+1 Использование aesencдля создания 128 «случайных» бит просто прекрасно.
DocMax
13

Python 2 , 86 байт

from random import*;R=random
z=R()*2-1
a=(1-z*z)**.5*1j**(4*R())
print a.real,a.imag,z

Попробуйте онлайн!

Генерирует z-координату равномерно от -1 до 1. Затем координаты x и y выбираются равномерно по кругу радиуса (1-z*z)**.5.

Может быть неочевидно, что сферическое распределение в коэффициенте равномерно по координате z (и так по каждой координате). Это нечто особенное для измерения 3. Посмотрите на это доказательство того, что площадь поверхности горизонтального среза сферы пропорциональна ее высоте. Хотя срезы около экватора имеют больший радиус, срезы около полюса имеют больший внутренний заголовок, и оказывается, что эти два эффекта точно отменяются.

Чтобы сгенерировать случайный угол на этом круге, мы поднимаем мнимую единицу 1jдо равномерно случайной степени между 0 и 4, что избавляет нас от необходимости использовать функции триггера, pi или e, для любой из которых потребуется импорт. Затем мы извлекаем реальную мнимую часть. Если мы можем вывести комплексное число для двух координат, последняя строка может быть просто print a,z.


86 байт

from random import*
a,b,c=map(gauss,[0]*3,[1]*3)
R=(a*a+b*b+c*c)**.5
print a/R,b/R,c/R

Попробуйте онлайн!

Создает три нормали и масштабирует результат.


Python 2 с NumPy, 57 байтов

from numpy import*
a=random.randn(3)
print a/sum(a*a)**.5

Попробуйте онлайн!

sum(a*a)**.5короче чем linalg.norm(a). Мы могли бы также сделать dot(a,a)для той же длины, что и sum(a*a). В Python 3 это можно сократить до a@aиспользования оператора new @.

XNOR
источник
1
Мне нравится твой первый подход. У меня возникают проблемы с пониманием того, как избежать смещения в сторону экватора, если zиз равномерного распределения оставить неизменным.
Джитс
2
@Jitse Сферическое распределение по коэффициенту равномерно по каждой координате. Это что-то особенное для измерения 3. Смотрите, например, это доказательство того, что площадь поверхности среза сферы пропорциональна ее высоте. Что касается интуиции, что это смещено к экватору, обратите внимание, что, хотя срезы около экватора имеют больший радиус, у срезов около полюса больше заголовка внутрь, что дает большую площадь, и оказывается, что эти два эффекта точно отменяются.
xnor
Очень хорошо! Спасибо за разъяснения и ссылки.
Джитс
@ Jitse Спасибо, я добавил это к телу. Хотя я понял, что у меня только положительная выборка z, и исправил это на несколько байтов.
xnor
1
@ Jitse Действительно, площадь поверхности сферы равна площади боковой поверхности окружающего цилиндра!
Нил
13

Октава , 40 33 22 байта

Мы выбираем форму стандартного нормального распределения 3d и нормализуем вектор:

(x=randn(1,3))/norm(x)

Попробуйте онлайн!

flawr
источник
Только для октавы (то есть не для MATLAB) вы можете сохранить байт с этим
Том Карпентер
1
@ TomCarpenter Спасибо! В этом случае, поскольку это всего лишь одно выражение, мы можем даже опустить disp:)
flawr
10

Unity C # , 34 байта

f=>UnityEngine.Random.onUnitSphere

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

Draco18s
источник
Хорошее использование встроенного +1, Вы можете просто отправить функцию, чтобы быть немного корочеf=>Random.onUnitSphere
LiefdeWen
@LiefdeWen Я знал о лямбдах, я просто не был уверен, достаточно ли этого (с точки зрения действительности в Code Golf), потому что он не объявляет fType; использование varтолько работает внутри метода и System.Func<Vector3>дольше.
Draco18s
1
В codegolf возвращение функции совершенно нормально, и вам не нужно считать счет, то есть вы можете делать хитрые вещи с динамическими параметрами. Вы также не считаете последнюю точку с запятой. Вы, однако, считаете все, используя операторы, которые вы добавляете. так что ваш счетчик байтов должен включать использование. Но f=>Random.onUnitSphereэто совершенно действительное представление
LiefdeWen
@LiefdeWen Да, я просто не был уверен, как обрабатывается декларация, и на самом деле не чувствовал себя «в поиске мета».
Draco18s
f=>UnityEngine.Random.onUnitSphere спасает вас using
Orace
6

MATL , 10 байт

1&3Xrt2&|/

Попробуйте онлайн!

объяснение

При этом используется первый подход, описанный в задаче.

1&3Xr  % Generate a 1×3 vector of i.i.d standard Gaussian variables
t      % Duplicate
2&|    % Compute the 2-norm
/      % Divide, element-wise. Implicitly display
Луис Мендо
источник
6

Рубин , 34 50 49 байтов

->{[z=rand*2-1]+((1-z*z)**0.5*1i**(rand*4)).rect}

Попробуйте онлайн!

Возвращает массив из 3 чисел [z,y,x].

xи yгенерируются путем повышения i(квадратный корень из -1) до случайной степени между 0 и 4. Это комплексное число должно быть соответствующим образом масштабировано в соответствии со zзначением в соответствии с теоремой Пифагора:(x**2 + y**2) + z**2 = 1.

zКоординат (который генерируется первая) просто равномерно распределено число между -1 и 1. Хотя это и не сразу видно, дА / дг для среза через сферу постоянна (и равна периметру окружности того же радиуса, вся сфера.).

Это, по-видимому, было обнаружено Архимедом, который описал его очень не в форме исчисления, и это известно как теорема Архимеда о шляпной коробке. Смотрите https://brilliant.org/wiki/surface-area-sphere/

Еще одна ссылка из комментариев на ответ xnor. Удивительно короткий URL, описывающий удивительно простую формулу: http://mathworld.wolfram.com/Zone.html

Уровень реки St
источник
@Jitse Я забыл уменьшить x и y при больших значениях z. Эффективно точки определили цилиндр. Это исправлено, но стоит много байтов! Я мог бы сохранить несколько, если результат может быть выражен комплексным числом, [z, x+yi]я оставлю это как есть, если вы не скажете, что все в порядке.
Уровень Река St
Выглядит хорошо! Мне очень нравится этот подход. Для согласованности требуемый результат - три числа с плавающей запятой, поэтому я предлагаю оставить это так.
Джитс
Почему бы не использовать z*zвместо z**2?
Стоимость чернил
@ValueInk да, спасибо, я понял, что пропустил это z*z. Я редактировал это сейчас. Другая вещь, которую я мог бы сделать, это заменить rand*4чем-то вроде z*99или x*9E9(эффективно ограничивая возможные значения очень тонкой спиралью на сфере), но я думаю, что это снижает качество случайного.
Уровень Река St
4

05AB1E , 23 22 байта

[тε5°x<Ýs/<Ω}DnOtDî#}/

Реализует 2-й алгоритм.

Попробуйте онлайн или получите еще несколько случайных результатов .

Объяснение:

ПРИМЕЧАНИЕ: 05AB1E не имеет встроенной функции для получения случайного десятичного значения в диапазоне [0,1), Вместо этого я создаю список с шагом0,00001и выберите случайные значения из этого списка. Это приращение может быть изменено на0,000000001путем изменения 5к 9в коде (хотя это стало бы довольно медленно ..).

[            # Start an infinite loop:
 тε          #  Push 100, and map (basically, create a list with 3 values):
   5°        #   Push 100,000 (10**5)
     x       #   Double it to 200,000 (without popping)
      <      #   Decrease it by 1 to 199,999
       Ý     #   Create a list in the range [0, 199,999]
        s/   #   Swap to get 100,000 again, and divide each value in the list by this
          <  #   And then decrease by 1 to change the range [0,2) to [-1,1)
           Ω #   And pop and push a random value from this list
  }          #  After the map, we have our three random values
   D         #   Duplicate this list
    n        #   Square each inner value
     O       #   Take the sum of these squares
      t      #   Take the square-root of that
       D     #   Duplicate that as well
        î    #   Ceil it, and if it's now exactly 1:
         #   #    Stop the infinite loop
}/           # After the infinite loop: normalize by dividing
             # (after which the result is output implicitly)
Кевин Круйссен
источник
1
С помощью L<1 в равной степени так же, как L1, Единственный критерий дляLИкс в том, что 0<Икс1, Вы можете также принять векторы сL<0,5если это сохранит какие-либо байты. Любое значение меньше или равно1 устраняет предвзятость
Джитс
@Jitse Хорошо, в моих ответах на Java и 05AB1E реализована нормализация. Я надеюсь, что сейчас все правильно.
Кевин Круйссен
@Jitse На самом деле сохранил байт, проверив v1 как v==1, вместо того v<1, Но спасибо за разъяснение, что только0<Икс1 это требование, и нет строгого требование к LДо тех пор, пока это 1,
Кевин Круйссен
4

TI-BASIC, 15 байтов *

:randNorm(0,1,3
:Ans/√(sum(Ans²

Используя алгоритм «сгенерируйте 3 нормально распределенных значения и нормализуйте этот вектор».

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

*: randNorm(это двухбайтовый токен , остальные - однобайтовые токены . Я посчитал начальный (неизбежный) :, без этого это было бы 14 байтов. Сохраненный как программа с однобуквенным именем, он занимает 24 байта памяти, что включает 9 байтов служебной информации файловой системы.

Гарольд
источник
3

JavaScript (ES7),  77 76  75 байт

Реализует 3- й алгоритм, используягрех(φ)знак равногрех(соз-1(Z))знак равно1-Z2,

with(Math)f=_=>[z=2*(r=random)()-1,cos(t=2*PI*r(q=(1-z*z)**.5))*q,sin(t)*q]

Попробуйте онлайн!

комментарии

with(Math)                       // use Math
f = _ =>                         //
  [ z = 2 * (r = random)() - 1,  // z = 2 * j - 1
    cos(                         //
      t =                        // θ =
        2 * PI *                 //   2 * π * i
        r(q = (1 - z * z) ** .5) // q = sin(ɸ) = sin(arccos(z)) = √(1 - z²)
                                 // NB: it is safe to compute q here because
                                 //     Math.random ignores its parameter(s)
    ) * q,                       // x = cos(θ) * sin(ɸ)
    sin(t) * q                   // y = sin(θ) * sin(ɸ)
  ]                              //

JavaScript (ES6), 79 байт

Реализует 2- й алгоритм.

f=_=>(n=Math.hypot(...v=[0,0,0].map(_=>Math.random()*2-1)))>1?f():v.map(x=>x/n)

Попробуйте онлайн!

комментарии

f = _ =>                         // f is a recursive function taking no parameter
  ( n = Math.hypot(...           // n is the Euclidean norm of
      v =                        // the vector v consisting of:
        [0, 0, 0].map(_ =>       //
          Math.random() * 2 - 1  //   3 uniform random values in [-1, 1]
        )                        //
  )) > 1 ?                       // if n is greater than 1:
    f()                          //   try again until it's not
  :                              // else:
    v.map(x => x / n)            //   return the normalized vector
Arnauld
источник
3

Обработка 26 байтов

Полная программа

print(PVector.random3D());

Это реализация https://github.com/processing/processing/blob/master/core/src/processing/core/PVector.java

  static public PVector random3D(PVector target, PApplet parent) {
    float angle;
    float vz;
    if (parent == null) {
      angle = (float) (Math.random()*Math.PI*2);
      vz    = (float) (Math.random()*2-1);
    } else {
      angle = parent.random(PConstants.TWO_PI);
      vz    = parent.random(-1,1);
    }
    float vx = (float) (Math.sqrt(1-vz*vz)*Math.cos(angle));
    float vy = (float) (Math.sqrt(1-vz*vz)*Math.sin(angle));
    if (target == null) {
      target = new PVector(vx, vy, vz);
      //target.normalize(); // Should be unnecessary
    } else {
      target.set(vx,vy,vz);
    }
    return target;
  }
PrincePolka
источник
2
Возможно, вы захотите прояснить, что реализация не является частью вашего количества байтов. Я пропустил это при первом чтении, затем сделал двойной дубль.
Уровень Река St
Мне нравится, что реализация использует по существу тот же подход, что и я,
Level River St
2

Python 2 , 86 байт

from random import*
x,y,z=map(gauss,[0]*3,[1]*3);l=(x*x+y*y+z*z)**.5
print x/l,y/l,z/l

Попробуйте онлайн!

Реализует первый алгоритм.


Python 2 , 107 103 байта

from random import*
l=2
while l>1:x,y,z=map(uniform,[-1]*3,[1]*3);l=(x*x+y*y+z*z)**.5
print x/l,y/l,z/l

Попробуйте онлайн!

Реализует второй алгоритм.

TFeld
источник
2
@RobinRyder Эта реализация отклоняет векторы с начальной длиной> 1, что является допустимым, как указано в запросе.
Джитс
@ Джитс Хорошо, извини. Я неправильно прочитал код.
Робин Райдер
2

Haskell , 125 123 119 118 байт

import System.Random
f=mapM(\_->randomRIO(-1,1))"lol">>= \a->last$f:[pure$(/n)<$>a|n<-[sqrt.sum$map(^2)a::Double],n<1]

Попробуйте онлайн!

Делает три униформы случайных и бракованных выборок.

Angs
источник
Похоже, ваши рандомы из распределения (0,1) вместо (-1,1), так что покрыта только 1/8 сферы.
Джитс
@ Джитс Гоча, спасибо, что заметили.
Анг
2

JavaScript, 95 байт

f=(a=[x,y,z]=[0,0,0].map(e=>Math.random()*2-1))=>(s=Math.sqrt(x*x+y*y+z*z))>1?f():a.map(e=>e/s)

Вам не нужно не вводить a.

Наруйоко
источник
Вау, я полностью пропустил это. Исправлена.
Наруйоко
2

Юлия 1,0 , 24 байта

x=randn(3)
x/hypot(x...)

Попробуйте онлайн!

Рисует вектор из 3 значений, взятый из нормального распределения около 0 со стандартным отклонением 1. Затем просто нормализует их.

user3263164
источник
randn()из нескольких быстрых тестов, похоже, не привязан к требуемому диапазону. Кроме того, это не включает проверку hypot()возврата значения >1, которая должна быть отклонена.
лохматый
3
@ Шагги, похоже, randnимитирует стандартное нормальное распределение, а не равномерное (0,1), поэтому этот подход идентичен подходу R.
Джузеппе
@ Giuseppe Да, именно так!
user3263164
@ Джузеппе, я думаю, что у меня может не быть правильного понимания математики, стоящей за этим испытанием, но, если я правильно вас понимаю, вы говорите, что если какой-либо из поплавков находится за пределами границ, [-1,1)то делите их на гипотенуза, которая будет >1, компенсирует это? Это заставляет меня задуматься, нужна ли троичная форма в моем решении ...
лохматый
@ Shaggy нет, нормальное / гауссово распределение имеет некоторые свойства (в частности, вращательную инвариантность), которых нет у формы, см. , Например , этот комментарий
Джузеппе
2

MathGolf , 21 19 18 байт

{╘3Ƀ∞(ß_²Σ√_1>}▲/

Реализация 2-го алгоритма.

Попробуйте онлайн или посмотрите несколько выходов одновременно .

Объяснение:

{              }▲   # Do-while true by popping the value:
                   #  Discard everything on the stack to clean up previous iterations
  3É                #  Loop 3 times, executing the following three operations:
    ƒ               #   Push a random value in the range [0,1]
                   #   Double it to make the range [0,2]
      (             #   Decrease it by 1 to make the range [-1,1]
       ß            #  Wrap these three values into a list
        _           #  Duplicate the list of random values
         ²          #  Square each value in the list
          Σ         #  Sum them
                   #  And take the square-root of that
            _       #  Duplicate it as well
             1>     #  And check if it's larger than 1
                 /  # After the do-while, divide to normalize
                    # (after which the entire stack joined together is output implicitly,
                    #  which is why we need the `╘` to cleanup after every iteration)
Кевин Круйссен
источник
2

Java 8 ( модифицированный 3-й алгоритм @Arnauld ), 131 126 119 111 109 байт

v->{double k=2*M.random()-1,t=M.sqrt(1-k*k),r[]={k,M.cos(k=2*M.PI*M.random())*t,M.sin(k)*t};return r;}

Порт из @Arnauld 's JavaScript answer , так что обязательно проголосуйте за него!
-2 байта благодаря @ OlivierGrégoire .

Это реализовано как:

Кзнак равноN[-1,1)
Tзнак равно1-К2
Uзнак равно2π×(N[0,1))
Икс,Y,Zзнак равно{К,соз(U)×T,грех(U)×T}

Попробуйте онлайн.

Предыдущая реализация третьего алгоритма ( 131 126 119 байт):

Math M;v->{double k=2*M.random()-1,t=2*M.PI*M.random();return k+","+M.cos(t)*M.sin(k=M.acos(k))+","+M.sin(t)*M.sin(k);}

Реализуется как:

Кзнак равноN[-1,1)
Tзнак равно2π×(N[0,1))
Икс,Y,Zзнак равно{К,соз(T)×грех(агссоз(К)),грех(T)×грех(агссоз(К))}

Попробуйте онлайн.

Объяснение:

Math M;                         // Math on class-level to use for static calls to save bytes
v->{                            // Method with empty unused parameter & double-array return
  double k=2*M.random()-1,      //  Get a random value in the range [-1,1)
         t=M.sqrt(1-k*k),       //  Calculate the square-root of 1-k^2
    r[]={                       //  Create the result-array, containing:
         k,                     //   X: the random value `k`
         M.cos(k=2*M.PI         //   Y: first change `k` to TAU (2*PI)
                     *M.random()//       multiplied by a random [0,1) value
                )               //      Take the cosine of that
                 *t,            //      and multiply it by `t`
         M.sin(k)               //   Z: Also take the sine of the new `k` (TAU * random)
                  *t};          //      And multiply it by `t` as well
  return r;}                    //  Return this array as result

Java 8 (2-й алгоритм), 153 143 байта

v->{double x=2,y=2,z=2,l;for(;(l=Math.sqrt(x*x+y*y+z*z))>1;y=m(),z=m())x=m();return x/l+","+y/l+","+z/l;};double m(){return Math.random()*2-1;}

Попробуйте онлайн.

2-й алгоритм:

v->{                              // Method with empty unused parameter & String return-type
  double x=2,y=2,z=2,l;           //  Start results a,b,c all at 2
  for(;(l=Math.sqrt(x*x+y*y+z*z)) //  Loop as long as the hypotenuse of x,y,z
       >1;                        //  is larger than 1
    y=m(),z=m())x=m();            //   Calculate a new x, y, and z
  return x/l+","+y/l+","+z/l;}    //  And return the normalized x,y,z as result
double m(){                       // Separated method to reduce bytes, which will:
  return Math.random()*2-1;}      //  Return a random value in the range [-1,1)
Кевин Круйссен
источник
Использование sqrt(1-k*k)фактически экономит больше байтов в Java, чем в JS. :)
Арно
@ Арнаулд Да. Вместо 3x M.sin, 1x M.cosи 1x M.acosваш подход использует 2x M.sinи 1x M.sqrt, из которых в основном поступают дополнительные сохраненные байты. :)
Кевин Круйссен
108 байт. Использует модифицированный 2-й алгоритм, в котором разрешены только значения, где s == 1 (вместо s <= 1 и затем нормализация). Иногда дает ответ, но в основном не из-за тайм-аута. Изменить: Ой, я забыл Math.sqrt результат
Оливье Грегуар
На самом деле нет необходимости в sqrt, потому что sqrt (1) == 1. Так что я стою с моим предложением гольфа.
Оливье Грегуар
1
109 байтов (вы можете использовать свой строковый вывод вместо того, double[]чтобы не изменять счетчик байтов.)
Оливье Грегуар
1

Pyth , 24 байта

W<1Ks^R2JmtO2.0 3;cR@K2J

Попробуйте онлайн!

Использует алгоритм № 2

W                         # while 
 <1                       #   1 < 
   Ks                     #       K := sum(
     ^R2                  #               map(lambda x:x**2,
        Jm      3         #                    J := map(                            , range(3))
          tO2.0           #                             lambda x: random(0, 2.0) - 1           )):
                 ;        #   pass
                   R   J  # [return] map(lambda x:            , J)
                  c @K2   #                        x / sqrt(K)
ar4093
источник
1

OCaml , 110 99 95 байтов

(fun f a c s->let t,p=f 4.*.a 0.,a(f 2.-.1.)in[c t*.s p;s t*.s p;c p])Random.float acos cos sin

РЕДАКТИРОВАТЬ: сбрил некоторые байты, вставляя я а также J, заменяя первое let ... inна a fun, и используя ассоциативность операторов, чтобы избежать некоторых слов ().

Попробуйте онлайн


Оригинальное решение:

Random.(let a,c,s,i,j=acos,cos,sin,float 4.,float 2. in let t,p=i*.(a 0.),a (j-.1.) in[c t*.s p;s t*.s p;c p])

Сначала я определяю:

aзнак равноагссоз,  сзнак равносоз,  sзнак равногрехя~UNIF(0,4),  J~UNIF(0,2)

Random.floatФункция OCaml включает в себя границы. Затем,

Tзнак равнояa(0)знак равнояπ2,  пзнак равноa(J-1)

Это очень похоже на реализацию третьего примера (с φзнак равноп а также θзнак равноT) - кроме того, что я выбираю я а также J в больших интервалах, чтобы избежать умножения (с 2) позже.

Сасват Падхи
источник
1
Я не совсем знаком с этим языком, но похоже, что вы используете случайные числа с плавающей точкой между сферическими координатами 0и 1непосредственно. Это неверно, как показано в примечаниях к вызовам 3 и 4, так как в итоге вы получаете уклон к полюсам сферы. Вы можете исправить это, применив метод, показанный в примечании 4.
Джитс
Спасибо! Совершенно пропустил это. Исправил ошибку и обновил мой ответ
Сасват Падхи
1
Выглядит хорошо! Очень хороший первый ответ!
Джитс
Спасибо :) Я смог уменьшить его до 100 байт!
Сасват Падхи