aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fns.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/src/fns.c b/src/fns.c
index 7914bd47790..b193ad648a9 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -54,10 +54,55 @@ DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
54 return argument; 54 return argument;
55} 55}
56 56
57static Lisp_Object
58ccall2 (Lisp_Object (f) (ptrdiff_t nargs, Lisp_Object *args),
59 Lisp_Object arg1, Lisp_Object arg2)
60{
61 Lisp_Object args[2] = {arg1, arg2};
62 return f (2, args);
63}
64
65static Lisp_Object
66get_random_bignum (Lisp_Object limit)
67{
68 /* This is a naive transcription into bignums of the fixnum algorithm.
69 I'd be quite surprised if that's anywhere near the best algorithm
70 for it. */
71 while (true)
72 {
73 Lisp_Object val = make_fixnum (0);
74 Lisp_Object lim = limit;
75 int bits = 0;
76 int bitsperiteration = FIXNUM_BITS - 1;
77 do
78 {
79 /* Shift by one so it is a valid positive fixnum. */
80 EMACS_INT rand = get_random () >> 1;
81 Lisp_Object lrand = make_fixnum (rand);
82 bits += bitsperiteration;
83 val = ccall2 (Flogior,
84 Fash (val, make_fixnum (bitsperiteration)),
85 lrand);
86 lim = Fash (lim, make_fixnum (- bitsperiteration));
87 }
88 while (!EQ (lim, make_fixnum (0)));
89 /* Return the remainder, except reject the rare case where
90 get_random returns a number so close to INTMASK that the
91 remainder isn't random. */
92 Lisp_Object remainder = Frem (val, limit);
93 if (!NILP (ccall2 (Fleq,
94 ccall2 (Fminus, val, remainder),
95 ccall2 (Fminus,
96 Fash (make_fixnum (1), make_fixnum (bits)),
97 limit))))
98 return remainder;
99 }
100}
101
57DEFUN ("random", Frandom, Srandom, 0, 1, 0, 102DEFUN ("random", Frandom, Srandom, 0, 1, 0,
58 doc: /* Return a pseudo-random integer. 103 doc: /* Return a pseudo-random integer.
59By default, return a fixnum; all fixnums are equally likely. 104By default, return a fixnum; all fixnums are equally likely.
60With positive fixnum LIMIT, return random integer in interval [0,LIMIT). 105With positive integer LIMIT, return random integer in interval [0,LIMIT).
61With argument t, set the random number seed from the system's entropy 106With argument t, set the random number seed from the system's entropy
62pool if available, otherwise from less-random volatile data such as the time. 107pool if available, otherwise from less-random volatile data such as the time.
63With a string argument, set the seed based on the string's contents. 108With a string argument, set the seed based on the string's contents.
@@ -71,6 +116,12 @@ See Info node `(elisp)Random Numbers' for more details. */)
71 init_random (); 116 init_random ();
72 else if (STRINGP (limit)) 117 else if (STRINGP (limit))
73 seed_random (SSDATA (limit), SBYTES (limit)); 118 seed_random (SSDATA (limit), SBYTES (limit));
119 if (BIGNUMP (limit))
120 {
121 if (0 > mpz_sgn (*xbignum_val (limit)))
122 xsignal2 (Qwrong_type_argument, Qnatnump, limit);
123 return get_random_bignum (limit);
124 }
74 125
75 val = get_random (); 126 val = get_random ();
76 if (FIXNUMP (limit) && 0 < XFIXNUM (limit)) 127 if (FIXNUMP (limit) && 0 < XFIXNUM (limit))