From: Paul Eggert Date: Sat, 1 Sep 2012 01:04:26 +0000 (-0700) Subject: Better seed support for (random). X-Git-Tag: emacs-24.2.90~457 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=0e23ef9ddeefadcba94824c09e412c961de283e7;p=emacs.git Better seed support for (random). * doc/lispref/numbers.texi (Random Numbers): Document new behavior of the calls (random) and (random STRING). * etc/NEWS: Document new behavior of (random), (random "string"). * lisp/play/5x5.el, lisp/play/animate.el, lisp/play/cookie1.el: * lisp/play/dissociate.el, lisp/play/doctor.el, lisp/play/dunnet.el: * lisp/play/gomoku.el, lisp/play/landmark.el, lisp/play/mpuz.el: * lisp/play/tetris.el, lisp/play/zone.el: * lisp/calc/calc-comb.el (math-init-random-base): * lisp/play/blackbox.el (bb-init-board): * lisp/play/life.el (life): * lisp/server.el (server-use-tcp): * lisp/type-break.el (type-break): Remove unnecessary call to (random t). * lisp/net/sasl.el (sasl-unique-id-function): Change (random t) to (random), now that the latter is more random. * lisp/play/life.el (life-initialized): Remove no-longer-needed var. * lisp/gnus/gnus-sync.el (gnus-sync-lesync-setup): * lisp/gnus/message.el (message-canlock-generate, message-unique-id): Change (random t) to (random), now that the latter is more random. * lisp/org/org-id.el (org-id-uuid): Change (random t) to (random), now that the latter is more random. * src/emacs.c (main): Call init_random. * src/fns.c (Frandom): Set the seed from a string argument, if given. Remove long-obsolete Gentzel cruft. * src/lisp.h, src/sysdep.c (seed_random): Now takes address and size, not long. (init_random): New function. --- diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index c014c0fce45..30169d6b7a9 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,9 @@ +2012-09-01 Paul Eggert + + Better seed support for (random). + * numbers.texi (Random Numbers): Document new behavior of + the calls (random) and (random STRING). + 2012-08-21 Martin Rudalics * windows.texi (Window Point): Document recent changes in diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi index ce0716f39ef..17f3ee099bd 100644 --- a/doc/lispref/numbers.texi +++ b/doc/lispref/numbers.texi @@ -1199,30 +1199,32 @@ numbers are not truly random, but they have certain properties that mimic a random series. For example, all possible values occur equally often in a pseudo-random series. -In Emacs, pseudo-random numbers are generated from a ``seed'' number. +In Emacs, pseudo-random numbers are generated from a ``seed''. Starting from any given seed, the @code{random} function always -generates the same sequence of numbers. Emacs always starts with the -same seed value, so the sequence of values of @code{random} is actually -the same in each Emacs run! For example, in one operating system, the -first call to @code{(random)} after you start Emacs always returns -@minus{}1457731, and the second one always returns @minus{}7692030. This -repeatability is helpful for debugging. - -If you want random numbers that don't always come out the same, execute -@code{(random t)}. This chooses a new seed based on the current time of -day and on Emacs's process @acronym{ID} number. +generates the same sequence of numbers. Emacs typically starts with a +different seed each time, so the sequence of values of @code{random} +typically differs in each Emacs run. + +Sometimes you want the random number sequence to be repeatable. For +example, when debugging a program whose behavior depends on the random +number sequence, it is helpful to get the same behavior in each +program run. To make the sequence repeat, execute @code{(random "")}. +This sets the seed to a constant value for your particular Emacs +executable (though it may differ for other Emacs builds). You can use +other strings to choose various seed values. @defun random &optional limit This function returns a pseudo-random integer. Repeated calls return a series of pseudo-random integers. If @var{limit} is a positive integer, the value is chosen to be -nonnegative and less than @var{limit}. +nonnegative and less than @var{limit}. Otherwise, the value +might be any integer representable in Lisp. If @var{limit} is @code{t}, it means to choose a new seed based on the current time of day and on Emacs's process @acronym{ID} number. -On some machines, any integer representable in Lisp may be the result -of @code{random}. On other machines, the result can never be larger -than a certain maximum or less than a certain (negative) minimum. +If @var{limit} is a string, it means to choose a new seed based on the +string's contents. + @end defun diff --git a/etc/ChangeLog b/etc/ChangeLog index 11aba88c6a1..f3f244c7e39 100644 --- a/etc/ChangeLog +++ b/etc/ChangeLog @@ -1,3 +1,8 @@ +2012-09-01 Paul Eggert + + Better seeds for (random). + * NEWS: Document new behavior of (random), (random "string"). + 2012-08-28 Andreas Schwab * charsets/MULE-ethiopic.map: Fix typo in comment. diff --git a/etc/NEWS b/etc/NEWS index 14521744670..58298a9a437 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -527,6 +527,11 @@ inefficiency, and not namespace-clean. * Incompatible Lisp Changes in Emacs 24.3 +** (random) by default now returns a different random sequence in +every Emacs run. Use (random S), where S is a string, to set the +random seed to a value based on S, in order to get a repeatable +sequence in later calls. + ** The function `x-select-font' can return a font spec, instead of a font name as a string. Whether it returns a font spec or a font name depends on the graphical library. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index ce4493d4c76..68bb8e06e87 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,19 @@ +2012-09-01 Paul Eggert + + Better seed support for (random). + * play/5x5.el, play/animate.el, play/cookie1.el, play/dissociate.el: + * play/doctor.el, play/dunnet.el, play/gomoku.el, play/landmark.el: + * play/mpuz.el, play/tetris.el, play/zone.el: + * calc/calc-comb.el (math-init-random-base): + * play/blackbox.el (bb-init-board): + * play/life.el (life): + * server.el (server-use-tcp): + * type-break.el (type-break): + Remove unnecessary call to (random t). + * net/sasl.el (sasl-unique-id-function): + Change (random t) to (random), now that the latter is more random. + * play/life.el (life-initialized): Remove no-longer-needed var. + 2012-08-31 Alp Aker * window.el (switch-to-prev-buffer, switch-to-next-buffer): diff --git a/lisp/allout-widgets.el b/lisp/allout-widgets.el index 962a8fb557a..c5790603d11 100644 --- a/lisp/allout-widgets.el +++ b/lisp/allout-widgets.el @@ -1374,7 +1374,6 @@ FROM and TO must be in increasing order, as must be the pairs in RANGES." ;; (time-trial ;; '(let ((size 10000) ;; doing) -;; (random t) ;; (dotimes (count size) ;; (setq doing (random size)) ;; (funcall try doing (+ doing (random 5))) diff --git a/lisp/calc/calc-comb.el b/lisp/calc/calc-comb.el index 199bbf0ae35..431ea18f580 100644 --- a/lisp/calc/calc-comb.el +++ b/lisp/calc/calc-comb.el @@ -77,7 +77,7 @@ 4877 4889 4903 4909 4919 4931 4933 4937 4943 4951 4957 4967 4969 4973 4987 4993 4999 5003]) -;; The variable math-prime-factors-finished is set by calcFunc-prfac to +;; The variable math-prime-factors-finished is set by calcFunc-prfac to ;; indicate whether factoring is complete, and used by calcFunc-factors, ;; calcFunc-totient and calcFunc-moebius. (defvar math-prime-factors-finished) @@ -510,8 +510,8 @@ (while (<= (length math-stirling-local-cache) n) (let ((i (1- (length math-stirling-local-cache))) row) - (setq math-stirling-local-cache - (vconcat math-stirling-local-cache + (setq math-stirling-local-cache + (vconcat math-stirling-local-cache (make-vector (length math-stirling-local-cache) nil))) (aset math-stirling-cache k math-stirling-local-cache) (while (< (setq i (1+ i)) (length math-stirling-local-cache)) @@ -572,7 +572,6 @@ (let ((i 200)) (while (> (setq i (1- i)) 0) (math-random-base)))) - (random t) (setq var-RandSeed nil math-random-cache nil math-random-shift -4) ; assume RAND_MAX >= 16383 @@ -629,7 +628,7 @@ (i (/ (+ n slop) 3)) (rnum 0)) (while (> i 0) - (setq rnum + (setq rnum (math-add (math-random-three-digit-number) (math-mul rnum 1000))) @@ -823,11 +822,11 @@ (setq sum (% (+ sum - (calcFunc-mod + (calcFunc-mod q 1000000)) 111111)) - (setq q - (math-quotient + (setq q + (math-quotient q 1000000))) (cond ((= (% sum 3) 0) '(nil 3)) ((= (% sum 7) 0) '(nil 7)) diff --git a/lisp/gnus/ChangeLog b/lisp/gnus/ChangeLog index b3aeb96e9fe..a4e3d9bde2b 100644 --- a/lisp/gnus/ChangeLog +++ b/lisp/gnus/ChangeLog @@ -1,3 +1,10 @@ +2012-09-01 Paul Eggert + + Better seeds for (random). + * gnus-sync.el (gnus-sync-lesync-setup): + * message.el (message-canlock-generate, message-unique-id): + Change (random t) to (random), now that the latter is more random. + 2012-08-31 Dave Abrahams * auth-source.el (auth-sources): Fix macos keychain access. diff --git a/lisp/gnus/gnus-sync.el b/lisp/gnus/gnus-sync.el index 15d94810c3a..ca8662ff936 100644 --- a/lisp/gnus/gnus-sync.el +++ b/lisp/gnus/gnus-sync.el @@ -225,7 +225,7 @@ When SALT is nil, a random one will be generated using `random'." (security-object (concat url "/_security")) (user-record `((names . [,user]) (roles . []))) (couch-user-name (format "org.couchdb.user:%s" user)) - (salt (or salt (sha1 (format "%s" (random t))))) + (salt (or salt (sha1 (format "%s" (random))))) (couch-user-record `((_id . ,couch-user-name) (type . user) diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el index 8fd89b1742c..18088423eb0 100644 --- a/lisp/gnus/message.el +++ b/lisp/gnus/message.el @@ -4820,9 +4820,7 @@ Do not use this for anything important, it is cryptographically weak." (require 'sha1) (let (sha1-maximum-internal-length) (sha1 (concat (message-unique-id) - (format "%x%x%x" (random) - (progn (random t) (random)) - (random)) + (format "%x%x%x" (random) (random) (random)) (prin1-to-string (recent-keys)) (prin1-to-string (garbage-collect)))))) @@ -5525,7 +5523,6 @@ In posting styles use `(\"Expires\" (make-expires-date 30))'." ;; You might for example insert a "." somewhere (not next to another dot ;; or string boundary), or modify the "fsf" string. (defun message-unique-id () - (random t) ;; Don't use microseconds from (current-time), they may be unsupported. ;; Instead we use this randomly inited counter. (setq message-unique-id-char diff --git a/lisp/net/sasl.el b/lisp/net/sasl.el index c6e95970f3d..4e759a4e6b2 100644 --- a/lisp/net/sasl.el +++ b/lisp/net/sasl.el @@ -183,7 +183,7 @@ It contain at least 64 bits of entropy." ;; Don't use microseconds from (current-time), they may be unsupported. ;; Instead we use this randomly inited counter. (setq sasl-unique-id-char - (% (1+ (or sasl-unique-id-char (logand (random t) (1- (lsh 1 20))))) + (% (1+ (or sasl-unique-id-char (logand (random) (1- (lsh 1 20))))) ;; (current-time) returns 16-bit ints, ;; and 2^16*25 just fits into 4 digits i base 36. (* 25 25))) diff --git a/lisp/org/ChangeLog b/lisp/org/ChangeLog index cf9c32006ac..152af5f43ed 100644 --- a/lisp/org/ChangeLog +++ b/lisp/org/ChangeLog @@ -1,3 +1,9 @@ +2012-09-01 Paul Eggert + + Better seed support for (random). + * org-id.el (org-id-uuid): + Change (random t) to (random), now that the latter is more random. + 2012-07-29 Paul Eggert Don't use the abbreviation "win" to refer to Windows (Bug#10421). diff --git a/lisp/org/org-id.el b/lisp/org/org-id.el index 55e826f3ae6..a93f804946f 100644 --- a/lisp/org/org-id.el +++ b/lisp/org/org-id.el @@ -318,7 +318,7 @@ So a typical ID could look like \"Org:4nd91V40HI\"." (defun org-id-uuid () "Return string with random (version 4) UUID." (let ((rnd (md5 (format "%s%s%s%s%s%s%s" - (random t) + (random) (current-time) (user-uid) (emacs-pid) diff --git a/lisp/play/5x5.el b/lisp/play/5x5.el index e6df0df8282..abc78cd495c 100644 --- a/lisp/play/5x5.el +++ b/lisp/play/5x5.el @@ -953,8 +953,6 @@ lest." (y-or-n-p prompt) t)) -(random t) - (provide '5x5) ;;; 5x5.el ends here diff --git a/lisp/play/animate.el b/lisp/play/animate.el index 9919600202f..2398a7b89c7 100644 --- a/lisp/play/animate.el +++ b/lisp/play/animate.el @@ -201,8 +201,6 @@ the buffer *Birthday-Present-for-Name*." (animate-string "my sunshine" 18 34) (animate-string "to stay!" 19 34)) -(random t) - (provide 'animate) ;;; animate.el ends here diff --git a/lisp/play/blackbox.el b/lisp/play/blackbox.el index eb2d784c8e5..db2e18188e5 100644 --- a/lisp/play/blackbox.el +++ b/lisp/play/blackbox.el @@ -93,7 +93,7 @@ (define-key map (vector 'remap oldfun) newfun)) -(defvar blackbox-mode-map +(defvar blackbox-mode-map (let ((map (make-keymap))) (suppress-keymap map t) (blackbox-redefine-key map 'backward-char 'bb-left) @@ -257,7 +257,6 @@ a reflection." (bb-goto (cons bb-x bb-y))) (defun bb-init-board (num-balls) - (random t) (let (board pos) (while (>= (setq num-balls (1- num-balls)) 0) (while diff --git a/lisp/play/cookie1.el b/lisp/play/cookie1.el index cbf29a26a71..dbd6e893473 100644 --- a/lisp/play/cookie1.el +++ b/lisp/play/cookie1.el @@ -53,9 +53,6 @@ ;;; Code: -; Randomize the seed in the random number generator. -(random t) - (defconst cookie-delimiter "\n%%\n\\|\n%\n\\|\0" "Delimiter used to separate cookie file entries.") diff --git a/lisp/play/dissociate.el b/lisp/play/dissociate.el index 8f9f8cea24f..238b2a86c17 100644 --- a/lisp/play/dissociate.el +++ b/lisp/play/dissociate.el @@ -94,8 +94,6 @@ Default is 2." (funcall search-function overlap opoint t)))))) (sit-for 0)))) -(random t) - (provide 'dissociate) ;;; dissociate.el ends here diff --git a/lisp/play/doctor.el b/lisp/play/doctor.el index fdae2ec9326..57dbb1452f3 100644 --- a/lisp/play/doctor.el +++ b/lisp/play/doctor.el @@ -1620,8 +1620,6 @@ Hack on previous word, setting global variable DOCTOR-OWNER to correct result." (defun doctor-chat () (doctor-type (doc$ doctor--chatlst))) -(random t) - (provide 'doctor) ;;; doctor.el ends here diff --git a/lisp/play/dunnet.el b/lisp/play/dunnet.el index 22a2642f751..2d62b800ef4 100644 --- a/lisp/play/dunnet.el +++ b/lisp/play/dunnet.el @@ -3010,7 +3010,6 @@ drwxr-xr-x 3 root staff 2048 Jan 1 1970 ..") (dun-uexit nil))) -(random t) (setq tloc (+ 60 (random 18))) (dun-replace dun-room-objects tloc (append (nth tloc dun-room-objects) (list 18))) diff --git a/lisp/play/gomoku.el b/lisp/play/gomoku.el index 6d73e2ccb65..3dba99d98d5 100644 --- a/lisp/play/gomoku.el +++ b/lisp/play/gomoku.el @@ -1197,8 +1197,6 @@ If the game is finished, this command requests for another game." (move-to-column (+ gomoku-x-offset (* gomoku-square-width (1- gomoku-board-width))))) -(random t) - (provide 'gomoku) ;;; gomoku.el ends here diff --git a/lisp/play/landmark.el b/lisp/play/landmark.el index e9f555093db..e103249da49 100644 --- a/lisp/play/landmark.el +++ b/lisp/play/landmark.el @@ -1683,8 +1683,6 @@ Use \\[describe-mode] for more info." ;;;allout-layout: (0 : -1 -1 0) ;;;End: -(random t) - (provide 'landmark) ;;; landmark.el ends here diff --git a/lisp/play/life.el b/lisp/play/life.el index e9133f84862..87ec0226af5 100644 --- a/lisp/play/life.el +++ b/lisp/play/life.el @@ -111,9 +111,6 @@ ;; Sadly, mode-line-format won't display numbers. (defvar life-generation-string nil) -(defvar life-initialized nil - "Non-nil if `life' has been run at least once.") - ;;;###autoload (defun life (&optional sleeptime) "Run Conway's Life simulation. @@ -121,9 +118,6 @@ The starting pattern is randomly selected. Prefix arg (optional first arg non-nil from a program) is the number of seconds to sleep between generations (this defaults to 1)." (interactive "p") - (or life-initialized - (random t)) - (setq life-initialized t) (or sleeptime (setq sleeptime 1)) (life-setup) (catch 'life-exit diff --git a/lisp/play/mpuz.el b/lisp/play/mpuz.el index c0c8803f896..e16bb2f1bde 100644 --- a/lisp/play/mpuz.el +++ b/lisp/play/mpuz.el @@ -35,8 +35,6 @@ :prefix "mpuz-" :group 'games) -(random t) ; randomize - (defcustom mpuz-silent 'error "Set this to nil if you want dings on inputs. The value t means never ding, and `error' means only ding on wrong input." diff --git a/lisp/play/tetris.el b/lisp/play/tetris.el index b811a21605b..9cc33304589 100644 --- a/lisp/play/tetris.el +++ b/lisp/play/tetris.el @@ -635,8 +635,6 @@ tetris-mode keybindings: (tetris-mode) (tetris-start-game)) -(random t) - (provide 'tetris) ;;; tetris.el ends here diff --git a/lisp/play/zone.el b/lisp/play/zone.el index 34e21193437..1cfc6c59987 100644 --- a/lisp/play/zone.el +++ b/lisp/play/zone.el @@ -675,8 +675,6 @@ If nil, `zone-pgm-random-life' chooses a value from 0-3 (inclusive).") (kill-buffer nil)))) -(random t) - ;;;;;;;;;;;;;;; (provide 'zone) diff --git a/lisp/server.el b/lisp/server.el index 6d34df351ca..4fd55bcf6d1 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -94,7 +94,6 @@ (setq val t) (unless load-in-progress (message "Local sockets unsupported, using TCP sockets"))) - (when val (random t)) (set-default sym val)) :group 'server :type 'boolean diff --git a/lisp/type-break.el b/lisp/type-break.el index f0c81125f0c..8a95508d939 100644 --- a/lisp/type-break.el +++ b/lisp/type-break.el @@ -577,7 +577,6 @@ as per the function `type-break-schedule'." (unless type-break-terse-messages (message "Press any key to resume from typing break.")) - (random t) (let* ((len (length type-break-demo-functions)) (idx (random len)) (fn (nth idx type-break-demo-functions))) diff --git a/src/ChangeLog b/src/ChangeLog index 4db48bbb969..ad96c948466 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2012-09-01 Paul Eggert + + Better seed support for (random). + * emacs.c (main): Call init_random. + * fns.c (Frandom): Set the seed from a string argument, if given. + Remove long-obsolete Gentzel cruft. + * lisp.h, sysdep.c (seed_random): Now takes address and size, not long. + (init_random): New function. + 2012-08-31 Dmitry Antipov Remove mark_ttys function and fix tty_display_info initialization. diff --git a/src/emacs.c b/src/emacs.c index 7ff5c43dbea..842546461b6 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1281,6 +1281,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem init_data (); init_atimer (); running_asynch_code = 0; + init_random (); no_loadup = argmatch (argv, argc, "-nl", "--no-loadup", 6, NULL, &skip_args); diff --git a/src/fns.c b/src/fns.c index f6acdcada3f..2dee8515799 100644 --- a/src/fns.c +++ b/src/fns.c @@ -74,32 +74,16 @@ Other values of LIMIT are ignored. */) (Lisp_Object limit) { EMACS_INT val; - Lisp_Object lispy_val; if (EQ (limit, Qt)) - { - EMACS_TIME t = current_emacs_time (); - seed_random (getpid () ^ EMACS_SECS (t) ^ EMACS_NSECS (t)); - } + init_random (); + else if (STRINGP (limit)) + seed_random (SSDATA (limit), SBYTES (limit)); + val = get_random (); if (NATNUMP (limit) && XFASTINT (limit) != 0) - { - /* Try to take our random number from the higher bits of VAL, - not the lower, since (says Gentzel) the low bits of `random' - are less random than the higher ones. We do this by using the - quotient rather than the remainder. At the high end of the RNG - it's possible to get a quotient larger than n; discarding - these values eliminates the bias that would otherwise appear - when using a large n. */ - EMACS_INT denominator = (INTMASK + 1) / XFASTINT (limit); - do - val = get_random () / denominator; - while (val >= XFASTINT (limit)); - } - else - val = get_random (); - XSETINT (lispy_val, val); - return lispy_val; + val %= XFASTINT (limit); + return make_number (val); } /* Heuristic on how many iterations of a tight loop can be safely done diff --git a/src/lisp.h b/src/lisp.h index 80c49703f52..2815a2ae325 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3405,7 +3405,8 @@ extern void child_setup_tty (int); extern void setup_pty (int); extern int set_window_size (int, int, int); extern EMACS_INT get_random (void); -extern void seed_random (long); +extern void seed_random (void *, ptrdiff_t); +extern void init_random (void); extern int emacs_open (const char *, int, int); extern int emacs_close (int); extern ptrdiff_t emacs_read (int, char *, ptrdiff_t); diff --git a/src/sysdep.c b/src/sysdep.c index 183ee005227..edd54de84d4 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -1765,19 +1765,37 @@ init_signals (void) #endif /* !RAND_BITS */ void -seed_random (long int arg) +seed_random (void *seed, ptrdiff_t seed_size) { +#if defined HAVE_RANDOM || ! defined HAV_LRAND48 + unsigned int arg = 0; +#else + long int arg = 0; +#endif + unsigned char *argp = (unsigned char *) &arg; + unsigned char *seedp = seed; + ptrdiff_t i; + for (i = 0; i < seed_size; i++) + argp[i % sizeof arg] ^= seedp[i]; #ifdef HAVE_RANDOM - srandom ((unsigned int)arg); + srandom (arg); #else # ifdef HAVE_LRAND48 srand48 (arg); # else - srand ((unsigned int)arg); + srand (arg); # endif #endif } +void +init_random (void) +{ + EMACS_TIME t = current_emacs_time (); + uintmax_t v = getpid () ^ EMACS_SECS (t) ^ EMACS_NSECS (t); + seed_random (&v, sizeof v); +} + /* * Return a nonnegative random integer out of whatever we've got. * It contains enough bits to make a random (signed) Emacs fixnum.