Titik acak pada sebuah bola


31

Tantangan

Tulis sebuah program atau fungsi yang tidak membutuhkan input dan menghasilkan vektor dengan panjang dalam arah acak yang seragam secara teoritis .1

Ini sama dengan titik acak pada bola yang dijelaskan oleh

x2+y2+z2=1

menghasilkan distribusi seperti itu

Distribusi acak titik-titik pada bola dengan jari-jari 1.

Keluaran

Tiga mengapung dari distribusi acak yang seragam secara teoritis yang persamaan x2+y2+z2=1 berlaku untuk batas presisi.

Komentar tantangan

  • Distribusi acak harus seragam secara teori . Artinya, jika generator bilangan pseudo-acak harus diganti dengan RNG sejati dari bilangan real , itu akan menghasilkan distribusi acak yang seragam dari titik-titik di bola.
  • Menghasilkan tiga angka acak dari distribusi seragam dan menormalkannya tidak valid: akan ada bias terhadap sudut ruang tiga dimensi.
  • Demikian pula, menghasilkan dua angka acak dari distribusi seragam dan menggunakannya sebagai koordinat bola tidak valid: akan ada bias terhadap kutub bola.
  • Keseragaman yang tepat dapat dicapai oleh algoritma termasuk tetapi tidak terbatas pada:
    • Hasilkan tiga angka acak , dan dari distribusi normal (Gaussian) sekitar dan normalkan kembali. xyz00
    • Hasilkan tiga angka acak , dan dari distribusi seragam dalam kisaran . Hitung panjang vektor dengan . Kemudian, jika , tolak vektor dan hasilkan seperangkat angka baru. Lain, jika , normalkan vektor dan kembalikan hasilnya. xyz( - 1 , 1 ) l = (1,1)l=x2+y2+z2l>1l1
    • Hasilkan dua angka acak dan dari distribusi seragam dalam kisaran dan konversikan menjadi koordinat bola seperti: sehingga , dan dapat dihitung denganij( 0 , 1 ) θ(0,1)
      θ=2×π×iϕ=cos1(2×j1)
      xyz
      x=cos(θ)×sin(ϕ)y=sin(θ)×sin(ϕ)z=cos(ϕ)
  • Berikan jawaban singkat tentang algoritma yang Anda gunakan di jawaban Anda.
  • Baca lebih lanjut tentang memilih sphere point di MathWorld .

Contoh keluaran

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

Komentar umum

  • Ini adalah , jadi jawabannya menggunakan byte paling sedikit di setiap bahasa yang menang.
  • Aturan standar , aturan I / O, dan aturan celah berlaku.
  • Harap sertakan tautan Cobalah Online atau yang setara untuk menunjukkan bahwa kode Anda berfungsi.
  • Harap motivasikan jawaban Anda dengan penjelasan kode Anda.

Apakah saya boleh memilih 3 real secara seragam dalam [-1, 1], lalu menolaknya (dan ulangi) jika jumlah kuadratnya bukan 1?
Grimmy

6
@Grimy Saya suka celah itu. Tidak, itu tidak diperbolehkan, karena secara teoritis tidak ada peluang untuk output apa pun.
Jitse

Bukankah saran @ Grimy mirip dengan implementasi contoh kedua yang Anda sebutkan? Solusi itu secara teoritis juga tidak memiliki peluang untuk menghasilkan keluaran apa pun
Saswat Padhi

2
@SaswatPadhi Tidak, yang memiliki peluang pi/6 ≈ 0.5236menghasilkan output. Itulah area bola yang tertulis dalam kubus unit-area
Luis Mendo

1
@LuisMendo, begitu. Probabilitasnya adalah ~ 0,5 dalam kasus itu, seperti yang Anda sebutkan. Untuk proposal Grimy, itu ~ 0.
Saswat Padhi

Jawaban:



24

R , 23 byte

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

Cobalah online!

Menghasilkan 3 realisasi dari distribusi dan menormalkan vektor yang dihasilkan.N(0,1)

Plot 1000 realisasi:

masukkan deskripsi gambar di sini


2
Bisakah Anda membenarkan 3 sumbu yang terdistribusi secara normal menghasilkan distribusi yang seragam di atas bola? (Saya tidak melihatnya)
Jeffrey mendukung Monica

4
@ Jeffrey Ini cukup terkenal dalam probabilitas / statistik; tetapi bukti untuk 2D (yang meluas dengan rapi hingga 3 dimensi) kira-kira: misalkan dan independen. Kemudian dan , jadi dengan independensi mana , jadi jelas bahwa distribusi hanya bergantung pada besarnya , dan dengan demikian arahnya terdistribusi secara seragam. f X ( x ) = K e - 1X,YN(0,1)fY(y)=Ke-1fX(x)=Ke12x2fXY(x,y)=K2e-1fY(y)=Ke12y2fXY(x,y)=K2e12(x2+y2)=fZ(z)=K2e12z2z=(x,y)zz
Giuseppe

1
Jadi, distribusi normal memberi kita titik - titik yang terdistribusi secara merata di sekitar lingkaran, dan membaginya dengan besarnya memastikan titik-titik itu terletak pada lingkaran
Giuseppe

23

x86-64 Kode Mesin - 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  

Menggunakan algoritma kedua, dimodifikasi. Mengembalikan vektor [x, y, z, 0]dalam xmm0.

Penjelasan:

push 4Fh
push 3f800000h

Mendorong nilai untuk 1 dan 2 ^ 31 sebagai pelampung ke tumpukan. Data tumpang tindih karena ekstensi tanda, menghemat beberapa byte.

vbroadcastss xmm1,dword ptr [rsp+5] Memuat nilai untuk 2 ^ 31 ke dalam 4 posisi xmm1.

rdrand      eax  
jnc         rand  
movd        xmm0,eax

Menghasilkan bilangan bulat 32-bit acak dan memuatnya ke bawah xmm0.

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

Menghasilkan bilangan bulat 32 bit acak, mengonversinya menjadi float (ditandatangani) dan dibagi 2 ^ 31 untuk mendapatkan angka antara -1 dan 1.

vdpps xmm2,xmm0,xmm0,7Fhmenambahkan kuadrat dari 3 float bawah menggunakan produk titik dengan sendirinya, menutupi float atas. Ini memberi panjang

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

Membandingkan panjang kuadrat dengan 1 dan menolak nilai jika tidak sama dengan 1. Jika panjang kuadrat adalah satu, maka panjangnya juga satu. Itu berarti vektor sudah dinormalisasi dan menyimpan akar kuadrat dan membelah.

pop         rax  
pop         rax 

Kembalikan tumpukan.

ret mengembalikan nilai dalam xmm0

Cobalah secara Online .


7
+1 Menggunakan aesencuntuk menghasilkan 128 bit "acak" sungguh indah.
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

Cobalah online!

Menghasilkan koordinat z secara seragam dari -1 hingga 1. Kemudian koordinat x dan y disampel secara seragam pada lingkaran jari-jari (1-z*z)**.5.

Mungkin tidak jelas bahwa distribusi bola berseragam faktor di atas koordinat z (dan juga untuk setiap koordinat). Ini adalah sesuatu yang istimewa untuk dimensi 3. Lihat bukti ini bahwa luas permukaan irisan horizontal bola sebanding dengan tingginya. Meskipun irisan di dekat khatulistiwa memiliki jari-jari lebih besar, irisan di dekat kutub diberi judul lebih ke dalam, dan ternyata kedua efek ini benar-benar membatalkan.

Untuk menghasilkan sudut acak pada lingkaran ini, kami menaikkan unit imajiner 1jke kekuatan acak yang seragam antara 0 dan 4, yang menyelamatkan kita dari kebutuhan akan fungsi trigonometri, pi, atau e, yang semuanya membutuhkan impor. Kami kemudian mengekstrak bagian imajiner nyata. Jika kita dapat menampilkan bilangan kompleks untuk dua koordinat, baris terakhir bisa saja 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

Cobalah online!

Menghasilkan tiga normals dan mengukur hasilnya.


Python 2 dengan numpy, 57 byte

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

Cobalah online!

sum(a*a)**.5lebih pendek dari linalg.norm(a). Kita juga bisa melakukan dot(a,a)dengan panjang yang sama sum(a*a). Dalam Python 3, ini dapat disingkat a@amenggunakan operator baru @.


1
Saya suka pendekatan pertama Anda. Saya mengalami kesulitan memahami bagaimana bias terhadap khatulistiwa dihindari jika z, dari distribusi yang seragam, dibiarkan tidak dimodifikasi.
Jitse

2
@ Jitse Distribusi bola dalam seragam faktor atas setiap koordinat. Ini adalah sesuatu yang spesial untuk dimensi 3. Lihat misalnya bukti ini bahwa luas permukaan sepotong bola sebanding dengan tingginya. Mengenai intuisi bahwa ini bias ke ekuator, perhatikan bahwa sementara irisan di dekat ekuator memiliki jari-jari lebih besar, irisan di dekat kutub diberi judul lebih ke dalam yang memberi lebih banyak area, dan ternyata kedua efek ini benar-benar membatalkan.
xnor

Sangat bagus! Terima kasih atas klarifikasi dan referensi.
Jitse

@Jitse Terima kasih, saya menambahkannya ke tubuh. Namun saya menyadari bahwa saya hanya mengambil sampel positif z, dan memperbaikinya selama beberapa byte.
xnor

1
@ Jitse Memang, luas permukaan bola sama dengan luas permukaan lateral silinder penutup!
Neil

13

Oktaf , 40 33 22 byte

Kami sampel membentuk distribusi normal standar 3d dan menormalkan vektor:

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

Cobalah online!


Untuk Oktaf saja (yaitu bukan MATLAB), Anda dapat menyimpan byte dengan ini
Tom Carpenter

1
@TomCarpenter Terima kasih! Dalam hal ini karena hanya satu ekspresi kita bahkan dapat menghilangkan disp:)
flawr

10

Unity C # , 34 byte

f=>UnityEngine.Random.onUnitSphere

Unity memiliki builtin untuk nilai acak unit sphere, jadi saya pikir saya akan mempostingnya.


Baik penggunaan built in +1, Anda bisa mengirimkan fungsi menjadi sedikit lebih pendekf=>Random.onUnitSphere
LiefdeWen

@LiefdeKetika saya tahu tentang lambdas, saya hanya tidak yakin apakah itu sudah cukup (dalam hal validitas pada Code Golf) karena tidak menyatakan fTipe; varhanya menggunakan karya di dalam metode dan System.Func<Vector3>lebih lama.
Draco18s

1
Dalam codegolf mengembalikan suatu fungsi baik-baik saja, dan Anda tidak harus menghitung deklarasi baik yang berarti Anda dapat melakukan hal-hal licik dengan parameter dinamis. Anda juga tidak menghitung titik koma terakhir. Namun Anda menghitung semua menggunakan pernyataan yang Anda tambahkan. jadi jumlah byte Anda perlu menyertakan penggunaan. Tetapi f=>Random.onUnitSphereini adalah pengiriman yang benar-benar valid
LiefdeWen

@LiefdeWen Ya, saya hanya tidak yakin bagaimana deklarasi itu ditangani dan tidak benar-benar merasa ingin "mencari meta."
Draco18s

f=>UnityEngine.Random.onUnitSpheremenghemat Andausing
Orace

6

MATL , 10 byte

1&3Xrt2&|/

Cobalah online!

Penjelasan

Ini menggunakan pendekatan pertama yang dijelaskan dalam tantangan.

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

Ruby , 34 50 49 byte

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

Cobalah online!

Mengembalikan array 3 angka [z,y,x].

xdan ydihasilkan dengan menaikkan i(akar kuadrat dari -1) ke kekuatan acak antara 0 dan 4. Angka kompleks ini perlu diskalakan sesuai dengan znilai yang sesuai dengan teorema Pythagoras:(x**2 + y**2) + z**2 = 1.

The zkoordinat (yang dihasilkan pertama) hanyalah sebuah nomor terdistribusi secara merata antara -1 dan 1. Meskipun tidak segera jelas, dA / dz untuk sepotong melalui bola adalah konstan (dan sama untuk perimeter lingkaran radius yang sama seperti seluruh bola.).

Ini rupanya ditemukan oleh Archimedes yang menggambarkannya dengan cara yang sangat tidak mirip kalkulus, dan dikenal sebagai teorema Archimedes Hat-Box. Lihat https://brilliant.org/wiki/surface-area-sphere/

Referensi lain dari komentar pada jawaban xnor. URL yang sangat pendek, menggambarkan formula sederhana yang mengejutkan: http://mathworld.wolfram.com/Zone.html


@Jitse saya lupa untuk memperkecil x dan y pada nilai z yang tinggi. Secara efektif titik menentukan silinder. Sudah diperbaiki sekarang tapi harganya banyak byte! Saya bisa menghemat beberapa jika outputnya dapat diekspresikan dengan angka kompleks [z, x+yi]saya akan membiarkannya apa adanya kecuali Anda mengatakan itu OK.
Level River St

Kelihatan bagus! Saya sangat suka pendekatan ini. Untuk konsistensi, output yang diperlukan adalah tiga mengapung, jadi saya sarankan membiarkannya seperti ini.
Jitse

Mengapa tidak menggunakan z*zbukan z**2?
Value Ink

@ ValueInk ya terima kasih, saya menyadari bahwa saya telah melewatkannya z*z. Saya sudah mengeditnya sekarang. Hal lain yang bisa saya lakukan adalah mengganti rand*4dengan sesuatu seperti z*99atau x*9E9(secara efektif membatasi nilai yang mungkin untuk spiral yang sangat halus pada bola) tetapi saya pikir itu mengurangi kualitas acak.
Level River St

4

05AB1E , 23 22 byte

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

Menerapkan algoritma ke-2.

Cobalah online atau dapatkan beberapa keluaran acak .

Penjelasan:

CATATAN: 05AB1E tidak memiliki builtin untuk mendapatkan nilai desimal acak dalam kisaran . Sebagai gantinya, saya membuat daftar dengan peningkatan , dan memilih nilai acak dari daftar itu. Peningkatan ini dapat diubah menjadi dengan mengubah ke dalam kode (meskipun itu akan menjadi agak lambat ..).[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
Menggunakan sama dengan . Satu-satunya kriteria untuk adalah . Anda mungkin juga menerima vektor dengan jika akan menghemat byte. Nilai apa pun yang lebih kecil dari atau sama dengan menghapus bias. l<1l1lx0<x1l<0.51
Jitse

@ Jitse Ok, menerapkan normalisasi pada jawaban Java dan 05AB1E saya. Saya harap semuanya benar sekarang.
Kevin Cruijssen

@Jitse Sebenarnya menyimpan byte dengan memeriksa sebagai , bukan . Tetapi terima kasih atas klarifikasi bahwa hanya merupakan persyaratan, dan tidak ada persyaratan ketat pada , asalkan . v1v==1v<10<x1l1
Kevin Cruijssen

4

TI-BASIC, 15 byte *

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

Menggunakan algoritma "menghasilkan 3 nilai yang didistribusikan secara normal dan menormalkan vektor itu".

Mengakhiri program dengan ekspresi secara otomatis mencetak hasil pada Homescreen setelah program berakhir, sehingga hasilnya benar-benar ditampilkan, bukan hanya dihasilkan dan dihitamkan.

*: randNorm(adalah token dua byte , sisanya adalah token satu byte . Saya sudah menghitung awal (tidak dapat dihindari) :, tanpa itu akan menjadi 14 byte. Disimpan sebagai program dengan nama satu huruf, dibutuhkan 24 byte memori, yang mencakup 9 byte overhead sistem file.


3

JavaScript (ES7),  77 76  75 byte

Menerapkan algoritma 3 rd , menggunakan .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]

Cobalah online!

Berkomentar

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

Menerapkan algoritma 2 nd .

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

Cobalah online!

Berkomentar

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

Memproses 26 byte

Program lengkap

print(PVector.random3D());

Ini adalah implementasi 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
Anda mungkin ingin membuatnya lebih jelas bahwa implementasi bukan bagian dari jumlah byte Anda. Saya melewatkannya pada bacaan pertama, lalu melakukan pengambilan ganda.
Level River St

Saya suka bahwa implementasi pada dasarnya menggunakan pendekatan yang sama dengan saya, meskipun
Level River 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

Cobalah online!

Menerapkan algoritma pertama.


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

Cobalah online!

Menerapkan algoritma kedua.


2
@RobinRyder Implementasi ini menolak vektor dengan panjang awal> 1, yang valid sebagaimana ditentukan dalam tantangan.
Jitse

@ Just Right, maaf. Saya salah membaca kode.
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]

Cobalah online!

Apakah tiga seragam seragam dan sampel penolakan.


Sepertinya tebaran Anda berasal dari distribusi (0,1), bukan (-1,1), sehingga hanya 1/8 bola yang tercakup.
Jitse

@ Jitse Gotcha, terima kasih sudah memperhatikan.
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)

Anda tidak perlu untuk tidak memasukkan a.


Wow, aku benar-benar merindukan itu. Tetap.
Naruyoko

2

Julia 1.0 , 24 byte

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

Cobalah online!

Menarik vektor dari 3 nilai, yang diambil dari distribusi normal sekitar 0 dengan standar deviasi 1. Kemudian normalkan saja.


randn(), dari beberapa tes cepat, tampaknya tidak terikat pada kisaran yang diperlukan. Juga, ini tidak termasuk cek untuk hypot()mengembalikan nilai >1, yang harus ditolak.
Shaggy

3
@ Shaggy akan muncul randnmensimulasikan dari distribusi normal standar daripada seragam (0,1), jadi pendekatan ini identik dengan yang R.
Giuseppe

@ Giuseppe Ya, persis!
user3263164

@ Giuseppe, saya pikir saya mungkin tidak memiliki pemahaman yang baik tentang matematika di balik tantangan ini, tetapi, jika saya memahami Anda dengan benar, Anda mengatakan bahwa jika ada pelampung yang berada di luar batas [-1,1)kemudian dibagi oleh mereka oleh hypotenuse, yang mana >1, offset itu? Itu membuat saya bertanya-tanya apakah ternary dalam solusi saya diperlukan ...
Shaggy

@Shaggy tidak, distribusi normal / Gaussian memiliki beberapa properti (khususnya, invarian rotasi) yang tidak dimiliki seragam, lihat komentar ini , misalnya
Giuseppe

2

MathGolf , 21 19 18 byte

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

Implementasi dari algoritma ke-2.

Cobalah secara online atau lihat beberapa keluaran lainnya secara bersamaan .

Penjelasan:

{              }▲   # 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 ( Algoritma ke-3 modifikasi @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;}

Port dari jawaban JavaScript @Arnauld , jadi pastikan untuk menghapusnya!
-2 byte terima kasih kepada @ OlivierGrégoire .

Ini diimplementasikan sebagai:

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

Cobalah online.

Implementasi algoritma 3 sebelumnya ( 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);}

Diimplementasikan sebagai:

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

Cobalah online.

Penjelasan:

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 (algoritme kedua), 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;}

Cobalah online.

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

Menggunakan sqrt(1-k*k)sebenarnya menghemat lebih banyak byte di Jawa daripada di JS. :)
Arnauld

@Arnauld Yap. Alih-alih 3x M.sin, 1x M.cosdan 1x M.acos, pendekatan Anda menggunakan 2x M.sindan 1x M.sqrt, yang merupakan asal tambahan byte yang disimpan. :)
Kevin Cruijssen

108 bytes Menggunakan algoritma ke-2 yang dimodifikasi di mana saya hanya mengizinkan nilai di mana s == 1 (bukan s <= 1 dan kemudian dinormalisasi). Terkadang memberikan jawaban tetapi sebagian besar tidak karena batas waktu. Sunting: Ups, saya lupa hasil Math.sqrt
Olivier Grégoire

Sebenarnya, tidak, tidak perlu sqrt karena sqrt (1) == 1. Jadi saya mendukung saran golf saya.
Olivier Grégoire

1
109 byte (Anda dapat menggunakan output string bukan double[]karena itu tidak mengubah byte-count.)
Olivier Grégoire

1

Japt , 20 byte

Implementasi Port of Arnauld untuk algoritma ke-2.

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

Menguji

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

Cobalah online!

Menggunakan algoritma # 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: Memotong beberapa byte dengan inlining dan , mengganti yang pertama dengan a , dan mengambil keuntungan dari asosiatif operator untuk menghindari beberapa paren .ijlet ... infun()

Cobalah online


Solusi asli:

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

Pertama saya mendefinisikan:

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

Random.floatFungsi OCaml termasuk batas. Kemudian,

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

Ini sangat mirip dengan implementasi contoh ke-3 (dengan dan ) kecuali bahwa saya memilih dan dalam interval yang lebih besar untuk menghindari perkalian (dengan 2) nanti.ϕ=pθ=tij


1
Saya tidak terlalu terbiasa dengan bahasa ini, tetapi sepertinya Anda menggunakan mengapung acak di antara 0dan 1langsung sebagai koordinat bola. Ini tidak benar, seperti yang diperlihatkan dalam tantangan 3 dan 4, karena Anda berakhir dengan bias terhadap kutub bola. Anda dapat memperbaikinya dengan menerapkan metode yang ditunjukkan pada komentar 4.
Jitse

Terima kasih! Benar-benar merindukan itu. Memperbaiki bug dan memperbarui jawaban saya
Saswat Padhi

1
Kelihatan bagus! Jawaban pertama yang sangat bagus!
Jitse

Terima kasih :) Saya bisa menguranginya menjadi di bawah-100 byte!
Saswat Padhi
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.