SICP Упражнение 3.57: Сколько сложений выполняется, когда мы вычисляем n-е число Фибоначчи, используя определение fib, основанное на процедуре add-streams?Покажите, что количество добавлений было бы экспоненциально больше, если бы мы реализовали (задержка «exp») просто как (lambda () «exp»), без использования оптимизации, предусмотренной процедурой memo-proc, описанной в 3.5.1.
Есть много решений онлайн.Большинство утверждают, что неоптимизированная версия memo-proc-последовательности FIB-последовательности такая же, как вычисление незапамятной регулярной FIB-функции.При отслеживании дополнений для неоптимизированной версии memo-proc я вижу другую историю.
Пусть A (n) будет количеством дополнений, выполненных для (stream-ref fibs n)
- A (0) = 0
- A (1) = 0
- A (2) = 1
- A (3) = 3
- A (4) = 7
- A (5) = 14
- A (6) = 26
При использовании подстановки и определения функций для не-оптимизированный (незапамятный поток) я могу точно видеть, что это за добавления и почему они происходят, но у меня возникают проблемы с придуманием хорошего уравнения, чтобы ответить на вопрос, что оно на самом деле экспоненциально.
Добавлениянапример, для A (4):
- 1 + 0
- 1 + 0
- 1 + 1
- 1 +0
- 1 + 1
- 1 + 0
- 2 + 1
Вот некоторый псевдокод для отображения замен (stream-refвыдумки 4), где '.'представляет infix stream-cons, а {e} представляет обещание выполнить e.
(cddddr fibs)
(cddr (add-streams (cdr fibs) fibs))
(cddr (stream-map + (cdr fibs) fibs)))
(cddr ((+ 1 0) . {stream-map + (cddr fibs) (cdr fibs)}))
(cdr (stream-map + (cddr fibs) (cdr fibs)))
(cdr (stream-map + ((+ 1 0) . {stream-map + (cddr fibs (cdr fibs)}) (cdr fibs))
(cdr (+ 1 1) . {stream-map + (stream-map + (cddr fibs) (cdr fibs)) (cddr fibs)})
(stream-map + (stream-map + (cddr fibs) (cdr fibs)) (cddr fibs))
(stream-map + (stream-map + ((+ 1 0) . {stream-map + (cddr fibs) (cdr fibs)}) (cdr fibs)) (cddr fibs)
(stream-map + (stream-map + ((+ 1 0) . {stream-map + (cddr fibs) (cdr fibs)}) (1 . {stream-map + (cdr fibs) fibs)})) (cddr fibs))
(stream-map + ((+ 1 1) . {stream-map + (stream-map + (cddr fibs) (cdr fibs)) (stream-map + (cdr fibs) fibs)}) ((+ 1 0) . {stream-map + (cddr fibs) (cdr fibs)})
(+ 2 1) . {stream-map + (stream-map + (stream-map + (cddr fibs) (cdr fibs)) (stream-map + (cdr fibs) fibs))) (stream-map + (cddr fibs) (cdr fibs))}
Вот фактический код ракетки:
#lang racket
(define-syntax-rule (delay f) (lambda () f))
(define (force f) (f))
(define stream-null? null?)
(define the-empty-stream '())
(define-syntax-rule (cons-stream a b)
(cons a (delay b)))
(define stream-car car)
(define (stream-cdr stream) (force (cdr stream)))
(define (add-streams s1 s2)
(define (add x y)
(begin
(display "Adding ")
(display x)
(display " + ")
(display y)
(newline)
(+ x y)))
(stream-map add s1 s2))
(define (stream-map proc . argstreams)
(if (stream-null? (car argstreams))
the-empty-stream
(cons-stream
(apply proc (map stream-car argstreams))
(apply stream-map
(cons proc
(map stream-cdr
argstreams))))))
(define (stream-ref s n)
(if (= n 0)
(stream-car s)
(stream-ref (stream-cdr s) (- n 1))))
(define fibs
(cons-stream
0 (cons-stream
1 (add-streams
(stream-cdr fibs) fibs))))
(stream-ref fibs 4)
Большинство ответов онлайн говорят что-то вроде a (n)= a (n - 1) + a (n - 2) + 1 Отслеживаемый вывод рассказывает другую историю