Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

random number generator

Status
Not open for further replies.

MrDEB

Well-Known Member
I downloaded the random number generator that is supposed to generate nmbers from 1 - 5 but it doesn't do what it is supposed to

here is the code including the "rand" module


Device = 18F43K22
Clock = 16

// int osc and IO pin libraries
Include "intosc.bas"
#option DIGITALIO_INIT = true // automatically call setalldigital
Include "setdigitalio.bas"

// lcd
#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
Include "LCD.bas"
Include "convert.bas"

//Include "RNDByte.bas"
Include "Rand.bas"
Include "convert.bas"
Dim Y As Byte



TRISB=0

InitializeRND(4)'if desired

main:
Y=GetRND()
PORTB = (Y)

WriteAt(1,1,DecToStr(Y)," ")
DelayMS(2000)
Cls
GoTo main


{
RandGen Module
This is the Module code For the above example. Just copy And paste into the Swordfish IDE And Save in you UserLibrary folder As "RNDByte.bas"...

{
*****************************************************************************
* Name : RndByte.BAS *
* Author : David Eather *
* Notice : This code is placed into the Public Domain *
* : *
* Date : 19/07/2011 *
* Version : 1.0 *
* Notes : call InitializeRND(pValue) with a value between 0-255 *
* : call GetRND() to get a Byte 0 to 255 *
*****************************************************************************
}

{
Module Rand

Dim LCG,GLFSR As Byte

Public Function GetRND() As Byte
'LCG
LCG=(7*LCG+17)

'Galios LFSR
If (GLFSR And 1) = 1 Then
GLFSR = GLFSR Xor 135 '135 is the tap
GLFSR = (GLFSR >> 1) Or $80
Else
GLFSR = (GLFSR >> 1)
End If
result = GLFSR Xor LCG
End Function

Public Sub InitializeRND(ByVal ReSeed As Byte)
LCG = ReSeed
GLFSR = LCG Xor $55 'just making the start values very different - not realy important
If GLFSR = 0 Then 'except that GLFSR must not be zero
GLFSR=1
EndIf
End Sub

GLFSR=1
LCG=84
End
 
Have you ever considered – [cont]

Following the very explicit directions to use the module?

Screenshot_20230408_184631_Edge.jpg
 
You did not follow the directions in the wiki about saving three versions of the include file depending on the variable type, so when the example code looked for the include file, it wasn't found.

Rather than spending a few minutes READING and UNDERSTANDING the "usage" part of the instructions, you ASSumed the example code was wrong and changed it.

Typical great job [/sarcasm]

Screenshot_20230410_060138_Edge.jpg
 
I read and followed the Wiki instructions but the results were not what I am after. I even followed the post about the random number for 5 but couldn't get it to display on the LCD.
the only code that I got ANY results from is this code but it fails to display anything below 6. Only 255 or less Going to look at using a const array instead of a random number,
Code:
Device = 18F43K22
Clock = 16

// int osc and IO pin libraries
Include "intosc.bas"
#option DIGITALIO_INIT = true       // automatically call setalldigital
Include "setdigitalio.bas"

// lcd
#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
Include "LCD.bas"
Include "convert.bas"

//Include "RNDByte.bas" 
Include "Rand.bas"
Include "convert.bas"
Dim Y As Byte 



 TRISB=0

 InitializeRND(4)'if desired

main:
 Y=GetRND()
 PORTB  = (Y)

WriteAt(1,1,DecToStr(Y),"   ")
                  DelayMS(2000)
                  Cls
 GoTo main
 
I think you misunderstand what the module does.
It doesn't give you a random number from 1 to 5, it gives you a random byte value 0-255.
There's no provision for getting a number limited to a range of values.

That said, it's pretty convoluted to have to use different code modules. I'll combine all that into a single module and let you pick the output datatype.
 
There was a thread about 6 years ago that discussed LFSR for pseudorandom number generation : https://www.electro-tech-online.com/threads/how-to-create-an-lsfr-in-assembler.152554/#post-1311702

Pommie and I participated in it. The catch is that with a given seed and taps, a series of pseudo random numbers are generated, however, that series is reproduced with the same taps and seed. So, for an 8-bit seed, you get all 256 numbers just once. That is certainly not random. Pommie extended it to a 32-bit seed and watched it all night to confirm that every integer occurred once. ;)

My understanding is that given a list of true random numbers, you can perform manipulations on the numbers without upsetting the randomness. Based on that, there are a few things MrDeb might want to consider with an 8-bit LFSR product. I would consider some modulo options::
1) Mask any 5 bits (e.g., the msb 5 = modulo 8)) to give a series of 0 to 7 . Then ignore the values of 0, 6, and 7.
2) Divide the 8-bit number by 5 and record the remainder (i.e., 0 to 4). Then change 0 to 5.
3) Modulo 6 would give 0 to 5 and ignore 0

Doing modulo will work easily with any length seed. I would suggest Pommie's code with a 32-bit seed which might obscure the cyclical nature of LFSR. Regardless of seed, MrDeb wight want to change it periodically, say use the count on a free running timer (e.g., Timer0 for 8-bit or Timer1 for 16-bit would be my suggestion).

John
 
Last edited:
Any LFSR will suffer from lack of duplicates. A good "card counter" would beat you. Adding modulo/masking probably obscures that deficiency a little.

As an alternative, the 18F43K22 has 4 kb of linear RAM. Why not use some of that for a large table of better random numbers? If it is large enough, say 1 kb, players/users will not pick up on the cyclical nature. There are sources of random numbers from which such a table could be constructed. Any calculation needed to reduce the range to what you want could be done ahead of time,, so access would be quite fast.

One source that is pretty close to random are the digits of pi (or other irrational numbers) taken after the first 10 or so digits (See: http://www.subidiom.com/pi/ ). As an example of how its randomness differs from LFSR, take the repeat sequence 5555. That appears at the 24,466th digit of pi. Here is that sequence: 48697221612852489742555551607637167505489617 from the source just given.
 
So, for an 8-bit seed, you get all 256 numbers just once.
If you look at the article mrdeb linked to in post 1, the author claims the method used is a combination of two different methods. and not just a LFSR.

I can't attest to the result, but I do know that if you run it 256 times you do get a distribution of values from 0 to 255. Some never occur, some occur more than a few times.
 
Fair enough.
I just wasted some time looking at the table approach with pi. Started with 2 selections of 250 numbers (the maximum allowed on that site). Deleted 9's (56 instances), 8 (46), 7(44), 6(64), and 0(38) = 248 deletions. Result was 5(72), 4(50), 3(48), 2(50), and 1(32) = 252 total. Just make 5 the house number.

254112432255152511552535522152445534351445455125344343425523435222424232
533225341344151545352142335551534535415432143352132543254112432255152511
552535522152445534351445455125344343425523435222424232533225341344151545
352142335551534535415432143352132543

Maybe using a true "random number" table would give a more even distribution.
 
Everything seems more complex than necessary until you define your expectations for the output distribution of 5 numbers and repeatability from inputs.
 
Well there's a lot of confusing 'crap' in this thread :D

The standard 'rand()' functions are perfectly fine for almost any purpose you might need - the main issue is getting a reasonably random seed to start with.

It's also (obviously) trivial to generate 'random' numbers between whatever range you want.

C:
int RandomRange(int lower, int upper)
{
    return (rand() % (upper - lower + 1)) + lower;
}
 
My interpretation of this thread is that 3 issues are at work:
1) How do you get a set of random numbers?
2) How do you work with that set to constrain it to max and min values?
3) What is perhaps the simplest way to help MrDeb get something that works?

There was discussion of LFSR, because that specifically came up. Further reading of the link by MrDeb indicates LFSR is is only part of that algorithm, and the full method is probably much better.

In terms of constraining that set to a range, your code does noting different from any of the modulo suggestions. Calculating modulo can be done different ways. (I've attached a version from stackoverflow that is quite similar to your post.)

The main problem as I see it is #3. The TS has tried and apparently cannot get even a set of "random" numbers. So, I suggested just copying a sufficiently large table from somewhere and calculating a result that would equal %5 then adding 1 to each value. What can be easier and quicker with that 18F chip than using a large lookup table in linear RAM? I used pi as an example because it was simple for me to find. But as I noted, that small sample unfortunately had uneven distribution of 5 and 1. I am not suggesting it is not random, but I assume it is not what MrDeb wants and suggested just trying another table of random numbers..
 

Attachments

  • untitled_C.txt
    299 bytes · Views: 232
For the task at hand, which I believe has some human interaction, could this be as simple as the following?

1. Start a free-running timer when the program launches.

2. Fetch the timer value when triggered.

3. Apply the following:

Code:
RandomNumber = (TimerValue MOD (MaxDesiredValue – 1)) + 1

Say the max desired value is 5 (and the minimum is 1):

TimerValue MOD (5 – 1) will return values from 0 to 4. Adding 1 to the result gets the desired range of 1 to 5.

Since there is a human triggering event, the timer value would be essentially random if the timer interval is in the uSec range.


For those not familiar with the MOD function, here's a calculator to illustrate how it works.
 
Mrdeb should check the swordfish user module wiki page.
There's now a V2 of that random number generator... much simpler to use and includes a function to get a random number given a lower and upper range.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top