2014-04-04 18 views
5

Ich möchte die Summe von 1 + 1/2 + 1/3 + ... + 1/100000000 (mit Doppel-Float) berechnen.Wie wird dieses Stück Racket-Code optimiert?

Mit SBCL, läuft dieser Code so schnell wie in C:

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

Wie kann ich diesen Code in typisierten Racket zu optimieren? Ich habe versucht

#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)) 

Dieser Code ist nur ein bisschen schneller als untypisierte. Kann ich weiter gehen?

+4

Ein schneller Vorschlag ist das ['optimization-coach' Paket] (https://github.com/stamourv/optimization-coach/tree/master). –

Antwort

7

Wenn Sie Optimization Coach auf diesem wie Greg vorgeschlagen ausführen, teilt es Ihnen sofort mit, dass der Schleifenkörper langsam ist, da die /-Funktion gemischte Arithmetik ausführt (auf einem Fixnum und einem Flonum). Wenn Sie (fx->fl i) an Stelle von i einfügen, ist es schneller (fast 2x auf meinem Gerät).

Auch, wenn Sie dies in DrRacket timing möchten Sie es mit der ausführbaren racket stattdessen Zeit. DrRacket fügt Debugging-Instrumente hinzu, die während der Entwicklung helfen, aber nicht für das Timing geeignet sind.

+4

Die Verwendung von 'exact-> inexact' oder' unsafe-fx-> fl' anstelle von 'fx-> fl' ergibt eine weitere ~ 30% ige Beschleunigung, da es nicht überprüft, ob das Argument tatsächlich eine fixnum ist. – stchang

+4

Auch einige vorläufige Benchmarks zeigen, dass der optimierte typisierte Racket-Code für dieses Programm ~ 10% schneller ist als SBCL. – stchang

2

Hier ist eine neue Version, in der ich ein kleines Hilfsmakro zum Summieren von Floats gemacht habe.

#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))) 

Beachten Sie, dass mit Positive-Fixnum als die Art bedeutet, wir brauchen keine zusätzliche Conversions nicht - typisierten Racket weiß, dass i ist nie 0, und so kann die / immer optimiert werden. Dies läuft jetzt fast genau so schnell wie SBCL auf meiner Maschine.

Der einzige Unterschied zwischen diesem und dem SBCL Codes ist die Notwendigkeit angeben, dass die Fixnum positiv ist, die erforderlich ist, weil SBCL die gleiche Semantik für (/ 1.0 0) hat und (/ 1.0 0.0) - es eine Ausnahme auslöst, während Racket +inf.0 in das erzeugt zweiter Fall und eine Ausnahme im ersten Fall.

Ich plane, for/flsum oder etwas ähnliches zu Racket selbst hinzuzufügen.