2014-04-04 12 views
5

Tôi muốn tính tổng của 1 + 1/2 + 1/3 + ... + 1/100000000 (sử dụng phao kép).Làm cách nào để tối ưu hóa đoạn mã Racket này?

Với SBCL, mã này chạy nhanh như trong C:

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

Làm thế nào tôi có thể tối ưu hóa mã này trong Typed vợt? Tôi đã thử

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

Mã này chỉ nhanh hơn một chút so với mã chưa được nhập. Tôi có thể đi xa hơn không?

+4

Một đề xuất nhanh là thử gói ['tối ưu hóa-huấn luyện viên] (https://github.com/stamourv/optimization-coach/tree/master). –

Trả lời

7

Nếu bạn chạy Trình tối ưu hóa trên Greg như được đề xuất, nó ngay lập tức cho bạn biết rằng thân vòng lặp chậm do chức năng / đang thực hiện phép tính số học (trên bản fixnum và flonum). Nếu bạn chèn (fx->fl i) vào vị trí i, nó nhanh hơn (gần 2x trên máy của tôi).

Ngoài ra, nếu bạn đang định thời gian này trong DrRacket, bạn sẽ muốn đặt thời gian với phiên bản thực thi racket. DrRacket thêm công cụ gỡ lỗi giúp trong quá trình phát triển, nhưng không tốt cho thời gian.

+4

Sử dụng 'exact-> inexact' hoặc' unsafe-fx-> fl' thay vì 'fx-> fl' cho tốc độ tăng tốc ~ 30% khác vì nó bỏ qua việc kiểm tra xem đối số có thực sự là một fixnum hay không. – stchang

+4

Ngoài ra, một số điểm chuẩn sơ bộ cho thấy rằng mã được đánh máy tối ưu hóa cho chương trình này là ~ 10% nhanh hơn SBCL. – stchang

2

Đây là phiên bản mới, trong đó tôi đã tạo một macro trợ giúp nhỏ để tính tổng số phao.

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

Lưu ý rằng việc sử dụng Positive-Fixnum như các loại nghĩa là chúng ta không cần bất kỳ chuyển đổi bổ sung - Typed vợt biết rằng i không bao giờ là 0, và do đó / luôn có thể được tối ưu hóa. Điều này bây giờ chạy gần như chính xác nhanh như SBCL trên máy tính của tôi.

Sự khác biệt duy nhất giữa nó và mã SBCL là sự cần thiết để xác định rằng các Fixnum là tích cực, đó là cần thiết vì SBCL có ngữ nghĩa tương tự cho (/ 1.0 0)(/ 1.0 0.0) - nó đặt ra một ngoại lệ, trong khi vợt sản xuất +inf.0 trong trường hợp thứ hai và một ngoại lệ trong trường hợp đầu tiên.

Tôi dự định thêm for/flsum hoặc thứ gì đó giống như nó vào Racket.

Các vấn đề liên quan