如何优化这条Racket代码?

时间:2014-04-04 17:02:25

标签: optimization racket sbcl typed-racket

我想计算1 + 1/2 + 1/3 + ... + 1/100000000的总和(使用双浮点数)。

使用SBCL,此代码的运行速度与C:

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

如何在Typed Racket中优化此代码?我试过了

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

此代码仅比无类型代码快一点。我可以走得更远吗?

2 个答案:

答案 0 :(得分:7)

如果像Greg建议的那样运行优化教练,它会立即告诉你循环体很慢,因为/函数正在进行混合算术(在fixnum和flonum上)。如果您插入(fx->fl i)代替i它会更快(在我的机器上接近2倍)。

另外,如果您在DrRacket中计时,则需要使用racket可执行文件计时。 DrRacket添加了调试工具,可以在开发过程中提供帮助,但对时间安排并不好。

答案 1 :(得分:2)

这是一个新版本,我在其中制作了一个辅助宏来总结花车。

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

请注意,使用Positive-Fixnum作为类型意味着我们不需要任何其他转换 - Typed Racket知道i永远不会为0,因此/始终可以优化。现在,这几乎与我机器上的SBCL一样快。

它与SBCL代码之间的唯一区别是需要指定fixnum是正数,这是必需的,因为SBCL具有与(/ 1.0 0)(/ 1.0 0.0)相同的语义 - 它引发了异常,而Racket在第二种情况下产生+inf.0,在第一种情况下产生例外。

我计划将for/flsum或类似内容添加到Racket本身。