Chúng ta có hai hàm tính toán giai thừa của một số đã cho. Cái đầu tiên, !
, sử dụng kiểu tích lũy. Thứ hai, fact
, sử dụng đệ quy tự nhiên.Hiệu suất của kiểu đệ quy và ắc quy
(define (! n0)
(local (;; accumulator is the product of all natural numbers in [n0, n)
(define (!-a n accumulator)
(cond
[(zero? n) accumulator]
[else (!-a (sub1 n) (* n accumulator))])))
(!-a n0 1)))
và
(define (fact n)
(cond
[(= 0 n) 1]
[else (* n (fact (- n 1)))]))
Ở dưới cùng của Mục 31, HtDP khẳng định rằng phiên bản đệ quy một cách tự nhiên thường là nhanh nếu không nhanh hơn so với phiên bản accumulator, nhưng không nêu rõ lý do tại sao. Tôi đã làm một số đọc về điều này và có vẻ như câu trả lời là 'tail call optimization/elimination', nhưng bài viết Wikipedia dường như là mâu thuẫn với những gì HtDP nói, ít nhất là đối với hiệu suất. Tại sao cái này rất?
Tại nơi làm việc, kiểu đệ quy nhanh hơn. Ở nhà, phong cách tích lũy nhanh hơn. Có không có heuristic chung để hướng dẫn một sự lựa chọn như là phong cách thường được ưa thích? Tôi hiểu rằng phong cách tích lũy là hiệu quả bộ nhớ hơn, nhưng nếu chúng ta hạn chế các cuộc thảo luận để thực hiện một mình, nó là không rõ ràng, ít nhất là với tôi, đó là sự lựa chọn tốt hơn.
Tôi đã nghĩ về điều này một chút nữa, và sẽ phải sang bên kia với bài viết trên Wikipedia về tính ưu việt của đệ quy ắc-style trong trường hợp chung. Nó không chỉ làm giảm việc sử dụng không gian stack/heap, truy cập bộ nhớ luôn ở phía sau quyền truy cập đăng ký và chỉ có thể được hiển thị rõ ràng hơn khi đa lõi ở đây. Tuy nhiên, HtDP chứng minh rằng việc kiểm tra thực tế là bắt buộc trong mọi trường hợp.
Cảm ơn bạn đã thấu hiểu. Điều đó đã được giải thích rất rõ. Điều lý tưởng là nếu ai đó có thể xác minh nó trên phiên bản Windows 64-bit của Racket. – Greenhorn