Testing random numbers, as in simulating throwing a dice:
proc roll {} { set seed [expr {[clock clicks] + [pid] + [clock seconds]}] set seed [expr {$seed - ($seed * 2)}] #set seed [expr sqrt($seed)] expr (srand ($seed)) set seed 0 set number [expr {rand() * 6}] return [set number [expr {round($number)}]] } set ::a 0 set ::1 0 set ::2 0 set ::3 0 set ::4 0 set ::5 0 set ::6 0 proc statistics {} { set a 0 while {$a != 100000} { set roll [roll] while {$roll == 0} { set roll [roll] } foreach value {1 2 3 4 5 6} { if {$value == $roll} { incr ::$value } } incr a } set a 0 puts ">1= $::1" puts ">2= $::2" puts ">3= $::3" puts ">4= $::4" puts ">5= $::5" puts ">6= $::6" set ::1 0 set ::2 0 set ::3 0 set ::4 0 set ::5 0 set ::6 0 }
This snippet of code should produce random numbers in the range of 1-6, but if you apply a large enough sample, you notice that the output becomes rather predictable. The generator tends to favor 3 and 4 in this instance, and favors 1 rather than 6. This might have something to do with the way round() handles its math, but given the source code above, theres a rather large degree of predictability going on. If I were a gambler Id have my money on 3 everytime.
100000 >1= 17471 >2= 6785 >3= 25872 >4= 24633 >5= 19663 >6= 5576 100000 >1= 17226 >2= 7011 >3= 25862 >4= 25001 >5= 19008 >6= 5892 100000 >1= 17361 >2= 7183 >3= 24947 >4= 24568 >5= 19996 >6= 5945
originally created by Davou
AM 2007-02-15: Why do you seed and reseed rand() every time? That is not the proper way to use rand(). I think much of the non-randomness you are experiencing could be attributed to that (the seeds tend to be correlated!)
MS Notes that there is one more problem with that code: you should not use round(), use round(ceil()) instead. The reason is that
expr {6*rand()}
will produce numbers uniformly distributed in (0,6). Rounding them, you get
(0,0.5) -> 0 (0.5,1.5) -> 1 (1.5,2.5) -> 2 ... (4.5,5.5) -> 5 (5.5,6) -> 6
In other words: you would get a whole lot of zeros (which you are not counting), and half as many sixes as the other numbers.
So: do not reseed at each call (as noted by AM), and use instead
proc roll {} { expr {round(ceil(rand()*6))} }
and see the stats behave rather well.
CJL couldn't resist reducing the code, while maintaining the original structural theme so that the original author can appreciate the differences:
proc roll {} { expr {1+int(6*rand())} } proc statistics {} { set 1 0 set 2 0 set 3 0 set 4 0 set 5 0 set 6 0 set a 0 while {$a != 100000} { incr [roll] incr a } puts ">1= $1" puts ">2= $2" puts ">3= $3" puts ">4= $4" puts ">5= $5" puts ">6= $6" }
A few inefficiencies that have been removed:
slebetman: For the sake of completeness here's a sampling of the results of the new code above:
% statistics >1= 16553 >2= 16593 >3= 16951 >4= 16518 >5= 16544 >6= 16841 % statistics >1= 16783 >2= 16536 >3= 16731 >4= 16691 >5= 16597 >6= 16662 % statistics >1= 16496 >2= 16813 >3= 16697 >4= 16700 >5= 16601 >6= 16693
Looks good to me.
EB: you get better distribution with rand() when multiplying by a large value and then using modulo:
set n [expr {round(rand()*65535)%6+1}]