Making the following changes reduced the run time from 13.5 seconds to
about 3 seconds. I'm running under FreeBSD with a 1.1 Ghz Athlon.
(I also rearranged the code a little for test purposes and to avoid
magic-numbers scattered around the code but that shouldn't present any
problems....)
----------------------------------------
(declaim (optimize (speed 3) (safety 1) (space 0)))
(declaim (fixnum *sides* *num*))
(defconstant *sides* 10)
(defconstant *num* 6)
(declaim (type (simple-array (unsigned-byte 32) (#.*sides*)) r))
(defvar r (make-array *sides* :element-type '(unsigned-byte 32)))
(defun check (dice num succ fail botch)
(declare (type (simple-array (unsigned-byte 32) (#.*num*)) dice)
(type (simple-array (unsigned-byte 32) (#.*sides*)) succ fail botch))
;; reset counters
(dotimes (i *sides*)
(setf (aref r i) 0))
;; scan dices
(let ((ones 0))
(dotimes (i num)
(if (= (aref dice i) 0)
(incf ones)
(progn
(loop for j from (aref dice i) downto 1
do (incf (aref r j))))))
;; record results
(dotimes (i *sides*)
(cond
((> (aref r i) ones) (incf (aref succ i)))
((and (> ones 0) (= (aref r i) 0)) (incf (aref botch i)))
(t (incf (aref fail i)))))))
(defun increment (dice num)
(declare (type (simple-array (unsigned-byte 32) (#.*num*)) dice))
(loop for i from 0 below num
do (incf (aref dice i))
when (>= (aref dice i) *sides*) do (setf (aref dice i) 0)
else do (return-from increment nil)
finally (return-from increment t)))
(defun test-it ()
(let* ((num *num*)
(dice (make-array num :initial-element 0 :element-type '(unsigned-byte 32)))
(succ (make-array *sides* :initial-element 0 :element-type '(unsigned-byte
32)))
(fail (make-array *sides* :initial-element 0 :element-type '(unsigned-byte
32)))
(botch (make-array *sides* :initial-element 0 :element-type '(unsigned-byte
32))))
(declare (fixnum num))
(declare (type (simple-array (unsigned-byte 32) (#.*num*)) dice)
(type (simple-array (unsigned-byte 32) (#.*sides*)) succ fail botch))
(format t "Start...~%")
(loop
do (check dice num succ fail botch)
until (increment dice num))
(print succ)
(print fail)
(print botch)
))
----------------------------------------
I also noticed that using (unsigned-byte 16) instead of
(unsigned-byte 32) reduces the run time still further, to a bit more
than 2 seconds.
The main point is that CMUCL only optimizes specialized arrays of the
following types:
bit
(unsigned-byte 2)
(unsigned-byte 4)
(unsigned-byte 8)
(unsigned-byte 16)
(unsigned-byte 32)
base-character
single-float
double-float
(at least according to the version of the user manual I have). FIXNUM
is not one of these types --- I suppose that's because it's not a
native-hardware word size.
--
Fred Gilham [EMAIL PROTECTED]
We have yet to find the Galileo who will question
our me-centred universe. --- Christina Odone