3 ms·
I'm still on the far low end of the curve, but APL (I prefer APL due to its non-ASCIIness) has quite a beauty in it. For "play" I wrote a sample for a normal di
by RBerenguel 12y ago
I'm still on the far low end of the curve, but APL (I prefer APL due to its non-ASCIIness) has quite a beauty in it. For "play" I wrote a sample for a normal distribution (using Box-Müller, since it was simpler than other, faster algorithms.) Here's the code (u is a function returning a sample from a uniform between 0 and 1, so just calling u is a random number in [0,1]). The only non-self evident bits would be →(s≥1)/ (which means if s greater than 1, jump to whatever label is after the slash) and ⍟var which is Pi times var. APL is really neat, and this is not even an example of a nice, array-oriented algorithm.
∇a←norm;uu;vv;s
⍝ Normal distribution around 0 (using the Box-Muller transform in polar form
⍝ Local variables go in the header after semicolons
CHOOSE:
uu←u
vv←u
s←(uu * 2)+vv * 2
→(s≥1)/CHOOSE
→(s=0)/CHOOSE
m←(((¯2×⍟s)÷s) * 0.5)
a←uu×m
∇
Edit: forgot to format
- gjm11 12y agoOther things that are non-self-evident except to people already familiar with APL: * means exponentiation, not multiplication; and "⍟var which is Pi times var" is incorrect: it's actually log(var). I have to confess that I don't find this sort of example very compelling; Box-Muller isn't much more than a one-liner in any language. I mean, here it is in C, not noted for its richly expressive terseness: double norm(void) { while (1) { double u=rand01(), v=rand01(); double s = u*u+v*v; if (0 < s && s <= 1) return u * sqrt(-2*log(s)/s); } } (I assumed that we already had a rand01() function equivalent to your "u"; I suggest that in any nontrivial program the gain in brevity from the single-character name is outweighed by being unable to call a local variable "u" and, if you have a bunch of these, the cognitive load of remembering what all the single-character names mean.) I bet the C implementation is distinctly easier to make sense of for most mathematicians and most programmers, and it's not even substantially longer. (APL: 94 non-blank characters. C: 111 non-blank characters. I remark that counting non-blank characters is about as favourable a metric for APL as one can reasonably ask for.) One can code-golf it further: combine the declaration of u,v with that of s (saves 5 non-blank characters --> 106); switch to your "u" instead of my "rand01" and rename u,v to (say) x,y (saves 10 characters --> 96); convert to do/while and use commas instead of {;;;} for body (saves 4 characters -> 92). That looks like this, and I think is still pretty easy to read: double norm(void) { double x,y,s; do x=u(), y=u(), s=x*x+y*y; while (s==0 || s>1); return x*sqrt(-2*log(s)/s); } (Note: character-counting is by hand and it's entirely possible I'm out by a couple of chars either way.) [EDITED to fix formatting screwage; aargh, I hate HN's treatment of asterisks]
- RBerenguel 12y agoYou are right, π times is the monadic "circle" function... Still trying to learn fluently all operators. And indeed, it's not a specially good example, but I don't have a lot of APL code written (the "nicest" being a Mandelbrot set one-liner), the "longest" being this one and a function to generate histograms, but way harder to read, since it uses quite a few operators: ∇a←n hist x ⍝ Histogram data from x in n buckets s←x[⍋ x] mx←¯1 ↑ s mn←1 ↑ s bk←mn+(⍳n)×(mx-mn)÷n a←+/(~(↑bk)<s) s←((↑bk)<s)/s bk←1↓bk LOOP:→(0=⍴bk)/END a←a,+/(~(↑bk)<s) s←((↑bk)<s)/s bk←1↓bk →LOOP END: ∇ Not brilliant, and even at the time of writing (5 or 6 months ago) I had the feeling it may be possible to write it loopless or close enough. Variables in this one are still "global" since (even if it works) I was still checking it for possible bugs.