[racket] deceptive perfomance for typed racket in integer division
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;
}
----------------------------------------------------------