(until (is (len winset) set-count)
(let n (rand:1up top)
(if (>= n bottom) (insortnew < n winset))))
is not optimal.
Because, say if `bottom' is 30 and `top' is 40, in nearly the 3/4 of times, you'll call 'rand but not use the result, and you'll make a wasted loop turn.
A solution:
(def genWIN->Nums2 (set-count bottom top)
"Generates a list of `set-count' random numbers, each
in the range between `bottom' and `top' (inclusives).
The generation doesn't waste any CPU cycle :-)."
(let winset nil
(until (is (len winset) set-count)
(let n (rand (- (1up top) bottom))
(insortnew < (+ n bottom) winset)))
(prall:pretty-nums winset)))
The idea is, for `bottom'=30 and `top'=40, to get a random number between 0 and 11, and then add `bottom' to it.
That's awesome. I hadn't gone that far... and have yet to create any sort of habitual thinking around optimizations...
Need to think like you more.
Thanks.
T.
From what I've seen, the numbers should be fairly random.
It is often humans that misunderstand randomness, and not computers, as said in the linked article in CatDancer's post.
However, randomness is a complex issue in computing, and it's good to keep it in mind.
See for example:
$ man 3 rand # here on a linux system
[...]
NOTES
The versions of rand() and srand() in the Linux C Library use
the same random number generator as random(3) and srandom(3),
so the lower-order bits should be as random as the higher-order
bits.
However, on older rand() implementations, and on current
implementations on different systems, the lower-order bits are
much less random than the higher-order bits.
It means, on old systems, the situation is something like:
- rand() outputs a 4 bits integer, so the value goes from 0 to 15,
- if you do 'rand() % 10', there is a 2/16 probability you get a number in [0, 5],
and only 1/16 you get a number in [6, 9].
Mind if I ask where the other 13/16 went? Since rand() % 10 can only output 0-10 there are only 10 possibilities, all of which are covered in your two ranges.
Either people frequently have problems with statistics as well, or random numbers are really complicated ;)
Well, I'm totally not an expert in "randomness assisted by computer", I just know it's something, like cryptography, where you should be careful before implementing your own solution.
And I am bad in maths, and statistics/probas are so tricky (at least for me), you are right.
However, a code demonstration (in Perl, sorry, for perf/convenience):
# We fake a bad `rand()' function by only taking
# values between 0 and 15.
$cnt{rand(15) % 10} += 1 for (0..1_000_000);
print $_, "\t", $cnt{$_}, "\n" for (sort keys %cnt);
What you said is correct; the only problem is that with the numbers you quoted, the total probability of rolling a number in the range [0,10) is 2/16 + 1/16 = 3/16 < 1 :) The numbers you meant to quote, as borne out by your data above, are a 10/16 = 5/8 chance to get a number in the range [0,5), and a 6/16 = 3/8 chance to get a number in the range [6,10). (Equivalently, a 12/16 = 3/4 chance to get a number in the range [0,5] and a 4/16 = 1/4 chance to get a number in the range [6,9], but since that doesn't partition the [0,10) range evenly, it's less instructive.)