Community discussions

MikroTik App
 
User avatar
TealFrog
just joined
Topic Author
Posts: 23
Joined: Sun Oct 02, 2011 11:56 am

Pseudo Random Number Generator Script (Mersenne Twister)

Tue Nov 22, 2011 11:36 am

The following script was created to produce better (pseudo) random generated numbers on a MikroTik router. The script is based on the Mersenne Twister (MT) algorithm. The script will work as written, cut-and-paste, for demonstration purposes. The script is intended to be modified for use with other scripts by either changing the "arrAdjRandNumValues" local variable to a global scope or by storing the variable's contents to a file. The output generated from this script can be used as input to another script requiring random numbers.

The script can use either a static seed (integer) defined in the script or by default can generate a dynamic seed. The dynamic seed uses a combination of date, time and other values to seed a formula loosely based on the rand() function of the C programming language. The results are then used as the seed for the MT algorithm. The script is meant to generate positive integers. The script outputs the numbers generated to the console.

The script started out as an experiment and out of my own (obsessive) curiosity. I've opted not to put too much more time and effort into the script. The script has very limited usefulness since other alternatives exist. However, the script was intended to be a standalone solution. The script may prove useful under the right circumstances.
# A pseudo random number generator MikroTik script. 
# Based on the Mersenne Twister pseudorandom number algorithm. 
# v1.3 Tested and Developed on ROS v5.8

# Configuration Parameters
# intNumberOfRands - Number of pseudorandom number values to generate
:local intNumberOfRands 100
# intRandFloor - Lowest numeric range for generated values (must be positive value)
:local intRandFloor 0 
# intRandCeiling - Highest numeric range for generated values (must be positive value)
:local intRandCeiling 100
# blnShowStats - Displays distribution for generated numbers (default false)
:local blnShowStats false
# blnOneRndPerLine - Display generated values one per line on program completions (default false)
:local blnOneRndPerLine false
# blnGenerateSeed - Use a system generated seed for value generation (default true)
:local blnGenerateSeed true
# intSeed - Static seed value above Boolean value must be false to use (default 19650218)
:local intSeed 19650218
# Remaining values are associated with system generated seed values, blnGeneratedSeed=true to use
# blnUseWiFi - Use wireless statistics as part of seed generation, experimental (default false)
:local blnUseWiFi false
# strWiFiName - Name of wireless interface, above blnUseWiFi must be true (default wlan1)
:local strWiFiName "wlan1"
# strOutFile - Temporary file used to gather wireless statistics
:local strOutFile "RndOutTraff"
# No need to modify variable beyond this line
:local arrInitValues { 0x123; 0x234; 0x345; 0x456 }
:local intInitArrayLen [ :len $arrInitValues ]
:local arrLngRandNumValues {}
:local arrAdjRandNumValues {}
:local N 624
:local M 397
:local intUpperBitMask 0x80000000
:local intLowerBitMask 0x7fffffff
:local intMatrixA 0x9908b0df
:local arrMagicValues [ :toarray ( 0, $intMatrixA ) ]
:local intProgressEvery 0
:local intPctDone 0
:local arrMerTwist {}
:local intMersTwistArrLen ( $N + 1 )
:local intTotalValues 0
:local intWiHiValue 0
:local intWiLowValue 0
:local intRandNumber 0
:local intSeenValue 0
:local arrSeenValues [ :toarray $intSeenValue ]
:put "Running..."
:for i from=( $intRandFloor ) to=( $intRandCeiling - 1 ) do={
    :set arrSeenValues ( $arrSeenValues, $intSeenValue )
} 
:if ( $blnGenerateSeed = true ) do={
    :put "Generating seed value from system events."
    :local intUpTime [ /system resource get uptime ];
    :if ( $blnUseWiFi = true ) do={
        :put "Using wireless for seed generation."
        :local lcv 1
        :local blnContinue true
        :do {
            :put "Attempt $lcv to gather wireless traffic statistics."
            /interface monitor-traffic $strWiFiName once file=$strOutFile
            /delay 3s
            :local strInFile ($strOutFile . ".txt")
            :local strContent [/file get [/file find name=$strInFile] contents]
            :if ( [ :len $strContent ] < 1 ) do={
                :put "No content generated for wireless statistics."
            } else={
                :local intLocXmitBps ( [ :tonum [ :find $strContent \
                  "tx-bits-per-second:" 0 ] ] + 20 )
                :local intXmitBps [ :pick $strContent $intLocXmitBps ( [ :tonum \
                  [ :find $strContent "bps" $intLocXmitBps ] ] - 1 ) ]
                :local intXmitDecimalLoc [ :tonum [ :find $intXmitBps "." 0 ] ]
                :set intWiHiValue [ :tonum [ :pick $intXmitBps 0 $intXmitDecimalLoc ] ]
                :set intWiLowValue [ :tonum [ :pick $intXmitBps ( $intXmitDecimalLoc + 1 ) \
                  ( $intXmitDecimalLoc + 2 ) ] ] 
                :if ( [ :len [ :tostr intWiHiValue ] ] > 0 ) do={
                    :if ( [ :len [ :tostr intWiLowValue ] ] > 0 ) do={
                        :set blnContinue false
                    }
                } else={
                    :if ( lcv > 3 ) do={
                        :set intWiHiValue 0
                        :set intWiLowValue 0
                        :set blnContinue false
                    }
                }
                /file remove [ /file find name=$strInFile ];
            } 
            :set lcv ( $lcv + 1 )
        } while=( $blnContinue = true )
    }
    :local intClockValue ( [ :tonum [ :pick [ /system clock get time ] 6 8 ] ] % 6 )
    /delay 1s
    :local intCpuValue [/system resource get cpu-load ];
    :local strSysTime [ :tostr [ /system clock get time ] ]
    :local intSeconds ( ( [ :tonum [ :pick $strSysTime 0 2 ] ] ) * 3600 )
    :set intSeconds ( $intSeconds + ( ( [ :tonum [ :pick $strSysTime 3 5 ] ] ) * 60 ) )
    :set intSeconds ( $intSeconds + ( ( [ :tonum [ :pick $strSysTime 6 8 ] ] ) * ( \
      [ :tonum $intWiHiValue ] + [ :tonum $intWiLowValue ] ) ) )
    :local arrMons [ :toarray "jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec" ]
    :local strDate [ :tostr [ /system clock get date ] ]
    :local intDayCount ( ( [ :tonum [ :find $arrMons \
      [ :pick $strDate 0 3 ] ] ] * 30 ) + [ :tonum [ :pick $strDate 4 6 ] ] )
    :local intYear ( ( [ :tonum [ :pick $strDate 7 [ :len $strDate ] ] ] - 2011 ) * 365 )
    :set intSeed ( ( ( ( $intYear  + $intDayCount ) * 86400 ) + $intSeconds ) + \
      [ :tonum $intClockValue ] + [ :tonum $intCpuValue ] + \
      [ :tonum $intUpTime ] + [ :tonum $intWiHiValue ] + [ :tonum $intWiLowValue ] )
    :set intSeed ( ( ( $intSeed * 1103515245 + 12345 ) / 65536) % 32768 ) 
    :put "Using system dynamically generated seed value: $intSeed"
 } else {
     :put "Using static seed stored in script variable with value: $intSeed"
     :put "Numbers will be testable and repeatable (deterministic)."
 }
# End of creating seed
# $arrMerTwist[N] is array for the state vector
:put "Step 1: Initializing (seeding) array for state vector."
:set arrMerTwist [ :toarray ( [ :tonum $intSeed ] & 0xffffffff ) ]
:set intTotalValues ( $N - 1 )
:set intProgressEvery ( $intTotalValues / 20 )
:set intPctDone 0
# if ( $intMersTwistArrLen = N+1 ) means arrMerTwist[N] is not initialized */
:set intMersTwistArrLen ( $N + 1 )
:for lcv from=1 to=( $N - 1 ) do={
    :if ( ( $lcv % $intProgressEvery ) = 0 ) do={
        :set intPctDone ( $intPctDone + 5 )
        :put "Step 1: $intPctDone% completed."
    }
    :local intValue1 [ :tonum [ :pick $arrMerTwist ( $lcv - 1 ) ] ]
    :set intValue1 ( $intValue1 ^ ( $intValue1 >> 30 ) )
    :set intValue1 ( $intValue1 * 1812433253 )
    :set intValue1 ( $intValue1 + $lcv )
    :set intValue1 ( $intValue1 & 0xffffffff )
    :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist 0 $lcv ], $intValue1 ) ]
    :set intMersTwistArrLen [ :tonum $lcv ]
}
:set intMersTwistArrLen ( $intMersTwistArrLen + 1 )
:put "Step 2: Starting initialization by array"
:local i 1
:local j 0
:local k [ :tonum $intInitArrayLen ]
:if ( $N > $intInitArrayLen ) do={
    :set k [ :tonum $N ]
}
:local intTotalValues ( [ :tonum $k ] - 1 )
:set intProgressEvery ( $intTotalValues / 20 )
:set intPctDone 0
:while ( $k > 0 ) do={
    :if ( ( $k % $intProgressEvery ) = 0 ) do={
        :set intPctDone ( $intPctDone + 5 )
        :put "Step 2: $intPctDone% completed."
    }      
    :local intValue1 [ :tonum [ :pick $arrMerTwist ( $i - 1 ) ] ]
    :set intValue1 ( $intValue1 ^ ( $intValue1 >> 30 ) )
    :set intValue1 ( $intValue1 * 1664525 )
    :set intValue1 ( ( [ :tonum [ :pick $arrMerTwist $i ] ] ) ^ $intValue1 )
    :set intValue1 ( $intValue1 + ( [ :tonum [ :pick $arrInitValues $j ] ] ) )
    :set intValue1 ( $intValue1 + [ :tonum $j ] )
    :set intValue1 ( $intValue1 & 0xffffffff )
    :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist 0 $i ], $intValue1, \
      [ :pick $arrMerTwist ( $i + 1 ) [ :len $arrMerTwist ] ] ) ]
    :set i ( $i + 1 )
    :set j ( $j + 1 )
    :if ( $i >= $N ) do={
        :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist ( $N - 1 ) ], \
          [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] ) ]
        :set i 1
    }
    :if ( $j >= $intInitArrayLen ) do={
        :set j 0
    }
    :set k ( $k - 1 )
}
:put "Step 3: Last portion of initialization by array."
:set k ( $N - 1 )
:set intTotalValues $k 
:set intProgressEvery ( $intTotalValues / 20 )
:set intPctDone 0
:while ( $k > 0 ) do={
    :if ( ( $k % $intProgressEvery ) = 0 ) do={
        :set intPctDone ( $intPctDone + 5 )
        :put "Step 3: $intPctDone% completed."
    }
    :local intValue1 [ :tonum [ :pick $arrMerTwist ( $i - 1 ) ] ]
    :set intValue1 ( $intValue1 ^ ( $intValue1 >> 30 ) )
    :set intValue1 ( $intValue1 * 1566083941 )
    :set intValue1 ( ( [ :tonum [ :pick $arrMerTwist $i ] ] ) ^ $intValue1 )
    :set intValue1 ( $intValue1 - $i )
    :set intValue1 ( $intValue1 & 0xffffffff )
    :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist 0 $i ], $intValue1, \
      [ :pick $arrMerTwist ( $i + 1 ) [ :len $arrMerTwist ] ] ) ]
    :set i ( $i + 1 )
    :if ( $i >= $N ) do={
        :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist ( $N - 1 ) ], \
          [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] ) ]
        :set  i 1
    }
    :set k ( $k - 1 )
}
# MSB is 1; assuring non-zero initial array
:set arrMerTwist [ :toarray ( [ :tonum 0x80000000 ], [ :pick $arrMerTwist 1 \
  [ :len $arrMerTwist]  ] ) ]
:put "Initialization completed."
# Main Program generate pseudorandom numbers
:put "Starting number generation."
:local intRandNumVal 0
:for i from=0 to=( $intNumberOfRands - 1 ) do={
    :put ("Generating random number " . ( $i + 1 ) . " of $intNumberOfRands.")
    :if ( $intMersTwistArrLen >= $N ) do={
        :if ( $intMersTwistArrLen = ( $N + 1 ) ) do={
            :put "** ERROR state vector array is uninitalized. **"
            :error "Unrecoverable error program terminiated."
        }
        :local intValue1 0
        :local intValue2 0
        :local kk 0
        :set intTotalValues ( $N - $M ) 
        :set intProgressEvery ( $intTotalValues / 20 )
        :set intPctDone 0
        :while ( $kk < ( $N - $M ) ) do={
            :if ( ( $kk % $intProgressEvery ) = 0 ) do={
                :put "Main Program sub task A: $intPctDone% completed."
                :set intPctDone ( $intPctDone + 5 )
            }
            :set intValue1 [ :tonum [ :pick $arrMerTwist $kk ] ]
            :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + 1 ) ] ]
            :set intRandNumVal [ :tonum ( ( $intValue1 & $intUpperBitMask ) | \
              ( $intValue2 & $intLowerBitMask ) ) ]
            :set intValue1 ( [ :tonum $intRandNumVal ] & 1 )
            :set intValue1 [ :tonum [ :pick $arrMagicValues $intValue1 ] ]
            :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + $M ) ] ]
            :set intValue1 [ :tonum ( ( $intValue2 ^ ( $intRandNumVal >> 1 ) ) ^ $intValue1 ) ]
            :if ( $kk < 1 ) do={
                :set arrMerTwist ( $intValue1, [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] )
            } else={
                :set arrMerTwist ( [ :pick $arrMerTwist 0 $kk ], $intValue1, \
                  [ :pick $arrMerTwist ( $kk + 1 ) [ :len $arrMerTwist ] ] ) 
            }
            :set kk ( $kk + 1 )
        }
        :set intTotalValues ( $N - 1 ) 
        :set intProgressEvery ( $intTotalValues / 20 )
        :set intPctDone 0
        :while ( $kk < ( $N - 1 ) ) do={
            :if ( ( $kk % $intProgressEvery ) = 0 ) do={
                :set intPctDone ( $intPctDone + 5 )
                :put "Main Program sub task B: $intPctDone% completed."
            }
            :set intValue1 [ :tonum [ :pick $arrMerTwist $kk ] ]
            :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + 1 ) ] ]
            :set intRandNumVal [ :tonum ( ( $intValue1 & $intUpperBitMask ) | \
              ( $intValue2 & $intLowerBitMask ) ) ]
	        :set intValue1 ( [ :tonum $intRandNumVal ] & 1 )
            :set intValue1 [ :tonum [ :pick $arrMagicValues $intValue1 ] ]
            :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + ( $M - $N ) ) ] ]
            :set intValue1 [ :tonum ( ( $intValue2 ^ ( $intRandNumVal >> 1 ) ) ^ $intValue1 ) ]
            :if ( $kk < 1 ) do={
                :set arrMerTwist ( $intValue1, [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] )
            } else={
                :set arrMerTwist ( [ :pick $arrMerTwist 0 $kk ], $intValue1, \
                  [ :pick $arrMerTwist ( $kk + 1 ) [ :len $arrMerTwist ] ] ) 
            }
            :set kk ( $kk + 1 )
        }
        :set intValue1 [ :tonum [ :pick $arrMerTwist ( $N - 1 ) ] ]
        :set intValue2 [ :tonum [ :pick $arrMerTwist 0 ] ]
        :set intRandNumVal [ :tonum ( ( $intValue1 & $intUpperBitMask ) | \
          ( $intValue2 & $intLowerBitMask ) ) ]
        :set intValue1 ( [ :tonum $intRandNumVal ] & 1 )
        :set intValue1 [ :tonum [ :pick $arrMagicValues $intValue1 ] ]
        :set intValue2 [ :tonum [ :pick $arrMerTwist ( $M - 1 ) ] ]
        :set intValue1 [ :tonum ( ( $intValue2 ^ ( $intRandNumVal >> 1 ) ) ^ $intValue1 ) ]
# Next line is for saftey, but ($N - 1) should never be < 1         
        :if ( ( $N - 1 ) < 1 ) do={
            :set arrMerTwist ( $intValue1, [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] )
        } else={
            :set arrMerTwist ( [ :pick $arrMerTwist 0 ( $N - 1 ) ], $intValue1, \
              [ :pick $arrMerTwist [ :tonum $N ] [ :len $arrMerTwist ] ] ) 
        }
        :set intMersTwistArrLen 0
    }
    :set intRandNumVal [ :tonum [ :pick $arrMerTwist $intMersTwistArrLen ] ]
    :set intMersTwistArrLen ( $intMersTwistArrLen + 1 )
# Tempering
    :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( $intRandNumVal >> 11 ) ) ]
    :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( ( [ :tonum $intRandNumVal ] << 7 ) \
      & 0x9d2c5680 ) ) ]
    :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( ( [ :tonum $intRandNumVal ] << 15 ) \
      & 0xefc60000 ) ) ]
    :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( [ :tonum $intRandNumVal ] >> 18 ) ) ]
# end genrand_int32
    :set arrLngRandNumValues ( $arrLngRandNumValues, $intRandNumVal )
# Some Error checking
    :if ( ( [ :len [ :tostr $intRandNumVal ] ] < 1 ) or ( [ :tonum $intRandNumVal ] = 0 ) ) \
      do={
        :put "** DIAGNOSTICS **"
        :put ("intRandNumVal($intRandNumVal) intMersTwistArrLen($intMersTwistArrLen) \
          intSeed($intSeed) len_mt(" . [ :len $arrMerTwist ] . ")")
        :put "Contents of \$arrMerTwist array:"
        :put $arrMerTwist
        :error "** ERROR ** Program execution halted no \$intRandNumVal value generated"
    }
# Done with error checking and diagnostic reporting    
    :set intRandNumber ( ( $intRandNumVal % ( $intRandCeiling - $intRandFloor + 1 ) ) \
      + $intRandFloor )    
    :set arrAdjRandNumValues ( $arrAdjRandNumValues, $intRandNumber )
    :set intSeenValue [ :tonum [ :pick $arrSeenValues ( $intRandNumber - $intRandFloor ) ] ]
    :set intSeenValue ( $intSeenValue + 1 )
    :if ( ( $intRandNumber - $intRandFloor ) = 0 ) do={
        :set arrSeenValues [ :toarray ( [ :tonum $intSeenValue ], [ :pick $arrSeenValues 1 \
          [ :len $arrSeenValues ] ] ) ]
    } else={
        :set arrSeenValues [ :toarray ( [ :pick $arrSeenValues 0 \
          ( $intRandNumber - $intRandFloor ) ], [ :tonum $intSeenValue ], \
          [ :pick $arrSeenValues ( ( $intRandNumber - $intRandFloor ) + 1 ) \
          [ :len $arrSeenValues ] ] ) ]
    }
#    :put "Generated raw random number is $intRandNumVal"
#    :put "Adjusted random value is: $intRandNumber"
}
:if ( $blnShowStats = true ) do={
    :if ( $blnGenerateSeed = true ) do={
        :put "Used dyamically generated seed value: $intSeed"
    } else={
        :put "Used static seed based on script \$intSeed value: $intSeed"
    }
    :put "Distribution of Numbers Generated [ #/Occurence ]"
    :local intTotalRandsGen 0
    :for i from=0 to=( [ :len $arrSeenValues ] - 1 ) do={
        :local intSeenCount [ :tonum [ :pick $arrSeenValues $i ] ]
        :set intTotalRandsGen ( $intTotalRandsGen + $intSeenCount )
        :set intRandNumber ( $i + $intRandFloor )
        :local strOutLine ( $intRandNumber . "/" . $intSeenCount )
        :for j from=1 to=( 16 - [ :len [ :tostr $strOutLine ] ] ) do={
            :set strOutLine " $strOutLine"
        }
        :set strOutLine "[$strOutLine] "
        :local intDrawToCol [ :tonum $intSeenCount ]
        :if ( $intDrawToCol > 62 ) do={
            :set intDrawToCol 62
        }
        :set j 1
        :while ( $j <= $intDrawToCol ) do={
            :set strOutLine [ :tostr ( $strOutLine . "*" ) ]
            :set j ( $j + 1 )
        }
        :put "$strOutLine"
    }
    :put "Total random numbers generated: $intTotalRandsGen"
}
:if ( $blnOneRndPerLine = true ) do={
    :foreach intRndValue in=( $arrAdjRandNumValues ) do={
        :put $intRndValue
    }
} else={
#    :put $arrLngRandNumValues
    :put $arrAdjRandNumValues
}
:put "Done."
 
Wyz4k
Member Candidate
Member Candidate
Posts: 240
Joined: Fri Jul 10, 2009 10:23 am

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Thu Nov 10, 2016 2:53 am

Thanks for that!

To make it compatible with 6.37.1 I just had to replace the empty array declaration {} with ""
 
helipos
Member Candidate
Member Candidate
Posts: 132
Joined: Sat Jun 25, 2016 11:32 am

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Sat Aug 31, 2019 3:36 am

Working with ROS 6.45.3.
Just some minor edits of syntax was required.
Big thanks to Tealfrog for the original code :)
      
                      # Configuration Parameters
              # intNumberOfRands - Number of pseudorandom number values to generate
              :local intNumberOfRands 100
              # intRandFloor - Lowest numeric range for generated values (must be positive value)
              :local intRandFloor 0 
              # intRandCeiling - Highest numeric range for generated values (must be positive value)
              :local intRandCeiling 100
              # blnShowStats - Displays distribution for generated numbers (default false)
              :local blnShowStats false
              # blnOneRndPerLine - Display generated values one per line on program completions (default false)
              :local blnOneRndPerLine false
              # blnGenerateSeed - Use a system generated seed for value generation (default true)
              :local blnGenerateSeed true
              # intSeed - Static seed value above Boolean value must be false to use (default 19650218)
              :local intSeed 19650218
              # Remaining values are associated with system generated seed values, blnGeneratedSeed=true to use
              # blnUseWiFi - Use wireless statistics as part of seed generation, experimental (default false)
              :local blnUseWiFi false
              # strWiFiName - Name of wireless interface, above blnUseWiFi must be true (default wlan1)
              :local strWiFiName "wlan1"
              # strOutFile - Temporary file used to gather wireless statistics
              :local strOutFile "RndOutTraff"
              # No need to modify variable beyond this line
              :local arrInitValues { 0x123; 0x234; 0x345; 0x456 }
              :local intInitArrayLen [ :len $arrInitValues ]
              :local arrLngRandNumValues ""
              :local arrAdjRandNumValues ""
              :local N 624
              :local M 397
              :local intUpperBitMask 0x80000000
              :local intLowerBitMask 0x7fffffff
              :local intMatrixA 0x9908b0df
              :local arrMagicValues [ :toarray ( 0, $intMatrixA ) ]
              :local intProgressEvery 0
              :local intPctDone 0
              :local arrMerTwist ""
              :local intMersTwistArrLen ( $N + 1 )
              :local intTotalValues 0
              :local intWiHiValue 0
              :local intWiLowValue 0
              :local intRandNumber 0
              :local intSeenValue 0
              :local arrSeenValues [ :toarray $intSeenValue ]
              :put "Running..."
              :for i from=( $intRandFloor ) to=( $intRandCeiling - 1 ) do={
                  :set arrSeenValues ( $arrSeenValues, $intSeenValue )
              } 
              :if ( $blnGenerateSeed = true ) do={
                  :put "Generating seed value from system events."
                  :local intUpTime [ /system resource get uptime ];
                  :if ( $blnUseWiFi = true ) do={
                      :put "Using wireless for seed generation."
                      :local lcv 1
                      :local blnContinue true
                      :do {
                          :put "Attempt $lcv to gather wireless traffic statistics."
                          /interface monitor-traffic $strWiFiName once file=$strOutFile
                          /delay 3s
                          :local strInFile ($strOutFile . ".txt")
                          :local strContent [/file get [/file find name=$strInFile] contents]
                          :if ( [ :len $strContent ] < 1 ) do={
                              :put "No content generated for wireless statistics."
                          } else={
                              :local intLocXmitBps ( [ :tonum [ :find $strContent \
                                "tx-bits-per-second:" 0 ] ] + 20 )
                              :local intXmitBps [ :pick $strContent $intLocXmitBps ( [ :tonum \
                                [ :find $strContent "bps" $intLocXmitBps ] ] - 1 ) ]
                              :local intXmitDecimalLoc [ :tonum [ :find $intXmitBps "." 0 ] ]
                              :set intWiHiValue [ :tonum [ :pick $intXmitBps 0 $intXmitDecimalLoc ] ]
                              :set intWiLowValue [ :tonum [ :pick $intXmitBps ( $intXmitDecimalLoc + 1 ) \
                                ( $intXmitDecimalLoc + 2 ) ] ] 
                              :if ( [ :len [ :tostr intWiHiValue ] ] > 0 ) do={
                                  :if ( [ :len [ :tostr intWiLowValue ] ] > 0 ) do={
                                      :set blnContinue false
                                  }
                              } else={
                                  :if ( lcv > 3 ) do={
                                      :set intWiHiValue 0
                                      :set intWiLowValue 0
                                      :set blnContinue false
                                  }
                              }
                              /file remove [ /file find name=$strInFile ];
                          } 
                          :set lcv ( $lcv + 1 )
                      } while=( $blnContinue = true )
                  }
                  :local intClockValue ( [ :tonum [ :pick [ /system clock get time ] 6 8 ] ] % 6 )
                  /delay 1s
                  :local intCpuValue [/system resource get cpu-load ];
                  :local strSysTime [ :tostr [ /system clock get time ] ]
                  :local intSeconds ( ( [ :tonum [ :pick $strSysTime 0 2 ] ] ) * 3600 )
                  :set intSeconds ( $intSeconds + ( ( [ :tonum [ :pick $strSysTime 3 5 ] ] ) * 60 ) )
                  :set intSeconds ( $intSeconds + ( ( [ :tonum [ :pick $strSysTime 6 8 ] ] ) * ( \
                    [ :tonum $intWiHiValue ] + [ :tonum $intWiLowValue ] ) ) )
                  :local arrMons [ :toarray "jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec" ]
                  :local strDate [ :tostr [ /system clock get date ] ]
                  :local intDayCount ( ( [ :tonum [ :find $arrMons \
                    [ :pick $strDate 0 3 ] ] ] * 30 ) + [ :tonum [ :pick $strDate 4 6 ] ] )
                  :local intYear ( ( [ :tonum [ :pick $strDate 7 [ :len $strDate ] ] ] - 2011 ) * 365 )
                  :set intSeed ( ( ( ( $intYear  + $intDayCount ) * 86400 ) + $intSeconds ) + \
                    [ :tonum $intClockValue ] + [ :tonum $intCpuValue ] + \
                    [ :tonum $intUpTime ] + [ :tonum $intWiHiValue ] + [ :tonum $intWiLowValue ] )
                  :set intSeed ( ( ( $intSeed * 1103515245 + 12345 ) / 65536) % 32768 ) 
                  :put "Using system dynamically generated seed value: $intSeed"
               } else={
                   :put "Using static seed stored in script variable with value: $intSeed"
                   :put "Numbers will be testable and repeatable (deterministic)."
               }
              # End of creating seed
              # $arrMerTwist[N] is array for the state vector
              :put "Step 1: Initializing (seeding) array for state vector."
              :set arrMerTwist [ :toarray ( [ :tonum $intSeed ] & 0xffffffff ) ]
              :set intTotalValues ( $N - 1 )
              :set intProgressEvery ( $intTotalValues / 20 )
              :set intPctDone 0
              # if ( $intMersTwistArrLen = N+1 ) means arrMerTwist[N] is not initialized */
              :set intMersTwistArrLen ( $N + 1 )
              :for lcv from=1 to=( $N - 1 ) do={
                  :if ( ( $lcv % $intProgressEvery ) = 0 ) do={
                      :set intPctDone ( $intPctDone + 5 )
                      :put "Step 1: $intPctDone% completed."
                  }
                  :local intValue1 [ :tonum [ :pick $arrMerTwist ( $lcv - 1 ) ] ]
                  :set intValue1 ( $intValue1 ^ ( $intValue1 >> 30 ) )
                  :set intValue1 ( $intValue1 * 1812433253 )
                  :set intValue1 ( $intValue1 + $lcv )
                  :set intValue1 ( $intValue1 & 0xffffffff )
                  :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist 0 $lcv ], $intValue1 ) ]
                  :set intMersTwistArrLen [ :tonum $lcv ]
              }
              :set intMersTwistArrLen ( $intMersTwistArrLen + 1 )
              :put "Step 2: Starting initialization by array"
              :local i 1
              :local j 0
              :local k [ :tonum $intInitArrayLen ]
              :if ( $N > $intInitArrayLen ) do={
                  :set k [ :tonum $N ]
              }
              :local intTotalValues ( [ :tonum $k ] - 1 )
              :set intProgressEvery ( $intTotalValues / 20 )
              :set intPctDone 0
              :while ( $k > 0 ) do={
                  :if ( ( $k % $intProgressEvery ) = 0 ) do={
                      :set intPctDone ( $intPctDone + 5 )
                      :put "Step 2: $intPctDone% completed."
                  }      
                  :local intValue1 [ :tonum [ :pick $arrMerTwist ( $i - 1 ) ] ]
                  :set intValue1 ( $intValue1 ^ ( $intValue1 >> 30 ) )
                  :set intValue1 ( $intValue1 * 1664525 )
                  :set intValue1 ( ( [ :tonum [ :pick $arrMerTwist $i ] ] ) ^ $intValue1 )
                  :set intValue1 ( $intValue1 + ( [ :tonum [ :pick $arrInitValues $j ] ] ) )
                  :set intValue1 ( $intValue1 + [ :tonum $j ] )
                  :set intValue1 ( $intValue1 & 0xffffffff )
                  :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist 0 $i ], $intValue1, \
                    [ :pick $arrMerTwist ( $i + 1 ) [ :len $arrMerTwist ] ] ) ]
                  :set i ( $i + 1 )
                  :set j ( $j + 1 )
                  :if ( $i >= $N ) do={
                      :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist ( $N - 1 ) ], \
                        [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] ) ]
                      :set i 1
                  }
                  :if ( $j >= $intInitArrayLen ) do={
                      :set j 0
                  }
                  :set k ( $k - 1 )
              }
              :put "Step 3: Last portion of initialization by array."
              :set k ( $N - 1 )
              :set intTotalValues $k 
              :set intProgressEvery ( $intTotalValues / 20 )
              :set intPctDone 0
              :while ( $k > 0 ) do={
                  :if ( ( $k % $intProgressEvery ) = 0 ) do={
                      :set intPctDone ( $intPctDone + 5 )
                      :put "Step 3: $intPctDone% completed."
                  }
                  :local intValue1 [ :tonum [ :pick $arrMerTwist ( $i - 1 ) ] ]
                  :set intValue1 ( $intValue1 ^ ( $intValue1 >> 30 ) )
                  :set intValue1 ( $intValue1 * 1566083941 )
                  :set intValue1 ( ( [ :tonum [ :pick $arrMerTwist $i ] ] ) ^ $intValue1 )
                  :set intValue1 ( $intValue1 - $i )
                  :set intValue1 ( $intValue1 & 0xffffffff )
                  :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist 0 $i ], $intValue1, \
                    [ :pick $arrMerTwist ( $i + 1 ) [ :len $arrMerTwist ] ] ) ]
                  :set i ( $i + 1 )
                  :if ( $i >= $N ) do={
                      :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist ( $N - 1 ) ], \
                        [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] ) ]
                      :set  i 1
                  }
                  :set k ( $k - 1 )
              }
              # MSB is 1; assuring non-zero initial array
              :set arrMerTwist [ :toarray ( [ :tonum 0x80000000 ], [ :pick $arrMerTwist 1 \
                [ :len $arrMerTwist]  ] ) ]
              :put "Initialization completed."
              # Main Program generate pseudorandom numbers
              :put "Starting number generation."
              :local intRandNumVal 0
              :for i from=0 to=( $intNumberOfRands - 1 ) do={
                  :put ("Generating random number " . ( $i + 1 ) . " of $intNumberOfRands.")
                  :if ( $intMersTwistArrLen >= $N ) do={
                      :if ( $intMersTwistArrLen = ( $N + 1 ) ) do={
                          :put "** ERROR state vector array is uninitalized. **"
                          :error "Unrecoverable error program terminiated."
                      }
                      :local intValue1 0
                      :local intValue2 0
                      :local kk 0
                      :set intTotalValues ( $N - $M ) 
                      :set intProgressEvery ( $intTotalValues / 20 )
                      :set intPctDone 0
                      :while ( $kk < ( $N - $M ) ) do={
                          :if ( ( $kk % $intProgressEvery ) = 0 ) do={
                              :put "Main Program sub task A: $intPctDone% completed."
                              :set intPctDone ( $intPctDone + 5 )
                          }
                          :set intValue1 [ :tonum [ :pick $arrMerTwist $kk ] ]
                          :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + 1 ) ] ]
                          :set intRandNumVal [ :tonum ( ( $intValue1 & $intUpperBitMask ) | \
                            ( $intValue2 & $intLowerBitMask ) ) ]
                          :set intValue1 ( [ :tonum $intRandNumVal ] & 1 )
                          :set intValue1 [ :tonum [ :pick $arrMagicValues $intValue1 ] ]
                          :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + $M ) ] ]
                          :set intValue1 [ :tonum ( ( $intValue2 ^ ( $intRandNumVal >> 1 ) ) ^ $intValue1 ) ]
                          :if ( $kk < 1 ) do={
                              :set arrMerTwist ( $intValue1, [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] )
                          } else={
                              :set arrMerTwist ( [ :pick $arrMerTwist 0 $kk ], $intValue1, \
                                [ :pick $arrMerTwist ( $kk + 1 ) [ :len $arrMerTwist ] ] ) 
                          }
                          :set kk ( $kk + 1 )
                      }
                      :set intTotalValues ( $N - 1 ) 
                      :set intProgressEvery ( $intTotalValues / 20 )
                      :set intPctDone 0
                      :while ( $kk < ( $N - 1 ) ) do={
                          :if ( ( $kk % $intProgressEvery ) = 0 ) do={
                              :set intPctDone ( $intPctDone + 5 )
                              :put "Main Program sub task B: $intPctDone% completed."
                          }
                          :set intValue1 [ :tonum [ :pick $arrMerTwist $kk ] ]
                          :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + 1 ) ] ]
                          :set intRandNumVal [ :tonum ( ( $intValue1 & $intUpperBitMask ) | \
                            ( $intValue2 & $intLowerBitMask ) ) ]
                      :set intValue1 ( [ :tonum $intRandNumVal ] & 1 )
                          :set intValue1 [ :tonum [ :pick $arrMagicValues $intValue1 ] ]
                          :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + ( $M - $N ) ) ] ]
                          :set intValue1 [ :tonum ( ( $intValue2 ^ ( $intRandNumVal >> 1 ) ) ^ $intValue1 ) ]
                          :if ( $kk < 1 ) do={
                              :set arrMerTwist ( $intValue1, [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] )
                          } else={
                              :set arrMerTwist ( [ :pick $arrMerTwist 0 $kk ], $intValue1, \
                                [ :pick $arrMerTwist ( $kk + 1 ) [ :len $arrMerTwist ] ] ) 
                          }
                          :set kk ( $kk + 1 )
                      }
                      :set intValue1 [ :tonum [ :pick $arrMerTwist ( $N - 1 ) ] ]
                      :set intValue2 [ :tonum [ :pick $arrMerTwist 0 ] ]
                      :set intRandNumVal [ :tonum ( ( $intValue1 & $intUpperBitMask ) | \
                        ( $intValue2 & $intLowerBitMask ) ) ]
                      :set intValue1 ( [ :tonum $intRandNumVal ] & 1 )
                      :set intValue1 [ :tonum [ :pick $arrMagicValues $intValue1 ] ]
                      :set intValue2 [ :tonum [ :pick $arrMerTwist ( $M - 1 ) ] ]
                      :set intValue1 [ :tonum ( ( $intValue2 ^ ( $intRandNumVal >> 1 ) ) ^ $intValue1 ) ]
              # Next line is for saftey, but ($N - 1) should never be < 1         
                      :if ( ( $N - 1 ) < 1 ) do={
                          :set arrMerTwist ( $intValue1, [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] )
                      } else={
                          :set arrMerTwist ( [ :pick $arrMerTwist 0 ( $N - 1 ) ], $intValue1, \
                            [ :pick $arrMerTwist [ :tonum $N ] [ :len $arrMerTwist ] ] ) 
                      }
                      :set intMersTwistArrLen 0
                  }
                  :set intRandNumVal [ :tonum [ :pick $arrMerTwist $intMersTwistArrLen ] ]
                  :set intMersTwistArrLen ( $intMersTwistArrLen + 1 )
              # Tempering
                  :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( $intRandNumVal >> 11 ) ) ]
                  :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( ( [ :tonum $intRandNumVal ] << 7 ) \
                    & 0x9d2c5680 ) ) ]
                  :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( ( [ :tonum $intRandNumVal ] << 15 ) \
                    & 0xefc60000 ) ) ]
                  :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( [ :tonum $intRandNumVal ] >> 18 ) ) ]
              # end genrand_int32
                  :set arrLngRandNumValues ( $arrLngRandNumValues, $intRandNumVal )
              # Some Error checking
                  :if ( ( [ :len [ :tostr $intRandNumVal ] ] < 1 ) or ( [ :tonum $intRandNumVal ] = 0 ) ) \
                    do={
                      :put "** DIAGNOSTICS **"
                      :put ("intRandNumVal($intRandNumVal) intMersTwistArrLen($intMersTwistArrLen) \
                        intSeed($intSeed) len_mt(" . [ :len $arrMerTwist ] . ")")
                      :put "Contents of \$arrMerTwist array:"
                      :put $arrMerTwist
                      :error "** ERROR ** Program execution halted no \$intRandNumVal value generated"
                  }
              # Done with error checking and diagnostic reporting    
                  :set intRandNumber ( ( $intRandNumVal % ( $intRandCeiling - $intRandFloor + 1 ) ) \
                    + $intRandFloor )    
                  :set arrAdjRandNumValues ( $arrAdjRandNumValues, $intRandNumber )
                  :set intSeenValue [ :tonum [ :pick $arrSeenValues ( $intRandNumber - $intRandFloor ) ] ]
                  :set intSeenValue ( $intSeenValue + 1 )
                  :if ( ( $intRandNumber - $intRandFloor ) = 0 ) do={
                      :set arrSeenValues [ :toarray ( [ :tonum $intSeenValue ], [ :pick $arrSeenValues 1 \
                        [ :len $arrSeenValues ] ] ) ]
                  } else={
                      :set arrSeenValues [ :toarray ( [ :pick $arrSeenValues 0 \
                        ( $intRandNumber - $intRandFloor ) ], [ :tonum $intSeenValue ], \
                        [ :pick $arrSeenValues ( ( $intRandNumber - $intRandFloor ) + 1 ) \
                        [ :len $arrSeenValues ] ] ) ]
                  }
              #    :put "Generated raw random number is $intRandNumVal"
              #    :put "Adjusted random value is: $intRandNumber"
              }
              :if ( $blnShowStats = true ) do={
                  :if ( $blnGenerateSeed = true ) do={
                      :put "Used dyamically generated seed value: $intSeed"
                  } else={
                      :put "Used static seed based on script \$intSeed value: $intSeed"
                  }
                  :put "Distribution of Numbers Generated [ #/Occurence ]"
                  :local intTotalRandsGen 0
                  :for i from=0 to=( [ :len $arrSeenValues ] - 1 ) do={
                      :local intSeenCount [ :tonum [ :pick $arrSeenValues $i ] ]
                      :set intTotalRandsGen ( $intTotalRandsGen + $intSeenCount )
                      :set intRandNumber ( $i + $intRandFloor )
                      :local strOutLine ( $intRandNumber . "/" . $intSeenCount )
                      :for j from=1 to=( 16 - [ :len [ :tostr $strOutLine ] ] ) do={
                          :set strOutLine " $strOutLine"
                      }
                      :set strOutLine "[$strOutLine] "
                      :local intDrawToCol [ :tonum $intSeenCount ]
                      :if ( $intDrawToCol > 62 ) do={
                          :set intDrawToCol 62
                      }
                      :set j 1
                      :while ( $j <= $intDrawToCol ) do={
                          :set strOutLine [ :tostr ( $strOutLine . "*" ) ]
                          :set j ( $j + 1 )
                      }
                      :put "$strOutLine"
                  }
                  :put "Total random numbers generated: $intTotalRandsGen"
              }
              :if ( $blnOneRndPerLine = true ) do={
                  :foreach intRndValue in=( $arrAdjRandNumValues ) do={
                      :put $intRndValue
                  }
              } else={
              #    :put $arrLngRandNumValues
                  :put $arrAdjRandNumValues
              }
              :put "Done."


Ps if anyone knows or can figure out how to get rid of the leading semi colon from the $arrAdjRandNumValues variable you would be a godsend!!
 
User avatar
SiB
Forum Guru
Forum Guru
Posts: 1888
Joined: Sun Jan 06, 2013 11:19 pm
Location: Poland

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Sat Aug 31, 2019 8:41 pm

Ps if anyone knows or can figure out how to get rid of the leading semi colon from the $arrAdjRandNumValues variable you would be a godsend!!
I change this code to function $FuncRandom with tree parameter intNumberOfRands intRandFloor intRandCeiling . Return from $FuncRandom is array. At the end I add examples how use it in any places of your final script.
local FuncRandom  do={
# Configuration Parameters
# intNumberOfRands - Number of pseudorandom number values to generate
:local intNumberOfRands $1
# intRandFloor - Lowest numeric range for generated values (must be positive value)
:local intRandFloor $2
# intRandCeiling - Highest numeric range for generated values (must be positive value)
:local intRandCeiling $3
# blnShowStats - Displays distribution for generated numbers (default false)
:local blnShowStats false
# blnOneRndPerLine - Display generated values one per line on program completions (default false)
:local blnOneRndPerLine false
# blnGenerateSeed - Use a system generated seed for value generation (default true)
:local blnGenerateSeed true
# intSeed - Static seed value above Boolean value must be false to use (default 19650218)
:local intSeed 19650218
# Remaining values are associated with system generated seed values, blnGeneratedSeed=true to use
# blnUseWiFi - Use wireless statistics as part of seed generation, experimental (default false)
:local blnUseWiFi false
# strWiFiName - Name of wireless interface, above blnUseWiFi must be true (default wlan1)
:local strWiFiName "wlan1"
# strOutFile - Temporary file used to gather wireless statistics
:local strOutFile "RndOutTraff"
# No need to modify variable beyond this line
:local arrInitValues { 0x123; 0x234; 0x345; 0x456 }
:local intInitArrayLen [ :len $arrInitValues ]
:local arrLngRandNumValues ""
:local arrAdjRandNumValues ""
:local N 624
:local M 397
:local intUpperBitMask 0x80000000
:local intLowerBitMask 0x7fffffff
:local intMatrixA 0x9908b0df
:local arrMagicValues [ :toarray ( 0, $intMatrixA ) ]
:local intProgressEvery 0
:local intPctDone 0
:local arrMerTwist ""
:local intMersTwistArrLen ( $N + 1 )
:local intTotalValues 0
:local intWiHiValue 0
:local intWiLowValue 0
:local intRandNumber 0
:local intSeenValue 0
:local arrSeenValues [ :toarray $intSeenValue ]
:put "Running..."
:for i from=( $intRandFloor ) to=( $intRandCeiling - 1 ) do={
    :set arrSeenValues ( $arrSeenValues, $intSeenValue )
} 
:if ( $blnGenerateSeed = true ) do={
    :put "Generating seed value from system events."
    :local intUpTime [ /system resource get uptime ];
    :if ( $blnUseWiFi = true ) do={
        :put "Using wireless for seed generation."
        :local lcv 1
        :local blnContinue true
        :do {
            :put "Attempt $lcv to gather wireless traffic statistics."
            /interface monitor-traffic $strWiFiName once file=$strOutFile
            /delay 3s
            :local strInFile ($strOutFile . ".txt")
            :local strContent [/file get [/file find name=$strInFile] contents]
            :if ( [ :len $strContent ] < 1 ) do={
                :put "No content generated for wireless statistics."
            } else={
                :local intLocXmitBps ( [ :tonum [ :find $strContent \
                  "tx-bits-per-second:" 0 ] ] + 20 )
                :local intXmitBps [ :pick $strContent $intLocXmitBps ( [ :tonum \
                  [ :find $strContent "bps" $intLocXmitBps ] ] - 1 ) ]
                :local intXmitDecimalLoc [ :tonum [ :find $intXmitBps "." 0 ] ]
                :set intWiHiValue [ :tonum [ :pick $intXmitBps 0 $intXmitDecimalLoc ] ]
                :set intWiLowValue [ :tonum [ :pick $intXmitBps ( $intXmitDecimalLoc + 1 ) \
                  ( $intXmitDecimalLoc + 2 ) ] ] 
                :if ( [ :len [ :tostr intWiHiValue ] ] > 0 ) do={
                    :if ( [ :len [ :tostr intWiLowValue ] ] > 0 ) do={
                        :set blnContinue false
                    }
                } else={
                    :if ( lcv > 3 ) do={
                        :set intWiHiValue 0
                        :set intWiLowValue 0
                        :set blnContinue false
                    }
                }
                /file remove [ /file find name=$strInFile ];
            } 
            :set lcv ( $lcv + 1 )
        } while=( $blnContinue = true )
    }
    :local intClockValue ( [ :tonum [ :pick [ /system clock get time ] 6 8 ] ] % 6 )
    /delay 1s
    :local intCpuValue [/system resource get cpu-load ];
    :local strSysTime [ :tostr [ /system clock get time ] ]
    :local intSeconds ( ( [ :tonum [ :pick $strSysTime 0 2 ] ] ) * 3600 )
    :set intSeconds ( $intSeconds + ( ( [ :tonum [ :pick $strSysTime 3 5 ] ] ) * 60 ) )
    :set intSeconds ( $intSeconds + ( ( [ :tonum [ :pick $strSysTime 6 8 ] ] ) * ( \
      [ :tonum $intWiHiValue ] + [ :tonum $intWiLowValue ] ) ) )
    :local arrMons [ :toarray "jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec" ]
    :local strDate [ :tostr [ /system clock get date ] ]
    :local intDayCount ( ( [ :tonum [ :find $arrMons \
      [ :pick $strDate 0 3 ] ] ] * 30 ) + [ :tonum [ :pick $strDate 4 6 ] ] )
    :local intYear ( ( [ :tonum [ :pick $strDate 7 [ :len $strDate ] ] ] - 2011 ) * 365 )
    :set intSeed ( ( ( ( $intYear  + $intDayCount ) * 86400 ) + $intSeconds ) + \
      [ :tonum $intClockValue ] + [ :tonum $intCpuValue ] + \
      [ :tonum $intUpTime ] + [ :tonum $intWiHiValue ] + [ :tonum $intWiLowValue ] )
    :set intSeed ( ( ( $intSeed * 1103515245 + 12345 ) / 65536) % 32768 ) 
    :put "Using system dynamically generated seed value: $intSeed"
 } else={
     :put "Using static seed stored in script variable with value: $intSeed"
     :put "Numbers will be testable and repeatable (deterministic)."
 }
# End of creating seed
# $arrMerTwist[N] is array for the state vector
:put "Step 1: Initializing (seeding) array for state vector."
:set arrMerTwist [ :toarray ( [ :tonum $intSeed ] & 0xffffffff ) ]
:set intTotalValues ( $N - 1 )
:set intProgressEvery ( $intTotalValues / 20 )
:set intPctDone 0
# if ( $intMersTwistArrLen = N+1 ) means arrMerTwist[N] is not initialized */
:set intMersTwistArrLen ( $N + 1 )
:for lcv from=1 to=( $N - 1 ) do={
    :if ( ( $lcv % $intProgressEvery ) = 0 ) do={
        :set intPctDone ( $intPctDone + 5 )
        :put "Step 1: $intPctDone% completed."
    }
    :local intValue1 [ :tonum [ :pick $arrMerTwist ( $lcv - 1 ) ] ]
    :set intValue1 ( $intValue1 ^ ( $intValue1 >> 30 ) )
    :set intValue1 ( $intValue1 * 1812433253 )
    :set intValue1 ( $intValue1 + $lcv )
    :set intValue1 ( $intValue1 & 0xffffffff )
    :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist 0 $lcv ], $intValue1 ) ]
    :set intMersTwistArrLen [ :tonum $lcv ]
}
:set intMersTwistArrLen ( $intMersTwistArrLen + 1 )
:put "Step 2: Starting initialization by array"
:local i 1
:local j 0
:local k [ :tonum $intInitArrayLen ]
:if ( $N > $intInitArrayLen ) do={
    :set k [ :tonum $N ]
}
:local intTotalValues ( [ :tonum $k ] - 1 )
:set intProgressEvery ( $intTotalValues / 20 )
:set intPctDone 0
:while ( $k > 0 ) do={
    :if ( ( $k % $intProgressEvery ) = 0 ) do={
        :set intPctDone ( $intPctDone + 5 )
        :put "Step 2: $intPctDone% completed."
    }      
    :local intValue1 [ :tonum [ :pick $arrMerTwist ( $i - 1 ) ] ]
    :set intValue1 ( $intValue1 ^ ( $intValue1 >> 30 ) )
    :set intValue1 ( $intValue1 * 1664525 )
    :set intValue1 ( ( [ :tonum [ :pick $arrMerTwist $i ] ] ) ^ $intValue1 )
    :set intValue1 ( $intValue1 + ( [ :tonum [ :pick $arrInitValues $j ] ] ) )
    :set intValue1 ( $intValue1 + [ :tonum $j ] )
    :set intValue1 ( $intValue1 & 0xffffffff )
    :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist 0 $i ], $intValue1, \
      [ :pick $arrMerTwist ( $i + 1 ) [ :len $arrMerTwist ] ] ) ]
    :set i ( $i + 1 )
    :set j ( $j + 1 )
    :if ( $i >= $N ) do={
        :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist ( $N - 1 ) ], \
          [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] ) ]
        :set i 1
    }
    :if ( $j >= $intInitArrayLen ) do={
        :set j 0
    }
    :set k ( $k - 1 )
}
:put "Step 3: Last portion of initialization by array."
:set k ( $N - 1 )
:set intTotalValues $k 
:set intProgressEvery ( $intTotalValues / 20 )
:set intPctDone 0
:while ( $k > 0 ) do={
    :if ( ( $k % $intProgressEvery ) = 0 ) do={
        :set intPctDone ( $intPctDone + 5 )
        :put "Step 3: $intPctDone% completed."
    }
    :local intValue1 [ :tonum [ :pick $arrMerTwist ( $i - 1 ) ] ]
    :set intValue1 ( $intValue1 ^ ( $intValue1 >> 30 ) )
    :set intValue1 ( $intValue1 * 1566083941 )
    :set intValue1 ( ( [ :tonum [ :pick $arrMerTwist $i ] ] ) ^ $intValue1 )
    :set intValue1 ( $intValue1 - $i )
    :set intValue1 ( $intValue1 & 0xffffffff )
    :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist 0 $i ], $intValue1, \
      [ :pick $arrMerTwist ( $i + 1 ) [ :len $arrMerTwist ] ] ) ]
    :set i ( $i + 1 )
    :if ( $i >= $N ) do={
        :set arrMerTwist [ :toarray ( [ :pick $arrMerTwist ( $N - 1 ) ], \
          [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] ) ]
        :set  i 1
    }
    :set k ( $k - 1 )
}
# MSB is 1; assuring non-zero initial array
:set arrMerTwist [ :toarray ( [ :tonum 0x80000000 ], [ :pick $arrMerTwist 1 \
  [ :len $arrMerTwist]  ] ) ]
:put "Initialization completed."
# Main Program generate pseudorandom numbers
:put "Starting number generation."
:local intRandNumVal 0
:for i from=0 to=( $intNumberOfRands - 1 ) do={
    :put ("Generating random number " . ( $i + 1 ) . " of $intNumberOfRands.")
    :if ( $intMersTwistArrLen >= $N ) do={
        :if ( $intMersTwistArrLen = ( $N + 1 ) ) do={
            :put "** ERROR state vector array is uninitalized. **"
            :error "Unrecoverable error program terminiated."
        }
        :local intValue1 0
        :local intValue2 0
        :local kk 0
        :set intTotalValues ( $N - $M ) 
        :set intProgressEvery ( $intTotalValues / 20 )
        :set intPctDone 0
        :while ( $kk < ( $N - $M ) ) do={
            :if ( ( $kk % $intProgressEvery ) = 0 ) do={
                :put "Main Program sub task A: $intPctDone% completed."
                :set intPctDone ( $intPctDone + 5 )
            }
            :set intValue1 [ :tonum [ :pick $arrMerTwist $kk ] ]
            :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + 1 ) ] ]
            :set intRandNumVal [ :tonum ( ( $intValue1 & $intUpperBitMask ) | \
              ( $intValue2 & $intLowerBitMask ) ) ]
            :set intValue1 ( [ :tonum $intRandNumVal ] & 1 )
            :set intValue1 [ :tonum [ :pick $arrMagicValues $intValue1 ] ]
            :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + $M ) ] ]
            :set intValue1 [ :tonum ( ( $intValue2 ^ ( $intRandNumVal >> 1 ) ) ^ $intValue1 ) ]
            :if ( $kk < 1 ) do={
                :set arrMerTwist ( $intValue1, [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] )
            } else={
                :set arrMerTwist ( [ :pick $arrMerTwist 0 $kk ], $intValue1, \
                  [ :pick $arrMerTwist ( $kk + 1 ) [ :len $arrMerTwist ] ] ) 
            }
            :set kk ( $kk + 1 )
        }
        :set intTotalValues ( $N - 1 ) 
        :set intProgressEvery ( $intTotalValues / 20 )
        :set intPctDone 0
        :while ( $kk < ( $N - 1 ) ) do={
            :if ( ( $kk % $intProgressEvery ) = 0 ) do={
                :set intPctDone ( $intPctDone + 5 )
                :put "Main Program sub task B: $intPctDone% completed."
            }
            :set intValue1 [ :tonum [ :pick $arrMerTwist $kk ] ]
            :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + 1 ) ] ]
            :set intRandNumVal [ :tonum ( ( $intValue1 & $intUpperBitMask ) | \
              ( $intValue2 & $intLowerBitMask ) ) ]
        :set intValue1 ( [ :tonum $intRandNumVal ] & 1 )
            :set intValue1 [ :tonum [ :pick $arrMagicValues $intValue1 ] ]
            :set intValue2 [ :tonum [ :pick $arrMerTwist ( $kk + ( $M - $N ) ) ] ]
            :set intValue1 [ :tonum ( ( $intValue2 ^ ( $intRandNumVal >> 1 ) ) ^ $intValue1 ) ]
            :if ( $kk < 1 ) do={
                :set arrMerTwist ( $intValue1, [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] )
            } else={
                :set arrMerTwist ( [ :pick $arrMerTwist 0 $kk ], $intValue1, \
                  [ :pick $arrMerTwist ( $kk + 1 ) [ :len $arrMerTwist ] ] ) 
            }
            :set kk ( $kk + 1 )
        }
        :set intValue1 [ :tonum [ :pick $arrMerTwist ( $N - 1 ) ] ]
        :set intValue2 [ :tonum [ :pick $arrMerTwist 0 ] ]
        :set intRandNumVal [ :tonum ( ( $intValue1 & $intUpperBitMask ) | \
          ( $intValue2 & $intLowerBitMask ) ) ]
        :set intValue1 ( [ :tonum $intRandNumVal ] & 1 )
        :set intValue1 [ :tonum [ :pick $arrMagicValues $intValue1 ] ]
        :set intValue2 [ :tonum [ :pick $arrMerTwist ( $M - 1 ) ] ]
        :set intValue1 [ :tonum ( ( $intValue2 ^ ( $intRandNumVal >> 1 ) ) ^ $intValue1 ) ]
# Next line is for saftey, but ($N - 1) should never be < 1         
        :if ( ( $N - 1 ) < 1 ) do={
            :set arrMerTwist ( $intValue1, [ :pick $arrMerTwist 1 [ :len $arrMerTwist ] ] )
        } else={
            :set arrMerTwist ( [ :pick $arrMerTwist 0 ( $N - 1 ) ], $intValue1, \
              [ :pick $arrMerTwist [ :tonum $N ] [ :len $arrMerTwist ] ] ) 
        }
        :set intMersTwistArrLen 0
    }
    :set intRandNumVal [ :tonum [ :pick $arrMerTwist $intMersTwistArrLen ] ]
    :set intMersTwistArrLen ( $intMersTwistArrLen + 1 )
# Tempering
    :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( $intRandNumVal >> 11 ) ) ]
    :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( ( [ :tonum $intRandNumVal ] << 7 ) \
      & 0x9d2c5680 ) ) ]
    :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( ( [ :tonum $intRandNumVal ] << 15 ) \
      & 0xefc60000 ) ) ]
    :set intRandNumVal [ :tonum ( $intRandNumVal ^ ( [ :tonum $intRandNumVal ] >> 18 ) ) ]
# end genrand_int32
    :set arrLngRandNumValues ( $arrLngRandNumValues, $intRandNumVal )
# Some Error checking
    :if ( ( [ :len [ :tostr $intRandNumVal ] ] < 1 ) or ( [ :tonum $intRandNumVal ] = 0 ) ) \
      do={
        :put "** DIAGNOSTICS **"
        :put ("intRandNumVal($intRandNumVal) intMersTwistArrLen($intMersTwistArrLen) \
          intSeed($intSeed) len_mt(" . [ :len $arrMerTwist ] . ")")
        :put "Contents of \$arrMerTwist array:"
        :put $arrMerTwist
        :error "** ERROR ** Program execution halted no \$intRandNumVal value generated"
    }
# Done with error checking and diagnostic reporting    
    :set intRandNumber ( ( $intRandNumVal % ( $intRandCeiling - $intRandFloor + 1 ) ) \
      + $intRandFloor )    
    :set arrAdjRandNumValues ( $arrAdjRandNumValues, $intRandNumber )
    :set intSeenValue [ :tonum [ :pick $arrSeenValues ( $intRandNumber - $intRandFloor ) ] ]
    :set intSeenValue ( $intSeenValue + 1 )
    :if ( ( $intRandNumber - $intRandFloor ) = 0 ) do={
        :set arrSeenValues [ :toarray ( [ :tonum $intSeenValue ], [ :pick $arrSeenValues 1 \
          [ :len $arrSeenValues ] ] ) ]
    } else={
        :set arrSeenValues [ :toarray ( [ :pick $arrSeenValues 0 \
          ( $intRandNumber - $intRandFloor ) ], [ :tonum $intSeenValue ], \
          [ :pick $arrSeenValues ( ( $intRandNumber - $intRandFloor ) + 1 ) \
          [ :len $arrSeenValues ] ] ) ]
    }
#    :put "Generated raw random number is $intRandNumVal"
#    :put "Adjusted random value is: $intRandNumber"
}
:if ( $blnShowStats = true ) do={
    :if ( $blnGenerateSeed = true ) do={
        :put "Used dyamically generated seed value: $intSeed"
    } else={
        :put "Used static seed based on script \$intSeed value: $intSeed"
    }
    :put "Distribution of Numbers Generated [ #/Occurence ]"
    :local intTotalRandsGen 0
    :for i from=0 to=( [ :len $arrSeenValues ] - 1 ) do={
        :local intSeenCount [ :tonum [ :pick $arrSeenValues $i ] ]
        :set intTotalRandsGen ( $intTotalRandsGen + $intSeenCount )
        :set intRandNumber ( $i + $intRandFloor )
        :local strOutLine ( $intRandNumber . "/" . $intSeenCount )
        :for j from=1 to=( 16 - [ :len [ :tostr $strOutLine ] ] ) do={
            :set strOutLine " $strOutLine"
        }
        :set strOutLine "[$strOutLine] "
        :local intDrawToCol [ :tonum $intSeenCount ]
        :if ( $intDrawToCol > 62 ) do={
            :set intDrawToCol 62
        }
        :set j 1
        :while ( $j <= $intDrawToCol ) do={
            :set strOutLine [ :tostr ( $strOutLine . "*" ) ]
            :set j ( $j + 1 )
        }
        :put "$strOutLine"
    }
    :put "Total random numbers generated: $intTotalRandsGen"
}
:if ( $blnOneRndPerLine = true ) do={
    :foreach intRndValue in=( $arrAdjRandNumValues ) do={
        :put $intRndValue
    }
} else={
    #:put "aa $arrLngRandNumValues"
    :return $arrAdjRandNumValues
}
}
# Your script.....
# Your script.....

# Run function with Numbers Min Max, examples
put [$FuncRandom "2" "44" "50" ];
#put ("Random 3x numbers in range 50-60 but display second result :".[$FuncRandom 3 50 60]->2)
#local SaveResults [$FuncRandom 1 0 100]

# Your script.....
# Your script.....


Alternalive.
I try and found and parse one of WebAPI to receive random number from any range I wont online. No consume CPU like upper one..
Example: one number, random from range 44..120. More at https://www.random.org/clients/http/
put ([/tool fetch mode=https http-method=get url="https://www.random.org/integers/\?num=1&min=44&max=120&col=1&base=10&format=plain&rnd=new" as-value output=user ]->"data")                         
91
 
User avatar
eworm
Forum Guru
Forum Guru
Posts: 1070
Joined: Wed Oct 22, 2014 9:23 am
Location: Oberhausen, Germany
Contact:

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Mon Sep 02, 2019 1:59 pm

Ps if anyone knows or can figure out how to get rid of the leading semi colon from the $arrAdjRandNumValues variable you would be a godsend!!
Someone proposed to replace
{}
with
""
for array declaration.
Both is wrong... you should use
[ :toarray "" ]
for empty array declaration. (see: How to define empty array)

Not tested, but I guess that could fix your issue.
 
helipos
Member Candidate
Member Candidate
Posts: 132
Joined: Sat Jun 25, 2016 11:32 am

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Sun Sep 15, 2019 4:17 am

I wont pretend to know what either of you are really talking about. I'm a fully qualified noob on scripting, ie good enough to cut, paste and hack away at code to make it do what i need.
All i was chasing was a random number in some global variable.

Anyway I've found another solution which was someone else's script I've modified. (sorry can't find it now to give credit)
:local Sum 0
:foreach Interface in=[ /interface find ] do={
  :set Sum ($Sum + [ /interface get $Interface tx-byte ])
}
:global random [:pick $Sum ([:len $Sum]-2) [:len $Sum]]
:set $random [:tonum $random]
:put $random
}
 
HughPH
newbie
Posts: 45
Joined: Sat Feb 13, 2016 2:55 am

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Dec 30, 2020 4:02 am

How about Perlin Noise?

The GLSL for a simplified noise based on Perlin would be
float rand(float n){return fract(sin(n) * 43758.5453123);}
Obviously we don't have sin so we would need to take an approximation from somewhere. What about Bhaskara I's sine approximation formula?
https://en.wikipedia.org/wiki/Bhaskara_ ... on_formula

Fract just returns the fractional part of the value.

So
float sin(float a){return (4 * a * (180 - a)) / (40500 - (x * (180 - x)));}

float rand(float n){return (sin(n) * 43758.5453123)%1;}
Or
float rand(float n){
sin = (4 * n * (180 - n)) / (40500 - (n * (180 - n)))
return (sin * 43758.5453123)%1;
}
Major snag here: This is designed to give us a normalised value between 0 (inclusive) and 1 (exclusive).

That's OK though, because RouterOS uses 64bit signed ints. So we can just shunt the decimal point 7 places to the right. And do some other tinkering to make sure we have numbers big enough. (I've just taken a hammer to a screw here, rather than figuring out exact numbers...)
:global rndPos ($rndPos + 1)
:local sin ((40000 * $rndPos * (180 - $rndPos)) / (40500 - ($rndPos * (180 - $rndPos))))
:local temp (($sin * 437585453123) % 1000000)
:if ($temp < 0) do={:put ($temp * -1)}
:if ($temp >= 0) do={:put ($temp)}

This should give you a sequence of pseudo-random numbers between 0 (inclusive) and 1000000 (exclusive). Just use modulo again to cut it down to whatever range you need.

I'm not sure where it wraps, this is back-of-a-fag-packet stuff. Someone with a better head for numbers could probably make it "proper". Also it's 2am and I had 5 hours sleep last night.

You can tweak the magic number, 437585453123
It might be possible to put in a feedback loop so that the output becomes (or influences) the next magic number, which would increase the range - but it's necessary to make sure that it doesn't get too small. (As an extreme example, if the output was 157689724000000000001 then the new magic number would come out as 1 if you just used modulo to pull the last 12 digits.)
Last edited by HughPH on Wed Dec 30, 2020 4:38 pm, edited 1 time in total.
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3291
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Dec 30, 2020 1:06 pm

Use Certificate generator to make your random number.

viewtopic.php?t=164114

Script here:
viewtopic.php?p=824660#p824660
 
HughPH
newbie
Posts: 45
Joined: Sat Feb 13, 2016 2:55 am

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Dec 30, 2020 5:05 pm

Neat, thanks! I suppose that could be adapted to derive a number from the generated password - just by using the hex conversion and multiplying up before adding the next value. A lot of it would go away if you just want a 64bit random number.
:local hexSrc ([/certificate scep-server otp generate minutes-valid=0 as-value]->"password")
:for i from=1 to=16 step=2 do={
  :set $hex "0x$[:pick $hexSrc $i ($i+2)]"
  :set $num ($num*256 + $hex)
}
:put ($num)
Then again use mod to get a number in a specific range.
 
msatter
Forum Guru
Forum Guru
Posts: 2897
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Dec 30, 2020 6:35 pm

This will generate a lot of random things.

viewtopic.php?f=9&t=169030&p=830719
 
HughPH
newbie
Posts: 45
Joined: Sat Feb 13, 2016 2:55 am

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Dec 30, 2020 8:21 pm

Awesome, thanks

My need was just for a number - which is how I came across this post, and not the others.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Sat May 22, 2021 7:54 pm

I write my own version:

Random number between 0 and 99 or string between 00 and 99
viewtopic.php?f=9&t=175453&p=858629
 
User avatar
mozerd
Forum Veteran
Forum Veteran
Posts: 872
Joined: Thu Oct 05, 2017 3:39 pm
Location: Canada
Contact:

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Sat Feb 19, 2022 1:59 am

@Sob …. MikroTik are memory misers because the value proposition is tied to lowest cost providing best possible functionality …. So to add a function library would require adding more memory …. In mfg for every cent in additional cost requires a 400% return …. So it’s understandable that tradeoffs must be made …. In the CPE industry the buyer (I.e. ISPs) strives for the lowest cost possible

As a techie I want far more memory because that will provide much more functionality…. Like for example a function library that does not limite file size processing would be nice …. Versus the kluge like chucking etc etc etc. :)
 
tangent
Forum Guru
Forum Guru
Posts: 1351
Joined: Thu Jul 01, 2021 3:15 pm
Contact:

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Sat Feb 19, 2022 2:49 am

…MikroTik are memory misers…

All of that is true, but it goes further than you say. We've got people griping about how the brandest newest features (e.g. ZeroTier) aren't supported on ancient MIPS CPUs and at the same time griping about how ROS 7 isn't "finished" yet because it isn't 100% feature-for-feature identical to ROS 6.

But heaven forfend they deprecate something so horribly broken it shouldn't be used any more like PPTP or telnet. You threaten that, and you get people crawling out to defend it with their very Internet lives.

How is MikroTik supposed to navigate between Scylla and Charybdis? You can't have infinite new features on fixed-memory hardware from arbitrarily far in the past.

To return to the topic, I like the solution up-thread to pull the data from random.org. Delegate the hard work of providing arbitrary PRNGs to someone else's hardware.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3253
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Mar 02, 2022 3:20 pm

On this particular topic, they did add ":rndnum" in V7:
:put [:rndnum from=1 to=1000]
149
See a more colorful example here: viewtopic.php?t=165722&hilit=color#p896227.

They did add a [:timestamp] too in V7, but (2*$new-functions / 4*years)~("nothing"|"nil").
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3291
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Mar 02, 2022 3:41 pm

Hmm, how did I miss this...

Any documentation on this? I did not find any.

Generate mac
:put [:rndstr length=12 from="0123456789abcdef"]
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3253
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Mar 02, 2022 4:22 pm

Hmm, how did I miss this...
Any documentation on this? I did not find any.
I use the CLI and the "tab completion", which is how I found it last year in one of the betas. But seem documented now:
https://help.mikrotik.com/docs/display/ ... alcommands
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3291
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Mar 02, 2022 5:53 pm

Manual has an error in the example for rndstr
:put [:rndnum from="abcdef%^&" length=33];
should be
:put [:rndstr from="abcdef%^&" length=33]
Also do not need the ; at end of each line in manual as well. Its only needed to separate multiple command on same line.
 
msatter
Forum Guru
Forum Guru
Posts: 2897
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Mar 02, 2022 7:29 pm

Nice that Mikrotik got it now. My script could produce a lot and has even a help function to explain the different options.

viewtopic.php?p=828840
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3253
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Mar 02, 2022 8:04 pm



Alternalive.
I try and found and parse one of WebAPI to receive random number from any range I wont online. No consume CPU like upper one..
Example: one number, random from range 44..120. More at https://www.random.org/clients/http/
put ([/tool fetch mode=https http-method=get url="https://www.random.org/integers/\?num=1&min=44&max=120&col=1&base=10&format=plain&rnd=new" as-value output=user ]->"data")                         
91
…MikroTik are memory misers…
To return to the topic, I like the solution up-thread to pull the data from random.org. Delegate the hard work of providing arbitrary PRNGs to someone else's hardware.


I wrapped random.org approach into a function, [$RNDORGINT min= max= base=] so to cover all the bases ;).
# based on https://www.random.org/clients/http/
# from comment here https://forum.mikrotik.com/viewtopic.php?t=56933
:global RNDORGINT
:set RNDORGINT do={
    # params
    :local lmin [:tonum $min]
    :local lmax [:tonum $max]
    :local lbase [:tonum $base]
    # consts
    :local lnum 1
    :local lformat "plain"
    :local lcol "1"
    :local lrnd "new"
    # defaults
    :if ([:typeof $lmin]!="num") do={:set lmin 0}
    :if ([:typeof $lmax]!="num") do={:set lmax 1000}
    :if ([:typeof $lbase]!="num" ) do={:set lbase 10}
    :if (!([:tostr $lbase]~("2|8|10|16"))) do={:error "Base must be 2, 8, 10, or 16"}
    # setup url
    :local url "https://www.random.org/integers/?"
    :set url "$($url)min=$lmin&max=$lmax&base=$lbase"
    :set url "$($url)&num=$lnum&col=$lcol&format=$lformat&rnd=$lrnd"
    :local headers "Content-Type: text/plain"
    # now get number from random.org using fetch
    :local resp [/tool fetch url=$url http-header-field=$headers output=user as-value]
    :local rndasstr ($resp->"data")
    # return it as string
    :return $rndasstr
}

The function can be used like so:
# Note: $RNDORGINT returns a string at present, (:typeof [$RNDORGINT])="str"

# default is min=1 max=1000 base=10
:put [$RNDORGINT].
# 449

:put [$RNDORGINT min=1 max=2]
# 1

:put [$RNDORGINT min=1000 max=9999]
# 4803

# base can be 2, 8, 10, or 16
:put [$RNDORGINT min=1000 max=9999 base=2]
00101011000011

# negative numbers
:put [$RNDORGINT min=-10 max=0]
# -3

Last edited by Amm0 on Thu Mar 03, 2022 5:20 pm, edited 1 time in total.
 
msatter
Forum Guru
Forum Guru
Posts: 2897
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Wed Mar 02, 2022 8:58 pm

If you put three CR/ENTERS between each of the code box you get a seperate code box:
one

two
It is is just like scripting with Mikrotik...bumping your nose into walls, many many times till the hurting stops. ;-)
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3253
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Pseudo Random Number Generator Script (Mersenne Twister)

Thu Mar 03, 2022 5:44 pm

If you put three CR/ENTERS between each of the code box you get a seperate code box:
one

two
It is is just like scripting with Mikrotik...bumping your nose into walls, many many times till the hurting stops. ;-)
LOL, totally. The world has moved on to markdown, but we're on stuck on Wiki v1 style in the forum with some odd rules. But I can deal with that...

I just wish they'd make some progress on adding some of backlog of "missing" script functions. I'm not even [:pick]y about which ones, I'd say more of my script code is actually some workaround (e.g. JSON, date/time parsing, type checking, string manipulation, etc., etc.). Maybe once the V7 bug settle down, we'll see some progress. But a 10 year response time for a :rndnum isn't hopeful ;-).

Who is online

Users browsing this forum: No registered users and 18 guests