Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Rnd2

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • David Roberts
    replied
    I think it does but if you just wanted to repeat the last sequence then remove the statement marked *

    Code:
    PRINT "Randomise, ToggleScope":PRINT
    Randomise
    ToggleScope
    FOR i = 1 TO 10
      PRINT Rnd2
    NEXT
    PRINT
    PRINT "ToggleScope, RepeatLastSequence":PRINT
    ToggleScope                                                          ' * Remove to just repeat
    RepeatLastSequence
    FOR i = 1 TO 10
      PRINT Rnd2
    NEXT
    PRINT:PRINT "**********":PRINT
    Added: I'd forgotten how this worked - six years ago!

    Note by John Gleason: "The significant changes to your original code are: 1) toggleScope uses only one generator so it cannot un-toggle then repeat the last sequence anymore. To repeat it
    must be in the same toggle state." from here post #3.

    Revision:
    Code:
    PRINT "Randomise, ToggleScope":PRINT
    Randomise
    ToggleScope
    FOR i = 1 TO 10
        PRINT Rnd2
    NEXT
    PRINT
    WAITKEY$
    PRINT "RepeatLastSequence":PRINT
    RepeatLastSequence
    FOR i = 1 TO 10
        PRINT Rnd2
    NEXT
    PRINT:PRINT "**********":PRINT
    from here opening post.
    Last edited by David Roberts; 21 Aug 2014, 10:06 PM.

    Leave a comment:


  • Arthur Gomide
    replied
    Hi David,

    Your code at post #2 do not work as desired, see below
    Code:
    **********
    
    Randomise, ToggleScope
    
    -.595117101522795
     .920743669071494
    -.520147503025958
    -.316013233723124
     7.20697677982881E-3
     .897971030503953
     .250192549348052
    -.22613654066091
    -.14576787743641
     .49641197236139
    
    ToggleScope, RepeatLastSequence
    
     .595117101522795
     .920743669071494
     .520147503025958
     .316013233723124
     7.20697677982881E-3
     .897971030503953
     .250192549348052
     .22613654066091
     .14576787743641
     .49641197236139
    
    **********

    Leave a comment:


  • David Roberts
    replied
    The CPRNG.inc macros create a local instance of an object. In the above an instance is created locally in PBMain. If we wanted to generate random numbers in a function, for example, as well then we would need to create another instance. However, if the second instance is created before the instance in PBMain is destroyed then it would use the same starting point as the first instance.

    We can avoid repetition if the PBmain instance is destroyed before calling Test and created again, if needed, on returning.

    Of course, we could have a function calling a function, which is what we have with PBMain , and it could get a bit messy.

    Another solution is to create a global instance illustrated in the following.

    Rand is declared globally and assigned in PBMain.

    Code:
    #Compile Exe
    #Optimize speed
    #Dim All
    #Tools Off
    #Register None
    
    #Include "WIN32API.INC"
    
    %NOMMIDS  = 1
    %NOGDI    = 1
    
    #Include "CPRNG.inc"
    
    [COLOR="Red"]Global Rand As IPRNG[/COLOR]
    
    Function PBMain
    
      Local i As Long
      
      [COLOR="Red"]Let Rand = Class "CPRNG"[/COLOR]
      
      Print "In PBMain"
      For i = 1 To 5
        Print rand.number
      Next
      Print
      
      Test
        
      Rand = Nothing
      
      WaitKey$
    
    End Function
    
    Function Test As Long
     
     Local i as long
     
     Print "In Test"
     For i = 1 To 5
       Print rand.number
     Next
     
    End Function
    Last edited by David Roberts; 9 Sep 2008, 07:38 AM.

    Leave a comment:


  • David Roberts
    replied
    Added a Method Range. Shied away from features to avoid 'If something' in generator code as in post #1. That could be done in post #1 via a multi-function approach and there is no real difference with a multi-method approach but it 'feels' different using the one interface.

    Usage: Rand.Range(a, b) outputting as Long but could be Quad.
    Last edited by David Roberts; 8 Sep 2008, 08:44 AM. Reason: Syntax this time - oh dear <smile>

    Leave a comment:


  • David Roberts
    replied
    Added: Method Range

    From post #1 above.
    If RND2 were as fast as RND its sequence would be used up in about 5617 years.
    Of course, in practice it would take much longer if we actually did anything with the numbers generated.

    It is not a big leap to think of a sequence which lives for the life of a PC as opposed to the life of an application. With such a sequence every sub-sequence would be brand spanking new, never seen before and never to be used again. That is not strictly true. If we roll a dice 100 times we should not be surprised to see a six, say, a few times or if we rolled a dice twice 1000 times we should not be surprised to see a three, say, followed by a five, say, a few times. With a period suchas RND2, or RND for that matter, sub-sequences of 20, say, will probably exist more than once. The larger the sub-sequence the less likely it will exist more than once. This is the nature of randomness and the point of this exercise is that whilst we may recognise a sub-sequence it cannot be the same sub-sequence.

    To achieve a sequence which is forever 'open' all we need to do is to simply remember the last seed(s) used. To this end, the easiest method is to dump to a file.

    This sequence is available to any application and it may be used by more than one running application. If a second application opens before the first has closed then it will use the same seeds. This is probably not an issue but we will have a problem if the last application to close has used less random numbers than other closed applications had used. In this case the seeds used in future will have been used before. If a counter was dumped along with the seeds and each application incremented this counter then we can ensure that the seeds are overwritten only if the last application's counter exceeded the counter on file.

    The above concept may be written using a Function but it will have to have code to handle initialization and termination and this will impact on its use between those stages, albeit small. On the other hand if we used a Class available in PB9 and CC5 then we can write initialization and termination code which has no impact between those stages via the Class Methods Create and Destroy respectfully. The termination code determines whether the latest version of the file is to be overwritten or not.

    The code differs to post #1 above in that it generates random numbers and nothing else - no bells and whistles.

    On the very first time an object is created if the file "c:\rand.dat" [ or whatever you decide to use ] is not found then a file will be created.

    The generator's multiplier is 'hard wired' in the Class and I have used one which is not used by post #1 above - a different sequence then.

    Copy the folowing code and Save As "CPRNG.inc" wherever you keep your include files.

    Code:
    ' CPRNG.inc
     
    Macro CreateRandObject
      Local Rand As IPRNG
      Let Rand = Class "CPRNG"
    End Macro
     
    Macro DestroyRandObject
      Rand = Nothing
    End Macro
     
    Class CPRNG
     
      Instance mwcSoph As Dword
      Instance mwcRandom, mwcCarry As Long
      Instance UsageCounter As Quad
     
      Class Method Create
        Local fn As Long
        fn = FreeFile
        mwcSoph = 4221479778???
        If IsFile("c:\rand.dat") Then ' [COLOR="Red"]change path to suit[/COLOR]
          Open "c:\rand.dat" For Input As #fn
            Input #fn, mwcRandom, mwcCarry, UsageCounter
          Close #fn
        Else
          mwcRandom = &ha5b218da
          mwcCarry = &h3fe8700c
          UsageCounter = 0
          Open "c:\rand.dat" For Output As #fn ' [COLOR="Red"]again change path to suit[/COLOR]
            Write #fn, mwcRandom, mwcCarry, UsageCounter
          Close #fn
        End If
      End Method
     
      Class Method Destroy
        Local fn, dummy As Long, Counter As Quad
        fn = FreeFile
        Open "c:\rand.dat" For Input As #fn
          Input #fn, dummy, dummy, Counter
        Close #fn
        If UsageCounter > Counter Then
          Open "c:\rand.dat" For Output As #fn ' [COLOR="Red"]and again[/COLOR]
            Write #fn, mwcRandom, mwcCarry, UsageCounter
          Close #fn
        End If
      End Method
     
      Interface IPRNG
     
        Inherit IUnknown
     
        Method Number As Ext
          Local TmwcSoph As Dword
          Local TmwcRandom, TmwcCarry As Long
          Local eqp, rndl As Long, eq As Quad
     
          eqp = VarPtr( eq )
     
          ' Temporary assignments for asm code
          TmwcSoph = mwcSoph
          TmwcRandom = mwcRandom
          TmwcCarry = mwcCarry
     
          GoSub sRandomLong
          Incr UsageCounter
          Poke Long, eqp, rndl
          Do
            GoSub sRandomLong
            Incr UsageCounter
            ! And rndL, &h0fffffff
            Poke Long, eqp + 4, rndl
          Loop While eq > 999999999999999999
     
          ' Update Instance variables for next execution
          mwcRandom = TmwcRandom
          mwcCarry = TmwcCarry
     
          Method = eq / 1000000000000000000
     
        Exit Method
     
          sRandomLong:
            ! mov eax, TmwcSoph
            ! mov ecx, TmwcRandom
            ! mul ecx
            ! Add eax, TmwcCarry
            ! adc edx, 0
            ! mov TmwcRandom, eax
            ! mov TmwcCarry,  edx
            rndl = TmwcRandom
          Return
     
        End Method
        
        Method Range( a As Long, b As Long ) As Long
          If b < a Then Swap a, b
          Method = Int( ( b - a + 1) * Me.Number + a )
        End Method
    
      End Interface
     
    End Class
    The object creation and destruction is handled by the macros CreateRandObject and DestroyRandObject respectfully.

    In use we would have something like

    Code:
    #Compile Exe
    #Dim All
     
    #Include "CPRNG.inc" ' [COLOR="Red"]change to your path[/COLOR]
     
    Function PBMain
     
      CreateRandObject
     
      ' Your masterpiece here which gets random numbers from Rand.Number
     
      DestroyRandObject
     
    End Function
    How fast?

    From post #1
    On my machine 10,000,000 iterations of RND take about 321 milliseconds. RND2 takes about 587ms and with the enhanced scope takes about 637ms. With all the bells and whistles stripped out of RND2, number generation and nothing else, we are looking at about 460ms.
    Try this.

    Code:
    #Compile Exe
    #Optimize speed
    #Dim All
    #Tools Off
    #Register None
     
    #Include "WIN32API.INC"
     
    %NOMMIDS  = 1
    %NOGDI    = 1
     
    #Include "CPRNG.inc" ' [COLOR="Red"]change to your path[/COLOR]
     
    Function PBMain
     
      Local i,j As Long, x As Ext, qFreq, qTimer As Quad
     
      CreateRandObject
     
      QueryPerformanceFrequency qFreq
     
      Tix qTimer
      For i = 1 To 10000000
        x = Rnd
      Next
      Tix End qTimer
      Print Using$("#####.##",qTimer*1000/qFreq) + "ms"
     
     
      Tix qTimer
      For i = 1 To 10000000
        x = Rand.Number
      Next
      Tix End qTimer
      Print Using$("#####.##",qTimer*1000/qFreq) + "ms"
      
      Print: Print "Choose from range 1 to 49":Print
      For j = 1 To 5
        For i = 1 To 6
          Print Using$("###", Rand.Range(1, 49));
        Next
        Print
      Next
      
      DestroyRandObject
     
      WaitKey$
     
    End Function
    NB: In the above it assumed that the Time Stamp Counter and the Performance Counter have the same frequency. If not then just use Tix for comparison.

    On one run I got

    323.39ms
    553.70ms

    This is not bad considering that Instance variables cannot be referenced by name as an operand assembler opcode and temporary variables are used in their stead.

    We can have a repeat sequence scenario for comparing two algorithms. One way would be to save the data on Rand.dat, create an object, use it with the first algorithm, destroy it and then overwrite Rand.dat with the saved data and then create another object for the second algorithm. However, if the second algorithm used less random numbers than the first we would have a sequence position that had been passed. We could code to avoid that but a much simpler approach is to use a duplicate object along the lines of the following pseudo code.
    Code:
    Local Rand1, Rand2 As IPRNG
    Let Rand1 = Class "CPRNG"
    Let Rand2 = Class "CPRNG"
    Execute Algorithm 1 using Rand1.Number
    Execute Algorithm 2 using Rand2.Number
    Rand1 = Nothing
    Rand2 = Nothing
    It does not matter what order we destroy the objects. The seeds and usage count in Rand.dat would reflect the final state of whichever object used the most random numbers.

    Any comments, tips, criticism can be posted at the same discussion set up for post #1 here.
    Last edited by David Roberts; 8 Sep 2008, 08:32 AM. Reason: Removed CurrentUsageCounter - no longer used

    Leave a comment:


  • John Gleason
    replied
    Discussion here

    Leave a comment:


  • David Roberts
    replied
    Code:
    #COMPILE EXE
    #DIM ALL
    #TOOLS OFF
    
    #INCLUDE "WIN32API.INC"
    
    %NOMMIDS  = 1
    %NOGDI    = 1
                 
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ' Rnd2 Macros
    MACRO ToggleScope = Rnd2(1)
    MACRO RepeatLastRND2 = Rnd2(0)             
    MACRO RandomiseInt(prm1) = Rnd2(-prm1)
    MACRO Randomise = Rnd2(-385)
    MACRO DefaultSequence = Rnd2(-386)
    MACRO RepeatLastSequence = Rnd2(-387)
    MACRO GotoBookmark = Rnd2(-387)
    MACRO Bookmark = Rnd2(-388)
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ' System Timer Macros
    GLOBAL qFreq, qOverhead, qStart, qStop AS QUAD
    GLOBAL f AS STRING
    
    MACRO InitializeTimer
      f = "#####.##"
      QueryPerformanceFrequency qFreq
      QueryPerformanceCounter qStart ' Intel suggestion. First use may be suspect
      QueryPerformanceCounter qStart ' So, wack it twice <smile>
      QueryPerformanceCounter qStop
      qOverhead = qStop - qStart     ' Relatively small
    END MACRO
    
    MACRO StartTimer = QueryPerformanceCounter qStart
    MACRO StopTimer = QueryPerformanceCounter qStop
    
    MACRO sTimeTaken = USING$(f,(qStop - qStart - qOverhead)*1000/qFreq) + "ms"
    MACRO nTimeTaken = (qStop - qStart - qOverhead)*1000/qFreq
    
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    DECLARE FUNCTION Rnd2( OPT LONG , LONG ) AS EXT
    
    FUNCTION PBMAIN( ) AS LONG
    LOCAL i, j AS LONG, x AS EXT
                                                                                     
      InitializeTimer
          
      PRINT "No chosen sequence":PRINT
      FOR i = 1 TO 5
        PRINT Rnd2
      NEXT
      PRINT
      PRINT "DefaultSequence":PRINT
      DefaultSequence
      FOR i = 1 TO 5
        PRINT Rnd2
      NEXT
      PRINT
      PRINT:PRINT "**********":PRINT
      
      PRINT "RandomiseInt(123)":PRINT
      RandomiseInt(123)
      FOR i = 1 TO 5
        PRINT Rnd2
      NEXT
      PRINT
      PRINT "RepeatLastSequence":PRINT
      RepeatLastSequence
      FOR i = 1 TO 5
        PRINT Rnd2
      NEXT
      PRINT:PRINT "**********":PRINT
      
      PRINT "Randomise":PRINT
      Randomise
      FOR i = 1 TO 5
        PRINT Rnd2
      NEXT
      PRINT
      PRINT "RepeatLastSequence":PRINT
      RepeatLastSequence
      FOR i = 1 TO 5
        PRINT Rnd2
      NEXT
      PRINT:PRINT "**********":PRINT
      
      PRINT "Randomise, ToggleScope":PRINT
      Randomise
      ToggleScope
      FOR i = 1 TO 10
        PRINT Rnd2
      NEXT
      PRINT
      PRINT "ToggleScope, RepeatLastSequence":PRINT
      ToggleScope
      RepeatLastSequence
      FOR i = 1 TO 10
        PRINT Rnd2
      NEXT
      PRINT:PRINT "**********":PRINT
      
      PRINT "Repeat last number generated";RepeatLastRND2
      PRINT:PRINT "**********":PRINT                                                             
      
      PRINT "Choose from range 1 to 49":PRINT
      FOR j = 1 TO 5
        FOR i = 1 TO 6
          PRINT USING$("###",Rnd2(1, 49));
        NEXT
        PRINT
      NEXT
      PRINT:PRINT "**********":PRINT
      
      PRINT "Bookmark/GotoBookmark example":PRINT
      Randomise
      FOR i = 1 TO 5
        PRINT Rnd2
      NEXT
      PRINT
      PRINT "Bookmark":PRINT
      Bookmark
      FOR i = 1 TO 5
        PRINT rnd2
      NEXT
      PRINT
      PRINT "GotoBookmark":PRINT
      GotoBookmark
      FOR i = 1 TO 5
        PRINT rnd2
      NEXT
      PRINT:PRINT "**********":PRINT
        
      PRINT "10,000,000 iterations":PRINT
      
      StartTimer
        FOR i = 1 TO 10000000
          x = RND
        NEXT i
      StopTimer
      
      PRINT "Rnd:       ";sTimeTaken
      
      Randomise
      StartTimer
        FOR i = 1 TO 10000000
          x = Rnd2
        NEXT i
      StopTimer
      
      PRINT "Rnd2 [0,1):";sTimeTaken
      
      RepeatLastSequence
      ToggleScope
      StartTimer
        FOR i = 1 TO 10000000
          x = Rnd2
        NEXT i
      StopTimer
      
      PRINT "Rnd2 (1,1):";sTimeTaken
      
      waitkey$
    
    END FUNCTION
    
    FUNCTION Rnd2( OPT One AS LONG, Two AS LONG ) AS EXT
    
    '-----------------------------------------------------------------------------------------
    'creates an EXT random test value from 0 to +0.9999... (or -0.9999... to +0.9999...)
    'where each of the 18 digits are statistically random.
    'Period is ~2^61 EXT values before repeating--many years.
    '-----------------------------------------------------------------------------------------
    STATIC eqp, oneTime, FirstTogScopePass, rndL AS LONG, eq AS QUAD
    STATIC mwcSoph, SavedmwcSoph, mwcSophFF AS DWORD
    STATIC mwcRandom, mwcCarry, SavedmwcRandom, SavedmwcCarry, mwcRandomFF, mwcCarryFF AS LONG
    STATIC TogScope AS LONG, ptrMultiplier, ptrToggleMultipliers AS DWORD PTR
    STATIC rndE AS EXT, RandomizeYet AS LONG
    LOCAL Range AS LONG, Seed AS SINGLE
    
      IF VARPTR(One) <> 0 THEN ' at least one optional parameter passed otherwise belt down to 'If OneTime = 0'
        
        IF VARPTR(Two) = 0 THEN ' just the one then
          
          IF One = 0 THEN ' Repeat the last number generated
            
            FUNCTION = rndE ' will, of course, be zero if no rndE calculated yet
            EXIT FUNCTION
            
          ELSEIF One < 0 THEN
          
            ptrMultiplier = CODEPTR(multiplier) ' to list of prime constant pre-sets
            mwcRandom = &ha5b218da ' can be any LONG > 1 or < -1
            mwcCarry  = &h3fe8700c ' can be any positive LONG less than mwcSoph and > 1
            
            SELECT CASE AS LONG One
              
              CASE -384 TO -1 ' RandomiseInt
                
                mwcSoph = @ptrMultiplier[ABS(One) - 1]
                SavedmwcSoph = mwcSoph
                SavedmwcRandom = mwcRandom
                SavedmwcCarry = mwcCarry
                          
              CASE -385 ' Randomise                                                                      
                
                IF NOT RandomizeYet THEN
                  Seed = TIMER*2^32/86400 ' 60*60*24
                  RANDOMIZE Seed
                  RandomizeYet = %True
                END IF
                mwcSoph = @ptrMultiplier[RND(0,383)]
                !dw &h310f              ;time stamp counter To vary seed1
                !Add mwcRandom, eax     ;vary seed1
                GOSUB sRandomLong ' Shuffle mwcRandom a bit more and shuffle mwcCarry
                SavedmwcSoph = mwcSoph
                SavedmwcRandom = mwcRandom
                SavedmwcCarry = mwcCarry
                
              CASE -386 ' DefaultSequence
                
                mwcSoph = 4221732234???
                mwcRandom = &ha5b218da
                mwcCarry  = &h3fe8700c
                SavedmwcSoph = mwcSoph
                SavedmwcRandom = mwcRandom
                SavedmwcCarry = mwcCarry
                
              CASE -387 ' RepeatLastSequence
                
                IF mwcSoph = 0 THEN ' there wasn't a last sequence so use default
                  mwcSoph = 4221732234???
                  mwcRandom = &ha5b218da
                  mwcCarry  = &h3fe8700c
                  SavedmwcSoph = mwcSoph
                  SavedmwcRandom = mwcRandom
                  SavedmwcCarry = mwcCarry
                ELSE
                  mwcSoph = SavedmwcSoph
                  mwcRandom = SavedmwcRandom
                  mwcCarry = SavedmwcCarry
                END IF
                
              CASE -388 ' Bookmark
                
                SavedmwcSoph = mwcSoph
                SavedmwcRandom = mwcRandom
                SavedmwcCarry = mwcCarry
              
              CASE ELSE
                
                FUNCTION = -1 ' Error
                EXIT FUNCTION
                
            END SELECT
            
          ELSE 'make it 50/50 + and -
          
            TogScope = NOT TogScope
            
            IF FirstTogScopePass = 0 THEN
              FirstTogScopePass = 1
              ptrToggleMultipliers = CODEPTR(ToggleMultipliers)
              IF NOT RandomizeYet THEN
                Seed = TIMER*2^32/86400 ' 60*60*24
                RANDOMIZE Seed
                RandomizeYet = %True
              END IF
              mwcSophFF = @ptrToggleMultipliers[RND(0,11)] ' 50/50 + and - uses its own random sequence and stays with it
              mwcRandomFF = &ha5b218da
              mwcCarryFF  = &h3fe8700c
              !dw &h310f              ;time stamp counter To vary seed1
              !Add mwcRandomFF, eax   ;vary seed1
              GOSUB sRandomFF ' Shuffle mwcRandomFF a bit more and shuffle mwcCarryFF
            END IF
            
          END IF 'One = 0
          
          FUNCTION = 0 ' OK
          EXIT FUNCTION
          
        ELSE ' both optional parameters passed so
        
          Range = %True ' and fall through code
          
        END IF ' VarPtr(Two) = 0
        
      END IF ' VarPtr(One) <> 0
      
      IF OneTime = 0 THEN ' otherwise start crunching
        OneTime = 1
        IF mwcSoph = 0 THEN ' the parameter section above has yet to be entered, unless RepeatLastRND2,
          mwcSoph = 4221732234??? ' so use default configuration and fall through code
          mwcRandom = &ha5b218da
          mwcCarry  = &h3fe8700c
          SavedmwcSoph = mwcSoph
          SavedmwcRandom = mwcRandom
          SavedmwcCarry = mwcCarry
        END IF
        eqp = VARPTR( eq )
      END IF
      
      
      GOSUB sRandomLong 'sub to generate LONG rnd value
      POKE LONG, eqp, rndl 
      DO 'DO LOOP runs avg. of 2.3 loops / Rnd2. It's needed for perfectly linear distribution
        GOSUB sRandomLong
        ! And rndL, &h0fffffff
        POKE LONG, eqp + 4, rndl
      LOOP WHILE eq > 999999999999999999
      
      rndE = eq / 1000000000000000000 ' divide it to make its range 0 to .999999999999999999
        
      ' Cannot leave yet - couple of questions to ask
      IF Range THEN
        IF  Two < One THEN SWAP One, Two
        rndE = INT( (Two - One + 1)*rndE + One )
      ELSEIF TogScope THEN
        GOSUB sRandomFF 'make it 50/50 + and -
        IF rndL > 0 THEN rndE = -rndE
      END IF
      
      FUNCTION = rndE
      
    EXIT FUNCTION
    
    ' Engine by John Gleason
    sRandomLong: 'here we generate a random LONG from 0 to &hffffffff
    !mov eax, mwcSoph
    !mov ecx, mwcRandom
    !mul ecx
    !Add eax, mwcCarry
    !adc edx, 0
    !mov mwcRandom, eax
    !mov mwcCarry,  edx
    !mov rndL, eax
    RETURN 'done generating, rndL holds final value
    
    sRandomFF: ' As sRandomLong but used exclusively by TogScope
    ! mov eax, mwcSophFF
    ! mov ecx, mwcRandomFF
    ! mul ecx
    ! Add eax, mwcCarryFF
    ! adc edx, 0
    ! mov mwcRandomFF, eax
    ! mov mwcCarryFF, edx
    ! mov rndL, eax
    RETURN
    
    ToggleMultipliers:
    !DD 4221474930???, 4221475530???, 4221475614???, 4221476664???, 4221477015???, 4221477093???
    !DD 4221477489???, 4221477834???, 4221478689???, 4221478848???, 4221479685???, 4221479778???
    
    ' Ruined for choice by that man again, John Gleason
    multiplier:
    !DD 4221480339???, 4221480549???, 4221480579???, 4221480663???, 4221481263???, 4221481914???, 4221482613???, 4221482670???
    !DD 4221483033???, 4221483405???, 4221484758???, 4221485325???, 4221485910???, 4221485925???, 4221486498???, 4221487443???
    !DD 4221488559???, 4221489459???, 4221490755???, 4221490794???, 4221491259???, 4221491949???, 4221492453???, 4221493668???
    !DD 4221494070???, 4221494178???, 4221495243???, 4221496245???, 4221496938???, 4221497178???, 4221497475???, 4221497895???
    !DD 4221498069???, 4221498099???, 4221498153???, 4221499248???, 4221499413???, 4221499884???, 4221500409???, 4221501990???
    !DD 4221502998???, 4221503544???, 4221503964???, 4221505260???, 4221507753???, 4221508200???, 4221508875???, 4221509904???
    !DD 4221509949???, 4221510765???, 4221512160???, 4221512919???, 4221513444???, 4221514263???, 4221515289???, 4221515325???
    !DD 4221515445???, 4221520290???, 4221520554???, 4221521718???, 4221521844???, 4221522618???, 4221524268???, 4221524439???
    !DD 4221524964???, 4221525570???, 4221526335???, 4221526608???, 4221527565???, 4221528030???, 4221528099???, 4221528255???
    !DD 4221528675???, 4221533160???, 4221533169???, 4221533193???, 4221533343???, 4221535059???, 4221535143???, 4221535674???
    !DD 4221537060???, 4221537138???, 4221538230???, 4221538968???, 4221539343???, 4221539799???, 4221540048???, 4221540270???
    !DD 4221540279???, 4221540774???, 4221541563???, 4221541680???, 4221541929???, 4221542283???, 4221543339???, 4221543390???
    !DD 4221543504???, 4221544818???, 4221544914???, 4221545025???, 4221546045???, 4221546768???, 4221547230???, 4221547569???
    !DD 4221549219???, 4221550308???, 4221550563???, 4221551088???, 4221551433???, 4221551460???, 4221552075???, 4221552879???
    !DD 4221552894???, 4221553764???, 4221554763???, 4221554958???, 4221555114???, 4221556344???, 4221557439???, 4221557898???
    !DD 4221557943???, 4221558348???, 4221558810???, 4221560484???, 4221560628???, 4221560733???, 4221561378???, 4221561879???
    !DD 4221562518???, 4221562899???, 4221564303???, 4221564585???, 4221564654???, 4221566130???, 4221566613???, 4221569700???
    !DD 4221570165???, 4221570639???, 4221570660???, 4221573558???, 4221574185???, 4221574365???, 4221574575???, 4221575349???
    !DD 4221576675???, 4221576969???, 4221577479???, 4221578124???, 4221578553???, 4221579039???, 4221579393???, 4221581049???
    !DD 4221581973???, 4221582468???, 4221582795???, 4221583113???, 4221583740???, 4221584445???, 4221584478???, 4221584583???
    !DD 4221585630???, 4221588705???, 4221590124???, 4221590175???, 4221590295???, 4221590589???, 4221591480???, 4221591555???
    !DD 4221591708???, 4221591774???, 4221591888???, 4221592413???, 4221592614???, 4221593094???, 4221593295???, 4221593955???
    !DD 4221594573???, 4221596799???, 4221598914???, 4221599334???, 4221600195???, 4221600384???, 4221600888???, 4221602253???
    !DD 4221602379???, 4221604428???, 4221605268???, 4221605613???, 4221605634???, 4221606255???, 4221606264???, 4221606303???
    !DD 4221606375???, 4221607620???, 4221608643???, 4221608718???, 4221608973???, 4221610023???, 4221610200???, 4221611724???
    !DD 4221612249???, 4221612660???, 4221613068???, 4221613320???, 4221613998???, 4221614298???, 4221614808???, 4221615168???
    !DD 4221615174???, 4221617064???, 4221618120???, 4221618714???, 4221618744???, 4221620364???, 4221620430???, 4221620658???
    !DD 4221622959???, 4221623070???, 4221623889???, 4221624450???, 4221624939???, 4221625434???, 4221625605???, 4221626340???
    !DD 4221626835???, 4221626895???, 4221627129???, 4221628809???, 4221629538???, 4221630465???, 4221631734???, 4221632805???
    !DD 4221633780???, 4221633933???, 4221634779???, 4221635040???, 4221635439???, 4221636588???, 4221637875???, 4221638013???
    !DD 4221638244???, 4221638673???, 4221639135???, 4221639420???, 4221639705???, 4221639798???, 4221640134???, 4221640284???
    !DD 4221640995???, 4221641088???, 4221641184???, 4221641943???, 4221644190???, 4221644658???, 4221646134???, 4221647289???
    !DD 4221648000???, 4221649440???, 4221650313???, 4221652239???, 4221653394???, 4221653994???, 4221654009???, 4221655173???
    !DD 4221656073???, 4221656160???, 4221657090???, 4221657375???, 4221657579???, 4221658050???, 4221658089???, 4221659550???
    !DD 4221659715???, 4221659805???, 4221660045???, 4221660555???, 4221661440???, 4221662523???, 4221662655???, 4221663060???
    !DD 4221663300???, 4221663354???, 4221663939???, 4221664254???, 4221664620???, 4221665280???, 4221665349???, 4221666090???
    !DD 4221667080???, 4221667590???, 4221668130???, 4221668478???, 4221668625???, 4221670179???, 4221670200???, 4221670578???
    !DD 4221671529???, 4221671718???, 4221672750???, 4221674115???, 4221676560???, 4221677718???, 4221678195???, 4221679899???
    !DD 4221681219???, 4221683115???, 4221684654???, 4221685398???, 4221685830???, 4221686454???, 4221686694???, 4221688359???
    !DD 4221690588???, 4221690948???, 4221691479???, 4221692103???, 4221693153???, 4221694200???, 4221694569???, 4221694998???
    !DD 4221695028???, 4221695073???, 4221696114???, 4221696249???, 4221696594???, 4221696744???, 4221696774???, 4221696879???
    !DD 4221697623???, 4221698295???, 4221699195???, 4221699324???, 4221699348???, 4221699825???, 4221699975???, 4221702369???
    !DD 4221703209???, 4221703464???, 4221703659???, 4221704703???, 4221704718???, 4221706098???, 4221708114???, 4221708708???
    !DD 4221709890???, 4221709959???, 4221711558???, 4221711843???, 4221712458???, 4221712668???, 4221714948???, 4221714999???
    !DD 4221717123???, 4221717219???, 4221717573???, 4221717678???, 4221718110???, 4221718200???, 4221718434???, 4221718488???
    !DD 4221718644???, 4221720504???, 4221721668???, 4221722193???, 4221722568???, 4221722718???, 4221723513???, 4221723588???
    !DD 4221723645???, 4221723708???, 4221724410???, 4221724470???, 4221725298???, 4221727518???, 4221727935???, 4221728259???
    !DD 4221728379???, 4221728430???, 4221729435???, 4221729624???, 4221729828???, 4221731115???, 4221732060???, 4221732234???
    
    END FUNCTION
    Last edited by David Roberts; 1 Sep 2008, 04:01 AM.

    Leave a comment:


  • David Roberts
    started a topic Rnd2

    Rnd2

    IF you have been here before THEN GOTO post #4 for another idea (Needs PB9 and/or CC5)

    RND2 is simply John Gleason's rndExt function introduced at post #6 in Walter Henn's Random Number (RND) Problem thread here with some functionality similar to PB's RND.

    RND2 is a bit cheeky but not carved in stone, is it?

    Blue text use following indicates a macro name.

    Simplest form: Print RND2 or x = RND2. This is equivalent to RND's floating point mode. As with RND a default sequence is used and with no argument generates the next number in sequence. This is also true if RND has a positive argument but not so for RND2 - a positive argument has a different role, covered later in ToggleScope.

    With RND we have one sequence and a user seed determines a starting position in that sequence. With RND2 we have a multiplier which sets up a unique sequence and two user seeds determine where in that sequence we start from.

    To ensure a different starting position with RND we could use Randomize (same as Randomize Timer). Recently, John Gleason sent me a large batch of multipliers and I have used the 384 largest for RND2. The period for the method used here is dependent upon the multiplier and the multipliers used are greater than the one used with rndExt. The two user seeds may not be any old seeds and must adhere to rules but they are not that restrictive. To make life simple RND2 uses default seeds and to ensure a different start RND2 firstly chooses one of the 384 multipliers at random. The first seed is then 'shuffled' by making use of the Time Stamp Counter. The chosen multiplier, 'shuffled' first seed and default second seed are then fed into the generator. This further 'shuffles' the first seed and 'shuffles' the second seed.

    To achieve this we simply use the macro Randomise ie 's' instead of 'z'.

    Notice that we do not have 'Randomise n' where n is a numeric expression. RND fixes a multiplier, it is assumed, and varies the seed. The above tack, which does make life easier, fixes the seeds, initially, and varies the multiplier.

    The generator has a period close to 2^63. It is used more than once in RND2, as it is in rndExt, thus reducing the effective period which is about 2^61. On my machine RND's sequence in a tight loop will be used up in about 330 seconds. If RND2 were as fast as RND its sequence would be used up in about 5617 years. It is not as fast so you may need to change the motherboard's battery.

    The default seed for RND can be duplicated by Randomize Cvs(Chr$(255,255,255,255)). With RND2 we use the macro DefaultSequence. This simply uses the two default seeds, mentioned above, and the largest multiplier from our list of 384.

    RND has a special effects mode. RND(0) repeats the last number generated and so does RND2(0) and the macro RepeatLastRND2.

    If RND has a negative argument then the generator is re-seeded giving then a fixed sequence or, rather, a fixed starting point. For example, Print RND(-123) which, of course, is effectively the same as Randomize -123: Print RND. We do not have a 'Randomise n' but we do have access to 384 multipliers and we get to them via RandomiseInt(n) with n = 1,2,...,384. The 'Int' is to remind us an integer parameter is required.

    In general, re-seeding may lead to sequence overlapping and should then be avoided. However, if we are comparing two algorithms, for example, then having them 'fed' with the same sequence may be desirable.

    With RND we can re-seed from a random position. For example, t = Timer: Randomize t. Later we can 'Randomize t' again.

    With RND2 we use RepeatLastSequence.

    In practice we could have something like the following pseudo code:

    Code:
    RND                              RND2
     
        t = Timer
        Randomize t                      Randomise
        Execute algorithm 1              Execute algorithm 1
        Randomize t                      RepeatLastSequence
        Execute algorithm 2              Execute algorithm 2
    With the fixed sequence approach we would use a RandomiseInt(n) twice but the second instance could be replaced with RepeatLastSequence. RepeatLastSequence then works with both fixed starting positions and random starting positions.

    Whilst in this vein there is a final command which does not have a RND equivalent. Suppose we have some initialization code which makes use of random numbers and we then want to consider two algorithms. The first part would probably need to be random but the two algorithms may be better tested with the same sequence. To this end Bookmark can be used just prior to algorithm 1 to capture the chosen multiplier and the two current user seeds. To return to the bookmark just prior to algorithm 2 we can use either GotoBookmark or RepeatLastSequence - they are identical in execution.

    Pseudo code example:

    Code:
    Randomise
    Initialize
    Bookmark
    Execute algorithm 1
    GotoBookmark ( or RepeatLastSequence )
    Execute algorithm 2
    With the exception of RepeatLastRND2 all of the above commands return either false if no error or true in the event of an error.

    ToggleScope is also a departure from RND. RND2's default scope is, as with RND, [0,1). Numbers generated after the first use of ToggleScope fall in the range (0,1), and back to [0,1] when invoked again. This additional scope was introduced by John Gleason in RndExt. However, in RndExt the generator is used to assign the sign which, obviously, has an effect on the period. More importantly, care would have to be taken when using ToggleScope and RepeatLastSequence else we lose synchronisation. Both of these issues can be eliminated by giving ToggleScope its own generator. It also has its own set of multipliers apart rom the 384 already used and the sequence is set up in exactly the same way as Randomise. ToggleScope is the macro for RND2 with a positive parameter.

    RND's Integer Range mode, RND(a,b) is replicated with RND2 as RND2(a,b).

    How fast?

    On my machine 10,000,000 iterations of RND take about 321 milliseconds. RND2 takes about 587ms and with the enhanced scope takes about 637ms. With all the bells and whistles stripped out of RND2, number generation and nothing else, we are looking at about 460ms. On the one hand this shows how fast the generator is but, on the other hand, it shows how fast RND is - it still has the bells and whistles.

    The function RND2 is in post #2 and PBMAIN gives it a little work out.

    In this particular case nothing much is gained by the new compilers so the code is left as compiled with PBCC4.

    Final comment: Thanks John.
    Last edited by David Roberts; 7 Sep 2008, 10:36 AM. Reason: Forgot to use CODE for the pseudo code sections.
Working...
X