aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2022-08-01 00:38:33 -0700
committerPaul Eggert2022-08-01 01:17:15 -0700
commitafa67ed6f20780ee8e99a5cac1bcc4899d83adea (patch)
treea7c090e32030b05e74e9abf1c57bcf570fe0294c
parent2fd2008e6717189627019e30591bc788f7957917 (diff)
downloademacs-afa67ed6f20780ee8e99a5cac1bcc4899d83adea.tar.gz
emacs-afa67ed6f20780ee8e99a5cac1bcc4899d83adea.zip
Fix year-285428751 bug in hanoi-unix-64
* lisp/play/hanoi.el (hanoi-move-period, hanoi, hanoi-unix) (hanoi-unix-64): Use integers, not floating point, to avoid rounding errors for timestamps greater than 2**53.
-rw-r--r--lisp/play/hanoi.el44
1 files changed, 21 insertions, 23 deletions
diff --git a/lisp/play/hanoi.el b/lisp/play/hanoi.el
index 227dd790af5..58fb82b6ed0 100644
--- a/lisp/play/hanoi.el
+++ b/lisp/play/hanoi.el
@@ -73,7 +73,7 @@
73 "Non-nil means that hanoi poles are oriented horizontally." 73 "Non-nil means that hanoi poles are oriented horizontally."
74 :type 'boolean) 74 :type 'boolean)
75 75
76(defcustom hanoi-move-period 1.0 76(defcustom hanoi-move-period 1
77 "Time, in seconds, for each pole-to-pole move of a ring. 77 "Time, in seconds, for each pole-to-pole move of a ring.
78If nil, move rings as fast as possible while displaying all 78If nil, move rings as fast as possible while displaying all
79intermediate positions." 79intermediate positions."
@@ -112,35 +112,32 @@ intermediate positions."
112 (prefix-numeric-value current-prefix-arg)))) 112 (prefix-numeric-value current-prefix-arg))))
113 (if (< nrings 0) 113 (if (< nrings 0)
114 (error "Negative number of rings")) 114 (error "Negative number of rings"))
115 (hanoi-internal nrings (make-list nrings 0) (float-time))) 115 (hanoi-internal nrings (make-list nrings 0) (time-convert nil 'integer)))
116 116
117;;;###autoload 117;;;###autoload
118(defun hanoi-unix () 118(defun hanoi-unix ()
119 "Towers of Hanoi, UNIX doomsday version. 119 "Towers of Hanoi, 32-bit UNIX doomsday version.
120Displays 32-ring towers that have been progressing at one move per 120Display 32-ring towers that have been progressing at one move per
121second since 1970-01-01 00:00:00 GMT. 121second since 1970-01-01 00:00:00 UTC.
122 122
123Repent before ring 31 moves." 123Repent before ring 31 moves."
124 (interactive) 124 (interactive)
125 (let* ((start (ftruncate (float-time))) 125 (let* ((start (time-convert nil 'integer))
126 (bits (cl-loop repeat 32 126 (bits (nreverse (cl-loop repeat 32
127 for x = (/ start (expt 2.0 31)) then (* x 2.0) 127 for x = start then (ash x -1)
128 collect (truncate (mod x 2.0)))) 128 collect (logand x 1))))
129 (hanoi-move-period 1.0)) 129 (hanoi-move-period 1))
130 (hanoi-internal 32 bits start))) 130 (hanoi-internal 32 bits start)))
131 131
132;;;###autoload 132;;;###autoload
133(defun hanoi-unix-64 () 133(defun hanoi-unix-64 ()
134 "Like `hanoi-unix', but pretend to have a 64-bit clock. 134 "Like `hanoi-unix', but with a 64-bit clock."
135This is, necessarily (as of Emacs 20.3), a crock. When the
136`current-time' interface is made s2G-compliant, hanoi.el will need
137to be updated."
138 (interactive) 135 (interactive)
139 (let* ((start (ftruncate (float-time))) 136 (let* ((start (time-convert nil 'integer))
140 (bits (cl-loop repeat 64 137 (bits (nreverse (cl-loop repeat 64
141 for x = (/ start (expt 2.0 63)) then (* x 2.0) 138 for x = start then (ash x -1)
142 collect (truncate (mod x 2.0)))) 139 collect (logand x 1))))
143 (hanoi-move-period 1.0)) 140 (hanoi-move-period 1))
144 (hanoi-internal 64 bits start))) 141 (hanoi-internal 64 bits start)))
145 142
146(defun hanoi-internal (nrings bits start-time) 143(defun hanoi-internal (nrings bits start-time)
@@ -378,9 +375,10 @@ BITS must be of length nrings. Start at START-TIME."
378 (/ (- tick flyward-ticks fly-ticks) 375 (/ (- tick flyward-ticks fly-ticks)
379 ticks-per-pole-step)))))))) 376 ticks-per-pole-step))))))))
380 (if hanoi-move-period 377 (if hanoi-move-period
381 (cl-loop for elapsed = (- (float-time) start-time) 378 (cl-loop for elapsed = (float-time (time-subtract nil start-time))
382 while (< elapsed hanoi-move-period) 379 while (time-less-p elapsed hanoi-move-period)
383 with tick-period = (/ (float hanoi-move-period) total-ticks) 380 with tick-period = (/ (float-time hanoi-move-period)
381 total-ticks)
384 for tick = (ceiling elapsed tick-period) do 382 for tick = (ceiling elapsed tick-period) do
385 (hanoi-ring-to-pos ring (funcall tick-to-pos tick)) 383 (hanoi-ring-to-pos ring (funcall tick-to-pos tick))
386 (hanoi-sit-for (- (* tick tick-period) elapsed))) 384 (hanoi-sit-for (- (* tick tick-period) elapsed)))
@@ -389,7 +387,7 @@ BITS must be of length nrings. Start at START-TIME."
389 (hanoi-sit-for 0))) 387 (hanoi-sit-for 0)))
390 ;; Always make last move to keep pole and ring data consistent 388 ;; Always make last move to keep pole and ring data consistent
391 (hanoi-ring-to-pos ring (car to)) 389 (hanoi-ring-to-pos ring (car to))
392 (if hanoi-move-period (+ start-time hanoi-move-period)))) 390 (if hanoi-move-period (time-add start-time hanoi-move-period))))
393 391
394;; update display and pause, quitting with a pithy comment if the user 392;; update display and pause, quitting with a pithy comment if the user
395;; hits a key. 393;; hits a key.