So far, while testing the speeds of different approaches to writing the same function, I've been using the time
function, and generally it gives me a good indication of the relative speeds of different functions (since they typically differ by around 100k cycles).
While attempting to find the fastest approach for a factorial
function, however, time
has been lacking. Not only do these methods seem to differ by only 10k-30k cycles, but their overall time vary by around half that amount too (which is expected, I guess).
The three factorial
functions:
(defun factorial-recusion (n) ; 1st
(if (equal n 1)
1
(* n (factorial (- n 1)))))
(defun factorial-loop (n) ; 2nd
(let ((solution 1))
(loop for x from n downto 2
do (setf solution (* solution x))
finally (return solution))))
(defun factorial-do (n) ; 3rd
(let ((solution 1))
(do ((x n (1- x)))
((< x 2) (return solution))
(setf solution (* solution x)))))
So, I guess I have two questions:
1.) Which method of factorial
should be fastest (if any actually is), and why?
2.) If I were to find out for myself the faster function through a general method, what's the best way to do so (for some reason I think LOC is a bad indicator of speed)? Perhaps there is a way to view the disassembly of Lisp bytecode? Or maybe there's a better, more rigorous way?
I'm currently running Linux 3.2.0-26, SBCL, on Ubuntu 12.04 x86-64.
SBCL does not compile to 'bytecode'. It compiles to native machine code.
You can disassemble a Lisp function by using DISASSEMBLE
.
Speed in your factorial function is dominated by bignum arithmetic multiplication once the numbers get into the bignum range.
To make it clearer: which iteration construct you use, DO or LOOP, does not matter much. Most of the time is spent multiplying bignums. The recursive version also does not make much of a difference.
That's a typical benchmark problem: many simple numeric benchmarks are dominated by runtimes of a few arithmetic operations (like multiplication of bignums). They will not measure much of the different in speed of general language operations (like the various types of control flow).
A slow Lisp with a fast bignum library will likely be faster than an optimizing Lisp compiler with Bignum code written in Lisp.