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:
Przemyslaw Czerpak
2011-09-23 16:36:37 +00:00
parent 2ae90b92ba
commit da1a9239f1
3 changed files with 66 additions and 42 deletions

View File

@@ -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

View File

@@ -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 )

View File

@@ -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 );
}