Losowy punkt na kuli

31

Wyzwanie

Napisz program lub funkcję, która nie pobiera danych wejściowych i wysyła wektor o długości w teoretycznie jednorodnym losowym kierunku.1

Jest to równoważne losowemu punktowi na kuli opisanemu przez

x2+y2+z2=1

powodując taką dystrybucję

Losowy rozkład punktów na kuli o promieniu 1.

Wydajność

Trzy zmiennoprzecinkowe z teoretycznie jednorodnego rozkładu losowego, dla którego równanie jest zgodne z granicami dokładności.x2+y2+z2=1

Uwagi na temat wyzwania

  • Rozkład losowy musi być teoretycznie jednolity . Oznacza to, że gdyby generator liczb pseudolosowych został zastąpiony prawdziwym RNG z liczb rzeczywistych , spowodowałoby to jednolity losowy rozkład punktów na kuli.
  • Generowanie trzech liczb losowych z jednolitego rozkładu i ich normalizacja jest nieprawidłowe: nastąpi odchylenie w kierunku narożników przestrzeni trójwymiarowej.
  • Podobnie, generowanie dwóch liczb losowych z równomiernego rozkładu i stosowanie ich jako współrzędnych sferycznych jest nieprawidłowe: nastąpi odchylenie w kierunku biegunów kuli.
  • Właściwą jednorodność można osiągnąć za pomocą algorytmów, w tym między innymi:
    • Generowania trzech liczb losowych , i z pomocą normalnego (Gaussa) rozkład wokół i normalizować je. xyz00
    • Generowania trzech liczb losowych, , i z równomiernym rozkładem w zakresie . Oblicz długość wektora o . Następnie, jeśli , odrzuć wektor i wygeneruj nowy zestaw liczb. W przeciwnym razie, jeśli , znormalizuj wektor i zwróć wynik. xyz( - 1 , 1 ) l = (1,1)l=x2+y2+z2l>1l1
    • Generowanie dwóch liczb losowych i z równomiernym rozkładem w przedziale i przekształcają je na sferyczne współrzędnych tak: , aby , i można było obliczyć za pomocąij( 0 , 1 ) θ(0,1)
      θ=2×π×iϕ=cos1(2×j1)
      xyz
      x=cos(θ)×sin(ϕ)y=sin(θ)×sin(ϕ)z=cos(ϕ)
  • Podaj w swojej odpowiedzi krótki opis używanego algorytmu.
  • Przeczytaj więcej na temat wybierania punktów kuli na MathWorld .

Przykłady wyników

[ 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]

Uwagi ogólne

Jitse
źródło
Czy dobrze jest równomiernie wybrać 3 reale w [-1, 1], a następnie odrzucić je (i powtórzyć), jeśli suma ich kwadratów nie wynosi 1?
Grimmy
6
@Grimy, podoba mi się ta luka. Nie, jest to niedozwolone, ponieważ teoretycznie nie ma szans na jakiekolwiek wyjście.
Jitse
Czy sugestia @ Grimy nie jest podobna do wspomnianego przez Ciebie drugiego przykładu? To rozwiązanie ma również teoretycznie zerową szansę na uzyskanie jakiegokolwiek wyniku
Saswat Padhi
2
@SaswatPadhi Nie, to ma szansę pi/6 ≈ 0.5236wyprodukować wyjście. Jest to obszar kuli wpisany w sześcian obszaru jednostkowego
Luis Mendo
1
@LuisMendo Rozumiem, prawda. Jak wspomniałeś, prawdopodobieństwo wynosi w tym przypadku ~ 0,5. Dla propozycji Grimy'ego jest to ~ 0.
Saswat Padhi

Odpowiedzi:

24

R , 23 bajty

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

Wypróbuj online!

Generuje 3 realizacje rozkładu N(0,1) i normalizuje uzyskany wektor.

Działka z 1000 realizacji:

wprowadź opis zdjęcia tutaj

Robin Ryder
źródło
2
Czy możesz uzasadnić 3-osiowy rozkład normalnie powodujący równomierny rozkład na kuli? (Nie widzę tego)
Jeffrey wspiera Monikę
4
X,YN(0,1)fX(x)=Ke12x2fY(y)=Ke12y2fXY(x,y)=K2e12(x2+y2)=fZ(z)=K2e12z2z=(x,y)zz
1
Tak więc rozkład normalny daje nam równomiernie rozmieszczone punkty wokół koła, a dzielenie przez jasność zapewnia, że ​​punkty leżą na okręgu
Giuseppe
23

x86-64 Kod maszynowy - 63 62 55 49 bajtów

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  

Używa zmodyfikowanego drugiego algorytmu. Zwraca wektor [x, y, z, 0]w xmm0.

Wyjaśnienie:

push 4Fh
push 3f800000h

Przesuwa wartość 1 i 2 ^ 31 jako liczbę zmiennoprzecinkową do stosu. Dane nakładają się z powodu rozszerzenia znaku, co pozwala zaoszczędzić kilka bajtów.

vbroadcastss xmm1,dword ptr [rsp+5] Ładuje wartość 2 ^ 31 w 4 pozycjach xmm1.

rdrand      eax  
jnc         rand  
movd        xmm0,eax

Generuje losową 32-bitową liczbę całkowitą i ładuje ją do dolnej części xmm0.

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

Generuje losową 32-bitową liczbę całkowitą, zamień ją na zmiennoprzecinkową (podpisaną) i podziel przez 2 ^ 31, aby uzyskać liczby od -1 do 1.

vdpps xmm2,xmm0,xmm0,7Fhdodaje kwadraty dolnych 3 pływaków, używając samego produktu kropkowego, maskując górny pływak. To daje długość

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

Porównuje długość do kwadratu z 1 i odrzuca wartości, jeśli nie jest równa 1. Jeśli długość do kwadratu wynosi jeden, to długość jest również równa. Oznacza to, że wektor jest już znormalizowany i zapisuje pierwiastek kwadratowy i dzieli.

pop         rax  
pop         rax 

Przywróć stos.

ret zwraca wartość w xmm0

Wypróbuj online .

mnie'
źródło
7
+1 Używanie aesencdo tworzenia 128 „losowych” bitów jest po prostu piękne.
DocMax
13

Python 2 , 86 bajtów

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

Wypróbuj online!

Generuje współrzędną z równomiernie od -1 do 1. Następnie współrzędne xiy są próbkowane równomiernie na okręgu o promieniu (1-z*z)**.5.

Może nie być oczywiste, że rozkład sferyczny jest równomierny w stosunku do współrzędnej z (i tak w przypadku każdej współrzędnej). Jest to coś specjalnego dla wymiaru 3. Zobacz ten dowód, że pole powierzchni poziomego wycinka kuli jest proporcjonalne do jego wysokości. Chociaż plastry w pobliżu równika mają większy promień, plastry w pobliżu bieguna są bardziej skierowane do wewnątrz i okazuje się, że te dwa efekty dokładnie się anulują.

Aby wygenerować losowy kąt na tym okręgu, podnosimy wyimaginowaną jednostkę 1jdo równomiernie losowej mocy od 0 do 4, co oszczędza nam konieczności korzystania z funkcji wyzwalania, pi lub e, z których każda wymagałaby importu. Następnie wydobywamy prawdziwą wyimaginowaną część. Jeśli możemy wyprowadzić liczbę zespoloną dla dwóch współrzędnych, ostatnia linia może po prostu być print a,z.


86 bajtów

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

Wypróbuj online!

Generuje trzy normalne i skaluje wynik.


Python 2 z numpy, 57 bajtów

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

Wypróbuj online!

sum(a*a)**.5jest krótszy niż linalg.norm(a). Możemy również zrobić dot(a,a)dla tej samej długości co sum(a*a). W Pythonie 3 można to skrócić do a@akorzystania z nowego operatora @.

xnor
źródło
1
Lubię twoje pierwsze podejście. Mam problem ze zrozumieniem, w jaki sposób można uniknąć uprzedzeń w kierunku równika, jeżeli zz jednolitego rozkładu pozostanie niezmodyfikowany.
Jitse
2
@ Jitse Rozkład sferyczny jest jednorodny dla każdej współrzędnej. Jest to coś specjalnego dla wymiaru 3. Zobacz na przykład dowód, że pole powierzchni kuli jest proporcjonalne do jej wysokości. Jeśli chodzi o intuicję, że jest to stronnicze w stosunku do równika, zauważ, że podczas gdy plastry w pobliżu równika mają większy promień, te w pobliżu bieguna są nazwane bardziej do wewnątrz, co daje więcej obszaru, i okazuje się, że te dwa efekty dokładnie się anulują.
xnor
Bardzo dobrze! Dziękuję za wyjaśnienie i odniesienie.
Jitse
@Jitse Dzięki, dodałem to do ciała. Zrozumiałem jednak, że próbowałem tylko pozytywnie zi naprawiłem to na kilka bajtów.
xnor
1
@Jitse Rzeczywiście pole powierzchni kuli jest równe polu powierzchni bocznej otaczającego cylindra!
Neil
13

Oktawa , 40 33 22 bajtów

Próbkujemy z 3d standardowego rozkładu normalnego i normalizujemy wektor:

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

Wypróbuj online!

wada
źródło
Tylko dla Octave (tj. Nie MATLAB), możesz zaoszczędzić bajt dzięki temu
Tom Carpenter
1
@TomCarpenter Thanks! W tym przypadku, ponieważ jest to tylko jedno wyrażenie, możemy nawet pominąć disp:)
flawr
10

Unity C # , 34 bajty

f=>UnityEngine.Random.onUnitSphere

Unity ma wbudowane losowe wartości kuli jednostkowej, więc pomyślałem, że to opublikuję.

Draco18s
źródło
Dobre wykorzystanie wbudowanego +1, możesz po prostu przesłać funkcję, aby była nieco krótszaf=>Random.onUnitSphere
LiefdeWen
@LiefdeWen Wiedziałem o lambdach, po prostu nie byłem pewien, czy to wystarczy (pod względem ważności na Code Golf), ponieważ nie deklaruje ftypu; używanie vardziała tylko wewnątrz metody i System.Func<Vector3>było dłuższe.
Draco18s
1
W codegolf zwracanie funkcji jest całkowicie w porządku i nie musisz liczyć deklaracji, co oznacza, że ​​możesz robić podstępne rzeczy z parametrami dynamicznymi. Nie wliczasz również ostatniego średnika. Liczysz się jednak za pomocą dodanych instrukcji. więc twoja liczba bajtów musi obejmować użycie. Ale f=>Random.onUnitSpherejest to całkowicie poprawne zgłoszenie
LiefdeWen
@LiefdeWen Tak, po prostu nie byłem pewien, jak potraktowano deklarację i tak naprawdę nie miałem ochoty na „wyszukiwanie meta”.
Draco18s
f=>UnityEngine.Random.onUnitSphereratuje ciusing
Orace
6

MATL , 10 bajtów

1&3Xrt2&|/

Wypróbuj online!

Wyjaśnienie

Wykorzystuje to pierwsze podejście opisane w wyzwaniu.

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
Luis Mendo
źródło
6

Rubin , 34 50 49 bajtów

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

Wypróbuj online!

Zwraca tablicę 3 liczb [z,y,x].

xi ysą generowane przez podniesienie i(pierwiastek kwadratowy z -1) do losowej potęgi między 0 a 4. Ta liczba zespolona musi być odpowiednio skalowana zgodnie z zwartością zgodną z twierdzeniem Pitagorasa:(x**2 + y**2) + z**2 = 1.

zWspółrzędnych (który jest wytwarzany na początku) jest to po prostu liczba równomiernie rozłożone pomiędzy 1 i 1. Chociaż nie jest oczywiste, DA / dz na wskroś kuli jest stała (i wynosi na obwodzie okręgu o tym samym promieniu jak cała kula).

Zostało to najwyraźniej odkryte przez Archimedesa, który opisał to w sposób bardzo podobny do rachunku różniczkowego i jest znany jako twierdzenie Archimedesa o Hat-Box. Zobacz https://brilliant.org/wiki/surface-area-sphere/

Kolejne odniesienie z komentarzy do odpowiedzi xnora. Zaskakująco krótki URL opisujący zaskakująco prostą formułę: http://mathworld.wolfram.com/Zone.html

Level River St
źródło
@Jitse Zapomniałem przeskalować xiy przy wysokich wartościach z. W efekcie punkty zdefiniowały walec. Jest już naprawione, ale kosztowało dużo bajtów! Mógłbym zapisać kilka, jeśli wynik może być wyrażony liczbą zespoloną [z, x+yi], zostawię go takim, jakim jest, chyba że powiesz, że to jest w porządku.
Level River St
Wygląda dobrze! Naprawdę podoba mi się to podejście. Aby uzyskać spójność, wymagane dane wyjściowe to trzy zmiennoprzecinkowe, więc sugeruję pozostawienie go w ten sposób.
Jitse
Dlaczego nie użyć z*zzamiast z**2?
Wartość tuszu
@ValueInk tak, dzięki, zdałem sobie sprawę, że za tym tęskniłem z*z. Zredagowałem to teraz. Inną rzeczą, którą mogłem zrobić, to zastąpić rand*4czymś takim z*99lub x*9E9(skutecznie ograniczając możliwe wartości do bardzo cienkiej spirali na kuli), ale myślę, że to obniża jakość losowości.
Level River St
4

05AB1E , 23 22 bajtów

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

Implementuje drugi algorytm.

Wypróbuj online lub uzyskaj kilka losowych wyników .

Wyjaśnienie:

UWAGA: 05AB1E nie ma wbudowanej funkcji pobierania losowej wartości dziesiętnej z zakresu . Zamiast tego tworzę listę w przyrostach co i wybieram losowe wartości z tej listy. Ten przyrost może być zmieniony na zmieniając się w kodzie (choć byłoby stać raczej powolny ..).[0,1)0.000010.00000000159

[            # 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)
Kevin Cruijssen
źródło
1
Użycie jest równie ważne jak . Jedynym kryterium dla jest to, że . Równie dobrze możesz zaakceptować wektory o wartości jeśli pozwoli to zaoszczędzić jakieś bajty. Każda wartość mniejsza lub równa usuwa błąd systematyczny. l<1l1lx0<x1l<0.51
Jitse
@Jitse Ok, zaimplementowałem normalizację w moich odpowiedziach w Javie i 05AB1E. Mam nadzieję, że teraz wszystko jest w porządku.
Kevin Cruijssen
@ Jitse Właściwie zapisano bajt, sprawdzając jako , zamiast . Ale dzięki za wyjaśnienie, że tylko jest wymaganiem i nie ma ścisłego wymagania na , o ile jest to . v1v==1v<10<x1l1
Kevin Cruijssen
4

TI-BASIC, 15 bajtów *

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

Za pomocą algorytmu „wygeneruj 3 normalnie rozłożone wartości i znormalizuj ten wektor”.

Zakończenie programu wyrażeniem automatycznie drukuje wynik na ekranie głównym po zakończeniu programu, więc wynik jest faktycznie pokazywany, a nie tylko generowany i zakłócany.

*: randNorm(jest tokenem dwubajtowym , pozostałe to tokeny jednobajtowe . Policzyłem początkowy (nieunikniony) :, bez tego będzie to 14 bajtów. Zapisany jako program o nazwie jednoliterowej zajmuje 24 bajty pamięci, w tym 9 bajtów narzutu na system plików.

Harold
źródło
3

JavaScript (ES7),  77 76  75 bajtów

Implementuje 3 rd algorytm użyciu .sin(ϕ)=sin(cos1(z))=1z2

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

Wypróbuj online!

Skomentował

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 bajtów

Implementuje 2 nd algorytmu.

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

Wypróbuj online!

Skomentował

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
źródło
3

Przetwarzanie 26 bajtów

Pełny program

print(PVector.random3D());

To jest implementacja 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
źródło
2
Możesz wyjaśnić, że implementacja nie jest częścią liczby bajtów. Przegapiłem to przy pierwszym czytaniu, a potem zrobiłem podwójne przyjęcie.
Level River St
Podoba mi się, że implementacja używa zasadniczo tego samego podejścia co ja
Level River St
2

Python 2 , 86 bajtów

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

Wypróbuj online!

Implementuje pierwszy algorytm.


Python 2 , 107 103 bajtów

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

Wypróbuj online!

Implementuje drugi algorytm.

TFeld
źródło
2
@RobinRyder Ta implementacja odrzuca wektory o początkowej długości> 1, która jest poprawna jak określono w wyzwaniu.
Jitse
@Jitse Racja, przepraszam. Źle odczytałem kod.
Robin Ryder
2

Haskell , 125 123 119 118 bajtów

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

Wypróbuj online!

Wykonuje losowanie trzech mundurów i próbkę odrzucenia.

Angs
źródło
Wygląda na to, że twoje losy pochodzą z rozkładu (0,1) zamiast (-1,1), tak że pokrywa się tylko 1/8 kuli.
Jitse
@Jitse gotcha, dzięki za zauważenie.
Angs
2

JavaScript, 95 bajtów

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)

Państwo nie potrzebują nie do wejścia a.

Naruyoko
źródło
Wow, zupełnie za tym tęskniłem. Naprawiony.
Naruyoko,
2

Julia 1.0 , 24 bajty

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

Wypróbuj online!

Rysuje wektor 3 wartości, narysowany z rozkładu normalnego wokół 0 z odchyleniem standardowym 1. Następnie je normalizuje.

użytkownik3263164
źródło
randn(), z kilku szybkich testów, nie wydaje się być związany z wymaganym zakresem. Nie obejmuje to również sprawdzania hypot()zwrotu wartości >1, którą należy odrzucić.
Shaggy
3
@ Shaggy wydaje się, że randnsymuluje ze standardowego rozkładu normalnego, a nie jednolitego (0,1), więc to podejście jest identyczne z R.
Giuseppe,
@Giuseppe Tak, dokładnie!
user3263164,
@Giuseppe, myślę, że może nie rozumiem dobrze matematyki stojącej za tym wyzwaniem, ale jeśli dobrze cię rozumiem, mówisz, że jeśli którykolwiek z pływaków jest poza granicami, [-1,1)to dzielenie się przez nich przez przeciwprostokątna, która będzie >1, kompensuje to? To mnie zastanawia, czy trójnik w moim rozwiązaniu jest konieczny ...
Kudłaty
@ Shaggy nie, rozkład normalny / Gaussa ma pewne właściwości (w szczególności niezmienność rotacyjną), których mundur nie ma, patrz ten komentarz , na przykład
Giuseppe,
2

MathGolf , 21 19 18 bajtów

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

Implementacja drugiego algorytmu.

Wypróbuj online lub zobacz kilka innych wyników jednocześnie .

Wyjaśnienie:

{              }▲   # 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)
Kevin Cruijssen
źródło
2

Java 8 ( zmodyfikowany trzeci algorytm @Arnauld ), 131 126 119 111 109 bajtów

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;}

Port @Arnauld JavaScript odpowiedź „s , więc upewnij się, aby go upvote!
-2 bajty dzięki @ OlivierGrégoire .

Jest to realizowane jako:

k=N[1,1)
t=1k2
u=2π×(N[0,1))
x,y,z={k,cos(u)×t,sin(u)×t}

Wypróbuj online.

Poprzednia implementacja trzeciego algorytmu ( 131 126 119 bajtów):

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);}

Wdrożony jako:

k=N[1,1)
t=2π×(N[0,1))
x,y,z={k,cos(t)×sin(arccos(k)),sin(t)×sin(arccos(k))}

Wypróbuj online.

Wyjaśnienie:

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 (drugi algorytm), 153 143 bajty

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;}

Wypróbuj online.

Drugi algorytm:

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)
Kevin Cruijssen
źródło
Używanie sqrt(1-k*k)faktycznie oszczędza więcej bajtów w Javie niż w JS. :)
Arnauld
@Arnauld Yep. Zamiast 3x M.sin, 1x M.cosi 1x M.acos, twoje podejście używa 2x M.sini 1x M.sqrt, stąd najczęściej pochodzą dodatkowe zapisane bajty. :)
Kevin Cruijssen
108 bajtów Używa zmodyfikowanego 2. algorytmu, w którym dopuszczam tylko wartości, gdzie s == 1 (zamiast s <= 1, a następnie normalizuję). Czasami daje odpowiedź, ale przeważnie nie z powodu przekroczenia limitu czasu. Edycja: Ups, zapomniałem Math.sqrt wyniku
Olivier Grégoire
W rzeczywistości nie, nie ma potrzeby sqrt, ponieważ sqrt (1) == 1. Więc stoję z sugestią golfa.
Olivier Grégoire
1
109 bajtów (zamiast tego można użyć wyjściowego ciągu znaków double[], ponieważ nie zmienia to liczby bajtów.)
Olivier Grégoire,
1

Japt , 20 bajtów

Implementacja drugiego algorytmu przez port Arnaulda .

MhV=3ÆMrJ1
>1?ß:V®/U

Sprawdź to

MhV=3ÆMrJ1
Mh             :Get the hypotenuse of
  V=           :  Assign to V
    3Æ         :  Map the range [0,3)
      Mr       :    Random float
        J1     :    In range [-1,1)
>1?ß:V®/U      :Assign result to U
>1?            :If U is greater than 1
   ß           :  Run the programme again
    :V®/U      :Else map V, dividing all elements by U
Kudłaty
źródło
1

Pyth , 24 bajty

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

Wypróbuj online!

Wykorzystuje algorytm nr 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
źródło
1

OCaml , 110 99 95 bajtów

(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

EDYCJA: Ogoliłem niektóre bajty , wstawiając i , zastępując pierwszy przez a , i wykorzystując skojarzenie operatora, aby uniknąć niektórych parens .ijlet ... infun()

Wypróbuj online


Oryginalne rozwiązanie:

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])

Najpierw określam:

a=arccos,  c=cos,  s=siniunif(0,4),  junif(0,2)

Random.floatFunkcja OCaml obejmuje granice. Następnie,

t=ia(0)=iπ2,  p=a(j1)

Jest to bardzo podobne do trzeciej przykładowej implementacji (z i ) z tym wyjątkiem, że wybieram i w większych odstępach, aby później uniknąć pomnożenia (z 2).ϕ=pθ=tij

Saswat Padhi
źródło
1
Nie jestem do końca zaznajomiony z tym językiem, ale wygląda na to, że używasz losowych pływaków pomiędzy 0i 1bezpośrednio jako współrzędnych sferycznych. Jest to niepoprawne, jak pokazano w uwagach 3 i 4 wyzwania, ponieważ kończy się to tendencją do biegunów kuli. Możesz to poprawić, stosując metodę przedstawioną w uwadze 4.
Jitse
Dziękuję Ci! Zupełnie tego przegapiłem. Naprawiono błąd i zaktualizowałem moją odpowiedź
Saswat Padhi
1
Wygląda dobrze! Bardzo ładna pierwsza odpowiedź!
Jitse
Dziękuję :) Udało mi się zmniejszyć go do mniej niż 100 bajtów!
Saswat Padhi