2011-09-23 18:36 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/src/rtl/hbrandom.c
! fixed HB_RANDOMINTMAX() to return correct value for new PRNG
used by HB_RANDOM() and HB_RANDOMINT() functions
! fixed missing protection against initialization of PRNG seed with 0
* modified the range of hb_random_num() results from ( 0 , 1 ) to
[ 0, 1 )
% added alternative PRN calculation for builds with 64bit integers
! allocate separate PRNG seed for each thread (MT support)
* modified default initialization of PRNG:
if PRNG is not initialized or after HB_RANDOMSEED( 0 ) then
first call to HB_RANDOM() or HB_RANDOMINT() activates
initialization which generates new seed using current time
in milliseconds and HVM stack address (for MT modes).
I used such method because it nicely simplifies code and is
backward compatible with previous implementation.
If someone needs repeatable results from HB_RANDOM() and
HB_RANDOMINT() then he should initialize PRNG seed for each
thread with some fixed value i.e.:
HB_RANDOMSEED( 123456789 )
; Many thanks to Viktor and Mindaugas for their help.
* harbour/contrib/xhb/xhbole.prg
! added missing SETGET in method declaration.
Many thanks to Juan Galvez for locating the problem.
This commit is contained in:
@@ -16,6 +16,32 @@
|
||||
The license applies to all entries newer than 2009-04-28.
|
||||
*/
|
||||
|
||||
2011-09-23 18:36 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
|
||||
* harbour/src/rtl/hbrandom.c
|
||||
! fixed HB_RANDOMINTMAX() to return correct value for new PRNG
|
||||
used by HB_RANDOM() and HB_RANDOMINT() functions
|
||||
! fixed missing protection against initialization of PRNG seed with 0
|
||||
* modified the range of hb_random_num() results from ( 0 , 1 ) to
|
||||
[ 0, 1 )
|
||||
% added alternative PRN calculation for builds with 64bit integers
|
||||
! allocate separate PRNG seed for each thread (MT support)
|
||||
* modified default initialization of PRNG:
|
||||
if PRNG is not initialized or after HB_RANDOMSEED( 0 ) then
|
||||
first call to HB_RANDOM() or HB_RANDOMINT() activates
|
||||
initialization which generates new seed using current time
|
||||
in milliseconds and HVM stack address (for MT modes).
|
||||
I used such method because it nicely simplifies code and is
|
||||
backward compatible with previous implementation.
|
||||
If someone needs repeatable results from HB_RANDOM() and
|
||||
HB_RANDOMINT() then he should initialize PRNG seed for each
|
||||
thread with some fixed value i.e.:
|
||||
HB_RANDOMSEED( 123456789 )
|
||||
; Many thanks to Viktor and Mindaugas for their help.
|
||||
|
||||
* harbour/contrib/xhb/xhbole.prg
|
||||
! added missing SETGET in method declaration.
|
||||
Many thanks to Juan Galvez for locating the problem.
|
||||
|
||||
2011-09-20 17:12 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
|
||||
* include/hbapi.h
|
||||
* src/rtl/hbrandom.c
|
||||
|
||||
@@ -134,7 +134,7 @@ STATIC FUNCTION s_oleError( nGenCode, cDescript )
|
||||
CREATE CLASS TOLEAUTO FROM WIN_OLEAUTO
|
||||
VAR cClassName
|
||||
|
||||
METHOD hObj( xOle )
|
||||
METHOD hObj( xOle ) SETGET
|
||||
METHOD New( xOle, cClass, cLicense )
|
||||
METHOD GetActiveObject( cClass )
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
|
||||
#include "hbapi.h"
|
||||
#include "hbdate.h"
|
||||
#include "hbstack.h"
|
||||
|
||||
/* NOTE: core random generator algorithm is the work of Steve Park
|
||||
http://www.cs.wm.edu/~va/software/park/
|
||||
@@ -60,11 +61,43 @@
|
||||
|
||||
#define MODULUS 2147483647 /* DON'T CHANGE THIS VALUE */
|
||||
#define MULTIPLIER 48271 /* DON'T CHANGE THIS VALUE */
|
||||
#define DEFAULT 123456789 /* initial seed, use 0 < DEFAULT < MODULUS */
|
||||
#define MAXIMUM 0xFFFFFFFF
|
||||
|
||||
static HB_BOOL s_fInit = HB_FALSE;
|
||||
static HB_I32 s_seed = DEFAULT;
|
||||
static HB_TSD_NEW( s_seed, sizeof( HB_I32 ), NULL, NULL );
|
||||
#define SEED_PTR ( ( HB_I32 * ) hb_stackGetTSD( &s_seed ) )
|
||||
|
||||
/* Returns a double value between 0 and 1 */
|
||||
double hb_random_num( void )
|
||||
{
|
||||
HB_I32 * seed = SEED_PTR, t;
|
||||
|
||||
t = *seed;
|
||||
if( t == 0 )
|
||||
t = ( HB_I32 )
|
||||
( ( hb_dateMilliSeconds() ^ ( HB_PTRUINT ) hb_stackId() ) % MODULUS );
|
||||
|
||||
#if !defined( HB_LONG_LONG_OFF )
|
||||
t = ( HB_I32 ) ( ( HB_LONGLONG ) t * MULTIPLIER % MODULUS );
|
||||
#else
|
||||
{
|
||||
const HB_I32 Q = MODULUS / MULTIPLIER;
|
||||
const HB_I32 R = MODULUS % MULTIPLIER;
|
||||
|
||||
t = MULTIPLIER * ( t % Q ) - R * ( t / Q );
|
||||
if( t < 0 )
|
||||
t += MODULUS;
|
||||
}
|
||||
#endif
|
||||
|
||||
*seed = t;
|
||||
|
||||
return ( double ) ( t - 1 ) / ( MODULUS - 1 );
|
||||
}
|
||||
|
||||
void hb_random_seed( HB_I32 seed )
|
||||
{
|
||||
seed %= MODULUS;
|
||||
* SEED_PTR = ( seed < 0 ) ? seed + MODULUS : seed;
|
||||
}
|
||||
|
||||
/*
|
||||
* HB_RANDOM
|
||||
@@ -127,45 +160,10 @@ HB_FUNC( HB_RANDOMINT )
|
||||
|
||||
HB_FUNC( HB_RANDOMSEED )
|
||||
{
|
||||
hb_random_seed( HB_ISNUM( 1 ) ? ( HB_I32 ) hb_parni( 1 ) : ( HB_I32 ) hb_dateMilliSeconds() );
|
||||
|
||||
s_fInit = HB_TRUE;
|
||||
hb_random_seed( hb_parni( 1 ) );
|
||||
}
|
||||
|
||||
HB_FUNC( HB_RANDOMINTMAX )
|
||||
{
|
||||
#if MAXIMUM > HB_VMLONG_MAX
|
||||
hb_retnd( MAXIMUM );
|
||||
#else
|
||||
hb_retnint( MAXIMUM );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns a double value between 0 and 1 */
|
||||
double hb_random_num( void )
|
||||
{
|
||||
const HB_I32 Q = MODULUS / MULTIPLIER;
|
||||
const HB_I32 R = MODULUS % MULTIPLIER;
|
||||
|
||||
HB_I32 t;
|
||||
|
||||
if( ! s_fInit )
|
||||
{
|
||||
hb_random_seed( ( HB_I32 ) hb_dateMilliSeconds() );
|
||||
s_fInit = HB_TRUE;
|
||||
}
|
||||
|
||||
t = s_seed;
|
||||
t = MULTIPLIER * ( t % Q ) - R * ( t / Q );
|
||||
if( t <= 0 )
|
||||
t += MODULUS;
|
||||
s_seed = t;
|
||||
|
||||
return ( ( double ) t / MODULUS );
|
||||
}
|
||||
|
||||
void hb_random_seed( HB_I32 seed )
|
||||
{
|
||||
seed %= MODULUS;
|
||||
s_seed = ( seed <= 0 ) ? seed + MODULUS : seed;
|
||||
hb_retnint( MODULUS - 2 );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user