diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 4149d3803b..8a346b09fc 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -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 diff --git a/harbour/contrib/xhb/xhbole.prg b/harbour/contrib/xhb/xhbole.prg index d17e66f4c5..b4e187a218 100644 --- a/harbour/contrib/xhb/xhbole.prg +++ b/harbour/contrib/xhb/xhbole.prg @@ -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 ) diff --git a/harbour/src/rtl/hbrandom.c b/harbour/src/rtl/hbrandom.c index 761fe2049d..6626daeefa 100644 --- a/harbour/src/rtl/hbrandom.c +++ b/harbour/src/rtl/hbrandom.c @@ -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 ); }