Die Herausforderung
Schreiben Sie ein Programm oder eine Funktion, die keine Eingabe akzeptiert und einen Vektor der Länge in einer theoretisch einheitlichen Zufallsrichtung ausgibt .
Dies entspricht einem zufälligen Punkt auf der Kugel, der durch
was zu einer Verteilung wie z
Ausgabe
Drei floats aus einer theoretisch gleichmäßigen Zufallsverteilung, für die die Gleichung für Genauigkeitsgrenzen gilt.
Herausforderungsbemerkungen
- Die Zufallsverteilung muss theoretisch gleichmäßig sein . Das heißt, wenn der Pseudozufallszahlengenerator durch ein echtes RNG aus den reellen Zahlen ersetzt würde, würde dies zu einer gleichmäßigen Zufallsverteilung der Punkte auf der Kugel führen.
- Das Erzeugen von drei Zufallszahlen aus einer Gleichverteilung und deren Normalisierung ist ungültig: In Richtung der Ecken des dreidimensionalen Raums besteht eine Tendenz.
- In ähnlicher Weise ist es ungültig, zwei Zufallszahlen aus einer gleichmäßigen Verteilung zu erzeugen und als Kugelkoordinaten zu verwenden: Es besteht eine Tendenz zu den Polen der Kugel.
- Die richtige Einheitlichkeit kann durch Algorithmen erreicht werden, einschließlich, aber nicht beschränkt auf:
- Generieren Sie drei Zufallszahlen , und aus einer normalen (Gaußschen) Verteilung um und normalisieren Sie sie.
- Generieren Sie drei Zufallszahlen , und aus einer Gleichverteilung im Bereich . Berechnen Sie die Länge des Vektors mit . Wenn dann, lehnen Sie den Vektor ab und erzeugen Sie eine neue Menge von Zahlen. Sonst, wenn , normalisiere den Vektor und gib das Ergebnis zurück.
- Erzeugen Sie aus einer Gleichverteilung im Bereich ( 0 , 1 ) zwei Zufallszahlen und und rechnen Sie sie wie folgt in Kugelkoordinaten um:so dass,unddurch x berechnet werden können
- Geben Sie in Ihrer Antwort eine kurze Beschreibung des von Ihnen verwendeten Algorithmus an.
- Lesen Sie mehr über die Auswahl von Kugelpunkten in MathWorld .
Ausgabebeispiele
[ 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]
Allgemeine Bemerkungen
- Das ist Code-Golf , also gewinnt die Antwort mit den wenigsten Bytes in jeder Sprache.
- Es gelten Standardregeln , E / A-Regeln und Regelungslücken .
- Bitte fügen Sie einen Try it Online- Link oder einen vergleichbaren Link hinzu, um die Funktionsweise Ihres Codes zu demonstrieren.
- Bitte begründen Sie Ihre Antwort mit einer Erklärung Ihres Codes.
pi/6 ≈ 0.5236
, eine Ausgabe zu produzieren. Das ist die Fläche der Kugel, die in den EinheitsflächenwürfelAntworten:
Wolfram Language (Mathematica), 20 bytes
Try it online!
Does exactly what it says on the tin.
quelle
R, 23 bytes
Try it online!
Generates 3 realizations of theN(0,1) distribution and normalizes the resulting vector.
Plot of 1000 realizations:
quelle
x86-64 Machine Code -
63 62 5549 bytesUses the second algorithm, modified. Returns vector of
[x, y, z, 0]
in xmm0.Explanation:
Pushes the value for 1 and 2^31 as a float to the stack. The data overlap due to the sign extension, saving a few bytes.
vbroadcastss xmm1,dword ptr [rsp+5]
Loads the value for 2^31 into 4 positions of xmm1.Generates random 32-bit integer and loads it to bottom of xmm0.
Generates a random 32 bit integer, convert it to float (signed) and divide by 2^31 to get numbers between -1 and 1.
vdpps xmm2,xmm0,xmm0,7Fh
adds the squares of the lower 3 floats using a dot product by itself, masking out the top float. This gives the lengthCompares the length squared with 1 and rejects the values if it is not equal to 1. If the length squared is one, then the length is also one. That means the vector is already normalised and saves a square root and divide.
Restore the stack.
ret
returns value in xmm0Try it Online.
quelle
aesenc
to produce 128 "random" bits is just beautiful.Python 2, 86 bytes
Try it online!
Generates the z-coordinate uniformly from -1 to 1. Then the x and y coordinates are sampled uniformly on a circle of radius
(1-z*z)**.5
.It might not be obvious that the spherical distribution is in factor uniform over the z coordinate (and so over every coordinate). This is something special for dimension 3. See this proof that the surface area of a horizontal slice of a sphere is proportional to its height. Although slices near the equator have a bigger radius, slices near the pole are titled inward more, and it turns out these two effects exactly cancel.
To generate a random angle on this circle, we raise the imaginary unit
1j
to a uniformly random power between 0 and 4, which saves us from needing trig functions, pi, or e, any of which would need an import. We then extract the real imaginary part. If we can output a complex number for two of the coordinates, the last line could just beprint a,z
.86 bytes
Try it online!
Generates three normals and scales the result.
Python 2 with numpy, 57 bytes
Try it online!
sum(a*a)**.5
is shorter thanlinalg.norm(a)
. We could also dodot(a,a)
for the same length assum(a*a)
. In Python 3, this can be shortened toa@a
using the new operator@
.quelle
z
, from a uniform distribution, is left unmodified.z
though, and fixed that for a few bytes.Octave,
40 3322 bytesWe sample form a 3d standard normal distribution and normalize the vector:
Try it online!
quelle
disp
:)Unity C#, 34 bytes
Unity has a builtin for unit sphere random values, so I thought I'd post it.
quelle
f=>Random.onUnitSphere
f
's Type; usingvar
only works inside a method andSystem.Func<Vector3>
was longer.f=>Random.onUnitSphere
is a perfectly valid submissionf=>UnityEngine.Random.onUnitSphere
saves you theusing
MATL, 10 bytes
Try it online!
Explanation
This uses the first approach described in the challenge.
quelle
Ruby,
34 5049 bytesTry it online!
Returns an array of 3 numbers
[z,y,x]
.x
andy
are generated by raisingi
(square root of -1) to a random power between 0 and 4. This complex number needs to be scaled appropriately according to thez
value in accordance with Pythagoras theorem:(x**2 + y**2) + z**2 = 1.
The
z
coordinate (which is generated first) is simply a uniformly distributed number between -1 and 1. Though not immediately obvious, dA/dz for a slice through a sphere is constant (and equal to the perimeter of a circle of the same radius as the whole sphere.) .This was apparently discovered by Archimedes who described it in a very non-calculus-like way, and it is known as Archimedes Hat-Box theorem. See https://brilliant.org/wiki/surface-area-sphere/
Another reference from comments on xnor's answer. A surprisingly short URL, describing a surprisingly simple formula: http://mathworld.wolfram.com/Zone.html
quelle
[z, x+yi]
I'll leave it as it is unless you say that's OK.z*z
instead ofz**2
?z*z
. I've edited it in now. The other thing I could do is replacerand*4
with something likez*99
orx*9E9
(effectively limiting the possible values to a very fine spiral on the sphere) but I think that reduces the quality of the random.05AB1E,
2322 bytesImplements the 2nd algorithm.
Try it online or get a few more random outputs.
Explanation:
NOTE: 05AB1E doesn't have a builtin to get a random decimal value in the range[0,1) . Instead, I create a list in increments of 0.00001 , and pick random values from that list. This increment could be changed to 0.000000001 by changing the
5
to9
in the code (although it would become rather slow..).quelle
TI-BASIC, 15 bytes *
Using the algorithm "generate 3 normally distributed values and normalize that vector".
Ending a program with an expression automatically prints the result on the Homescreen after the program terminates, so the result is actually shown, not just generated and blackholed.
*:
randNorm(
is a two-byte token, the rest are one-byte tokens. I've counted the initial (unavoidable):
, without that it would be 14 bytes. Saved as a program with a one-letter name, it takes 24 bytes of memory, which includes the 9 bytes of file-system overhead.quelle
JavaScript (ES7),
77 7675 bytesImplements the 3rd algorithm, usingsin(ϕ)=sin(cos−1(z))=1−z2−−−−−√ .
Try it online!
Commented
JavaScript (ES6), 79 bytes
Implements the 2nd algorithm.
Try it online!
Commented
quelle
Processing 26 bytes
Full program
This is the implementation https://github.com/processing/processing/blob/master/core/src/processing/core/PVector.java
quelle
Python 2, 86 bytes
Try it online!
Implements the first algorithm.
Python 2,
107103 bytesTry it online!
Implements the second algorithm.
quelle
Haskell,
125123119118 bytesTry it online!
Does three uniforms randoms and rejection sampling.
quelle
JavaScript, 95 bytes
You
don'tneed not to inputa
.quelle
Julia 1.0, 24 bytes
Try it online!
Draws a vector of 3 values, drawn from a normal distribution around 0 with standard deviation 1. Then just normalizes them.
quelle
randn()
, from a couple of quick tests, doesn't seem to be bound to the required range. Also, this doesn't include a check forhypot()
returning a value>1
, which should be rejected.randn
simulates from a standard normal distribution rather than a uniform(0,1) one, so this approach is identical to the R one.[-1,1)
then dividing by them by the hypotenuse, which will be>1
, offsets that? That leads me to wonder if the ternary in my solution is necessary ...MathGolf,
211918 bytesImplementation of the 2nd algorithm.
Try it online or see a few more outputs at the same time.
Explanation:
quelle
Java 8 (@Arnauld's modified 3rd algorithm),
131126119111109 bytesPort of @Arnauld's JavaScript answer, so make sure to upvote him!
-2 bytes thanks to @OlivierGrégoire.
This is implemented as:
Try it online.
Previous 3rd algorithm implementation (
131126119 bytes):Implemented as:
Try it online.
Explanation:
Java 8 (2nd algorithm),
153143 bytesTry it online.
2nd algorithm:
quelle
sqrt(1-k*k)
actually saves more bytes in Java than it does in JS. :)M.sin
, 1xM.cos
and 1xM.acos
, your approach uses 2xM.sin
and 1xM.sqrt
, which is where the additional saved bytes mostly come from. :)double[]
as that doesn't change the byte-count.)Japt, 20 bytes
Port of Arnauld's implementation of the 2nd algorithm.
Test it
quelle
Pyth, 24 bytes
Try it online!
Uses algorithm #2
quelle
OCaml,
1109995 bytesEDIT: Shaved off some bytes by inliningi and j , replacing the first
let ... in
with afun
, and taking advantage of operator associativity to avoid some parens()
.Try it online
Original solution:
First I define:
OCaml's
Random.float
function includes the bounds. Then,This is very similar to the 3rd example implementation (withϕ=p and θ=t ) − except that I pick i and j within larger intervals to avoid multiplication (with 2) later on.
quelle
0
and1
directly as spherical coordinates. This is incorrect, as shown in the challenge remarks 3 and 4, since you end up with a bias towards the poles of the sphere. You can correct this by applying the method shown in remark 4.