I'm using Project Euler problem 5 brute force method to test out performance tweaking CL code. I'm new to the language and want to know how to do such things. I wrote a C implementation, which runs in about 1.3 seconds. My initial, naive CL implementation runs in around 15 seconds.
Here's my initial CL code
(defpackage :problem-5 (:use #:cl) (:export :divides-even-p :has-all-divisors :smallest-multiple) ) (in-package :problem-5) (defun divides-even-p (num divisor) (= 0 (rem num divisor)) ) (defun has-all-divisors (num start stop) (loop for divisor from start to stop do (cond ((not (divides-even-p num divisor)) (return-from has-all-divisors nil)) ) (+ divisor 1) ) t ) (defun smallest-multiple (n) (do ((multiple 1 (+ multiple 1))) ((has-all-divisors multiple 1 n) (format t "~A" multiple)) )) (time (smallest-multiple 20)) The tricks I've read about up til now are 1) optimize for speed and safety, 2) inline functions and 3) explicitly set variable types. Applying those things, I get the following code
(defpackage :problem-5 (:use #:cl) (:export :divides-even-p :has-all-divisors :smallest-multiple) ) (in-package :problem-5) (declaim (optimize (speed 3) (safety 0)) (inline divides-even-p) (inline has-all-divisors) ) (defun divides-even-p (num divisor) (declare (type integer num divisor)) (zerop (rem num divisor)) ) (defun has-all-divisors (num start stop) (declare (type integer num start stop)) (loop for divisor of-type integer from start to stop do (cond ((not (divides-even-p num divisor)) (return-from has-all-divisors nil)) ) ) t ) (defun smallest-multiple () (do ((multiple 1 (+ multiple 1))) ((has-all-divisors multiple 2 20) (format t "~A" multiple)) )) (time (smallest-multiple)) Now when I run that version, it runs in 7 seconds instead of 15. 2x speed up, so in the right direction. What else can be done to speed it up? The most glaring thing to me is the do loop in smallest-multiple. For one, I couldn't figure out how to specify a type for the multiple variable. How do you do that? Is there a better way to do open ended loops that would produce less code? How would you go about trying to increase the performance from here? The C code runs in about 1.3 seconds, so I'd be happy getting it down to 2 or 3 seconds.