Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is for loop so slow in Racket code

I am trying to find smallest non-divisor of numbers (https://codegolf.stackexchange.com/questions/105412/find-the-smallest-number-that-doesnt-divide-n). Following version using 'named let' works properly:

(define (f1 m)
  (let loop ((n 2))
    (cond
      [(= 0 (modulo m n))
       (loop (+ 1 n))]
      [else n])))

I am testing with:

(f 24)
(f 1234567)
(f 12252240)
(f 232792560)

Above version produces prompt output of: 5 2 19 and 23.

However, following version which uses built-in for loop is very slow and actually crashes with out of memory error with larger numbers:

(define (f2 m)
  (for/first ((i (range 2 m))
              #:when (not (= 0 (modulo m i)))
              #:final (not (= 0 (modulo m i))))
    i))

Is there some error in the code of second version or is for loop inefficient as compared with named let in Racket?

like image 713
rnso Avatar asked Jan 03 '17 13:01

rnso


1 Answers

The range function actually allocates a list, so the time for your function is dominated by the huge list allocation. Use in-range instead:

(define (f2 m)
  (for/first ([i (in-range 2 m)]
              #:when (not (= 0 (modulo m i)))
              #:final (not (= 0 (modulo m i))))
    i))

See also the section on for performance in the Racket Guide for more notes on the relative speed of different sequence forms.

like image 184
Ryan Culpepper Avatar answered Sep 28 '22 15:09

Ryan Culpepper