Skip to content

Brl.Random - threadsafe #20

@GWRon

Description

@GWRon

MarkCWM in the syntaxbomb.com forums just brought up an old thread (in which I replied...;-)

Grable enhanced brl.random to be threadsafe there.

Strict

Rem
bbdoc: Math/Random numbers
End Rem
Module BRL.Random

ModuleInfo "Version: 1.09"
ModuleInfo "Author: Mark Sibly, Floyd"
ModuleInfo "License: zlib/libpng"
ModuleInfo "Copyright: Blitz Research Ltd"
ModuleInfo "Modserver: BRL"

ModuleInfo "History: 1.09 [grable]"
ModuleInfo "History: Made seed==0 get seed from main thread (so threads start with main thread seed)"
ModuleInfo "History: 1.08 [grable]"
ModuleInfo "History: Added RndSeedMain() to get seed of main thread"
ModuleInfo "History: 1.07 [grable]"
ModuleInfo "History: Now thread-safe, each thread has its own seed"
ModuleInfo "History: 1.05 Release"
ModuleInfo "History: Fixed Rand() with negative min value bug"

Private
Const	RND_A=48271,RND_M=2147483647,RND_Q=44488,RND_R=3399

?Not Threaded
Global	rnd_state=$1234

?Threaded
Extern "C"
	Function bbThreadAllocData:Int()
	Function bbThreadSetData( index:Int, data:Int )
'	Function bbThreadGetData:Int( index:Int )
	Function bbThreadGetMain:Int Ptr()
	Function bbThreadGetCurrent:Int Ptr()
EndExtern

' reimplemented to allow 0
Function bbThreadGetData:Int( index:Int)
'	Return bbThreadGetCurrent()[2 + index]
	Local slots:Int Ptr = bbThreadGetCurrent() + 2
	Local rnd_state:Int = slots[index]
	If rnd_state = 0 Then
		slots[index] = rnd_state_init
		Return rnd_state_init
	EndIf
	Return rnd_state
EndFunction

Function bbThreadGetMainData:Int( index:Int)
	Return bbThreadGetMain()[2 + index]
EndFunction

Global rnd_state_init:Int = $1234
Global rnd_state_index:Int = bbThreadAllocData()
bbThreadSetData rnd_state_index, rnd_state_init
?
Public

Rem
bbdoc: Generate random float
returns: A random float in the range 0 (inclusive) to 1 (exclusive)
End Rem
Function RndFloat#()
?Threaded
	Local rnd_state:Int = bbThreadGetData(rnd_state_index)
?
	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
	
?Threaded
	bbThreadSetData( rnd_state_index, rnd_state)
?
	Return (rnd_state & $ffffff0) / 268435456#  'divide by 2^28
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
	
?Threaded
	Local rnd_state:Int = bbThreadGetData(rnd_state_index)
?

	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

?Threaded
	bbThreadSetData( rnd_state_index, rnd_state)
?
	Return (r_hi + r_lo/TWO27)/TWO29
End Function

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
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
End Function

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
Function Rand( min_value,max_value=1 )
	Local range=max_value-min_value
	If range>0 Return Int( RndDouble()*(1+range) )+min_value
	Return Int( RndDouble()*(1-range) )+max_value
End Function

Rem
bbdoc: Set random number generator seed
End Rem
Function SeedRnd( seed )
?Not Threaded
	rnd_state=seed & $7fffffff             				'enforces rnd_state >= 0
?Threaded
	Local rnd_state:Int = seed & $7fffffff			'enforces rnd_state >= 0
?
	If rnd_state=0 Or rnd_state=RND_M rnd_state=$1234	'disallow 0 and M
	
?Threaded
	If bbThreadGetCurrent() = bbThreadGetMain() Then rnd_state_init = rnd_state
	bbThreadSetData( rnd_state_index, rnd_state)
?
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
numbers.
End Rem
Function RndSeed()
?Not Threaded
	Return rnd_state
?Threaded
	Return bbThreadGetData(rnd_state_index)
?
End Function

?Threaded
Rem
bbdoc: Get random number generator seed of Main thread
returns: The current random number generator seed of the Main thread
about: Use in conjunction with SeedRnd, RndSeedMain allows you to reproduce sequences of random
numbers.
End Rem
Function RndSeedMain()
	Return bbThreadGetMainData(rnd_state_index)
End Function
?

http://www.mojolabs.nz/posts.php?topic=105978

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions