Punto casuale su una sfera


31

La sfida

Scrivi un programma o una funzione che non accetta input e genera un vettore di lunghezza 1 in una direzione casuale teoricamente uniforme .

Ciò equivale a un punto casuale sulla sfera descritto da

x2+y2+z2=1

risultante in una distribuzione come tale

Distribuzione casuale dei punti su una sfera con raggio 1.

Produzione

Tre galleggianti da una distribuzione casuale teoricamente uniforme per cui l'equazione x2+y2+z2=1 è vera ai limiti di precisione.

Commenti sulla sfida

  • La distribuzione casuale deve essere teoricamente uniforme . Cioè, se il generatore di numeri pseudo-casuali dovesse essere sostituito con un vero RNG dai numeri reali , si tradurrebbe in una distribuzione casuale uniforme di punti sulla sfera.
  • Generare tre numeri casuali da una distribuzione uniforme e normalizzarli non è valido: ci sarà una propensione verso gli angoli dello spazio tridimensionale.
  • Allo stesso modo, generare due numeri casuali da una distribuzione uniforme e usarli come coordinate sferiche non è valido: ci sarà una propensione verso i poli della sfera.
  • Una corretta uniformità può essere ottenuta mediante algoritmi che includono ma non si limitano a:
    • Generare tre numeri casuali x , y e z da una normale distribuzione (gaussiana) attorno 0 e normalizzare.
    • Genera tre numeri casuali x , y e z da una distribuzione uniforme nell'intervallo (1,1) . Calcola la lunghezza del vettore di l=x2+y2+z2 . Quindi, sel>1, rifiuta il vettore e genera un nuovo set di numeri. Altrimenti, sel1, normalizzare il vettore e restituire il risultato.
    • Genera due numeri casuali i e j da una distribuzione uniforme nell'intervallo (0,1) e convertili in coordinate sferiche in questo modo:
      θ=2×π×iϕ=cos1(2×j1)
      modo chex,yezpossano essere calcolati da
      x=cos(θ)×sin(ϕ)y=sin(θ)×sin(ϕ)z=cos(ϕ)
  • Fornisci nella tua risposta una breve descrizione dell'algoritmo che stai utilizzando.
  • Maggiori informazioni sulla selezione del punto sfera su MathWorld .

Esempi di output

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

Revisione generale


Va bene scegliere 3 reali in modo uniforme in [-1, 1], quindi rifiutarli (e ripetere) se la somma dei loro quadrati non è 1?
Grimmy,

6
@Grimy Mi piace quella scappatoia. No, non è consentito, poiché in teoria esiste una probabilità zero di qualsiasi output.
Jitse,

Il suggerimento di @ Grimy non è simile alla seconda implementazione di esempio citata da te? Questa soluzione ha anche teoricamente zero possibilità di produrre qualsiasi output
Saswat Padhi

2
@SaswatPadhi No, ha la possibilità pi/6 ≈ 0.5236di produrre un output. Questa è l'area della sfera inscritta nel cubo dell'unità-area
Luis Mendo il

1
@LuisMendo, capisco. La probabilità è ~ 0,5 in quel caso, come hai detto. Per la proposta di Grimy, è ~ 0.
Saswat Padhi,

Risposte:



24

R , 23 byte

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

Provalo online!

Genera 3 realizzazioni della distribuzione N(0,1) e normalizza il vettore risultante.

Trama di 1000 realizzazioni:

inserisci qui la descrizione dell'immagine


2
Riesci a giustificare una distribuzione a 3 assi normalmente con conseguente distribuzione uniforme sulla sfera? (Non lo vedo)
Jeffrey supporta Monica il

4
@Jeffrey È abbastanza noto in probabilità / statistiche; ma la dimostrazione per 2D (che si estende ordinatamente a 3 dimensioni) è approssimativamente: lascia X,YN(0,1) e indipendente. Quindi fX(x)=Ke12x2 ed , quindi per indipendenzafXYfY(y)=Ke12y2dovez=(x,y), quindi è chiaro che la distribuzione dizfXY(x,y)=K2e12(x2+y2)=fZ(z)=K2e12z2z=(x,y)z dipende esclusivamente dalla grandezza di , e quindi la direzione viene distribuita uniformemente. z
Giuseppe,

1
Quindi, la distribuzione normale ci dà punti distribuiti uniformemente intorno al cerchio e la divisione per grandezza assicura che i punti si trovino sul cerchio
Giuseppe,

23

x86-64 Codice macchina - 63 62 55 49 byte

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  

Utilizza il secondo algoritmo, modificato. Restituisce il vettore di [x, y, z, 0]in xmm0.

Spiegazione:

push 4Fh
push 3f800000h

Spinge il valore per 1 e 2 ^ 31 come float nello stack. I dati si sovrappongono a causa dell'estensione del segno, salvando alcuni byte.

vbroadcastss xmm1,dword ptr [rsp+5] Carica il valore per 2 ^ 31 in 4 posizioni di xmm1.

rdrand      eax  
jnc         rand  
movd        xmm0,eax

Genera intero a 32 bit casuale e lo carica fino alla fine di xmm0.

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

Genera un numero intero a 32 bit casuale, convertilo in float (con segno) e dividi per 2 ^ 31 per ottenere numeri tra -1 e 1.

vdpps xmm2,xmm0,xmm0,7Fhaggiunge i quadrati dei 3 galleggianti inferiori usando un prodotto a punti da solo, mascherando il galleggiante superiore. Questo dà la lunghezza

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

Confronta la lunghezza al quadrato con 1 e rifiuta i valori se non è uguale a 1. Se la lunghezza al quadrato è una, anche la lunghezza è una. Ciò significa che il vettore è già normalizzato e salva una radice quadrata e si divide.

pop         rax  
pop         rax 

Ripristina lo stack.

ret restituisce valore in xmm0

Provalo online .


7
+1 Usare aesencper produrre 128 bit "casuali" è semplicemente meraviglioso.
DocMax,

13

Python 2 , 86 byte

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

Provalo online!

Genera la coordinata z uniformemente da -1 a 1. Quindi le coordinate xey vengono campionate uniformemente su un cerchio di raggio (1-z*z)**.5.

Potrebbe non essere ovvio che la distribuzione sferica è in fattore uniforme sulla coordinata z (e quindi su ogni coordinata). Questo è qualcosa di speciale per la dimensione 3. Vedi questa prova che la superficie di una fetta orizzontale di una sfera è proporzionale alla sua altezza. Sebbene le sezioni vicino all'equatore abbiano un raggio maggiore, le sezioni vicino al polo sono più interne, e si scopre che questi due effetti si annullano esattamente.

Per generare un angolo casuale su questo cerchio, eleviamo l'unità immaginaria 1ja una potenza uniformemente casuale tra 0 e 4, il che ci salva dal bisogno di funzioni di innesco, pi, oe, ognuna delle quali avrebbe bisogno di un'importazione. Quindi estraiamo la vera parte immaginaria. Se riusciamo a produrre un numero complesso per due delle coordinate, l'ultima riga potrebbe essere print a,z.


86 byte

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

Provalo online!

Genera tre normali e scala il risultato.


Python 2 con numpy, 57 byte

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

Provalo online!

sum(a*a)**.5è più corto di linalg.norm(a). Potremmo anche fare dot(a,a)per la stessa lunghezza di sum(a*a). In Python 3, questo può essere abbreviato a@ausando il nuovo operatore @.


1
Mi piace il tuo primo approccio. Ho difficoltà a capire come si evita un pregiudizio verso l'equatore se z, da una distribuzione uniforme, non viene modificato.
Jitse,

2
@Jitse La distribuzione sferica è in fattore uniforme su ciascuna coordinata. Questo è qualcosa di speciale per la dimensione 3. Vedi ad esempio questa prova che la superficie di una fetta di una sfera è proporzionale alla sua altezza. Per quanto riguarda l'intuizione che questo è distorto dall'equatore, nota che mentre le sezioni vicino all'equatore hanno un raggio più grande, quelle vicino al polo sono titolate verso l'interno più che dà più area, e risulta che questi due effetti si annullano esattamente.
xnor

Molto bella! Grazie per il chiarimento e il riferimento.
Jitse,

@Jitse Grazie, l'ho aggiunto al corpo. Mi sono reso conto però che stavo solo campionando positivo z, e l' ho risolto per pochi byte.
xnor

1
@Jitse In effetti, la superficie di una sfera è uguale alla superficie laterale del cilindro racchiuso!
Neil,

13

Ottava , 40 33 22 byte

Campioniamo una distribuzione normale standard 3d e normalizziamo il vettore:

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

Provalo online!


Solo per Octave (ovvero non MATLAB), puoi salvare un byte con questo
Tom Carpenter,

1
@TomCarpenter Grazie! In questo caso, dato che è solo un'espressione, possiamo persino omettere disp:)
flawr

10

Unity C # , 34 byte

f=>UnityEngine.Random.onUnitSphere

Unity ha un valore incorporato per i valori casuali della sfera unitaria, quindi ho pensato di pubblicarlo.


Buon uso di un +1 incorporato, potresti semplicemente inviare una funzione per essere un po 'più brevef=>Random.onUnitSphere
LiefdeWen

@LiefdeQuando ero a conoscenza di lambdas, non ero sicuro che fosse abbastanza (in termini di validità su Code Golf) perché non sta dichiarando fil Tipo; usando varfunziona solo all'interno di un metodo ed è System.Func<Vector3>stato più lungo.
Draco18s

1
In codegolf la restituzione di una funzione è perfettamente corretta e non è necessario contare la dichiarazione, il che significa che è possibile eseguire operazioni subdole con parametri dinamici. Inoltre non conti l'ultimo punto e virgola. Tuttavia contate tutte le dichiarazioni usando che aggiungete. quindi il conteggio dei byte deve includere l'utilizzo. Ma f=>Random.onUnitSphereè una presentazione perfettamente valida
LiefdeWen

@LiefdeWen Sì, non ero sicuro di come fosse gestita la dichiarazione e non mi sentivo davvero "alla ricerca di meta".
Draco18s

f=>UnityEngine.Random.onUnitSphereti salva ilusing
Orace

6

MATL , 10 byte

1&3Xrt2&|/

Provalo online!

Spiegazione

Questo utilizza il primo approccio descritto nella sfida.

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

Rubino , 34 50 49 byte

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

Provalo online!

Restituisce un array di 3 numeri [z,y,x].

xe ysono generati elevando i(radice quadrata di -1) a una potenza casuale compresa tra 0 e 4. Questo numero complesso deve essere ridimensionato in modo appropriato in base al zvalore secondo il teorema di Pitagora:(x**2 + y**2) + z**2 = 1.

Il z coordinata (che viene generata per prima) è semplicemente un numero uniformemente distribuito tra -1 e 1. Anche se non immediatamente ovvio, dA / dz per una fetta attraverso una sfera è costante (ed uguale al perimetro di un cerchio dello stesso raggio di l'intera sfera.).

Ciò è stato apparentemente scoperto da Archimede che lo ha descritto in un modo non molto simile al calcolo ed è noto come teorema di Hat-Box di Archimede. Vedi https://brilliant.org/wiki/surface-area-sphere/

Un altro riferimento dai commenti sulla risposta di xnor. Un URL sorprendentemente breve, che descrive una formula sorprendentemente semplice: http://mathworld.wolfram.com/Zone.html


@Jitse Ho dimenticato di ridimensionare xey ad alti valori di z. In effetti i punti hanno definito un cilindro. Ora è stato risolto ma è costato molti byte! Potrei salvarne alcuni se l'output può essere espresso con un numero complesso [z, x+yi]lo lascerò così com'è a meno che tu non dica che va bene.
Level River St

Sembra buono! Mi piace molto questo approccio. Per coerenza, l'output richiesto è di tre float, quindi suggerisco di lasciarlo così.
Jitse,

Perché non usare z*zinvece di z**2?
Value Ink

@ValueInk sì grazie mi sono reso conto che mi mancava z*z. L'ho modificato ora. L'altra cosa che potrei fare è sostituire rand*4con qualcosa di simile z*99o x*9E9(limitare efficacemente i possibili valori a una spirale molto fine sulla sfera) ma penso che ciò riduca la qualità del casuale.
Level River St,

4

05AB1E , 23 22 byte

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

Implementa il secondo algoritmo.

Provalo online o ottieni altri risultati casuali .

Spiegazione:

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

1
l<1l1lx0<x1l<0.51

@Jitse Ok, ho implementato la normalizzazione nelle mie risposte sia Java che 05AB1E. Spero che ora sia tutto corretto.
Kevin Cruijssen,

v1v==1v<10<x1l1

4

TI-BASIC, 15 byte *

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

Utilizzando l'algoritmo "genera 3 valori normalmente distribuiti e normalizza quel vettore".

La fine di un programma con un'espressione stampa automaticamente il risultato sulla schermata iniziale al termine del programma, quindi il risultato viene effettivamente mostrato, non solo generato e modificato.

*: randNorm(è un token a due byte , il resto sono token a un byte . Ho contato l'iniziale (inevitabile) :, senza che sarebbe di 14 byte. Salvata come programma con un nome di una lettera, richiede 24 byte di memoria, che include i 9 byte di sovraccarico del file system.


3

JavaScript (ES7),  77 76  75 byte

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]

Provalo online!

Commentate

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 byte

Implementa il 2 ° algoritmo.

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

Provalo online!

Commentate

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

3

in lavorazione 26 byte

Programma completo

print(PVector.random3D());

Questa è l'implementazione 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;
  }

2
Potresti voler chiarire che l'implementazione non fa parte del conteggio dei byte. L'ho perso in prima lettura, quindi ho fatto una doppia ripresa.
Level River St

Mi piace che gli usi di implementazione essenzialmente lo stesso approccio di me, anche se
livello del fiume St

2

Python 2 , 86 byte

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

Provalo online!

Implementa il primo algoritmo.


Python 2 , 107 103 byte

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

Provalo online!

Implementa il secondo algoritmo.


2
@RobinRyder Questa implementazione rifiuta i vettori con una lunghezza iniziale> 1, che è valida come specificato nella sfida.
Jitse,

@Jitse Giusto, scusa. Ho letto male il codice.
Robin Ryder,

2

Haskell , 125 123 119 118 byte

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

Provalo online!

Fa tre uniformi randoms e campionamento di rifiuto.


Sembra che i tuoi random provengano dalla distribuzione (0,1) anziché (-1,1), quindi solo 1/8 della sfera è coperta.
Jitse,

@Jitse gotcha, grazie per averlo notato.
Angs,

2

JavaScript, 95 byte

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)

Non è necessario non inserire a.


Caspita, l'ho perso del tutto. Fisso.
Naruyoko,

2

Julia 1.0 , 24 byte

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

Provalo online!

Disegna un vettore di 3 valori, tratto da una distribuzione normale intorno a 0 con deviazione standard 1. Quindi li normalizza.


randn(), da un paio di test rapidi, non sembra essere legato all'intervallo richiesto. Inoltre, questo non include un controllo per la hypot()restituzione di un valore >1, che dovrebbe essere rifiutato.
Shaggy,

3
@Shaggy sembrerebbe randnsimulare da una distribuzione normale standard piuttosto che da una uniforme (0,1), quindi questo approccio è identico a quello R.
Giuseppe,

@Giuseppe Sì, esattamente!
user3263164

@Giuseppe, penso che potrei non avere una corretta comprensione della matematica dietro questa sfida ma, se ti sto capendo correttamente, stai dicendo che se qualcuno dei galleggianti è fuori dai limiti di [-1,1)allora dividendo per loro l'ipotenusa, che sarà >1, lo compensa? Questo mi porta a chiedermi se il ternario nella mia soluzione sia necessario ...
Shaggy,

@Shaggy no, la distribuzione normale / gaussiana ha alcune proprietà (in particolare, invarianza rotazionale) che l'uniforme non ha, vedi questo commento , ad esempio
Giuseppe,

2

MathGolf , 21 19 18 byte

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

Implementazione del secondo algoritmo.

Provalo online o vedi più uscite contemporaneamente .

Spiegazione:

{              }▲   # 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 ( 3o algoritmo modificato di @Arnauld ), 131 126 119 111 109 byte

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

Porta della risposta JavaScript di @Arnauld , quindi assicurati di votarlo!
-2 byte grazie a @ OlivierGrégoire .

Questo è implementato come:

k=N[1,1)
t=1-K2
u=2π×(N[0,1))
X,y,z={K,cos(u)×t,peccato(u)×t}

Provalo online.

Implementazione del terzo algoritmo precedente ( 131 126 119 byte):

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

Implementato come:

K=N[-1,1)
t=2π×(N[0,1))
X,y,z={K,cos(t)×peccato(ARccOS(K)),peccato(t)×peccato(ARccOS(K))}

Provalo online.

Spiegazione:

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 (secondo algoritmo), 153 143 byte

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

Provalo online.

2o algoritmo:

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)

L'uso in sqrt(1-k*k)realtà consente di risparmiare più byte in Java rispetto a JS. :)
Arnauld

@Arnauld Yep. Invece di 3x M.sin, 1x M.cose 1x M.acos, il tuo approccio utilizza 2x M.sine 1x M.sqrt, che è da dove provengono principalmente i byte salvati aggiuntivi. :)
Kevin Cruijssen,

108 byte Utilizza un secondo algoritmo modificato in cui consento solo valori in cui s == 1 (anziché s <= 1 e quindi in fase di normalizzazione). A volte dà una risposta, ma per lo più non a causa del timeout. Modifica: Oops, ho dimenticato il risultato Math.sqrt
Olivier Grégoire

In realtà, no, non c'è bisogno di sqrt perché sqrt (1) == 1. Quindi sto con il mio suggerimento per il golf.
Olivier Grégoire,

1
109 byte (è possibile utilizzare l'output della stringa anziché in double[]quanto ciò non modifica il conteggio dei byte.)
Olivier Grégoire

1

Japt , 20 byte

Implementazione di Port of Arnauld del secondo algoritmo.

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

Provalo

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

1

Pyth , 24 byte

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

Provalo online!

Utilizza l'algoritmo n. 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)

1

OCaml , 110 99 95 byte

(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

EDIT: rasato alcuni byte in linea io e j, sostituendo il primo let ... incon a fune sfruttando l'associatività dell'operatore per evitare alcune parentesi() .

Provalo online


Soluzione originale:

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

Per prima cosa definisco:

un'=ARccOS,  c=cos,  S=peccatoio~Unif(0,4),  j~Unif(0,2)

La Random.floatfunzione di OCaml include i limiti. Poi,

t=ioun'(0)=ioπ2,  p=un'(j-1)

Questo è molto simile all'implementazione del terzo esempio (con φ=p e θ=t) - tranne che scelgo io e j entro intervalli più grandi per evitare la moltiplicazione (con 2) in seguito.


1
Non ho molta familiarità con questo linguaggio, ma sembra che tu usi i galleggianti casuali tra 0e 1direttamente come coordinate sferiche. Questo non è corretto, come mostrato nelle osservazioni 3 e 4 della sfida, poiché si finisce con una propensione verso i poli della sfera. Puoi correggerlo applicando il metodo mostrato nell'osservazione 4.
Jitse

Grazie! Totalmente perso quello. Risolto il bug e aggiornato la mia risposta
Saswat Padhi il

1
Sembra buono! Molto bella la prima risposta!
Jitse il

Grazie :) Sono stato in grado di ridurlo a meno di 100 byte!
Saswat Padhi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.