From b0c56c0561011bdbfd525cda2ce380c1e8ee597e Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 15 Nov 2001 12:10:22 +0000 Subject: 16241: new rand48(param) math function --- ChangeLog | 6 +++ Doc/Zsh/mod_mathfunc.yo | 33 +++++++++++++++ Src/Modules/mathfunc.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++ zshconfig.ac | 3 +- 4 files changed, 147 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ea16180e4..141739d1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2001-11-15 Peter Stephenson + + * 16241: zshconfig.ac, Src/Modules/mathfunc.c, + Doc/Zsh/mod_mathfunc.yo: new rand48(param) math function calls + erand48(3), storing seed as hex string in $param. + 2001-11-14 Andrej Borsenkow * 16247: Completion/Mandrake/Command/_urpmi: completion diff --git a/Doc/Zsh/mod_mathfunc.yo b/Doc/Zsh/mod_mathfunc.yo index 05ce9fe45..637c22d8f 100644 --- a/Doc/Zsh/mod_mathfunc.yo +++ b/Doc/Zsh/mod_mathfunc.yo @@ -52,3 +52,36 @@ a floating point or integer value (by truncation) respectively. Note that the C tt(pow) function is available in ordinary math evaluation as the `tt(**)' operator and is not provided here. + +The function tt(rand48) is available if your system's mathematical library +has the function tt(erand48(3)). It returns a pseudo-random floating point +number between 0 and 1. It takes a single string optional argument. + +If the argument is not present, the random number seed is initialised by +three calls to the tt(rand(3)) function --- this produces the same random +numbers as the next three values of tt($RANDOM). + +If the argument is present, it gives the name of a scalar parameter where +the current random number seed will be stored. On the first call, the +value must contain at least twelve hexadecimal digits (the remainder of the +string is ignored), or the seed will be initialised in the same manner as +for a call to tt(rand48) with no argument. Subsequent calls to +tt(rand48)LPAR()var(param)RPAR() will then maintain the seed in the +parameter var(param) as a string of twelve hexadecimal digits, with no base +signifier. The random number sequences for different parameters are +completely independent, and are also independent from that used by calls to +tt(rand48) with no argument. + +For example, consider + +example(print $(( rand48(seed) )) +print $(( rand48() )) +print $(( rand48(seed) ))) + +Assuming tt($seed) does not exist, it will be initialised by the first +call. In the second call, the default seed is initialised; note, however, +that because of the properties of tt(rand()) there is a correlation between +the seeds used for the two initialisations, so for more secure uses, you +should generate your own 12-byte seed. The third call returns to the same +sequence of random numbers used in the first call, unaffected by the +intervening tt(rand48()). diff --git a/Src/Modules/mathfunc.c b/Src/Modules/mathfunc.c index 5ba7b557a..af4366420 100644 --- a/Src/Modules/mathfunc.c +++ b/Src/Modules/mathfunc.c @@ -82,6 +82,12 @@ MF_Y1, MF_YN }; +/* also functions taking a string argument */ + +enum { +MS_RAND48 +}; + /* * also to do, but differently argument or returned: abs (no type * conversion), atan2. @@ -119,6 +125,12 @@ enum { static struct mathfunc mftab[] = { + /* Functions taking string arguments */ +#ifdef HAVE_ERAND48 + /* here to avoid comma hassle */ + STRMATHFUNC("rand48", math_string, MS_RAND48), +#endif + NUMMATHFUNC("abs", math_func, 1, 1, MF_ABS | BFLAG(BF_FRAC) | TFLAG(TF_NOCONV|TF_NOASS)), NUMMATHFUNC("acos", math_func, 1, 1, MF_ACOS | BFLAG(BF_FRAC)), @@ -448,6 +460,100 @@ math_func(char *name, int argc, mnumber *argv, int id) return ret; } +/**/ +static mnumber +math_string(char *name, char *arg, int id) +{ + mnumber ret = zero_mnumber; + char *send; + /* + * Post-process the string argument, which is just passed verbatim. + * Not clear if any other functions that use math_string() will + * want this, but assume so for now. + */ + while (iblank(*arg)) + arg++; + send = arg + strlen(arg); + while (send > arg && iblank(send[-1])) + send--; + *send = '\0'; + + switch (id) + { +#ifdef HAVE_ERAND48 + case MS_RAND48: + { + static unsigned short seedbuf[3]; + static int seedbuf_init; + unsigned short tmp_seedbuf[3], *seedbufptr; + int do_init = 1; + + if (*arg) { + /* Seed is contained in parameter named by arg */ + char *seedstr; + seedbufptr = tmp_seedbuf; + if ((seedstr = getsparam(arg)) && strlen(seedstr) >= 12) { + int i, j; + do_init = 0; + /* + * Decode three sets of four hex digits corresponding + * to each unsigned short. + */ + for (i = 0; i < 3 && !do_init; i++) { + unsigned short *seedptr = seedbuf + i; + *seedptr = 0; + for (j = 0; j < 4; j++) { + if (*seedstr >= '0' && *seedstr <= '9') + *seedptr += *seedstr - '0'; + else if (tolower(*seedstr) >= 'a' && + tolower(*seedstr) <= 'f') + *seedptr += tolower(*seedstr) - 'a' + 10; + else { + do_init = 1; + break; + } + seedstr++; + if (j < 3) + *seedptr *= 16; + } + } + } + else if (errflag) + break; + } + else + { + /* Use default seed: must be initialised. */ + seedbufptr = seedbuf; + if (!seedbuf_init) + seedbuf_init = 1; + else + do_init = 1; + } + if (do_init) { + seedbufptr[0] = (unsigned short)rand(); + seedbufptr[1] = (unsigned short)rand(); + seedbufptr[2] = (unsigned short)rand(); + } + ret.type = MN_FLOAT; + ret.u.d = erand48(seedbufptr); + + if (*arg) + { + char outbuf[13]; + sprintf(outbuf, "%04x%04x%04x", (int)seedbufptr[0], + (int)seedbufptr[1], (int)seedbufptr[2]); + setsparam(arg, ztrdup(outbuf)); + } + } + break; +#endif + } + + return ret; +} + + /**/ int setup_(Module m) diff --git a/zshconfig.ac b/zshconfig.ac index c573359d9..4e1a0d882 100644 --- a/zshconfig.ac +++ b/zshconfig.ac @@ -938,7 +938,8 @@ AC_CHECK_FUNCS(strftime difftime gettimeofday \ brk sbrk \ pathconf sysconf \ tgetent tigetflag tigetnum tigetstr setupterm \ - pcre_compile pcre_study pcre_exec) + pcre_compile pcre_study pcre_exec \ + erand48) AC_FUNC_STRCOLL dnl Check if tgetent accepts NULL (and will allocate its own termcap buffer) -- cgit 1.4.1