Hey there!
I have been playing with nim for a few days. Now I stumbled upon a behavior that I do not understand. :P
The random generator does not behave like I expect.
import random
randomize()
echo random(1280)
This should echo a "random" number between 0 and 1280 (-1) right? Well, it does, kind of.
nim c -r rnd.nim
1118
nim c -r rnd.nim
1117
nim c -r rnd.nim
1116
nim c -r rnd.nim
1116
nim c -r rnd.nim
1117
This one behaves more random:
import random
randomize()
for i in 1..10
echo random(1200)
nim c -r rnd.nim
841
1014
609
635
547
574
1171
233
280
595
nim c -r rnd.nim
780
275
1029
985
1143
865
686
97
945
858
nim c -r rnd.nim
793
166
604
244
338
868
482
281
173
7
Is there a smarter way to create a random number with min/max value?
The random module is not very good at all, sorry for that. But there is a mersenne twister in the standard library.
This is what I use. Upper bound is exclusive.
proc rand*(maxval: uint32): uint32 =
let limit = uint32(high(uint32)) - uint32(high(uint32)) mod maxval
var bits = rand_u32()
while bits > limit:
bits = rand_u32()
result = bits mod maxval
Thanks for the replies! :)
No I have been using nim-0.17.0 so far. But nice to see that this is a fixable thing. I'll look into that later today. :)
Edit// @bluenote I added your fix now, and the result looks much more random. Thanks for that!
proc rand*(maxval: uint32): uint32 =
let limit = uint32(high(uint32)) - uint32(high(uint32)) mod maxval
var bits = rand_u32()
while bits > limit:
bits = rand_u32()
result = bits mod maxval
Looks suspicious. high - high is 0, isn't it? And there are MUCH more effective ways than while bits > limit (super slow for small numbers?).
Depending on what you're using the random numbers for, I also have a library that makes use of system sources of random (arc4random on OpenBSD, RtlGenRandom on Windows and /dev/urandom elsewhere) that I've been working on: https://github.com/euantorano/sysrandom.nim
It could do with some more heavy testing, as I haven't used it outside of testing during development yet.