[racket] deceptive perfomance for typed racket in integer division

From: daniel rupis (danielrupistralizavez at yahoo.es)
Date: Tue Dec 11 10:03:35 EST 2012

 I was comparing some code in Qi with that of sbcl, I posted a question in
comp.lang.lisp asking for a way to improve the perfomance, WJ gave a typed
racket version that was slower than sbcl and also much slower than cpp. 

 Daniel Rupis wrote:

 Note: The code compute the number of primes below 30000 by a very
 brute force attack. (I know there are far better algorithms for this
 task :))


 (defun divisibleRec(I J)
   (declare (optimize (speed 3) (safety 0) (compilation-speed 0))
        (type (integer 0 300000) I J))
   (when  (= J 1) (return-from divisibleRec nil))
   (if (zerop (rem  I J)) t  (divisibleRec I (1- J))))


Typed Racket:

#lang typed/racket

(define: (divisible-rec (i : Integer) (j : Integer)) : Boolean
  (cond ((= j 1) #f)
        ((zero? (modulo i j)) #t)
        (else (divisible-rec i (sub1 j)))))

 (defun divisible(N)
   (declare (optimize (speed 3) (safety 0) (compilation-speed 0))
        (type (integer 0 300000) N))
  (divisibleRec N  (1- N)))


(define: (divisible (n : Integer)) : Boolean
  (divisible-rec n (sub1 n)))

 (defun totalprimes(k)
  (declare (optimize (speed 3) (safety 0) (compilation-speed 0)))
   (loop for n of-type (integer 0 300000)  from 2 to k count (not
 (divisible n)))

(define: (total-primes (k : Integer)) : Integer
  (for/sum ([n (in-range 2 (add1 k))])
    (if (divisible n) 0 1)))

(displayln (total-primes 30999))
3340
 
Thanks to all that responded.

Results:
Original code            5.280 seconds of real time
Benjamin Kreuter code:   6.582 seconds of real time
 WJ code (typep racket) 10.544 seconds

 Conclusion:

1.- Typep racket is deceptively slow, I was expecting something better here
(racket people are  developing a math library with typep racket)

2.- Benjamin code is not a solution, it gives worse performance.

3.- Paul Khuong tell us that this problem will be here to stay for ever.

 What's the better way to include machine code like the one generate by C++ in
Lisp. That is inline the code for example only for functions from integer to
integers.

 Thanks again.


 
 I should say that I like racket, but I find macros in racket rather difficult.
I can use macros in common-lisp but I still can't use racket macros. (I am
trying to say that perhaps macros in racket are something difficult to grasp).



Original Qi code and C++ code (30000 -> 30999)

------- Qi Code ----------------------------------------

(define divisibleRec
  {number --> number --> boolean}
  I J -> (if (= J 1) false (if (= (fmod I J) 0) true (divisibleRec I (- J 1)))))

(define divisible
  {number --> boolean}
  I -> (divisibleRec I (- I 1)))

(define totalPrimesAcc
    {number --> number --> number}
    1 Acc -> Acc
    I Acc -> (if (= (divisible I) false) (totalPrimesAcc (- I 1) (+ 1 Acc))
(totalPrimesAcc (- I 1) Acc)))

(define totalPrimes
    {number --> number}
    I -> (totalPrimesAcc I 0))

(totalPrimes 30000)

----------------------------------------------------------------------

#include <stdio.h>

bool divisibleRec(int i, int j){
  if(j==1){ return false; }
  else if(i%j==0){ return true; }
  else{ return divisibleRec(i,j-1); }
}

bool divisible(int i){ return divisibleRec(i, i-1); }

int main(void){
  int i, count =0;
  for(i=2; i<30000; ++i){
    if(divisible(i)==false){
      count = count+1;
    }
  }
  printf("number of primes = %d\n",count);
  return 0;
}
----------------------------------------------------------



Posted on the users mailing list.