16241: new rand48(param) math function

This commit is contained in:
Peter Stephenson 2001-11-15 12:10:22 +00:00
parent 096e24858f
commit b0c56c0561
4 changed files with 147 additions and 1 deletions

View file

@ -1,3 +1,9 @@
2001-11-15 Peter Stephenson <pws@csr.com>
* 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 <bor@zsh.org>
* 16247: Completion/Mandrake/Command/_urpmi: completion

View file

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

View file

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

View file

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