sum
и length
каждый O (n) , что приводит к процессу O (2n) для average
.Ниже мы покажем, как стиль передачи продолжения можно использовать для процесса average
a O (n) .
(define (average xs (return /))
(if (empty? xs)
(return 0 0)
(average (cdr xs)
(lambda (sum len)
(return (+ sum (car xs))
(+ len 1))))))
(printf "~a~n" (average '(10 60 3 55 15 45 40)))
;; 228/7
Использование exact->inexact
в average
означает тольконеточный результат может быть возвращен.Дополнительные вычисления с неточными числами приводят к дополнительной неточности.Вы можете подумать, что inexact->exact
может обратить вспять все это, однако это может привести только к приближению.
(average '(10 60 3 55 15 45 40)
;; 32 4/7
(inexact->exact (exact->inexact (average '(10 60 3 55 15 45 40))))
;; 32 40210710958665/70368744177664
По этой причине обычно имеет смысл только преобразовать точное число в неточное непосредственно перед тем, как оно
(printf "~a\n" (exact->inexact (average '(10 60 3 55 15 45 40))))
;; 32.57142857142857
Наша средняя процедура также выдает ошибку, когда дается пустой список.
(average '())
;; error /: division by zero
В качестве альтернативы, мы могли бы записать среднее значение, используя именованное выражение let
,Также O (n) .
(define (average xs)
(let loop ((xs xs)
(sum 0)
(len 0))
(if (empty? xs)
(/ sum len)
(loop (cdr xs)
(+ sum (car xs))
(+ len 1)))))
(average '(10 60 3 55 15 45 40)
;; 32 4/7