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.
This commit is contained in:
hyung-hwan 2012-08-27 15:10:57 +00:00
parent 53c98cce93
commit a35c10fbfc
4 changed files with 114 additions and 36 deletions

View File

@ -26,6 +26,7 @@
#include <qse/cmn/sio.h> #include <qse/cmn/sio.h>
#include <qse/cmn/nwio.h> #include <qse/cmn/nwio.h>
#include <qse/cmn/path.h> #include <qse/cmn/path.h>
#include <qse/cmn/alg.h>
#include <qse/cmn/stdio.h> #include <qse/cmn/stdio.h>
#include "awk.h" #include "awk.h"
@ -139,7 +140,7 @@ int StdAwk::open ()
if (addFunction (QSE_T("rand"), 0, 0, (FunctionHandler)&StdAwk::rand, 0) <= -1 || 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("srand"), 0, 1, (FunctionHandler)&StdAwk::srand, 0) <= -1 ||
addFunction (QSE_T("system"), 1, 1, (FunctionHandler)&StdAwk::system, 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("setioattr"), 3, 3, (FunctionHandler)&StdAwk::setioattr, QSE_AWK_RIO) <= -1 ||
addFunction (QSE_T("getioattr"), 2, 2, (FunctionHandler)&StdAwk::getioattr, 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; qse_ntime_t now;
this->seed = (qse_gettime(&now) <= -1)? 0u: (unsigned int)now; this->seed = (qse_gettime(&now) <= -1)? 0u: (long_t)now;
this->seed += (qse_uintptr_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; this->cmgrtab_inited = false;
return 0; 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, int StdAwk::rand (Run& run, Value& ret, const Value* args, size_t nargs,
const char_t* name, size_t len) 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, int StdAwk::srand (Run& run, Value& ret, const Value* args, size_t nargs,
const char_t* name, size_t len) 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) if (nargs <= 0)
{ {
qse_ntime_t now;
this->seed = (qse_gettime (&now) <= -1)? this->seed = (qse_gettime (&now) <= -1)?
(this->seed >> 1): (unsigned int)now; (this->seed * this->seed): (long_t)now;
this->seed += (qse_uintptr_t)&now;
} }
else 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); return ret.setInt ((long_t)prevSeed);
} }

View File

@ -29,6 +29,7 @@
#include <qse/cmn/path.h> #include <qse/cmn/path.h>
#include <qse/cmn/htb.h> #include <qse/cmn/htb.h>
#include <qse/cmn/env.h> #include <qse/cmn/env.h>
#include <qse/cmn/alg.h>
#include <qse/cmn/stdio.h> /* TODO: remove dependency on qse_vsprintf */ #include <qse/cmn/stdio.h> /* TODO: remove dependency on qse_vsprintf */
#include "../cmn/mem.h" #include "../cmn/mem.h"
@ -112,7 +113,8 @@ typedef struct xtn_t
typedef struct rxtn_t typedef struct rxtn_t
{ {
unsigned int seed; qse_long_t seed;
qse_ulong_t prand; /* last random value returned */
struct struct
{ {
@ -1921,9 +1923,12 @@ qse_awk_rtx_t* qse_awk_rtx_openstd (
qse_awk_rtx_pushrcb (rtx, &rcb); qse_awk_rtx_pushrcb (rtx, &rcb);
rxtn->seed = (qse_gettime (&now) <= -1)? 0u: (unsigned int)now; rxtn->seed = (qse_gettime (&now) <= -1)? 0u: (qse_long_t)now;
rxtn->seed += (qse_uintptr_t)&now; /* i don't care if the seed becomes negative or overflows.
srand (rxtn->seed); * 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.files = icf;
rxtn->c.in.index = 0; 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) 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_t* rxtn;
rxtn = (rxtn_t*) QSE_XTN (rtx); rxtn = (rxtn_t*) QSE_XTN (rtx);
r = qse_awk_rtx_makefltval (
rtx, (qse_flt_t)(rand_r(rxtn->seed) % RAND_MAX) / RAND_MAX ); rxtn->prand = qse_randxsulong (rxtn->prand);
*/ randv = rxtn->prand % RANDV_MAX;
r = qse_awk_rtx_makefltval (
rtx, (qse_flt_t)(rand() % RAND_MAX) / RAND_MAX); r = qse_awk_rtx_makefltval (rtx, (qse_flt_t)randv / RANDV_MAX);
if (r == QSE_NULL) return -1; if (r == QSE_NULL) return -1;
qse_awk_rtx_setretval (rtx, r); 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_long_t lv;
qse_awk_val_t* r; qse_awk_val_t* r;
int n; int n;
unsigned int prev; qse_long_t prev;
qse_ntime_t now;
rxtn_t* rxtn; rxtn_t* rxtn;
rxtn = (rxtn_t*) QSE_XTN (rtx); 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) if (nargs <= 0)
{ {
qse_ntime_t now;
rxtn->seed = (qse_gettime (&now) <= -1)? rxtn->seed = (qse_gettime (&now) <= -1)?
(rxtn->seed >> 1): (unsigned int)now; (rxtn->seed * rxtn->seed): (qse_long_t)now;
rxtn->seed += (qse_uintptr_t)&now;
} }
else else
{ {
@ -2018,8 +2032,11 @@ static int fnc_srand (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm)
if (n <= -1) return -1; if (n <= -1) return -1;
rxtn->seed = lv; rxtn->seed = lv;
} }
/* i don't care if the seed becomes negative or overflows.
srand (rxtn->seed); * 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); r = qse_awk_rtx_makeintval (rtx, prev);
if (r == QSE_NULL) return -1; if (r == QSE_NULL) return -1;

View File

@ -844,16 +844,19 @@ static int val_int_to_str (
qse_awk_rtx_valtostr_out_t* out) qse_awk_rtx_valtostr_out_t* out)
{ {
qse_char_t* tmp; qse_char_t* tmp;
qse_long_t t; qse_ulong_t t;
qse_size_t rlen = 0; qse_size_t rlen = 0;
int type = out->type & ~QSE_AWK_RTX_VALTOSTR_PRINT; int type = out->type & ~QSE_AWK_RTX_VALTOSTR_PRINT;
t = v->val; if (v->val == 0) rlen++;
if (t == 0) rlen++;
else else
{ {
/* non-zero values */ /* 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; } while (t > 0) { rlen++; t /= 10; }
} }
@ -939,11 +942,10 @@ static int val_int_to_str (
} }
} }
t = v->val; if (v->val == 0) tmp[0] = QSE_T('0');
if (t == 0) tmp[0] = QSE_T('0');
else else
{ {
if (t < 0) t = -t; t = (v->val < 0)? (v->val * -1): v->val;
/* fill in the buffer with digits */ /* fill in the buffer with digits */
while (t > 0) while (t > 0)

View File

@ -41,3 +41,43 @@ qse_uint32_t qse_rand31 (qse_uint32_t seed)
return lo; 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