Схема - Мемоизация с "силой" и "задержкой" сравнения скорости

(define fibo   ; fibonacci
  (lambda (n)
    (cond ((= n 0) 0)
          ((= n 1) 1)
          ((= n 2) 1)
          (else (+ (fibo (- n 1)) (fibo(- n 2))
     )))))

(time (fibo 20))

(define (fiboN n)   ; fibonacci
    (delay (cond ((= n 0) 0)
          ((= n 1) 1)
          ((= n 2) 1)
          (else (+ (force (fiboN (- n 1))) (force (fiboN(- n 2))))))))

(time force( force (fiboN 20)))

Учитывая две функции Фибоначчи, описанные выше, я ожидал, что вторая будет работать быстрее, поскольку схема применяет запоминание для объектов с принудительной задержкой.

И все же второе волокно работает медленнее. С чего бы это? Я ошибаюсь в автоматическом запоминании в Схеме?

1 ответ

Решение

Вы путаете запоминание с отложенной (или ленивой) оценкой - взгляните на это объяснение, чтобы понять разницу между этими двумя понятиями.

Ваша вторая реализация fiboN откладывается, конечно, но это ничего не запоминает - конечно, как только мы force значение, которое не нужно будет принудительно вводить снова, но это не меняет того факта, что это рекурсивная функция, которая вызывается снова и снова для значений, которые мы уже получили, и дополнительные затраты на задержку / форсирование каждого значения сделает это медленнее, чем первая реализация.

Вот возможная реализация, которая на самом деле использует запоминание. Хитрость заключается в том, чтобы сохранить уже вычисленные значения где-нибудь, где мы можем получить к ним эффективный доступ - хеш-таблицу в этом примере:

(define fiboN
  (let ((memo (make-hash '((0 . 0) (1 . 1)))))
    (lambda (n)
      (unless (hash-has-key? memo n)
        (hash-set! memo n (+ (fiboN (- n 1)) (fiboN (- n 2)))))
      (hash-ref memo n))))

И результаты показывают, что это намного быстрее:

(time (fiboN 100))

cpu time: 0 real time: 1 gc time: 0
354224848179261915075
Другие вопросы по тегам