On Wed, Dec 22, 2010 at 12:52 PM, Rayne <[email protected]> wrote:
> I have a piece of code, and I'd like to see how fast it can be.
>
> (defn count-num-chars [^String s]
> (loop [s s acc 0]
> (if (seq s)
> (recur (rest s) (if (= (first s) \space) acc (inc acc)))
> acc)))
>
> This is the fastest I've been able to get it. The function is very
> simple. It takes a string and counts the number of non-space
> characters inside of that string.
>
> I've been testing this code against a 460 non-space character string.
> Here is the entire source, benchmarking and all:
>
> (def s (apply str (repeat 20 "This is a really long string")))
>
> (defn count-num-chars [^String s]
> (loop [s s acc 0]
> (if (seq s)
> (recur (rest s) (if (= (first s) \space) acc (inc acc)))
> acc)))
>
> (println "Chars outputted:" (count-num-chars s))
>
> (let [before (System/nanoTime)]
> (dotimes [_ 1000]
> (count-num-chars s))
> (let [after (System/nanoTime)]
> (println "Time (in nanoseconds):" (/ (- after before) 1000.0))))
>
> Running it gives me around 137343.295 nanoseconds.
I get around half that.
Yours calls seq every loop. Writing
(defn count-num-chars [^String s]
(loop [s (seq s) acc 0]
(if s
(recur (next s) (if (= (first s) \space) acc (inc acc)))
acc)))
results in about 10% savings.
Using primitive math:
(defn count-num-chars [^String s]
(loop [s (seq s) acc (int 0)]
(if s
(recur (next s) (if (= (first s) \space) acc (unchecked-inc acc)))
acc)))
yields up another 10% or so.
That's maybe 40,000ns, still over 10x slower than the Java
implementations you mentioned, but it's about the limits of the
savings we'll get while still using the seq abstraction, I suspect. To
get closer to Java performance means getting closer to Java means of
doing it:
(defn count-num-chars [^String s]
(let [l (int (.length s))]
(loop [i (int 0) acc (int 0)]
(if (< i l)
(recur (unchecked-inc i) (if (= (.charAt s i) \space) acc
(unchecked-inc acc)))
acc))))
15k nsec -- twice as fast as before. Still 5x slower than Java; I'm
not sure why. This is now directly equivalent to the obvious Java
implementation,
int l = s.length();
int acc = 0;
for (i = 0; i < l; ++i)
if (s.charAt(i) == ' ') ++acc;
and since the string is type-hinted it shouldn't be using reflection
for the length or charAt calls.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en