Shop OBEX P1 Docs P2 Docs Learn Events
So, what about xbasic? - Page 4 — Parallax Forums

So, what about xbasic?

1246789

Comments

  • RsadeikaRsadeika Posts: 3,837
    edited 2014-01-13 06:35
    Below is my first attempt at trying to get access to the QS button. My logic on this is that you have to set the pin for input mode, and then sense it for either a ground (0) condition or a power (1) condition(3.3V). I am making an assumption that when you press the button it goes from ground too power (1), and I sense for that. Because the code below is in a loop, technically when the button is held down, the designated LED should stay lit. Of course it is not working, so there must be a problem with my GetPinInp() function, or my assumption as to how 'ina' is supposed too be used, I think?

    Ray
    REM ==========
    REM testQS1.bas
    REM ==========
    /* Include items */
    include "print.bas"
    include "propeller.bas"
    include "extra.bas"
    
    
    do
        btn = GetPinInp(0)
        IF btn = 1 THEN
          high(17)
        ELSE
          low(17)
        END IF
    loop
    
    
    
    END
    
    /* Setup pin for input */
    def GetPinInp(pin)
        dira = dira | (0 << pin)  // Direction to input
        ina = ina | (0 << pin)  // Sense for input
    end def
    
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-13 06:51
    /* Setup pin for input */
    def GetPinInp(pin)
        dira = dira | (0 << pin)  // Direction to input
        ina = ina | (0 << pin)  // Sense for input
    end def
    

    This function doesn't return any value and also has problems with the masking of both DIRA and INA. You'll need something more like this:
    /* Setup pin for input */
    def GetPinInp(pin)
        dira = dira & ~(1<< pin)  // Direction to input
        return ina & (1 << pin)  // Sense for input
    end def
    

    You can then test the return value of GetPinInp for zero or non-zero. If you want GetPinInp to return 0 if the pin is low and 1 if the pin is high then you'll need this:
    /* Setup pin for input */
    def GetPinInp(pin)
        dira = dira & ~(1<< pin)  // Direction to input
        return (ina & (1 << pin)) <> 0  // Sense for input
    end def
    

    Even better would be:
    /* Setup pin for input */
    def GetPinInp(pin)
        dim mask = 1 << pin
        dira = dira & ~mask  // Direction to input
        return (ina & mask) <> 0  // Sense for input
    end def
    
    However none of this will work with the touch buttons on the QuickStart because they require more complex code to read them not just a GetPinInp function as I understand it. I've never actually used them though.
  • RsadeikaRsadeika Posts: 3,837
    edited 2014-01-13 07:25
    This is going to be a little more complicated than expected. Using the new def, in the code below, the LED is turned on, the button pin has power.
    do
        btn = GetPinInp(0)
        IF btn = 1 THEN 
         high(17)
        //ELSE
        //  low(17)
        END IF
    loop
    
    Now if I change it to IF btn = 0, the LED does not turn on. I guess that just verifies that the pin is not in a ground state.
    do
        btn = GetPinInp(0)
        IF btn = 0 THEN 
         high(17)
        //ELSE
        //  low(17)
        END IF
    loop
    
    So, by actually pressing the button, it seems like the condition is not being changed, or there needs to be some additional condition that should be checked. Now if you would be using a normal button, I guess this code would work because by pressing the button you would be breaking the circuit, and therefore you would check for power or ground, depending how the button circuit was setup. I guess I need some more info as to how the QS button circuit is setup, and how to deal with it, code wise.

    Ray
    /* Setup pin for input */
    def GetPinInp(pin)
        dim mask = 1 << pin
        dira = dira & ~mask  // Direction to input
        return (ina & mask) = 0  // Sense for input
    end def
    
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-13 07:35
    Rsadeika wrote: »
    /* Setup pin for input */
    def GetPinInp(pin)
        dim mask = 1 << pin
        dira = dira & ~mask  // Direction to input
        return (ina & mask) = 0  // Sense for input
    end def
    
    I edited my message after you read it. This function should be defined like this:
    /* Setup pin for input */
    def GetPinInp(pin)
        dim mask = 1 << pin
        dira = dira & ~mask  // Direction to input
        return (ina & mask) <> 0  // Sense for input
    end def
    
    Notice the last line of the function. I should be testing if the value is non-zero not zero as the original code did.

    However, I think you're going to need to read up on those touch buttons. You can't just read the state of a pin to determine if the button is pressed. It's more complicated than that I think.
  • RsadeikaRsadeika Posts: 3,837
    edited 2014-01-13 07:54
    Below is the actual Spin program for the QS button control, it looks very straight forward except for the PASM part. I think the trick would be, is to try too replicate some of PASM code within the xBasic loop to simulate a checking of the button(s). In the PASM code it looks like the pin state outa is being changed wile the dira stays the same. I am not sure as too how to replicate this in def statement. Also, I noticed that there is no use of ina, so what the heck is going on.

    Ray

    CON
    
      BUTTON_PINS   = $FF           ' The QuickStart's touch buttons are on the eight LSBs
      SAMPLES       = 32            ' Require 32 high redings to return true
    
    
    VAR
      
      long  Results
    
    
    PUB Start(Rate)
    
      Results := Rate
      cognew(@Entry, @Results)      ' Launch a new cog to read samples
    
    
    PUB State | Accumulator
    
      Accumulator := Results        ' Sample multiple times and return true
      repeat constant(SAMPLES - 1)  '  if every sample was highw
        Accumulator &= Results
      return Accumulator
    
    
    DAT
    
                            org
    Entry                                                                                                                                    
                  rdlong    WaitTime, par
                  mov       outa, #BUTTON_PINS              ' set TestPins high, but keep as inputs
    
                  mov       Wait, cnt                       ' preset the counter
                  add       Wait, WaitTime
    Loop
                  or        dira, #BUTTON_PINS              ' set TestPins as outputs (high)
                  andn      dira, #BUTTON_PINS              ' set TestPins as inputs (floating)
                  mov       Reading, #BUTTON_PINS           ' create a mask of applicable pins
                  waitcnt   Wait, WaitTime                  ' wait for the voltage to decay
                  andn      Reading, ina                    ' clear decayed pins from the mask
                  wrlong    Reading, par                    ' write the result to RAM
                  jmp       #Loop
    
    Reading       res       1
    WaitTime      res       1
    Wait          res       1
    
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-13 08:03
    Rsadeika wrote: »
    Below is the actual Spin program for the QS button control, it looks very straight forward except for the PASM part. I think the trick would be, is to try too replicate some of PASM code within the xBasic loop to simulate a checking of the button(s). In the PASM code it looks like the pin state outa is being changed wile the dira stays the same. I am not sure as too how to replicate this in def statement. Also, I noticed that there is no use of ina, so what the heck is going on.

    Ray

    CON
    
      BUTTON_PINS   = $FF           ' The QuickStart's touch buttons are on the eight LSBs
      SAMPLES       = 32            ' Require 32 high redings to return true
    
    
    VAR
      
      long  Results
    
    
    PUB Start(Rate)
    
      Results := Rate
      cognew(@Entry, @Results)      ' Launch a new cog to read samples
    
    
    PUB State | Accumulator
    
      Accumulator := Results        ' Sample multiple times and return true
      repeat constant(SAMPLES - 1)  '  if every sample was highw
        Accumulator &= Results
      return Accumulator
    
    
    DAT
    
                            org
    Entry                                                                                                                                    
                  rdlong    WaitTime, par
                  mov       outa, #BUTTON_PINS              ' set TestPins high, but keep as inputs
    
                  mov       Wait, cnt                       ' preset the counter
                  add       Wait, WaitTime
    Loop
                  or        dira, #BUTTON_PINS              ' set TestPins as outputs (high)
                  andn      dira, #BUTTON_PINS              ' set TestPins as inputs (floating)
                  mov       Reading, #BUTTON_PINS           ' create a mask of applicable pins
                  waitcnt   Wait, WaitTime                  ' wait for the voltage to decay
                  andn      Reading, ina                    ' clear decayed pins from the mask
                  wrlong    Reading, par                    ' write the result to RAM
                  jmp       #Loop
    
    Reading       res       1
    WaitTime      res       1
    Wait          res       1
    
    I guess that PASM code would have to be compiled into a PASM blob so it could be loaded with cognew. That isn't too difficult and you can see how it is done by look at the TV demo in the xbasic samples directory.
  • jazzedjazzed Posts: 11,803
    edited 2014-01-13 12:24
    Here are some functions that read quickstart buttons. They are not PASM, but they show how to do it. They will not work with the HID board installed.
    include "propeller.bas"
    
    
    REM ===============================================
    REM Get a specific button number.
    REM buttons are enumerated from 0 to 7.
    REM
    def getButton(number)
        dim mask = (1 << (number))
        dim buttons = getButtons
        return buttons & mask
    end def
    
    
    REM ===============================================
    REM Get all buttons at once
    REM Run this function from HUB if compiled for LMM.
    REM
    def getButtons
        dim n = 8
        dim result  = -1
        dim reading =  0
        dim pins = 0xFF
        OUTA = OUTA | pins               // output high to buttons
        
        do while(n > 0)                  // sample pins n times
            n = n - 1
            DIRA = DIRA | pins           // output high to buttons
            DIRA = DIRA ^ pins           // switch to input
            reading = pins
            waitcnt(CLKFREQ/1000+CNT)  // wait for RC time
            reading = INA & reading      // return button states
            result  = result & reading
        loop
        result = ~result & 0xFF
        return result
    end def
    

    Here are some print utility functions.
    dim hexarray(16) = {
        '0', '1', '2', '3', '4', '5', '6', '7'
        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
    }
    REM===================================================
    REM Print a hexidecimal number
    REM @param value - decimal number
    REM @param digits - number of digits to print
    REM
    def printHex(value, digits)
        dim n
        do while digits > 0
            digits = digits - 1
            n = (value >> (digits<<2)) & 0xf
            uartTx(hexarray(n))
        loop
    end def
    
    
    REM===================================================
    REM Print a binary number
    REM @param value - number
    REM @param digits - number of digits to print
    REM
    def printBin(value, digits)
        n = digits-1
        do while n > -1
            dig = '0' + ( (value & (1<<n)) >> n)
            uartTx(dig)
            n = n - 1
        loop
    end def
    
  • jazzedjazzed Posts: 11,803
    edited 2014-01-13 12:29
    Here is a video that shows how to add a quickstart board. http://www.youtube.com/watch?v=ffNYjOUmBaE

    I've noticed some issues with xbasic and quickstart. The xbasic loader needs to be updated.

    I've also noticed that the IDE will hang if you print too fast. Sometimes the IDE won't respond after closing the terminal. Click the + button if it is still "pressed" and "Ok" the terminal until the + button is not pressed.

    There are several things about the IDE that do not use improvements that were added to SimpleIDE. They will take time to update especially as I have other things going on. I'll get to them when I can.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-13 13:50
    Thanks for writing this Steve!!!
    jazzed wrote: »
    Here are some functions that read quickstart buttons. They are not PASM, but they show how to do it. They will not work with the HID board installed.
    include "propeller.bas"
    
    
    REM ===============================================
    REM Get a specific button number.
    REM buttons are enumerated from 0 to 7.
    REM
    def getButton(number)
        dim mask = (1 << (number))
        dim buttons = getButtons
        return buttons & mask
    end def
    
    
    REM ===============================================
    REM Get all buttons at once
    REM Run this function from HUB if compiled for LMM.
    REM
    def getButtons
        dim n = 8
        dim result  = -1
        dim reading =  0
        dim pins = 0xFF
        OUTA = OUTA | pins               // output high to buttons
        
        do while(n > 0)                  // sample pins n times
            n = n - 1
            DIRA = DIRA | pins           // output high to buttons
            DIRA = DIRA ^ pins           // switch to input
            reading = pins
            waitcnt(CLKFREQ/1000+CNT)  // wait for RC time
            reading = INA & reading      // return button states
            result  = result & reading
        loop
        result = ~result & 0xFF
        return result
    end def
    

    Here are some print utility functions.
    dim hexarray(16) = {
        '0', '1', '2', '3', '4', '5', '6', '7'
        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
    }
    REM===================================================
    REM Print a hexidecimal number
    REM @param value - decimal number
    REM @param digits - number of digits to print
    REM
    def printHex(value, digits)
        dim n
        do while digits > 0
            digits = digits - 1
            n = (value >> (digits<<2)) & 0xf
            uartTx(hexarray(n))
        loop
    end def
    
    
    REM===================================================
    REM Print a binary number
    REM @param value - number
    REM @param digits - number of digits to print
    REM
    def printBin(value, digits)
        n = digits-1
        do while n > -1
            dig = '0' + ( (value & (1<<n)) >> n)
            uartTx(dig)
            n = n - 1
        loop
    end def
    
  • RsadeikaRsadeika Posts: 3,837
    edited 2014-01-13 14:42
    Thanks jazzed, I gave the code a try and it works, as expected. Now I have to figure out what I will be doing with it. Thinking, thinking...

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2014-01-13 18:01
    Rsadeika wrote: »
    Thanks jazzed, I gave the code a try and it works, as expected. Now I have to figure out what I will be doing with it. Thinking, thinking...

    Ray
    Since you know C, you can port my Quickstart Whack-a-mole game.

    The only real challenge here is making the srand() and rand() functions. Look at these links for descriptions: srand() rand() ... Actual implementation of rand(), a pseudo-random number generator (PRNG), doesn't need to be very complicated. Look at the middle-square method (not a very good PRNG, but better than nothing).

    /**
     * This is a QuickStart Whack-a-Mole game.
     *
     * Copyright 2011 by Steve Denson.
     * Rights MIT Licensed. See end of file.
     */
     
    /**
     * The Blue LED moles are eating up your QuickStart yard!
     * You must get rid of them!
     *
     * Gameplay:
     *
     * All living moles will run around the QuickStart burrow during
     * the game and you'll know they're alive by the dimly lit LEDs.
     *
     * Sometimes a mole will pop up as brighly lit LED and you must
     * wack the mole pad to knock it out.
     *
     * When the moles are gone, your QuickStart yard will celebrate!
     *
     */
    #include <stdlib.h>             // for rand() and seed()
    #include <propeller.h>          // for propeller functions.
    
    
    /* game utilities */
    void    celebrate(void);        // no more moles
    int     rotateLeft(int mask);
    int     rotateRight(int mask);
    
    
    /* simple utilities */
    void    LEDOUT(int val);        // set leds to val
    void    msleep(int t);          // sleep for t ms
    int     getButton(int n);       // used to get button states
    int     getButtons();           // used to get button states
    
    
    /*
     * Main program entry point
     * Start with 8 moles and flick LEDs via rotating mask.
     * Choose a random mole to light for fraction of a second.
     * If the mole button is pushed while the LED is lit, kill the mole.
     * When all moles are dead celebrate - check button press for restart.
     */
    int main(void)
    {
        int molemask    = 0xff;     // live moles
    
    
        int ontime      = 1;        // flicker on time in ms
        int offtime     = 80;       // flicker off time
    
    
        int whacked     = 0;        // it's whacked?
        int direction   = 1;        // keep direction of LED mole run
    
    
        int popcount    = 6;        // initial popcount
        int countmask   = 0x1f00;   // allow up to 32 mole run steps
        int popmask     = 0x7;      // only 8 LEDs, choose from rand
    
    
        int popupspot   = 0;        // show popup position
        int popuptime   = 500;      // popup on time
    
    
        /* mole run forever loop */
        for(;;)
        {
            /* nothing whacked */
            whacked = 0;
            /* seed random function with Propeller CNT */
            srand(CNT);
    
    
            /* blank moles */
            LEDOUT(0);
            /* sleep a little */
            msleep(offtime);
    
    
            /* if all moles gone, celebrate */
            while(!molemask) {
                /* make LEDs dance */
                celebrate();
                /* if button press, restart game */
                if(getButtons()) {
                    molemask = 0xff;
                }
            }
    
    
            /* get popup spot */
            if(popcount-- == 0) {
                /* get random number */
                popupspot  = rand();
                /* use upper bits for popup count */
                popcount = (popupspot & countmask) >> 8;
                /* use lower popmask bits for popup mole LED */
                popupspot &= popmask;
    
    
                /* show popup and check button */
                if(molemask & (1<<popupspot)) {
                    /* set LED to show a mole to whack */
                    LEDOUT((1<<popupspot) & molemask);
                    /* single thread limit. sample twice */
                    msleep(popuptime>>1);
                    whacked = getButton(popupspot);
                    msleep(popuptime>>1);
                    whacked |= getButton(popupspot);
                    /* set back to mole mask */
                    LEDOUT(molemask);
                }
            }
    
    
            /* mole whacked ? */
            if(whacked) {
                molemask &= ~(1<<popupspot);
            }
    
    
            /* if a random bit is set switch direction */
            if(rand() & 0x20) {
                direction ^= 1;
            }
    
    
            /* set new mole run spots */
            if(direction) {
                molemask = rotateRight(molemask);
            }
            else {
                molemask = rotateLeft(molemask);
            }
    
    
            /* show mole run */
            LEDOUT(molemask);
            /* sleep a little so we can see the mole run */
            msleep(ontime);
    
    
        }
        return 0;
    }
    
    
    /*
     * make LEDs dance with a checker board pattern
     */
    void celebrate(void)
    {
        int n = 16;
        while(n-- > -1)
        {
            LEDOUT(0x55);
            msleep(50);
            LEDOUT(0xAA);
            msleep(50);
        }
        LEDOUT(0);
        msleep(400);
    }
    
    
    /*
     * rotate mask left
     */
    int rotateLeft(int mask)
    {
        int temp = mask << 1;
        mask = (temp & 0x100) ? 1 : 0;
        mask |= temp & 0xff;
        return mask;
    }
    
    
    /*
     * rotate mask right
     */
    int rotateRight(int mask)
    {
        int temp = mask >> 1;
        mask &= 0x01;
        mask <<= 7;
        mask |= temp;
        return mask;
    }
    
    
    /*
     * Set the LEDs to val
     */
    void LEDOUT(int val)
    {
        DIRA |= 0xff << 16;
        OUTA = (OUTA & ~(0xff<<16)) | (val<<16);
    }
    
    
    /*
     * msleep makes the cog wait for about t milliseconds.
     */
    void msleep(int t)
    {
        waitcnt((CLKFREQ/1000)*t+CNT);
    }
    
    
    /*
     * Get a specific button number.
     * buttons are enumerated from 0 to 7.
     */
    int getButton(int n)
    {
        return (getButtons() & (1<<n));
    }
    
    
    /*
     * Get all buttons at once
     * Run this function from HUB if compiled for LMM.
     */
    int getButtons()
    {
        int n = 16;
        int result  = -1;
        int reading =  0;
        int pins = 0xFF;
        OUTA |= pins;               //output high to buttons
    
    
        while(n--)
        {
            DIRA |= pins;           //output high to buttons
            DIRA ^= pins;           //switch to input
            reading = pins;
            msleep(2);              //wait for RC time
            reading &= INA;          //return button states
            result  &= reading;
        }
        result = ~result & 0xFF;
        return result;
    }
    
    
    /*
    +--------------------------------------------------------------------
    | TERMS OF USE: MIT License
    +--------------------------------------------------------------------
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files
    (the "Software"), to deal in the Software without restriction,
    including without limitation the rights to use, copy, modify, merge,
    publish, distribute, sublicense, and/or sell copies of the Software,
    and to permit persons to whom the Software is furnished to do so,
    subject to the following conditions:
    
    
    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.
    
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    +--------------------------------------------------------------------
    */
    
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-13 18:33
    Not sure if it will be useful but this is the code that xlisp uses to generate random numbers:
    /* xlosRand - return a random number between 0 and n-1 */
    xlEXPORT long xlosRand(long n)
    {
        long k1;
    
        /* make sure we don't get stuck at zero */
        if (rseed == 0L) rseed = 1L;
    
        /* algorithm taken from Dr. Dobbs Journal, November 1985, page 91 */
        k1 = rseed / 127773L;
        if ((rseed = 16807L * (rseed - k1 * 127773L) - k1 * 2836L) < 0L)
            rseed += 2147483647L;
    
        /* return a random number between 0 and n-1 */
        return rseed % n;
    }
    
  • jazzedjazzed Posts: 11,803
    edited 2014-01-13 23:48
    David posted the rand() function. The srand() function is easy.

    Just a little rewrite would look like below. The randomness is pretty good.
    int rseed = 1;
    
    /* seed the random number generator */
    void Seed(int n)
    {
        rseed = n;
    
        /* make sure we don't get stuck at zero */
        if (rseed == 0) rseed = 1;
    }
    
    /* Rand() return a random number between 0 and n-1 */
    int Rand(int n)
    {
        int k1;
    
    
        /* algorithm taken from Dr. Dobbs Journal, November 1985, page 91 */
        k1 = rseed / 127773;
        if ((rseed = 16807 * (rseed - k1 * 127773) - k1 * 2836) < 0)
            rseed += 2147483647;
    
    
        /* return a random number between 0 and n-1 */
        return rseed % n;
    }
    
  • Heater.Heater. Posts: 21,230
    edited 2014-01-14 01:42
    Jazzed,

    I think you broken the algorithm.

    In the original rseed is set to 1 if it ever happens to be zero.

    In yours if rseed is ever zero it gets stuck producing zeros forever.

    Are we sure the algorithm never produces a zero?

    Of course if it does not then it's not very random.

    Also there is that modulus operator which ensures the output is biased.
  • Heater.Heater. Posts: 21,230
    edited 2014-01-14 01:55
    Hmm...A quick test shows that thing never does produce zero if it starts from non-zero.
    It has a cycle length of 2147483646.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-14 03:45
    I think it's safer to leave the code like this. It may be that it never reaches zero if you start at 1 but there is no guarantee that it won't for other initial seed values.
    int rseed = 1;
    
    /* seed the random number generator */
    void Seed(int n)
    {
        rseed = n;
    }
    
    /* Rand() return a random number between 0 and n-1 */
    int Rand(int n)
    {
        int k1;
    
        /* make sure we don't get stuck at zero */
        if (rseed == 0) rseed = 1;
    
        /* algorithm taken from Dr. Dobbs Journal, November 1985, page 91 */
        k1 = rseed / 127773;
        if ((rseed = 16807 * (rseed - k1 * 127773) - k1 * 2836) < 0)
            rseed += 2147483647;
    
    
        /* return a random number between 0 and n-1 */
        return rseed % n;
    }
    
  • RsadeikaRsadeika Posts: 3,837
    edited 2014-01-14 04:16
    Yes, I think that xBasic should have a standard random number generator which would be included in one of the standard .bas modules that ships with a version of xBasic. Maybe the author of xBasic could keep control of the standard .bas modules, so we always have at least a version of xBasic that is a standard version. With the ability to create your own def functions, this language could get out of hand in a very short time.

    Ray
  • Heater.Heater. Posts: 21,230
    edited 2014-01-14 04:39
    David,
    It may be that it never reaches zero if you start at 1 but there is no guarantee that it won't for other initial seed values.

    Actually there probably is if our maths was up to it. However this is such a sad random number generator you can test it easily.

    Starting from an rseed value 42 it gets back to 42 after generating
    2147483647 numbers, which happens to be the maximum value of a 32 bit integer. Clearly it goes through all the possibilities in it's cycle without ever hitting zero. Ergo, where ever you start it will run around that same sequence never hitting zero.


  • max72max72 Posts: 1,155
    edited 2014-01-14 04:46
    You cannot use 42 as a test seed!
    being the answer to life the universe and everything, it is not a representative number...
    Massimo
  • Heater.Heater. Posts: 21,230
    edited 2014-01-14 04:58
    max72,

    At least this PRNG get's back to 42 faster than Deep Thought did.

    Can I suggest you use the JKISS32 algorithm. Which generates about 2 to the power 121 numbers before repeating itself and passes the Die Hard tests for randomness.
    This is KISS32:
    /* Implementation of a 32-bit KISS generator which uses no multiply instructions */ 
    
    static unsigned int x=123456789, y=234567891, z=345678912, w=456789123, c=0; 
     
    unsigned int JKISS32() 
    { 
     int t; 
     
     y ^= (y<<5); y ^= (y>>7); y ^= (y<<22); 
     t = z+w+c; z = w; c = t < 0; w = t&2147483647; 
     x += 1411392427; 
     
     return x + y + w; 
    } 
    
    You can read about it here: http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf


    P.S. 2**121 = 2.6 * 10**36. That should keep Deep Thought busy for a while!
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-14 05:37
    Heater. wrote: »
    max72,

    At least this PRNG get's back to 42 faster than Deep Thought did.

    Can I suggest you use the JKISS32 algorithm. Which generates about 2 to the power 121 numbers before repeating itself and passes the Die Hard tests for randomness.
    This is KISS32:
    /* Implementation of a 32-bit KISS generator which uses no multiply instructions */ 
    
    static unsigned int x=123456789, y=234567891, z=345678912, w=456789123, c=0; 
     
    unsigned int JKISS32() 
    { 
     int t; 
     
     y ^= (y<<5); y ^= (y>>7); y ^= (y<<22); 
     t = z+w+c; z = w; c = t < 0; w = t&2147483647; 
     x += 1411392427; 
     
     return x + y + w; 
    } 
    
    You can read about it here: http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf


    P.S. 2**121 = 2.6 * 10**36. That should keep Deep Thought busy for a while!
    How do I set the seed for this random number generator?
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-14 05:43
    Heater. wrote: »
    David,

    Actually there probably is if our maths was up to it. However this is such a sad random number generator you can test it easily.

    Starting from an rseed value 42 it gets back to 42 after generating
    2147483647 numbers, which happens to be the maximum value of a 32 bit integer. Clearly it goes through all the possibilities in it's cycle without ever hitting zero. Ergo, where ever you start it will run around that same sequence never hitting zero.


    Even if this algorithm does avoid hitting zero it is still incorrect to check for that case in the function that sets the seed. Someone might tweak the algorithm such that it does sometimes produce zero. Anyway, it isn't obvious that this code is valid so I think it should probably be changed back to the way the original works. I don't see any real advantage to the modified version.
  • Heater.Heater. Posts: 21,230
    edited 2014-01-14 06:10
    You can seed JKISS32 just by setting x, y, z, and w.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-14 06:13
    Heater. wrote: »
    You can seed JKISS32 just by setting x, y, z, and w.
    Will setting just one of them and leaving the rest at their defaults work? I'm trying to figure out how to implement the srand() function in C which takes only one argument.
  • Heater.Heater. Posts: 21,230
    edited 2014-01-14 06:50
    Yes it will work if you only set one of the state variables.

    Of course then you are limiting your self to only 4 billion starting positions as opposed to 10*36 or whatever it is when you set all the bits.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-14 07:00
    Heater. wrote: »
    Yes it will work if you only set one of the state variables.

    Of course then you are limiting your self to only 4 billion starting positions as opposed to 10*36 or whatever it is when you set all the bits.
    Thanks. I wasn't sure if there were any constraints on the values of any of those variables.
  • Heater.Heater. Posts: 21,230
    edited 2014-01-14 07:19
    Perhaps you could arrange that when you call the seeding function it shuffles all those state variables, z => w, y => z, z => y. Then sets x to the seed parameter. That way if someone really wanted to seed all the bits they could call it 4 times with different values.

    I don't think there are any constraints on the seed values but I seem to remember there is some weird stuff that goes on if you set all the seed bits to zero for example. The sequence you get out looks decidedly non-random, full of two many zeros bits all the time.

    This just demonstrates the enormous period of the thing. With a sequence length of 10E36 you should get about 10*25 different permutations of all the numbers you can represent in the 32 bits of the output. Some of those permutations will look decidedly non-random.

    You would expect that somewhere in there there are long stretches where there are far to many zeros in the 32 bit output.

    When you start with all state bits set to zero you are just in a very strange place.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-14 07:45
    Heater. wrote: »
    Perhaps you could arrange that when you call the seeding function it shuffles all those state variables, z => w, y => z, z => y. Then sets x to the seed parameter. That way if someone really wanted to seed all the bits they could call it 4 times with different values.

    I don't think there are any constraints on the seed values but I seem to remember there is some weird stuff that goes on if you set all the seed bits to zero for example. The sequence you get out looks decidedly non-random, full of two many zeros bits all the time.

    This just demonstrates the enormous period of the thing. With a sequence length of 10E36 you should get about 10*25 different permutations of all the numbers you can represent in the 32 bits of the output. Some of those permutations will look decidedly non-random.

    When you start with all state bits set to zero you are just in a very strange place.

    you would expect that somewhere in there there are long stretches where there are far to many zeros in the 32 bit output.
    Good suggestion about shuffling values. Thanks!
  • jazzedjazzed Posts: 11,803
    edited 2014-01-14 13:07
    Ya, I broke the re-seeding in my presentation of Rand(). Sorry.

    I've posted an xBasicIDE package update here. New revision is 0.2.1.

    This should fix the RevA Quickstart loading issue. There are many IDE enhancements. The terminal behaves much better for example. The IDE will also scan for the first available Propeller and set the com port for use (the port will be blank on startup). Other items: Added current file/path to window title. Fixed SaveAs project setting, Made editor tab with smaller. Added program bytes loaded size. Fixed progress bar.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-14 13:09
    jazzed wrote: »
    Ya, I broke the re-seeding in my presentation of Rand(). Sorry.

    I've posted an xBasicIDE package update here. New revision is 0.2.1.

    This should fix the RevA Quickstart loading issue. There are many IDE enhancements. The terminal behaves much better for example. The IDE will also scan for the first available Propeller and set the com port for use (the port will be blank on startup). Other items: Added current file/path to window title. Fixed SaveAs project setting, Made editor tab with smaller. Added program bytes loaded size. Fixed progress bar.

    Thanks Steve! Great work!!
Sign In or Register to comment.