2014-04-04 12 views
5

Voglio calcolare la somma di 1 + 1/2 + 1/3 + ... + 1/100000000 (usando doppio float).Come ottimizzare questo pezzo di codice Racket?

Con SBCL, questo codice viene eseguito più velocemente in C:

(loop for i fixnum from 1 to 100000000 sum (/ 1.0d0 i) double-float) 

Come faccio a ottimizzare questo codice nella tipizzati Racket? Ho provato

#lang typed/racket 

(define: (test) : Float 
     (for/fold: : Float 
        ([s : Float 0.0]) 
        ([i : Fixnum (in-range 1 100000001)]) 
        (+ s (/ 1.0 i)))) 

(time (test)) 

Questo codice è solo un po 'più veloce di quello non tipizzato. Posso andare oltre?

+4

Un suggerimento rapido è provare il pacchetto ['ottimizzazione-coach'] (https://github.com/stamourv/optimization-coach/tree/master). –

risposta

7

Se si esegue Optimization Coach su questo come suggerito da Greg, viene immediatamente indicato che il corpo del loop è lento perché la funzione / esegue l'aritmetica mista (su un fixnum e un flonum). Se inserisci uno al posto di i, è più veloce (vicino a 2x sulla mia macchina).

Inoltre, se si esegue il cronometraggio di questo in DrRacket, si vorrà temporizzarlo con l'eseguibile racket. DrRacket aggiunge strumentazione di debug che aiuta durante lo sviluppo, ma non va bene per i tempi.

+4

Usare 'exact-> inesatto' o' unsafe-fx-> fl' invece di 'fx-> fl' dà un altro ~ 30% di accelerazione perché omette di verificare che l'argomento sia effettivamente un fixnum. – stchang

+4

Inoltre, alcuni benchmark preliminari indicano che il codice ottimizzato per il racket digitato per questo programma è ~ 10% più veloce di SBCL. – stchang

2

Ecco una nuova versione, in cui ho creato una piccola macro di supporto per sommare i galleggianti.

#lang typed/racket 

(require syntax/parse/define) 

(define-simple-macro (for/flsum x ... (c ...) b ... e) 
    (for/fold : Float x ... ([s 0.0]) (c ...) b ... (+ s e))) 

(time (for/flsum ([i : Positive-Fixnum (in-range 1 100000001)]) (/ 1.0 i))) 

noti che usare Positive-Fixnum come il tipo significa che non abbiamo bisogno di alcuna conversione aggiuntivi - tipizzati Racket sa che non è mai i 0, e così il / può sempre essere ottimizzato. Ora funziona quasi esattamente alla velocità di SBCL sulla mia macchina.

L'unica differenza tra questo e il codice SBCL è la necessità di specificare che il Fixnum è positivo, che è necessaria perché SBCL ha la stessa semantica per (/ 1.0 0) e (/ 1.0 0.0) - solleva un'eccezione, che produce Racket +inf.0 nel secondo caso e un'eccezione nel primo caso.

Ho intenzione di aggiungere for/flsum o qualcosa di simile a Racket stesso.