Răsfoiți Sursa

Merge pull request #98 from HurryStarfish/patch-4

TRandom
Brucey 6 ani în urmă
părinte
comite
4b99dd25a7
1 a modificat fișierele cu 167 adăugiri și 32 ștergeri
  1. 167 32
      random.mod/random.bmx

+ 167 - 32
random.mod/random.bmx

@@ -6,49 +6,187 @@ bbdoc: Math/Random numbers
 End Rem
 Module BRL.Random
 
-ModuleInfo "Version: 1.06"
+ModuleInfo "Version: 1.07"
 ModuleInfo "Author: Mark Sibly, Floyd"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "Copyright: Blitz Research Ltd"
 ModuleInfo "Modserver: BRL"
 
+ModuleInfo "History: 1.07"
+ModuleInfo "History: Added support for multiple generators"
 ModuleInfo "History: 1.06"
 ModuleInfo "History: Module is now SuperStrict"
 ModuleInfo "History: 1.05 Release"
 ModuleInfo "History: Fixed Rand() with negative min value bug"
 
+? Threaded
+Import BRL.Threads
+?
+
 Private
-Global	rnd_state:Int=$1234
-Const	RND_A:Int=48271,RND_M:Int=2147483647,RND_Q:Int=44488,RND_R:Int=3399
+Const RND_A:Int=48271,RND_M:Int=2147483647,RND_Q:Int=44488,RND_R:Int=3399
+Global LastNewMs:Int = MilliSecs()
+Global SimultaneousNewCount:Int = 0
+? Threaded
+Global NewRandomMutex:TMutex = TMutex.Create()
+?
+Global GlobalRandom:TRandom = New TRandom
 Public
 
+Rem
+bbdoc: Random number generator
+about:
+By creating multiple TRandom objects, multiple independent
+random number generators can be used in parallel.
+End Rem
+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
+	bbdoc: Generate random float
+	returns: A random float in the range 0 (inclusive) to 1 (exclusive)
+	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
+	
+	Rem
+	bbdoc: Generate random double
+	returns: A random double in the range 0 (inclusive) to 1 (exclusive)
+	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
+	
+	Rem
+	bbdoc: Generate random double
+	returns: A random double in the range min (inclusive) to max (exclusive)
+	about: 
+	The optional parameters allow you to use Rnd in 3 ways:
+	
+	[ @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)
+	]
+	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
+	
+	Rem
+	bbdoc: Generate random integer
+	returns: A random integer in the range min (inclusive) to max (inclusive)
+	about:
+	The optional parameter allows you to use #Rand in 2 ways:
+	
+	[ @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)
+	]
+	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
+	
+	Rem
+	bbdoc: Set random number generator seed
+	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
+	
+	Rem
+	bbdoc: Get random number generator seed
+	returns: The current random number generator seed
+	about: Used in conjunction with SeedRnd, RndSeed allows you to reproduce sequences of random
+	numbers.
+	End Rem
+	Method RndSeed:Int()
+		Return rnd_state
+	End Method
+
+End Type
+
 Rem
 bbdoc: Generate random float
 returns: A random float in the range 0 (inclusive) to 1 (exclusive)
 End Rem
-Function RndFloat#()
-	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
+Function RndFloat:Float()
+	Return GlobalRandom.RndFloat()
 End Function
 
 Rem
 bbdoc: Generate random double
 returns: A random double in the range 0 (inclusive) to 1 (exclusive)
 End Rem
-Function RndDouble!()
-	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
+Function RndDouble:Double()
+	Return GlobalRandom.RndDouble()
 End Function
 
 Rem
@@ -63,9 +201,8 @@ The optional parameters allow you to use Rnd in 3 ways:
 * &Rnd(_x,y_) | Random double in the range x (inclusive) to y (exclusive)
 ]
 End Rem
-Function Rnd!( min_value!=1,max_value!=0 )
-	If max_value>min_value Return RndDouble()*(max_value-min_value)+min_value
-	Return RndDouble()*(min_value-max_value)+max_value
+Function Rnd:Double(minValue:Double = 1, maxValue:Double = 0)
+	Return GlobalRandom.Rnd(minValue, maxValue)
 End Function
 
 Rem
@@ -79,26 +216,24 @@ The optional parameter allows you to use #Rand in 2 ways:
 * &Rand(x,y) | Random integer in the range x to y (inclusive)
 ]
 End Rem
-Function Rand:Int( min_value:Int,max_value:Int=1 )
-	Local Range:Int=max_value-min_value
-	If Range>0 Return Int( RndDouble()*(1+Range) )+min_value
-	Return Int( RndDouble()*(1-Range) )+max_value
+Function Rand:Int(minValue:Int, maxValue:Int = 1)
+	Return GlobalRandom.Rand(minValue, maxValue)
 End Function
 
 Rem
 bbdoc: Set random number generator seed
 End Rem
-Function 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
+Function SeedRnd(seed:Int)
+	GlobalRandom.SeedRnd seed
 End Function
 
 Rem
 bbdoc: Get random number generator seed
 returns: The current random number generator seed
-about: Use 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.
 End Rem
 Function RndSeed:Int()
-	Return rnd_state
+	Return GlobalRandom.RndSeed()
 End Function
+