我想计算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))
此代码仅比无类型代码快一点。我可以走得更远吗?
答案 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本身。