vendredi 2 octobre 2015

Haskell: How to improve performance of deep recursion and random number generation

The problem of interest is to enhance the following Haskell program with a recursion depth of 100,000,000 by making it faster:

s :: Int32 -> Int32 -> IO Int32
s 0 acc = return $! acc
s n acc = do r <- randomRIO (0, maxBound :: Int32)
             s (n-1) $! (acc + r)

main = do z <- s 100000000 0
          putStrLn $ show z

This program takes about 70 seconds on my machine. However, a corresponding C program takes only one second:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>    

int main(){
    double startTime;
    double timeEllapsed;
    unsigned int sum;
    long long i;    

    startTime = clock();
    srand(time(NULL));    

    sum = 0;
    i = 0;
    for(i=0; i<100000000;i++){
      sum += rand();
    }    

    timeEllapsed = (clock() - startTime) / (CLOCKS_PER_SEC);    

    printf("sum = %u, time ellapsed = %lfs\n", sum, timeEllapsed);    

    return EXIT_SUCCESS;    
}

Where does this difference come from? Is the implementation of random numbers in the Haskell standard library slower? Or should you use a function different from randomRIO? Or has it to do with lazy evaluation? Can you optimize anything on the Haskell program and make it faster?

It's clear that there might be performance differences between a very high level language like Haskell and C, but I did not expect it to be in the order of ~70 times slower, so I wonder about the causes.




Aucun commentaire:

Enregistrer un commentaire