Rnd: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
mNo edit summary
m (moved Rnd, Rnd64 to Rnd: Removed Rnd64 due to updated calculation not fitting 64bit random result (need an operation resulting in a 128bit number).)
 
(10 intermediate revisions by 3 users not shown)
Line 3: Line 3:


==Description ==
==Description ==
Generates a random number within a range using the RtlGenRandom api.
Generates a random number within a range using the RtlGenRandom api.
 
It can be used as is, or as a random seed generator for other functions, like http://nsis.sourceforge.net/Random. The Microsoft C Runtime Library makes use of this function (RtlGenRandom) in its implementation of "rand_s".


== Example ==
== Example ==
Line 20: Line 22:
ExecWait 'notepad "${tempfile}"'
ExecWait 'notepad "${tempfile}"'
Delete "${tempfile}"</highlight-nsis>
Delete "${tempfile}"</highlight-nsis>
== Functions ==
== Function ==
<highlight-nsis>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
<highlight-nsis>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Gets a random number within a range with the RtlGenRandom api
;; Generate a random number using the RtlGenRandom api
;; P1 :out: Random number
;; P1 :out: Random number
;; P2 :in:  Minimum value
;; P2 :in:  Minimum value
;; P3 :in:  Maximum value
;; P3 :in:  Maximum value
;; min/max P2 and P3 values = -2 147 483 647 / 2 147 483 647
;; min/max P2 and P3 values = -2 147 483 647 / 2 147 483 647
;; max interval = 2 147 483 647
;; max range = 2 147 483 647 (31-bit)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
!define Rnd "!insertmacro _Rnd"
!define Rnd "!insertmacro _Rnd"
Line 39: Line 41:
   Exch $0  ;; Min / return value
   Exch $0  ;; Min / return value
   Exch
   Exch
   Exch $1  ;; Max / temp var
   Exch $1  ;; Max / random value
   Push "$3"  ;; difference between Max and Min
   Push "$3"  ;; Max - Min range
   Push "$4"  ;; random value
   Push "$4"  ;; random value buffer


   IntOp $3 $1 - $0
   IntOp $3 $1 - $0 ;; calculate range
   IntOp $3 $3 + 1
   IntOp $3 $3 + 1
   System::Call '*(i) i .r4'
   System::Call '*(l) i .r4'
   System::Call 'advapi32::SystemFunction036(i r4, i 4)'  ;; RtlGenRandom
   System::Call 'advapi32::SystemFunction036(i r4, i 4)'  ;; RtlGenRandom
   System::Call '*$4(i .r1)'
   System::Call '*$4(l .r1)'
   System::Free $4
   System::Free $4
   IntOp $1 $1 & 0x7FFFFFFF  ;; eliminate possible negative value
   ;; fit value within range
  IntOp $1 $1 % $3  ;; fit the value within the range
   System::Int64Op $1 * $3
   IntOp $0 $1 + $0  ;; index it with the minimum value
 
  Pop $4
   Pop $3
   Pop $3
  Pop $1
   System::Int64Op $3 / 0xFFFFFFFF
  Exch $0
FunctionEnd</highlight-nsis>
<highlight-nsis>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Gets a random number within a range with the RtlGenRandom api (Int64)
;; P1 :out: Random number
;; P2 :in:  Minimum value
;; P3 :in:  Maximum value
;; min/max P2 and P3 values = -9 223 372 036 854 775 807 / 9 223 372 036 854 775 807
;; max interval = 9 223 372 036 854 775 807
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
!define Rnd64 "!insertmacro _Rnd64"
!macro _Rnd64 _RetVal_ _Min_ _Max_
  Push "${_Max_}"
  Push "${_Min_}"
  Call Rnd64
  Pop ${_RetVal_}
!macroend
Function Rnd64
  Exch $0  ;; Min / return value
  Exch
  Exch $1  ;; Max / temp var
  Push "$3"  ;; difference between Max and Min
  Push "$4"  ;; random value
 
   System::Int64Op $1 - $0
   Pop $3
   Pop $3
   System::Int64Op $3 + 1
   IntOp $0 $3 + $0  ;; index with minimum value
  Pop $3
  System::Call '*(l) i .r4'
  System::Call 'advapi32::SystemFunction036(i r4, i 8)'  ;; RtlGenRandom
  System::Call '*$4(l .r1)'
  System::Free $4
  System::Int64Op $1 & 0x7FFFFFFFFFFFFFFF  ;; eliminate possible negative value
  Pop $1
  System::Int64Op $1 % $3  ;; fit the value within the range
  Pop $1
  System::Int64Op $1 + $0  ;; index it with the minimum value
  Pop $0
    
    
   Pop $4
   Pop $4

Latest revision as of 19:45, 7 December 2011

Author: Lloigor (talk, contrib)


Description

Generates a random number within a range using the RtlGenRandom api.

It can be used as is, or as a random seed generator for other functions, like http://nsis.sourceforge.net/Random. The Microsoft C Runtime Library makes use of this function (RtlGenRandom) in its implementation of "rand_s".

Example

!define tempfile "$EXEDIR\test_output.txt"
 
FileOpen $R0 "${tempfile}" "w"
StrCpy $3 0
loop:
   IntOp $3 $3 + 1
;--------------------------
   ${Rnd} $0 -50000 50000
;--------------------------
   FileWrite $R0 "$0$\r$\n"
   IntCmp $3 1000 0 loop
FileClose $R0
ExecWait 'notepad "${tempfile}"'
Delete "${tempfile}"

Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Generate a random number using the RtlGenRandom api
;; P1 :out: Random number
;; P2 :in:  Minimum value
;; P3 :in:  Maximum value
;; min/max P2 and P3 values = -2 147 483 647 / 2 147 483 647
;; max range = 2 147 483 647 (31-bit)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
!define Rnd "!insertmacro _Rnd"
!macro _Rnd _RetVal_ _Min_ _Max_
   Push "${_Max_}"
   Push "${_Min_}"
   Call Rnd
   Pop ${_RetVal_}
!macroend
Function Rnd
   Exch $0  ;; Min / return value
   Exch
   Exch $1  ;; Max / random value
   Push "$3"  ;; Max - Min range
   Push "$4"  ;; random value buffer
 
   IntOp $3 $1 - $0 ;; calculate range
   IntOp $3 $3 + 1
   System::Call '*(l) i .r4'
   System::Call 'advapi32::SystemFunction036(i r4, i 4)'  ;; RtlGenRandom
   System::Call '*$4(l .r1)'
   System::Free $4
   ;; fit value within range
   System::Int64Op $1 * $3
   Pop $3
   System::Int64Op $3 / 0xFFFFFFFF
   Pop $3
   IntOp $0 $3 + $0  ;; index with minimum value
 
   Pop $4
   Pop $3
   Pop $1
   Exch $0
FunctionEnd