Cool, thanks — this sounds good! I’ll take some time this weekend to identify 
the specific lines (as you noted, it’s a nested randomizer that gets called 
quite a bit). Thanks for the catch on the line 15 error for T200s… I’ll run 
that through Virtual T since neither of my T200s are operational (and they’ll 
soon be on sale so someone can lovingly bring them back to life).

Cheers,
Steve


--
Greetings from Steve Baker (he/him/his)
“Gravity brings me down…”




> On Feb 8, 2024, at 8:08 PM, B 9 <[email protected]> wrote:
> 
> On Tue, Dec 26, 2023 at 4:36 PM Steve Baker <[email protected] 
> <mailto:[email protected]>> wrote:
> 
>> That was one of the hardest parts about writing that app — I did a lot of 
>> research about tips and tricks, and have a few nested randomizer routines in 
>> there to compensate. While I have not done a statistical study with a 
>> significant sample set, it kicks out dice rolls that are very random, and 
>> the folks that I play with feel comfortable with its results. The source 
>> code is available and I’d be happy to highlight the key bits (some upfront 
>> prep early in the code and most of the randomizer functions are towards the 
>> back, etc).
> 
> Steve,
> 
> I was curious how nesting the randomizer had affected the quality of the 
> randomization, so I poked around at the source code for DICEBOX. While I had 
> a lot of fun trying to weave my way through the tightly crunched code, in the 
> end I wasn't able to extract just the randomizer. Could you help me grok it? 
> Once the routine is extracted, I think your RNG might be useful for anyone 
> else who wants to reuse your work.
> 
> I've already written code that can do a check of RNG uniformity via the χ² 
> (chi squared) test on a Model T. (See attachment). It rolls a D sided die N 
> times and returns a probability p that the RNG is selecting every number 
> equally. I just need your routine at line 10000 which takes variable D 
> (number of sides) as input and outputs variable R (random integer from 1 to 
> D, inclusive).
> 
> —b9
> 
> P.S. On the Tandy 200, DICEBOX needs a line 15 GOTO 100 or it gives an error.
> 
> 
> --- CUT HERE ---
> 
> 0 GOTO 1000 REM RNG Tester by hackerb9
> 1 DATA 0.000, 0.000, 0.001, 0.004, 0.016, 2.706, 3.841, 5.024, 6.635, 7.879
> 2 DATA 0.010, 0.020, 0.051, 0.103, 0.211, 4.605, 5.991, 7.378, 9.210, 10.597
> 3 DATA 0.072, 0.115, 0.216, 0.352, 0.584, 6.251, 7.815, 9.348, 11.345, 12.838
> 4 DATA 0.207, 0.297, 0.484, 0.711, 1.064, 7.779, 9.488, 11.143, 13.277, 14.860
> 5 DATA 0.412, 0.554, 0.831, 1.145, 1.610, 9.236, 11.070, 12.833, 15.086, 
> 16.750
> 6 DATA 0.676, 0.872, 1.237, 1.635, 2.204, 10.645, 12.592, 14.449, 16.812, 
> 18.548
> 7 DATA 0.989, 1.239, 1.690, 2.167, 2.833, 12.017, 14.067, 16.013, 18.475, 
> 20.278
> 8 DATA 1.344, 1.646, 2.180, 2.733, 3.490, 13.362, 15.507, 17.535, 20.090, 
> 21.955
> 9 DATA 1.735, 2.088, 2.700, 3.325, 4.168, 14.684, 16.919, 19.023, 21.666, 
> 23.589
> 10 DATA 2.156, 2.558, 3.247, 3.940, 4.865, 15.987, 18.307, 20.483, 23.209, 
> 25.188
> 11 DATA 2.603, 3.053, 3.816, 4.575, 5.578, 17.275, 19.675, 21.920, 24.725, 
> 26.757
> 12 DATA 3.074, 3.571, 4.404, 5.226, 6.304, 18.549, 21.026, 23.337, 26.217, 
> 28.300
> 13 DATA 3.565, 4.107, 5.009, 5.892, 7.042, 19.812, 22.362, 24.736, 27.688, 
> 29.819
> 14 DATA 4.075, 4.660, 5.629, 6.571, 7.790, 21.064, 23.685, 26.119, 29.141, 
> 31.319
> 15 DATA 4.601, 5.229, 6.262, 7.261, 8.547, 22.307, 24.996, 27.488, 30.578, 
> 32.801
> 16 DATA 5.142, 5.812, 6.908, 7.962, 9.312, 23.542, 26.296, 28.845, 32.000, 
> 34.267
> 17 DATA 5.697, 6.408, 7.564, 8.672, 10.085, 24.769, 27.587, 30.191, 33.409, 
> 35.718
> 18 DATA 6.265, 7.015, 8.231, 9.390, 10.865, 25.989, 28.869, 31.526, 34.805, 
> 37.156
> 19 DATA 6.844, 7.633, 8.907, 10.117, 11.651, 27.204, 30.144, 32.852, 36.191, 
> 38.582
> 20 DATA 7.434, 8.260, 9.591, 10.851, 12.443, 28.412, 31.410, 34.170, 37.566, 
> 39.997
> 21 DATA 8.034, 8.897, 10.283, 11.591, 13.240, 29.615, 32.671, 35.479, 38.932, 
> 41.401
> 22 DATA 8.643, 9.542, 10.982, 12.338, 14.041, 30.813, 33.924, 36.781, 40.289, 
> 42.796
> 23 DATA 9.260, 10.196, 11.689, 13.091, 14.848, 32.007, 35.172, 38.076, 
> 41.638, 44.181
> 24 DATA 9.886, 10.856, 12.401, 13.848, 15.659, 33.196, 36.415, 39.364, 
> 42.980, 45.559
> 25 DATA 10.520, 11.524, 13.120, 14.611, 16.473, 34.382, 37.652, 40.646, 
> 44.314, 46.928
> 26 DATA 11.160, 12.198, 13.844, 15.379, 17.292, 35.563, 38.885, 41.923, 
> 45.642, 48.290
> 27 DATA 11.808, 12.879, 14.573, 16.151, 18.114, 36.741, 40.113, 43.195, 
> 46.963, 49.645
> 28 DATA 12.461, 13.565, 15.308, 16.928, 18.939, 37.916, 41.337, 44.461, 
> 48.278, 50.993
> 29 DATA 13.121, 14.256, 16.047, 17.708, 19.768, 39.087, 42.557, 45.722, 
> 49.588, 52.336
> 30 DATA 13.787, 14.953, 16.791, 18.493, 20.599, 40.256, 43.773, 46.979, 
> 50.892, 53.672
> 40 DATA 20.707, 22.164, 24.433, 26.509, 29.051, 51.805, 55.758, 59.342, 
> 63.691, 66.766
> 50 DATA 27.991, 29.707, 32.357, 34.764, 37.689, 63.167, 67.505, 71.420, 
> 76.154, 79.490
> 60 DATA 35.534, 37.485, 40.482, 43.188, 46.459, 74.397, 79.082, 83.298, 
> 88.379, 91.952
> 70 DATA 43.275, 45.442, 48.758, 51.739, 55.329, 85.527, 90.531, 95.023, 
> 100.425, 104.215
> 80 DATA 51.172, 53.540, 57.153, 60.391, 64.278, 96.578, 101.879, 106.629, 
> 112.329, 116.321
> 90 DATA 59.196, 61.754, 65.647, 69.126, 73.291, 107.565, 113.145, 118.136, 
> 124.116, 128.299
> 100 DATA 67.328, 70.065, 74.222, 77.929, 82.358, 118.498, 124.342, 129.561, 
> 135.807, 140.169
> 110 REM Calculate p from df and X2
> 120 IF DF<1 THEN                            DF=1: PRINT "Using df =" DF
> 130 IF DF>100 THEN                          DF=100: PRINT "Using df =" DF
> 140 IF DF>30 AND (DF MOD 10) > 0 THEN       DF=DF\10: PRINT "Using df =" DF
> 150 ' Select a DATA line to read from
> 151 IF DF=1 THEN RESTORE 1
> 152 IF DF=2 THEN RESTORE 2
> 153 IF DF=3 THEN RESTORE 3
> 154 IF DF=4 THEN RESTORE 4
> 155 IF DF=5 THEN RESTORE 5
> 156 IF DF=6 THEN RESTORE 6
> 157 IF DF=7 THEN RESTORE 7
> 158 IF DF=8 THEN RESTORE 8
> 159 IF DF=9 THEN RESTORE 9
> 160 IF DF=10 THEN RESTORE 10
> 161 IF DF=11 THEN RESTORE 11
> 162 IF DF=12 THEN RESTORE 12
> 163 IF DF=13 THEN RESTORE 13
> 164 IF DF=14 THEN RESTORE 14
> 165 IF DF=15 THEN RESTORE 15
> 166 IF DF=16 THEN RESTORE 16
> 167 IF DF=17 THEN RESTORE 17
> 168 IF DF=18 THEN RESTORE 18
> 169 IF DF=19 THEN RESTORE 19
> 170 IF DF=20 THEN RESTORE 20
> 171 IF DF=21 THEN RESTORE 21
> 172 IF DF=22 THEN RESTORE 22
> 173 IF DF=23 THEN RESTORE 23
> 174 IF DF=24 THEN RESTORE 24
> 175 IF DF=25 THEN RESTORE 25
> 176 IF DF=26 THEN RESTORE 26
> 177 IF DF=27 THEN RESTORE 27
> 178 IF DF=28 THEN RESTORE 28
> 179 IF DF=29 THEN RESTORE 29
> 180 IF DF=30 THEN RESTORE 30
> 181 IF DF=40 THEN RESTORE 40
> 182 IF DF=50 THEN RESTORE 50
> 183 IF DF=60 THEN RESTORE 60
> 184 IF DF=70 THEN RESTORE 70
> 185 IF DF=80 THEN RESTORE 80
> 186 IF DF=90 THEN RESTORE 90
> 187 IF DF=100 THEN RESTORE 100
> 210 REM p value for columns in data
> 220 A(0)=1
> 230 A(1)=.995: A(2)=.990: A(3)=.975
> 240 A(4)=.950: A(5)=.900: A(6)=.100
> 250 A(7)=.050: A(8)=.025: A(9)=.010
> 260 A(10)=.005
> 300 REM X2 is chi square, M is alpha
> 310 FOR T=1 TO 10
> 320 READ M
> 330 IF X2 > M THEN NEXT
> 350 P=A(T-1)
> 390 RETURN
> 990 REM By hackerb9 February 2024.
> 999 '
> 1000 REM Chi Squared statistic to                
> 1001 REM check for uniformity of RNG.
> 1002 ' Note: This does NOT check for
> 1003 ' independence. For that, use
> 1004 ' autocorrelation, gap, poker
> 1005 ' or other "diehard" tests.
> 1010 ES$=CHR$(27) 'Screen Esc sequences
> 1020 PRINT ES$"U"; ' Turn off labels
> 1030 CLS
> 1038 ' d is number of histogram bins
> 1039 ' or, equivalently, sides of a die.
> 1040 D=6
> 1050 DIM X(D)
> 1059 ' n is number of times to roll.
> 1060 N=100
> 1069 ' is the count expected in a bin
> 1070 E=N/D
> 1099 '
> 1100 REM Roll dice and show histogram bins.
> 1120 PRINT"Rolling a";D;"sided die";N;"times";
> 1130 FOR I=1 TO N
> 1140     GOSUB 10000 ' R = random(D)
> 1150     X(R)=X(R)+1
> 1160     TT=(R-1)*4: GOSUB 1550
> 1170     PRINT X(R);
> 1180 NEXT I
> 1190 TT=D*4:GOSUB 1550: PRINT
> 1199 '
> 1200 REM Calculate chi square statistic
> 1201 ' Chi-Square = sum{(x(i)-E)^2 / E}
> 1210 FOR I=1 TO D: IF X(I)<5 THEN PRINT "Results may be inaccurate due to     
>    insufficient trials (n ="N", d ="D")": ELSE NEXT
> 1230 X2=0: DF=-1
> 1240 FOR I=1 TO D
> 1250     X2 = X2 + ( (X(I) - E)^2 / E)
> 1260     IF X(I) > 0 THEN DF=DF+1
> 1270 NEXT I
> 1280 PRINT "Chi square is";X2
> 1290 PRINT "Degrees of Freedom is";df
> 1299 '
> 1300 REM Set p (percentage points) by 
> 1301 REM looking up x2 (chi square)
> 1302 REM at df (degree of freedom) in
> 1303 REM the chisq distribution table.
> 1310 GOSUB 110
> 1399 '
> 1400 REM Interpret result 
> 1410 PRINT "p =" P*100 "%"
> 1420 PRINT"This Random Number Generator"
> 1430 IF P>0.95 THEN PRINT "is too regular. (BAD)": END
> 1440 IF P<0.05 THEN PRINT "is not uniformly distributed. (BAD)": END
> 1450 PRINT "seems uniformly distributed."
> 1460 END
> 1499 '
> 1500 'Move cursor to Row AA and Col BB
> 1510 PRINT ES$"Y"CHR$(32+AA)CHR$(32+BB);
> 1520 RETURN
> 1550 REM Move cursor to position TT
> 1560 AA=TT\40+1:BB=TT MOD 40:GOSUB 1500
> 1570 RETURN
> 9999 '
> 10000 REM RANDOM NUMBER GENERATOR 
> 10001 '  Input D, integer
> 10002 ' Output R, integer
> 10003 '        1..D, inclusive
> 10010 R=INT(D*RND(1))+1
> 10090 RETURN 
> 
> 
> <x2.ba>

Reply via email to