zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: better pseudorandom numbers
@ 2001-11-12 18:14 Peter Stephenson
  2001-11-15 11:59 ` Peter Stephenson
  0 siblings, 1 reply; 2+ messages in thread
From: Peter Stephenson @ 2001-11-12 18:14 UTC (permalink / raw)
  To: Zsh hackers list

This allows the mathfunc library access to erand48() where available.  It
makes use of the hitherto unused feature that Sven added, to allow math
functions to take string arguments.

Others may think of a better of doing things.  If there's an RNG expert
around, they probably disagree with everything.

I'm not happy with the way the seed is stored as raw bytes.  It might be
better to keep it as an array of three numbers and convert to and from
string format each time.  With 64-bit zlong's, it will fit in a single
integer parameter, but that's not portable.

Index: zshconfig.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/zshconfig.ac,v
retrieving revision 1.20
diff -u -r1.20 zshconfig.ac
--- zshconfig.ac	2001/10/10 16:02:24	1.20
+++ zshconfig.ac	2001/11/12 18:06:07
@@ -938,7 +938,8 @@
 	       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)
Index: Doc/Zsh/mod_mathfunc.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_mathfunc.yo,v
retrieving revision 1.2
diff -u -r1.2 mod_mathfunc.yo
--- Doc/Zsh/mod_mathfunc.yo	2000/05/11 00:01:03	1.2
+++ Doc/Zsh/mod_mathfunc.yo	2001/11/12 18:06:07
@@ -52,3 +52,34 @@
 
 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 be at least six bytes long, 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 raw string of bytes.  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 6-byte seed.  The third call returns to the same
+sequence of random numbers used in the first call, unaffected by the
+intervening tt(rand48()).
Index: Src/Modules/mathfunc.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/mathfunc.c,v
retrieving revision 1.2
diff -u -r1.2 mathfunc.c
--- Src/Modules/mathfunc.c	2000/05/26 09:47:28	1.2
+++ Src/Modules/mathfunc.c	2001/11/12 18:06:08
@@ -82,6 +82,12 @@
 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 @@
 
 
 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)),
@@ -167,7 +179,7 @@
   NUMMATHFUNC("tanh", math_func, 1, 1, MF_TANH),
   NUMMATHFUNC("y0", math_func, 1, 1, MF_Y0 | BFLAG(BF_POS)),
   NUMMATHFUNC("y1", math_func, 1, 1, MF_Y1 | BFLAG(BF_POS)),
-  NUMMATHFUNC("yn", math_func, 2, 2, MF_YN | BFLAG(BF_POS2) | TFLAG(TF_INT1))
+  NUMMATHFUNC("yn", math_func, 2, 2, MF_YN | BFLAG(BF_POS2) | TFLAG(TF_INT1)),
 };
 
 /**/
@@ -447,6 +459,78 @@
 
   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;
+		int seedstr_len;
+		seedbufptr = tmp_seedbuf;
+		if ((seedstr = getsparam(arg))) {
+		   unmetafy(seedstr, &seedstr_len);
+		   if (seedstr_len >= sizeof(tmp_seedbuf))
+		   {
+		       memcpy(tmp_seedbuf, seedstr,  sizeof(tmp_seedbuf));
+		       do_init = 0;
+		   }
+		} 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)
+		setsparam(arg, metafy((char *)seedbufptr, sizeof(tmp_seedbuf),
+				      META_DUP));
+	}
+	break;
+#endif
+    }
+
+    return ret;
+}
+
 
 /**/
 int

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: PATCH: better pseudorandom numbers
  2001-11-12 18:14 PATCH: better pseudorandom numbers Peter Stephenson
@ 2001-11-15 11:59 ` Peter Stephenson
  0 siblings, 0 replies; 2+ messages in thread
From: Peter Stephenson @ 2001-11-15 11:59 UTC (permalink / raw)
  To: Zsh hackers list

Peter Stephenson wrote:
> I'm not happy with the way the seed is stored as raw bytes.  It might be
> better to keep it as an array of three numbers and convert to and from
> string format each time.  With 64-bit zlong's, it will fit in a single
> integer parameter, but that's not portable.

I like this version better.  It stores the seed as 12 hex digits.  It's a
little extra work, but much more user-friendly for printing and setting.

Index: zshconfig.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/zshconfig.ac,v
retrieving revision 1.20
diff -u -r1.20 zshconfig.ac
--- zshconfig.ac	2001/10/10 16:02:24	1.20
+++ zshconfig.ac	2001/11/15 11:57:10
@@ -938,7 +938,8 @@
 	       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)
Index: Doc/Zsh/mod_mathfunc.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_mathfunc.yo,v
retrieving revision 1.2
diff -u -r1.2 mod_mathfunc.yo
--- Doc/Zsh/mod_mathfunc.yo	2000/05/11 00:01:03	1.2
+++ Doc/Zsh/mod_mathfunc.yo	2001/11/15 11:57:10
@@ -52,3 +52,36 @@
 
 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()).
Index: Src/Modules/mathfunc.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/mathfunc.c,v
retrieving revision 1.2
diff -u -r1.2 mathfunc.c
--- Src/Modules/mathfunc.c	2000/05/26 09:47:28	1.2
+++ Src/Modules/mathfunc.c	2001/11/15 11:57:10
@@ -82,6 +82,12 @@
 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 @@
 
 
 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)),
@@ -447,6 +459,100 @@
 
   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

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2001-11-15 12:00 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-11-12 18:14 PATCH: better pseudorandom numbers Peter Stephenson
2001-11-15 11:59 ` Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).