Pascal J. Bourguignon <pjb@informatimago.com> wrote:
+---------------
| jaycx2.3.calrobert@spamgourmet.com.remove (Robert Maas) writes:
| > I'll need to find a way to make a DEFUN-and-COMPILE factory that
| > takes a parameter of array size and automatically builds the correct
| > s-expression for the DEFUN and then EVALs then COMPILEs it. One way
| > is to print the s-expression to a string, substitute the literal
| > text within that string, then READ-FROM-STRING to get the new
| > s-expression. The amazing thing is that in Lisp that monstrosity is
| > actually doable!!
...
| Yes, but all this brutality is really not necessary. This is Lisp!
|
| (defparameter *one-random-definition*
| '(defun one-random ()
| (the (unsigned-byte 21)
| (random (the (unsigned-byte 21) %RAND-ARG%)))))
|
| (loop
| :for log2-of-max :from 1 :to 20
| :for rand-arg = (expt 2 log2-of-max)
| :do (eval (subst rand-arg '%rand-arg% *one-random-definition*))
| :collect (one-random))
|
| --> (1 0 0 2 11 1 81 107 19 873 1946 2584 7652 1368 13615 44345
| 28677 17764 101515 524618) ; for example
+---------------
Yes, this is Lisp, and as I told him in my parallel reply,
"We don' need no stinkin' strings!" ;-} ;-}
But the issue at question is GC'ing, and your version doesn't
address those problems, which can -- in CMUCL, at least -- only
be addressed at present (1) by compiling ONE-RANDOM [which your
code didn't], and (2) needing to use a literal numeric arg to
RANDOM if the arg is larger than KERNEL:RANDOM-FIXNUM-MAX [an
internal magic CMUCL constant]. My version [see my parallel reply
in <news:8dmdnc_m0Kv_3c_VnZ2dnUVZ_rrinZ2d@speakeasy.net>] did
handle both of those concerns:
(defun random-builder (arg)
(let ((*compile-print* nil))
(compile 'one-random `(lambda () (random ,arg)))
(compile 'many-randoms
`(lambda () (dotimes (k 50000) (one-random))))
nil))
...[remainder elided]...
and results in a MANY-RANDOMS function that does not cons.
If one wanted to pre-compile a bunch of them and save them away
somewhere [and also avoid polluting the global namespace as *my*
version did!! ;-} ;-} ], then of course a loop like yours would
certainly be the way to do it... but in CMUCL you can go all the
way to 2^32:
cmu> (defparameter *many-randoms*
(loop for log2-of-max from 1 to 32
for rand-arg = (expt 2 log2-of-max)
collect (let ((*compile-print* nil))
(compile 'nil `(lambda ()
(dotimes (k 50000)
(random ,rand-arg)))))
into results
finally (return (coerce results 'vector))))
*MANY-RANDOMS*
cmu> (type-of *many-randoms*)
(SIMPLE-VECTOR 32)
cmu> (time (funcall (aref *many-randoms* 31)))
; Compiling LAMBDA NIL:
; Compiling Top-Level Form:
; Evaluation took:
; 0.0f0 seconds of real time
; 8.27f-4 seconds of user run time
; 0.0f0 seconds of system run time
; 1,821,208 CPU cycles
; 0 page faults and
; 0 bytes consed.
;
NIL
cmu>
-Rob
p.s. Still ugly. The *real* fix is in "cmucl/src/compiler/float-tran.lisp"
[making args in (INTEGER 1 4294967296) work correctly on X86 platforms],
and awaits the attentions of the maintainers.
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607