NetLogo : How to make sure a variable stays in a defined range?
As you've discovered, random-normal
can be problematic because the result you get back can be literally any number.
One possible solution is to clamp the output of random-normal
within boundaries, as in Matt's answer. Note that this approach creates spikes at the boundaries of the range:
observer> clear-plot set-plot-pen-interval 0.01 set-plot-x-range -0.1 1.1
observer> histogram n-values 1000000 [ median (list 0 (random-normal 0.5 0.2) 1) ]
Another possible solution, as Marzy describes in the question itself, is to discard any out-of-bounds results random-normal
gives you and just keeping trying again until you get an in-bounds result. This avoids the spikes at the boundaries:
to-report random-normal-in-bounds [mid dev mmin mmax]
let result random-normal mid dev
if result < mmin or result > mmax
[ report random-normal-in-bounds mid dev mmin mmax ]
report result
end
observer> clear-plot set-plot-pen-interval 0.01 set-plot-x-range -0.1 1.1
observer> histogram n-values 1000000 [ random-normal-in-bounds 0.5 0.2 0 1 ]
Another solution is to ask yourself whether you really need a bell curve, or whether a triangle-shaped distribution would be just fine. You can get a triangle-shaped distribution of results very simply just by summing two calls to random-float
:
observer> clear-plot set-plot-pen-interval 0.01 set-plot-x-range 0 1
observer> histogram n-values 10000000 [ 0.5 + random-float 0.5 - random-float 0.5 ]
My favorite trick is this:
set x median (list 0 (y) 1)
Where y
is the random number (or put in an expression), 0
is the minimum, and 1
is the maximum.
It works because if y
is greater than 1
, then the median will be 1
. If y
is less than 0
, then the median will be 0
. Otherwise the median is y
.
For example, here is the random number in your example clamped to the range [0, 1]:
to test
let b median (list 0 (random-normal 0.5 0.1) 1)
print b
end
Answering very late to add another option for future seekers...
Another option if you're looking for a distribution that is bell-shaped like a normal distribution, but bounded, the Beta distribution can be a good choice. If you use parameters like 3,3 or 4,4, it looks a lot like a Normal distribution, but won't have any out-of-bounds values (it scales from 0 to 1, so it may have to be moved/scaled like you would a normal).
Netlogo doesn't have a built-in Beta, but you can get it from drawing from the built-in gamma twice, like this:
to-report random-beta [ #shape1 #shape2 ]
let Xa random-gamma #shape1 1
let Xb random-gamma #shape2 1
report Xa / (Xa + Xb)
end
For more mathematical detail, see: https://math.stackexchange.com/questions/190670/how-exactly-are-the-beta-and-gamma-distributions-related