From a35c10fbfced6df780e94941a8613cc9732fa071 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 27 Aug 2012 15:10:57 +0000 Subject: [PATCH] added qse_randxs32() and qse_randxs64(). changed awk's rand() to use these. fixed a bug of registering rand() with a wrong number of arguments in StdAwk. --- qse/lib/awk/StdAwk.cpp | 43 +++++++++++++++++++++++++---------- qse/lib/awk/std.c | 51 ++++++++++++++++++++++++++++-------------- qse/lib/awk/val.c | 16 +++++++------ qse/lib/cmn/alg-rand.c | 40 +++++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 36 deletions(-) diff --git a/qse/lib/awk/StdAwk.cpp b/qse/lib/awk/StdAwk.cpp index e120183f..b8824968 100644 --- a/qse/lib/awk/StdAwk.cpp +++ b/qse/lib/awk/StdAwk.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "awk.h" @@ -139,7 +140,7 @@ int StdAwk::open () if (addFunction (QSE_T("rand"), 0, 0, (FunctionHandler)&StdAwk::rand, 0) <= -1 || addFunction (QSE_T("srand"), 0, 1, (FunctionHandler)&StdAwk::srand, 0) <= -1 || addFunction (QSE_T("system"), 1, 1, (FunctionHandler)&StdAwk::system, 0) <= -1 || - addFunction (QSE_T("time"), 1, 1, (FunctionHandler)&StdAwk::time, 0) <= -1 || + addFunction (QSE_T("time"), 0, 0, (FunctionHandler)&StdAwk::time, 0) <= -1 || addFunction (QSE_T("setioattr"), 3, 3, (FunctionHandler)&StdAwk::setioattr, QSE_AWK_RIO) <= -1 || addFunction (QSE_T("getioattr"), 2, 2, (FunctionHandler)&StdAwk::getioattr, QSE_AWK_RIO) <= -1) { @@ -149,10 +150,13 @@ int StdAwk::open () qse_ntime_t now; - this->seed = (qse_gettime(&now) <= -1)? 0u: (unsigned int)now; - this->seed += (qse_uintptr_t)&now; + this->seed = (qse_gettime(&now) <= -1)? 0u: (long_t)now; + /* i don't care if the seed becomes negative or overflows. + * i just convert the signed value to the unsigned one. */ + this->prand = (qse_ulong_t)(this->seed * this->seed * this->seed); + /* make sure that the actual seeding is not 0 */ + if (this->prand == 0) this->prand++; - ::srand (this->seed); this->cmgrtab_inited = false; return 0; } @@ -401,29 +405,44 @@ int StdAwk::make_additional_globals (Run* run) int StdAwk::rand (Run& run, Value& ret, const Value* args, size_t nargs, const char_t* name, size_t len) { - return ret.setFlt ((flt_t)(::rand() % RAND_MAX) / RAND_MAX); +#if (QSE_SIZEOF_ULONG_T == 2) +# define RANDV_MAX 0x7FFFl +#elif (QSE_SIZEOF_ULONG_T == 4) +# define RANDV_MAX 0x7FFFFFFFl +#elif (QSE_SIZEOF_ULONG_T == 8) +# define RANDV_MAX 0x7FFFFFFFFFFFFFFl +#else +# error Unsupported +#endif + + this->prand = qse_randxsulong (this->prand); + long_t randv = this->prand % RANDV_MAX; + return ret.setFlt ((flt_t)randv / RANDV_MAX); } int StdAwk::srand (Run& run, Value& ret, const Value* args, size_t nargs, const char_t* name, size_t len) { - unsigned int prevSeed = this->seed; + long_t prevSeed = (long_t)this->seed; + + qse_ntime_t now; if (nargs <= 0) { - qse_ntime_t now; - this->seed = (qse_gettime (&now) <= -1)? - (this->seed >> 1): (unsigned int)now; - this->seed += (qse_uintptr_t)&now; + (this->seed * this->seed): (long_t)now; } else { - this->seed = (unsigned int)args[0].toInt(); + this->seed = args[0].toInt(); } + /* i don't care if the seed becomes negative or overflows. + * i just convert the signed value to the unsigned one. */ + this->prand = (qse_ulong_t)(this->seed * this->seed * this->seed); + /* make sure that the actual seeding is not 0 */ + if (this->prand == 0) this->prand++; - ::srand (this->seed); return ret.setInt ((long_t)prevSeed); } diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index 8457aab1..50a4c430 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -29,6 +29,7 @@ #include #include #include +#include #include /* TODO: remove dependency on qse_vsprintf */ #include "../cmn/mem.h" @@ -112,7 +113,8 @@ typedef struct xtn_t typedef struct rxtn_t { - unsigned int seed; + qse_long_t seed; + qse_ulong_t prand; /* last random value returned */ struct { @@ -1921,9 +1923,12 @@ qse_awk_rtx_t* qse_awk_rtx_openstd ( qse_awk_rtx_pushrcb (rtx, &rcb); - rxtn->seed = (qse_gettime (&now) <= -1)? 0u: (unsigned int)now; - rxtn->seed += (qse_uintptr_t)&now; - srand (rxtn->seed); + rxtn->seed = (qse_gettime (&now) <= -1)? 0u: (qse_long_t)now; + /* i don't care if the seed becomes negative or overflows. + * i just convert the signed value to the unsigned one. */ + rxtn->prand = (qse_ulong_t)(rxtn->seed * rxtn->seed * rxtn->seed); + /* make sure that the actual seeding is not 0 */ + if (rxtn->prand == 0) rxtn->prand++; rxtn->c.in.files = icf; rxtn->c.in.index = 0; @@ -1972,16 +1977,26 @@ void* qse_awk_rtx_getxtnstd (qse_awk_rtx_t* rtx) static int fnc_rand (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm) { - qse_awk_val_t* r; +#if (QSE_SIZEOF_ULONG_T == 2) +# define RANDV_MAX 0x7FFFl +#elif (QSE_SIZEOF_ULONG_T == 4) +# define RANDV_MAX 0x7FFFFFFFl +#elif (QSE_SIZEOF_ULONG_T == 8) +# define RANDV_MAX 0x7FFFFFFFFFFFFFFl +#else +# error Unsupported +#endif - /* + qse_awk_val_t* r; + qse_long_t randv; rxtn_t* rxtn; + rxtn = (rxtn_t*) QSE_XTN (rtx); - r = qse_awk_rtx_makefltval ( - rtx, (qse_flt_t)(rand_r(rxtn->seed) % RAND_MAX) / RAND_MAX ); - */ - r = qse_awk_rtx_makefltval ( - rtx, (qse_flt_t)(rand() % RAND_MAX) / RAND_MAX); + + rxtn->prand = qse_randxsulong (rxtn->prand); + randv = rxtn->prand % RANDV_MAX; + + r = qse_awk_rtx_makefltval (rtx, (qse_flt_t)randv / RANDV_MAX); if (r == QSE_NULL) return -1; qse_awk_rtx_setretval (rtx, r); @@ -1995,7 +2010,8 @@ static int fnc_srand (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm) qse_long_t lv; qse_awk_val_t* r; int n; - unsigned int prev; + qse_long_t prev; + qse_ntime_t now; rxtn_t* rxtn; rxtn = (rxtn_t*) QSE_XTN (rtx); @@ -2006,10 +2022,8 @@ static int fnc_srand (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm) if (nargs <= 0) { - qse_ntime_t now; rxtn->seed = (qse_gettime (&now) <= -1)? - (rxtn->seed >> 1): (unsigned int)now; - rxtn->seed += (qse_uintptr_t)&now; + (rxtn->seed * rxtn->seed): (qse_long_t)now; } else { @@ -2018,8 +2032,11 @@ static int fnc_srand (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm) if (n <= -1) return -1; rxtn->seed = lv; } - - srand (rxtn->seed); + /* i don't care if the seed becomes negative or overflows. + * i just convert the signed value to the unsigned one. */ + rxtn->prand = (qse_ulong_t)(rxtn->seed * rxtn->seed * rxtn->seed); + /* make sure that the actual seeding is not 0 */ + if (rxtn->prand == 0) rxtn->prand++; r = qse_awk_rtx_makeintval (rtx, prev); if (r == QSE_NULL) return -1; diff --git a/qse/lib/awk/val.c b/qse/lib/awk/val.c index e7a34253..efd671cf 100644 --- a/qse/lib/awk/val.c +++ b/qse/lib/awk/val.c @@ -844,16 +844,19 @@ static int val_int_to_str ( qse_awk_rtx_valtostr_out_t* out) { qse_char_t* tmp; - qse_long_t t; + qse_ulong_t t; qse_size_t rlen = 0; int type = out->type & ~QSE_AWK_RTX_VALTOSTR_PRINT; - t = v->val; - if (t == 0) rlen++; + if (v->val == 0) rlen++; else { /* non-zero values */ - if (t < 0) { t = -t; rlen++; } + if (v->val < 0) + { + t = v->val * -1; rlen++; + } + else t = v->val; while (t > 0) { rlen++; t /= 10; } } @@ -939,11 +942,10 @@ static int val_int_to_str ( } } - t = v->val; - if (t == 0) tmp[0] = QSE_T('0'); + if (v->val == 0) tmp[0] = QSE_T('0'); else { - if (t < 0) t = -t; + t = (v->val < 0)? (v->val * -1): v->val; /* fill in the buffer with digits */ while (t > 0) diff --git a/qse/lib/cmn/alg-rand.c b/qse/lib/cmn/alg-rand.c index 0540a25f..6babeaf3 100644 --- a/qse/lib/cmn/alg-rand.c +++ b/qse/lib/cmn/alg-rand.c @@ -41,3 +41,43 @@ qse_uint32_t qse_rand31 (qse_uint32_t seed) return lo; } + +/* + * Xorshift RNGs by George Marsaglia, The Florida State University + * http://www.jstatsoft.org/v08/i14/paper + */ + + +#if (QSE_SIZEOF_UINT32_T > 0) +qse_uint32_t qse_randxs32 (qse_uint32_t seed) +{ + qse_uint32_t x; + + QSE_ASSERT (seed != 0); + + x = seed; + + x ^= (x << 13); + x ^= (x >> 17); + x ^= (x << 5); + + return x; +} +#endif + +#if (QSE_SIZEOF_UINT64_T > 0) +qse_uint64_t qse_randxs64 (qse_uint64_t seed) +{ + qse_uint64_t x; + + QSE_ASSERT (seed != 0); + + x = seed; + + x ^= (x << 21); + x ^= (x >> 35); + x ^= (x << 4); + + return x; +} +#endif