Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : Random number behavior
Author | Message | ||||
daveculp Newbie Joined: 02/07/2020 Location: United StatesPosts: 22 |
Ive been messing around the CMM2 and today I was writing a simple random walker routine. It works like so: 1. Start in the middle of the screen 2. Generate a random color 3. Generate a random x offset in the range -1,0,1 4. Generate a random y offset in the range -1,0,1 5. Plot the point 6. Pause a bit 7. Go back to 2 and do it all over again It can make some interesting shapes but I noticed the random number generation didnt seem uniform so I kept track of how many times each number is generated. It turns out that the middle number (1) is being generated almost twice as much as the other two. Is this due to how MMBasic converts from a float to an int. Is there a better way to do this? In reality, the way this implementation works is it generates a number in the range of 0 to 2 inclusive then subtracts 1 to get the range of -1 to 1 inclusive. REM ================================================================================ REM RANDOM WALKER REM ================================================================================ x = MM.HRES/2 y = MM.VRES/2 DIM x_total(2) DIM y_total(2) DIM INTEGER step_x, step_y cls black do while INKEY$ = "" r = rnd * 255 g = rnd * 255 b = rnd * 255 step_x = (rnd*2) x_total(step_x) = x_total(step_x) + 1 step_y = (rnd*2) y_total(step_y) = y_total(step_y) + 1 step_x = step_x - 1 step_y = step_y - 1 x = x + step_x y = y + step_y pixel x,y, RGB(r,g,b) pause (10) loop print "x totals: ";x_total(0), x_total(1), x_total(2) print "y totals: ";y_total(0), y_total(1), y_total(2) Edited 2020-07-04 07:44 by daveculp |
||||
daveculp Newbie Joined: 02/07/2020 Location: United StatesPosts: 22 |
The last run resulted in the following totals: x totals: 2312 4464 2264 y totals: 2182 4546 2312 The numbers represent the number of times 0, 1 and 2 were generated. One is generated 2X as much as the other numbers. Im wondering if it has to do with how numbers are converted from floating point types to integers. |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5867 |
It is safer to control the conversion from float to INT yourself. step_x = int(rnd*3) That will give you a very well distributed series of random numbers. Jim VK7JH MMedit  MMBasic Help |
||||
daveculp Newbie Joined: 02/07/2020 Location: United StatesPosts: 22 |
Works beautifully now! Thanks! |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3641 |
In the version posted, with step_x = (rnd*2) x_total(step_x) = x_total(step_x) + 1 step_x should never be as large as 2 (because rnd is - or should be - always less than 1). So how is x_total(2) not 0? What am I missing? It looks like rnd is broken or else array indexing / the calculation of the index is. John Edited 2020-07-04 08:41 by JohnS |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5867 |
Going from float to INT uses rounding, not INT The first methods used could be regarded as 4 bins 0-0.5, 0.5-1.0, 1.0-1.5, 1.5-2.0 The middle two get bundled together. Jim VK7JH MMedit  MMBasic Help |
||||
Geoffg Guru Joined: 06/06/2011 Location: AustraliaPosts: 3163 |
When assigning a float to an integer MMBasic will round the float to the nearest integer. RND gives a number between 0 and 0.999999 so step_x = (rnd*2) could be rounded up to 2. However the INT() function simply discards the fractional portion. So INT(rnd*2) will never return 2. EDIT: Jim beat me to it. Geoff Edited 2020-07-04 08:55 by Geoffg Geoff Graham - http://geoffg.net |
||||
daveculp Newbie Joined: 02/07/2020 Location: United StatesPosts: 22 |
Based upon my experimentation I figured that was what was going on, I just wasnt sure how to fix it. Now I know to convert manually from a FLOAT to INT instead of having it do it automatically. Edited 2020-07-04 09:31 by daveculp |
||||
daveculp Newbie Joined: 02/07/2020 Location: United StatesPosts: 22 |
This also helped me fix anoyjer issue with a Sierpienski's triangle generation program. The triangle got generated but it was obviously less filled in in places, which would only happen if there was not an even distribution of random numbers. Applying this fixed it. |
||||
panky Guru Joined: 02/10/2012 Location: AustraliaPosts: 1094 |
Geoff, for negative numbers, does INT not round to the next more negative number? Ie. INT(-2.11) will round to -3 whereas FIX will just delete the fractional component of both positive and negative numbers? panky ... almost all of the Maximites, the MicromMites, the MM Extremes, the ArmMites, the PicoMite and loving it! |
||||
Geoffg Guru Joined: 06/06/2011 Location: AustraliaPosts: 3163 |
Yes, correct. You should use FIX() when you want a true integer conversion without any rounding. But in this case it worked as there were no negative numbers. It is a bit confusing but blame Bill because that is how he did it in Microsoft BASIC. Geoff Geoff Graham - http://geoffg.net |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3641 |
Oh! I don't recall other BASICs doing that. They do an implied FIX. John |
||||
Geoffg Guru Joined: 06/06/2011 Location: AustraliaPosts: 3163 |
From the GWBASIC User's Manual: Geoff Graham - http://geoffg.net |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3641 |
So I gather. It's a big surprise to me, as some (many?) others do not do that. Could make porting programs a bigger challenge than might be expected. I just checked, and by way of example DEC's BASIC-PLUS truncates. I wonder what the ANSI standard says. (I suspect I've never used anything but an integer for an array index, however.) John |
||||
Geoffg Guru Joined: 06/06/2011 Location: AustraliaPosts: 3163 |
MMBasic tries to keep compatibility with Microsoft BASIC. Annoyingly the ANSI standard does not cover integer types but it does specify that floats must be rounded when indexing arrays (which is an integer conversion). Geoff Geoff Graham - http://geoffg.net |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3641 |
It makes sense to do that. It also explains why the outer two (indices 0 & 2) of the totals posted roughly sum to the middle one. John |
||||
Print this page |