diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 565b14f6c4..4149d3803b 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -16,6 +16,24 @@ The license applies to all entries newer than 2009-04-28. */ +2011-09-20 17:12 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) + * include/hbapi.h + * src/rtl/hbrandom.c + + Changed Harbour's core pseudo-random generator from STD C rand()/srand() + to superior implementation. New implementation fixed MT problems with + the standard solution on certain targets (f.e. win/mingw, win/msvc) + Based on Przemek's patch which is in turn based on algorithm by + Steve Park: http://www.cs.wm.edu/~va/software/park/ suggested by me + on the list. Further modifications: + * HB_RANDOMINTMAX() adapted. Checkme, I'm not sure about this. + * HB_RANDOMSEED() updated. + + headers cleaned, copyright updated, note added + + automatic seed defaulting like in previous version (checkme, + we may as well drop it, though it will be create incompatibility) + ; per-thread seed didn't work well for me (even with new engine) + so I didn't implement it. + + added proto for hb_random_seed() + 2011-09-20 13:56 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * src/rtl/teditor.prg ! fixed following issue: in MEMOEDIT() insert mode the word wrap inserts diff --git a/harbour/include/hbapi.h b/harbour/include/hbapi.h index aa6a80ca05..a394367066 100644 --- a/harbour/include/hbapi.h +++ b/harbour/include/hbapi.h @@ -968,6 +968,7 @@ extern HB_EXPORT char * hb_strRemEscSeq( char * szText, HB_SIZE * nLen ); /* extern HB_EXPORT char * hb_numToStr( char * szBuf, HB_SIZE nSize, HB_MAXINT nNumber ); extern HB_EXPORT double hb_numRound( double dResult, int iDec ); /* round a number to a specific number of digits */ extern HB_EXPORT double hb_numInt( double dNum ); /* take the integer part of the number */ +extern HB_EXPORT void hb_random_seed( HB_I32 seed ); extern HB_EXPORT double hb_random_num( void ); extern HB_EXPORT void hb_random_block( void * data, HB_SIZE len ); extern HB_EXPORT double hb_numDecConv( double dNum, int iDec ); diff --git a/harbour/src/rtl/hbrandom.c b/harbour/src/rtl/hbrandom.c index 7e8d541473..761fe2049d 100644 --- a/harbour/src/rtl/hbrandom.c +++ b/harbour/src/rtl/hbrandom.c @@ -3,9 +3,10 @@ */ /* - * xHarbour Project source code: + * Harbour Project source code: * Random number generator routine * + * Copyright 2011 Przemyslaw Czerpak * Copyright 2003 Giancarlo Niccolai * www - http://harbour-project.org * @@ -53,11 +54,17 @@ #include "hbapi.h" #include "hbdate.h" -#include -#include +/* NOTE: core random generator algorithm is the work of Steve Park + http://www.cs.wm.edu/~va/software/park/ + */ -/* Globally available data, no need to MT it */ -static volatile HB_BOOL s_fInit = HB_FALSE; +#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; /* * HB_RANDOM @@ -120,32 +127,45 @@ HB_FUNC( HB_RANDOMINT ) HB_FUNC( HB_RANDOMSEED ) { - srand( HB_ISNUM( 1 ) ? ( unsigned ) hb_parni( 1 ) : ( unsigned ) hb_dateMilliSeconds() ); + hb_random_seed( HB_ISNUM( 1 ) ? ( HB_I32 ) hb_parni( 1 ) : ( HB_I32 ) hb_dateMilliSeconds() ); + s_fInit = HB_TRUE; } HB_FUNC( HB_RANDOMINTMAX ) { -#if RAND_MAX > HB_VMLONG_MAX - hb_retnd( RAND_MAX ); +#if MAXIMUM > HB_VMLONG_MAX + hb_retnd( MAXIMUM ); #else - hb_retnint( RAND_MAX ); + hb_retnint( MAXIMUM ); #endif } /* Returns a double value between 0 and 1 */ double hb_random_num( void ) { - double d1, d2; + const HB_I32 Q = MODULUS / MULTIPLIER; + const HB_I32 R = MODULUS % MULTIPLIER; + + HB_I32 t; if( ! s_fInit ) { - srand( ( unsigned ) hb_dateMilliSeconds() ); + hb_random_seed( ( HB_I32 ) hb_dateMilliSeconds() ); s_fInit = HB_TRUE; } - d1 = ( double ) rand(); - d2 = ( double ) RAND_MAX + 1.0; + t = s_seed; + t = MULTIPLIER * ( t % Q ) - R * ( t / Q ); + if( t <= 0 ) + t += MODULUS; + s_seed = t; - return d1 / d2; + return ( ( double ) t / MODULUS ); +} + +void hb_random_seed( HB_I32 seed ) +{ + seed %= MODULUS; + s_seed = ( seed <= 0 ) ? seed + MODULUS : seed; }