Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Fp_8.doc
Скачиваний:
1
Добавлен:
01.05.2025
Размер:
116.22 Кб
Скачать

8.4 Еще раз о числах Фибоначчи

Интересно, какую выгоду нам могут дать бесконечные потоки, применимые рядам чисел, поучаемых рекуррентным способом?

Как известно, последовательность чисел Фибоначчи начинается с двух единиц

Остальная её часть может быть выражена как сумма последовательности Фибоначчи и этой же последовательности, смещенной на один шаг, т.е.

1

1

2

3

5

8

13

...

Fn

...

1

1

2

3

5

8

...

Fn-1

...

1

1

2

3

5

...

Fn-2

...

По аналогии с потоком целых чисел, мы можем определить бесконечный поток чисел Фибоначчи и написать новую версию процедуры fib. Он определяется как сумма двух бесконечных потоков.

Сначала определим построение потока:

>(define fibST

(cons-stream 1

(cons-stream 1

(stream-add fibST (tail fibST) ))))

Теперь новое определение чисел Фибоначчи:

> (define (fibS n) (elem-no n fibST))

Смотрим, сколько времени затрачивается на получение числа Фибоначчи для n=100000

>(time (fibS 10000))

cpu time: 32 real time: 31 gc time: 0

Нет возможности привести это число, поскольку его длина займет не одну страницу

>(string-length (number->string (fib 100000)))

20897

Более интересно посмотреть на время его получения по ранее рассмотренной хвостовой рекурсии

>(define (fib-iter k ks count)

(cond ((= count 0) k)

(else (fib-iter ks (+ k ks) (- count 1)))))

>(define (fib n) (fib-iter 1 1 (- n 1)))

>(time (fib 10000))

cpu time: 15 real time: 15 gc time: 0

Заметим, что времена где-то одного порядка. НО ! Чтобы получить итерационную процедуру нам пришлось «покумекать», а реализация бесконечным потоком получилась как-то сама собой !

8.5 Простые числа

Рассмотрим последний пример организации бесконечного потока на задаче получения множества простых чисел.

Первый вариант.

Пусть критерием простоты числа n будет такое условие: если перебирая все числа от 2 до (ВАЖНО!) корня из n, мы не найдем ни одного числа на которое это n делится – оно простое.

>(define (prime? n)

(nodiv? 2 n (sqrt n)))

>(define (nodiv? m n limit)

(or (> m limit)

(and (not (= (remainder n m) 0)) ; не может быть четно

(nodiv? (+ m 1) n limit))))

> (prime? 123)

#f

> (prime? 101)

#t

Теперь множество простых чисел можно построить, отфильтровав бесконечный поток целых чисел с помощью написанного предиката prime?.

> (define primeSD

(stream-filter prime? (integers-from 2)))

Второй вариант. Наиболее «функциональный». Другой бесконечный поток.

Сначала изменим критерий простоты числа, чтобы проверять только делимость на простые числа.

> (define (primed? n)

(define (nodiv? s limit)

(or (> (head s) limit)

(and (not (= (remainder n (head s)) 0))

(nodiv? (tail s) limit))))

(nodiv? primeSD (sqrt n)))

> (primed? 127)

#t

> (primed? 125)

#f

И вот сам поток.

> (define primeSD

(cons-stream 2 (stream-filter primed? (integers-from 3))))

Это определение дважды рекурсивно, так как поток primeSD определяется через предикат primed?, который в свою очередь использует primeSD. Но в любой момент созданной части потока достаточно для проверки простоты очередного числа.

И, наконец, сравнения по времени выполнения

>(time (primed? 127691))

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]