|
@@ -6,12 +6,14 @@ bbdoc: Math/Random numbers
|
|
End Rem
|
|
End Rem
|
|
Module BRL.Random
|
|
Module BRL.Random
|
|
|
|
|
|
-ModuleInfo "Version: 1.07"
|
|
|
|
|
|
+ModuleInfo "Version: 1.08"
|
|
ModuleInfo "Author: Mark Sibly, Floyd"
|
|
ModuleInfo "Author: Mark Sibly, Floyd"
|
|
ModuleInfo "License: zlib/libpng"
|
|
ModuleInfo "License: zlib/libpng"
|
|
ModuleInfo "Copyright: Blitz Research Ltd"
|
|
ModuleInfo "Copyright: Blitz Research Ltd"
|
|
ModuleInfo "Modserver: BRL"
|
|
ModuleInfo "Modserver: BRL"
|
|
|
|
|
|
|
|
+ModuleInfo "History: 1.08"
|
|
|
|
+ModuleInfo "History: New API to enable custom random number generators."
|
|
ModuleInfo "History: 1.07"
|
|
ModuleInfo "History: 1.07"
|
|
ModuleInfo "History: Added support for multiple generators"
|
|
ModuleInfo "History: Added support for multiple generators"
|
|
ModuleInfo "History: 1.06"
|
|
ModuleInfo "History: 1.06"
|
|
@@ -24,15 +26,76 @@ Import BRL.Threads
|
|
?
|
|
?
|
|
|
|
|
|
Private
|
|
Private
|
|
-Const RND_A:Int=48271,RND_M:Int=2147483647,RND_Q:Int=44488,RND_R:Int=3399
|
|
|
|
|
|
+
|
|
|
|
+Global GlobalRandom:TRandom
|
|
|
|
+
|
|
|
|
+Global random_factories:TRandomFactory
|
|
|
|
+
|
|
|
|
+Public
|
|
|
|
+
|
|
|
|
+Type TRandomFactory
|
|
|
|
+ Field _succ:TRandomFactory
|
|
|
|
+
|
|
|
|
+ Method New()
|
|
|
|
+ If random_factories <> Null Then
|
|
|
|
+ Throw "Random already installed : " + random_factories.GetName()
|
|
|
|
+ End If
|
|
|
|
+ _succ=random_factories
|
|
|
|
+ random_factories=Self
|
|
|
|
+ End Method
|
|
|
|
+
|
|
|
|
+ Method Init()
|
|
|
|
+ GlobalRandom = Create()
|
|
|
|
+ End Method
|
|
|
|
+
|
|
|
|
+ Method GetName:String() Abstract
|
|
|
|
+
|
|
|
|
+ Method Create:TRandom(seed:Int) Abstract
|
|
|
|
+
|
|
|
|
+ Method Create:TRandom() Abstract
|
|
|
|
+
|
|
|
|
+End Type
|
|
|
|
+
|
|
|
|
+Private
|
|
Global LastNewMs:Int = MilliSecs()
|
|
Global LastNewMs:Int = MilliSecs()
|
|
Global SimultaneousNewCount:Int = 0
|
|
Global SimultaneousNewCount:Int = 0
|
|
? Threaded
|
|
? Threaded
|
|
Global NewRandomMutex:TMutex = TMutex.Create()
|
|
Global NewRandomMutex:TMutex = TMutex.Create()
|
|
?
|
|
?
|
|
-Global GlobalRandom:TRandom = New TRandom
|
|
|
|
Public
|
|
Public
|
|
|
|
|
|
|
|
+Function GenerateSeed:Int()
|
|
|
|
+ ? Threaded
|
|
|
|
+ NewRandomMutex.Lock
|
|
|
|
+ ?
|
|
|
|
+ Local currentMs:Int = MilliSecs()
|
|
|
|
+ Local auxSeed:Int
|
|
|
|
+ If currentMs = LastNewMs Then
|
|
|
|
+ SimultaneousNewCount :+ 1
|
|
|
|
+ auxSeed = SimultaneousNewCount
|
|
|
|
+ Else
|
|
|
|
+ LastNewMs = currentMs
|
|
|
|
+ SimultaneousNewCount = 0
|
|
|
|
+ auxSeed = 0
|
|
|
|
+ End If
|
|
|
|
+ ? Threaded
|
|
|
|
+ NewRandomMutex.Unlock
|
|
|
|
+ ?
|
|
|
|
+
|
|
|
|
+ Function ReverseBits:Int(i:Int)
|
|
|
|
+ If i = 0 Then Return 0
|
|
|
|
+ Local r:Int
|
|
|
|
+ For Local b:Int = 0 Until 8 * SizeOf i
|
|
|
|
+ r :Shl 1
|
|
|
|
+ r :| i & 1
|
|
|
|
+ i :Shr 1
|
|
|
|
+ Next
|
|
|
|
+ Return r
|
|
|
|
+ End Function
|
|
|
|
+ ' left-shift before reversing because SeedRnd ignores the most significant bit
|
|
|
|
+ Return currentMs ~ ReverseBits(auxSeed Shl 1)
|
|
|
|
+End Function
|
|
|
|
+
|
|
Rem
|
|
Rem
|
|
bbdoc: Random number generator
|
|
bbdoc: Random number generator
|
|
about:
|
|
about:
|
|
@@ -41,83 +104,17 @@ random number generators can be used in parallel.
|
|
End Rem
|
|
End Rem
|
|
Type TRandom
|
|
Type TRandom
|
|
|
|
|
|
- Private
|
|
|
|
-
|
|
|
|
- Field rnd_state:Int=$1234
|
|
|
|
-
|
|
|
|
- Public
|
|
|
|
-
|
|
|
|
- Rem
|
|
|
|
- bbdoc: Create a new random number generator
|
|
|
|
- End Rem
|
|
|
|
- Method New()
|
|
|
|
- ? Threaded
|
|
|
|
- NewRandomMutex.Lock
|
|
|
|
- ?
|
|
|
|
- Local currentMs:Int = MilliSecs()
|
|
|
|
- Local auxSeed:Int
|
|
|
|
- If currentMs = LastNewMs Then
|
|
|
|
- SimultaneousNewCount :+ 1
|
|
|
|
- auxSeed = SimultaneousNewCount
|
|
|
|
- Else
|
|
|
|
- LastNewMs = currentMs
|
|
|
|
- SimultaneousNewCount = 0
|
|
|
|
- auxSeed = 0
|
|
|
|
- End If
|
|
|
|
- ? Threaded
|
|
|
|
- NewRandomMutex.Unlock
|
|
|
|
- ?
|
|
|
|
-
|
|
|
|
- Function ReverseBits:Int(i:Int)
|
|
|
|
- If i = 0 Then Return 0
|
|
|
|
- Local r:Int
|
|
|
|
- For Local b:Int = 0 Until 8 * SizeOf i
|
|
|
|
- r :Shl 1
|
|
|
|
- r :| i & 1
|
|
|
|
- i :Shr 1
|
|
|
|
- Next
|
|
|
|
- Return r
|
|
|
|
- End Function
|
|
|
|
- ' left-shift before reversing because SeedRnd ignores the most significant bit
|
|
|
|
- Local seed:Int = currentMs ~ ReverseBits(auxSeed Shl 1)
|
|
|
|
- SeedRnd seed
|
|
|
|
- End Method
|
|
|
|
-
|
|
|
|
- Rem
|
|
|
|
- bbdoc: Create a new random number generator with the specified seed
|
|
|
|
- End Rem
|
|
|
|
- Method New(seed:Int)
|
|
|
|
- SeedRnd seed
|
|
|
|
- End Method
|
|
|
|
-
|
|
|
|
Rem
|
|
Rem
|
|
bbdoc: Generate random float
|
|
bbdoc: Generate random float
|
|
returns: A random float in the range 0 (inclusive) to 1 (exclusive)
|
|
returns: A random float in the range 0 (inclusive) to 1 (exclusive)
|
|
End Rem
|
|
End Rem
|
|
- Method RndFloat:Float()
|
|
|
|
- rnd_state=RND_A*(rnd_state Mod RND_Q)-RND_R*(rnd_state/RND_Q)
|
|
|
|
- If rnd_state<0 rnd_state=rnd_state+RND_M
|
|
|
|
- Return (rnd_state & $ffffff0) / 268435456# 'divide by 2^28
|
|
|
|
- End Method
|
|
|
|
|
|
+ Method RndFloat:Float() Abstract
|
|
|
|
|
|
Rem
|
|
Rem
|
|
bbdoc: Generate random double
|
|
bbdoc: Generate random double
|
|
returns: A random double in the range 0 (inclusive) to 1 (exclusive)
|
|
returns: A random double in the range 0 (inclusive) to 1 (exclusive)
|
|
End Rem
|
|
End Rem
|
|
- Method RndDouble:Double()
|
|
|
|
- Const TWO27! = 134217728.0 '2 ^ 27
|
|
|
|
- Const TWO29! = 536870912.0 '2 ^ 29
|
|
|
|
-
|
|
|
|
- rnd_state=RND_A*(rnd_state Mod RND_Q)-RND_R*(rnd_state/RND_Q)
|
|
|
|
- If rnd_state<0 rnd_state=rnd_state+RND_M
|
|
|
|
- Local r_hi! = rnd_state & $1ffffffc
|
|
|
|
-
|
|
|
|
- rnd_state=RND_A*(rnd_state Mod RND_Q)-RND_R*(rnd_state/RND_Q)
|
|
|
|
- If rnd_state<0 rnd_state=rnd_state+RND_M
|
|
|
|
- Local r_lo! = rnd_state & $1ffffff8
|
|
|
|
-
|
|
|
|
- Return (r_hi + r_lo/TWO27)/TWO29
|
|
|
|
- End Method
|
|
|
|
|
|
+ Method RndDouble:Double() Abstract
|
|
|
|
|
|
Rem
|
|
Rem
|
|
bbdoc: Generate random double
|
|
bbdoc: Generate random double
|
|
@@ -126,15 +123,12 @@ Type TRandom
|
|
The optional parameters allow you to use Rnd in 3 ways:
|
|
The optional parameters allow you to use Rnd in 3 ways:
|
|
|
|
|
|
[ @Format | @Result
|
|
[ @Format | @Result
|
|
- * &Rnd() | Random double in the range 0 (inclusive) to 1 (exclusive)
|
|
|
|
- * &Rnd(_x_) | Random double in the range 0 (inclusive) to n (exclusive)
|
|
|
|
- * &Rnd(_x,y_) | Random double in the range x (inclusive) to y (exclusive)
|
|
|
|
|
|
+ * `Rnd()` | Random double in the range 0 (inclusive) to 1 (exclusive)
|
|
|
|
+ * `Rnd(x)` | Random double in the range 0 (inclusive) to n (exclusive)
|
|
|
|
+ * `Rnd(x,y)` | Random double in the range x (inclusive) to y (exclusive)
|
|
]
|
|
]
|
|
End Rem
|
|
End Rem
|
|
- Method Rnd:Double(minValue:Double = 1, maxValue:Double = 0)
|
|
|
|
- If maxValue>minValue Return RndDouble()*(maxValue-minValue)+minValue
|
|
|
|
- Return RndDouble()*(minValue-maxValue)+maxValue
|
|
|
|
- End Method
|
|
|
|
|
|
+ Method Rnd:Double(minValue:Double = 1, maxValue:Double = 0) Abstract
|
|
|
|
|
|
Rem
|
|
Rem
|
|
bbdoc: Generate random integer
|
|
bbdoc: Generate random integer
|
|
@@ -143,23 +137,16 @@ Type TRandom
|
|
The optional parameter allows you to use #Rand in 2 ways:
|
|
The optional parameter allows you to use #Rand in 2 ways:
|
|
|
|
|
|
[ @Format | @Result
|
|
[ @Format | @Result
|
|
- * &Rand(x) | Random integer in the range 1 to x (inclusive)
|
|
|
|
- * &Rand(x,y) | Random integer in the range x to y (inclusive)
|
|
|
|
|
|
+ * `Rand(x)` | Random integer in the range 1 to x (inclusive)
|
|
|
|
+ * `Rand(x,y)` | Random integer in the range x to y (inclusive)
|
|
]
|
|
]
|
|
End Rem
|
|
End Rem
|
|
- Method Rand:Int(minValue:Int, maxValue:Int = 1)
|
|
|
|
- Local Range:Int=maxValue-minValue
|
|
|
|
- If Range>0 Return Int( RndDouble()*(1+Range) )+minValue
|
|
|
|
- Return Int( RndDouble()*(1-Range) )+maxValue
|
|
|
|
- End Method
|
|
|
|
|
|
+ Method Rand:Int(minValue:Int, maxValue:Int = 1) Abstract
|
|
|
|
|
|
Rem
|
|
Rem
|
|
bbdoc: Set random number generator seed
|
|
bbdoc: Set random number generator seed
|
|
End Rem
|
|
End Rem
|
|
- Method SeedRnd(seed:Int)
|
|
|
|
- rnd_state=seed & $7fffffff 'enforces rnd_state >= 0
|
|
|
|
- If rnd_state=0 Or rnd_state=RND_M rnd_state=$1234 'disallow 0 and M
|
|
|
|
- End Method
|
|
|
|
|
|
+ Method SeedRnd(seed:Int) Abstract
|
|
|
|
|
|
Rem
|
|
Rem
|
|
bbdoc: Get random number generator seed
|
|
bbdoc: Get random number generator seed
|
|
@@ -167,18 +154,42 @@ Type TRandom
|
|
about: Used in conjunction with SeedRnd, RndSeed allows you to reproduce sequences of random
|
|
about: Used in conjunction with SeedRnd, RndSeed allows you to reproduce sequences of random
|
|
numbers.
|
|
numbers.
|
|
End Rem
|
|
End Rem
|
|
- Method RndSeed:Int()
|
|
|
|
- Return rnd_state
|
|
|
|
- End Method
|
|
|
|
|
|
+ Method RndSeed:Int() Abstract
|
|
|
|
|
|
End Type
|
|
End Type
|
|
|
|
|
|
|
|
+Rem
|
|
|
|
+bbdoc: Creates a new TRandom instance.
|
|
|
|
+End Rem
|
|
|
|
+Function CreateRandom:TRandom()
|
|
|
|
+ If GlobalRandom Then
|
|
|
|
+ Return random_factories.Create()
|
|
|
|
+ Else
|
|
|
|
+ Throw "No Random installed. Maybe Import BRL.RandomDefault ?"
|
|
|
|
+ End If
|
|
|
|
+End Function
|
|
|
|
+
|
|
|
|
+Rem
|
|
|
|
+bbdoc: Creates a new TRandom instance with the given @seed.
|
|
|
|
+End Rem
|
|
|
|
+Function CreateRandom:TRandom(seed:Int)
|
|
|
|
+ If GlobalRandom Then
|
|
|
|
+ Return random_factories.Create(seed)
|
|
|
|
+ Else
|
|
|
|
+ Throw "No Random installed. Maybe Import BRL.RandomDefault ?"
|
|
|
|
+ End If
|
|
|
|
+End Function
|
|
|
|
+
|
|
Rem
|
|
Rem
|
|
bbdoc: Generate random float
|
|
bbdoc: Generate random float
|
|
returns: A random float in the range 0 (inclusive) to 1 (exclusive)
|
|
returns: A random float in the range 0 (inclusive) to 1 (exclusive)
|
|
End Rem
|
|
End Rem
|
|
Function RndFloat:Float()
|
|
Function RndFloat:Float()
|
|
- Return GlobalRandom.RndFloat()
|
|
|
|
|
|
+ If GlobalRandom Then
|
|
|
|
+ Return GlobalRandom.RndFloat()
|
|
|
|
+ Else
|
|
|
|
+ Throw "No Random installed. Maybe Import BRL.RandomDefault ?"
|
|
|
|
+ End If
|
|
End Function
|
|
End Function
|
|
|
|
|
|
Rem
|
|
Rem
|
|
@@ -186,7 +197,11 @@ bbdoc: Generate random double
|
|
returns: A random double in the range 0 (inclusive) to 1 (exclusive)
|
|
returns: A random double in the range 0 (inclusive) to 1 (exclusive)
|
|
End Rem
|
|
End Rem
|
|
Function RndDouble:Double()
|
|
Function RndDouble:Double()
|
|
- Return GlobalRandom.RndDouble()
|
|
|
|
|
|
+ If GlobalRandom Then
|
|
|
|
+ Return GlobalRandom.RndDouble()
|
|
|
|
+ Else
|
|
|
|
+ Throw "No Random installed. Maybe Import BRL.RandomDefault ?"
|
|
|
|
+ End If
|
|
End Function
|
|
End Function
|
|
|
|
|
|
Rem
|
|
Rem
|
|
@@ -196,13 +211,17 @@ about:
|
|
The optional parameters allow you to use Rnd in 3 ways:
|
|
The optional parameters allow you to use Rnd in 3 ways:
|
|
|
|
|
|
[ @Format | @Result
|
|
[ @Format | @Result
|
|
-* &Rnd() | Random double in the range 0 (inclusive) to 1 (exclusive)
|
|
|
|
-* &Rnd(_x_) | Random double in the range 0 (inclusive) to n (exclusive)
|
|
|
|
-* &Rnd(_x,y_) | Random double in the range x (inclusive) to y (exclusive)
|
|
|
|
|
|
+* `Rnd()` | Random double in the range 0 (inclusive) to 1 (exclusive)
|
|
|
|
+* `Rnd(x)` | Random double in the range 0 (inclusive) to n (exclusive)
|
|
|
|
+* `Rnd(x,y)` | Random double in the range x (inclusive) to y (exclusive)
|
|
]
|
|
]
|
|
End Rem
|
|
End Rem
|
|
Function Rnd:Double(minValue:Double = 1, maxValue:Double = 0)
|
|
Function Rnd:Double(minValue:Double = 1, maxValue:Double = 0)
|
|
- Return GlobalRandom.Rnd(minValue, maxValue)
|
|
|
|
|
|
+ If GlobalRandom Then
|
|
|
|
+ Return GlobalRandom.Rnd(minValue, maxValue)
|
|
|
|
+ Else
|
|
|
|
+ Throw "No Random installed. Maybe Import BRL.RandomDefault ?"
|
|
|
|
+ End If
|
|
End Function
|
|
End Function
|
|
|
|
|
|
Rem
|
|
Rem
|
|
@@ -212,19 +231,27 @@ about:
|
|
The optional parameter allows you to use #Rand in 2 ways:
|
|
The optional parameter allows you to use #Rand in 2 ways:
|
|
|
|
|
|
[ @Format | @Result
|
|
[ @Format | @Result
|
|
-* &Rand(x) | Random integer in the range 1 to x (inclusive)
|
|
|
|
-* &Rand(x,y) | Random integer in the range x to y (inclusive)
|
|
|
|
|
|
+* `Rand(x)` | Random integer in the range 1 to x (inclusive)
|
|
|
|
+* `Rand(x,y)` | Random integer in the range x to y (inclusive)
|
|
]
|
|
]
|
|
End Rem
|
|
End Rem
|
|
Function Rand:Int(minValue:Int, maxValue:Int = 1)
|
|
Function Rand:Int(minValue:Int, maxValue:Int = 1)
|
|
- Return GlobalRandom.Rand(minValue, maxValue)
|
|
|
|
|
|
+ If GlobalRandom Then
|
|
|
|
+ Return GlobalRandom.Rand(minValue, maxValue)
|
|
|
|
+ Else
|
|
|
|
+ Throw "No Random installed. Maybe Import BRL.RandomDefault ?"
|
|
|
|
+ End If
|
|
End Function
|
|
End Function
|
|
|
|
|
|
Rem
|
|
Rem
|
|
bbdoc: Set random number generator seed
|
|
bbdoc: Set random number generator seed
|
|
End Rem
|
|
End Rem
|
|
Function SeedRnd(seed:Int)
|
|
Function SeedRnd(seed:Int)
|
|
- GlobalRandom.SeedRnd seed
|
|
|
|
|
|
+ If GlobalRandom Then
|
|
|
|
+ GlobalRandom.SeedRnd seed
|
|
|
|
+ Else
|
|
|
|
+ Throw "No Random installed. Maybe Import BRL.RandomDefault ?"
|
|
|
|
+ End If
|
|
End Function
|
|
End Function
|
|
|
|
|
|
Rem
|
|
Rem
|
|
@@ -234,6 +261,9 @@ about: Used in conjunction with SeedRnd, RndSeed allows you to reproduce sequenc
|
|
numbers.
|
|
numbers.
|
|
End Rem
|
|
End Rem
|
|
Function RndSeed:Int()
|
|
Function RndSeed:Int()
|
|
- Return GlobalRandom.RndSeed()
|
|
|
|
|
|
+ If GlobalRandom Then
|
|
|
|
+ Return GlobalRandom.RndSeed()
|
|
|
|
+ Else
|
|
|
|
+ Throw "No Random installed. Maybe Import BRL.RandomDefault ?"
|
|
|
|
+ End If
|
|
End Function
|
|
End Function
|
|
-
|
|
|