• AVR Freaks

LockedRand() is terrible...

Author
wizpanda
Junior Member
  • Total Posts : 91
  • Reward points : 0
  • Joined: 2013/10/07 21:56:22
  • Location: 0
  • Status: offline
2014/09/28 11:25:49 (permalink)
0

Rand() is terrible...

I have read the xc8 manual to understand rand(), srand() workings but in practice the results are terrible (not remotely random). My code is trying to get random # from 1 to 5 inclusive. Results are 5 in about 10 trials so far...how exactly does srand() work? it takes an input value, does something to it...then send the results for rand()?
 

//Basic concept
void main (void)
{
   int i, Seed, Rand;

   Seed++;
   srand(Seed);
   Rand = (rand() % 5) + 1;
 
   for (i = 0; i != Rand; i++)
   {
        Down = 1, __delay_ms(50);//Press down
        Down = 0, __delay_ms(500);
   }
}

#1

13 Replies Related Threads

    flubydust
    Super Member
    • Total Posts : 1286
    • Reward points : 0
    • Joined: 2005/05/19 13:44:42
    • Status: offline
    Re: Rand() is terrible... 2014/09/28 11:58:36 (permalink)
    +1 (1)
    The first result returned by rand() will be as random as the uninitialised variable (+1) you seeded it with which on a particular chip is not going to be random.
     
    You read the XC8 manual without understanding. rand() returns the next value in a fixed pseudo-random sequence. srand() sets the current position in that sequence.
    #2
    wizpanda
    Junior Member
    • Total Posts : 91
    • Reward points : 0
    • Joined: 2013/10/07 21:56:22
    • Location: 0
    • Status: offline
    Re: Rand() is terrible... 2014/09/28 14:55:50 (permalink)
    +1 (1)
    srand() sets current position
    rand() sets next value in the sequence
     
    based on premise above I shouldnt have same result random number because "Seed" is initialised with zero and increments (by 1) each time that loop runs hence srand(Seed) should be different each loop...?
    #3
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11284
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: Rand() is terrible... 2014/09/28 15:14:01 (permalink)
    +1 (1)
    rand() will only give you a different sequence of random numbers for each different value of srand().  In order to get different random numbers every time your program runs, you must provide srand() with a different value, i.e., a "real" random number obtained from a source other than rand().  You have to search for sources of randomness in your PIC, such as analog inputs, clock drift between a crystal and the internal RC oscillator, etc.
     
    This is standard C; it has nothing to do with XC8.  You'll probably find that using the % operator does not give you good results anyway:  http://eternallyconfuzzle...arts/jsw_art_rand.aspx
    #4
    Ian.M
    Super Member
    • Total Posts : 13225
    • Reward points : 0
    • Joined: 2009/07/23 07:02:40
    • Location: UK
    • Status: offline
    Re: Rand() is terrible... 2014/09/28 15:46:59 (permalink)
    +1 (1)
    You ideally need 16 bits of entropy for the seed.  Incrementing it by one each time does nothing useful.
    The sourcecode for srand() and rand() is:

    #include    <stdlib.h>

    static    long    randx;
    static    char    randf;

    void
    srand(unsigned x)
    {
        randx = x;
        randf = 1;
    }

    rand(void)
    {
        if(!randf)
            srand(1);
        return((int)((randx = randx*1103515245L + 12345)>>16) & 077777);
    }

    It is *difficult* to get a good seed.   Techniques include timing user input and discarding all except a few low order bits, or setting a high clock speed and allowing a 16 bit timer to increment until a WDT reset.  As the timer is stopped by the reset, this allows you to measure the WDT period which is sensitive to supply voltage and temperature, so again the low order bits are reasonably random as long as the WDT period is a couple of orders of magnitude greater than the rollover period of the chosen number of low order bits.  You may also be able to pick up a few bits here and there from other peripherals e.g. the LSB of whatever ADC channels you have connected.
     
    • If you can accumulate 16 bits of true randomness before you need to use rand() simply seed with it. 
    • If you are only getting one or two bits of true randomness at a time as you are running, use them to decide how many rand() results to discard before the next one you actually use.
    • For intermediate numbers of random bits, shift them into a 16 bit integer as you get them, and use it XORed with rand() for reseeding.  For sequence generators that are difficult or costly to reseed or if you don't have the source so are unsure how effective seeding it is it is often better to simply XOR the rand() result with the currently accumulated entropy before use.  (XOR is one of the few operations that preserves randomness)

    --
    NEW USERS: Posting images, links and code - workaround for restrictions.
    I also support http://picforum.ric323.com because this forum is sometimes too broken to use!
    #5
    wizpanda
    Junior Member
    • Total Posts : 91
    • Reward points : 0
    • Joined: 2013/10/07 21:56:22
    • Location: 0
    • Status: offline
    Re: Rand() is terrible... 2014/09/28 16:24:25 (permalink)
    0
    Thx Ian...you answered my question "why incrementing seed by 1 appears to do nothing" and also answered my future question which was "whats the source code for rand() & srand()...article linked by jtemples is quite interesting...calling the rand() multiple times till it give results in specific range is tempting but potentialy time wasting.
     
    They (microchip/xc8) should do a random function with a "sister" function to select the order of value required...
    #6
    Ian.M
    Super Member
    • Total Posts : 13225
    • Reward points : 0
    • Joined: 2009/07/23 07:02:40
    • Location: UK
    • Status: offline
    Re: Rand() is terrible... 2014/09/28 17:00:01 (permalink)
    0

    do  {
       r=rand();
       for(n=1;r>=0;n++) r-=32767/5;
    } while(n>5);

    should do what you need.  The result is in n.
     
    It only calls rand() again for r values between 32765 and 32767.  Subtraction in a loop is likely to be faster than division by a large arbitrary number on any 8 bit PIC.

    --
    NEW USERS: Posting images, links and code - workaround for restrictions.
    I also support http://picforum.ric323.com because this forum is sometimes too broken to use!
    #7
    NKurzman
    A Guy on the Net
    • Total Posts : 17707
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: offline
    Re: Rand() is terrible... 2014/09/29 09:13:36 (permalink)
    +1 (1)
    "They (microchip/xc8) should do a random function with a "sister" function to select the order of value required..."
     
     That would be a non-ANSII addition.
     
    Depending on what you are doing the built in C function may not be enough. 
    It is certainly not random enough for gambling devices.
    #8
    cobusve
    Super Member
    • Total Posts : 493
    • Reward points : 0
    • Joined: 2012/04/02 16:15:40
    • Location: Chandler
    • Status: offline
    Re: Rand() is terrible... 2014/09/29 11:52:13 (permalink)
    +3 (3)
    The behavior of rand() and srand() are prescribed by the C standard. It is not up to Microchip to change it, in fact it would be very bad for Microchip to change it.

    Since you are looking only at the first value in this sequence it gives you the same value every time just like it is supposed to.

    With the same seed it MUST give the same result EVERY time. Your code runs rand with the same seed every time which means that it MUST give the same result EVERY time ...

    You can start here to learn how rand() works.

    http://stackoverflow.com/questions/1783629/why-do-i-get-the-same-result-with-rand-every-time-i-compile-and-run



     
    #9
    wizpanda
    Junior Member
    • Total Posts : 91
    • Reward points : 0
    • Joined: 2013/10/07 21:56:22
    • Location: 0
    • Status: offline
    Re: Rand() is terrible... 2014/09/29 20:24:46 (permalink)
    +1 (1)
    thx for all the info...I understand more now. A thought just hit me though...when a pic powers on according to datasheets some ports are in an undefined state hence we usually clear the ports before doing anything else...supposed we take advantage of that and read a port at power up and store the value as an initial seed...?
    btw my application isnt security related...instead just to select a game from a list of 6 with a fair amount of randomness.
     
    #10
    flubydust
    Super Member
    • Total Posts : 1286
    • Reward points : 0
    • Joined: 2005/05/19 13:44:42
    • Status: offline
    Re: Rand() is terrible... 2014/09/29 20:44:17 (permalink)
    +2 (2)
    wizpanda
    when a pic powers on according to datasheets some ports are in an undefined state



    Undefined is not random. Bi-stable circuits in chips will likely power up in one state much more than the other. There has even been suggestion that the aggregate non-randomness of the state of RAM on power up could be used to generate a key which uniquely identifies a particular chip.
    #11
    nsaspook
    Starting Member
    • Total Posts : 55
    • Reward points : 0
    • Joined: 2009/04/30 11:29:47
    • Location: 0
    • Status: offline
    Re: Rand() is terrible... 2014/09/29 20:58:32 (permalink)
    +1 (1)
    flubydust
    wizpanda
    when a pic powers on according to datasheets some ports are in an undefined state



    Undefined is not random. Bi-stable circuits in chips will likely power up in one state much more than the other. There has even been suggestion that the aggregate non-randomness of the state of RAM on power up could be used to generate a key which uniquely identifies a particular chip.




    I hacked some code a few years ago to test SRAM randomness. I had the basic code working but never really did anything with it.
    https://pic18-puf.googlecode.com/files/vtouch.zip
    #12
    wizpanda
    Junior Member
    • Total Posts : 91
    • Reward points : 0
    • Joined: 2013/10/07 21:56:22
    • Location: 0
    • Status: offline
    Re: Rand() is terrible... 2014/09/29 22:22:56 (permalink)
    0
    Ian.M

    do  {
       r=rand();//Generates random number
       for(n=1;r>=0;n++)//End condition relates to r
       r-=32767/5;//Essentially r=[r-1], where r{0-5}
     
    } while(n>5);//Cycles required to reach -ve r = n

    should do what you need.  The result is in n.
     
    It only calls rand() again for r values between 32765 and 32767.  Subtraction in a loop is likely to be faster than division by a large arbitrary number on any 8 bit PIC.



    Since r is unsigned int (0  - 32767 range), if r = rand() = 0, how would r become -ve which is required to break the "for loop"?
    #13
    ric
    Super Member
    • Total Posts : 23534
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: Rand() is terrible... 2014/09/29 23:06:32 (permalink)
    +1 (1)
    The r variable is a signed int.
    Yes, the value returned by rand is in the range (0-32767), but you then enter this for loop:
        for(n=1;r>=0;n++)//End condition relates to r
            r-=32767/5;//Essentially r=[r-1], where r{0-5}

    so it will certainly go negative after subtracting 32767/5 several times.
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #14
    Jump to:
    © 2019 APG vNext Commercial Version 4.5