14. Rekurencja 3. Zastosowania.
Contents
14. Rekurencja 3. Zastosowania.#
Treści kształcenia. Ciągi zadane rekurencyjnie w informatyce. Granice ciągów, algorytmy obliczania granic (problem zbieżności). Interpretacja geometryczna (programy), obliczanie granic ciągów rekurencyjnych, postać rekurencyjna a ogólna.
Efekty kształcenia: Student potrafi operować ciągami rekurencyjnymi, badać ich zbieżność i granice. Potrafi określić podstawowe wady i zalety takich ciągów w zastosowaniach informatycznych.
Ciągi rekurencyjne a obliczanie funkcji pierwiastek \(\sqrt{a}\).#
Metoda naiwna (jak to było w szkole…) jest zła: mamy zgadnąć (a komuter w tym nie pomoże…) kwadrat jak największej liczby nie przekarczającej \(a\). To działa ‘’w pamięci’’ np. dla \(\sqrt{10}\), znajdziemy \(3^2 = 9 < 10\), czyli \(3 < \sqrt{3}\) itp. Ale już np. dla
nie jest to dobry algorytm, nie mówiąc np. o obliczeniu tego pierwiastka:
A na komputerze:
def sqrt5(m:float):
i=float(0)
while(i**2 <= m):
i+=float(1/10)
x1=i
for j in range(10):
x2=m
x2/=x1
x2+=x1
x2/=2
x1=x2
return x2
[sqrt5(k) for k in range(1,10)]
[1.0,
1.414213562373095,
1.7320508075688772,
2.0,
2.23606797749979,
2.449489742783178,
2.6457513110645907,
2.82842712474619,
3.0]
Lepszym algorytmem było omawiane ujęcie poprzez twierdzenie Cauchy’ego o średnich. Ale to nadal dalekie od optymalności.
Kolejna metoda (rekurencyjna) będzie bazowała na poprzedniej, ale z wykorzystaniem tylko jednego ciągu. Metoda babilońska (Herona) (bazująca na geometrii - pierwiastek jako pole kwadratu o boku \(x\), rozpoczynamy od prostokąta i zmniejszamy różnicę pomiędzy długościami boków korzystając ze średniej arytmetycznej) \(a > 0\):
Jak widać: wyraz \(x_{n+1}\) jest tu średnią arytmetyczną liczb \(x_n\) oraz \(\frac{a}{x_n}\).
W pętli while
:
def sqrt9(fg:float):
n=fg/float(2)
lstX=float(0)
while n!=lstX:
lstX = n
n = (n + fg/n)/float(2)
return n
[sqrt9(k) for k in range(1,10)]
[1.0,
1.414213562373095,
1.7320508075688772,
2.0,
2.23606797749979,
2.449489742783178,
2.6457513110645907,
2.82842712474619,
3.0]
Albo w pętli for
:
def sqrt13(n:int):
a = float(n)
x=float(1)
for i in range(n):
x = float(1/2)*(x+a / x)
return x
[sqrt13(k) for k in range(1,10)]
[1.0,
1.4166666666666665,
1.7321428571428572,
2.0000000929222947,
2.236067977499978,
2.449489742783178,
2.6457513110645907,
2.82842712474619,
3.0]
A to w Python (interaktywne):
def newtonsqrt(n):
approx=0.5*n
better=0.5*(approx+n/approx)
while better!=approx:
approx=better
better=0.5*(approx+n/approx)
return approx
print(newtonsqrt(193792))
440.218127750323
def newton_method(number, number_iters = 500):
a = float(number)
for i in range(number_iters):
number = 0.5 * (number + a / number)
return number
a=int(input("Podaj pierwsza liczba:"))
b=int(input("Podaj druga liczba:"))
print("Pierwiastek z pierwszej liczby to:",newton_method(a))
print("Pierwiastek z drugiej liczby to:",newton_method(b))
Podaj pierwsza liczba: 154
Podaj druga liczba: 4579
Pierwiastek z pierwszej liczby to: 12.4096736459909
Pierwiastek z drugiej liczby to: 67.6683086828687
Dla porównania predefiniowana funkcja z modułu math Pythona (dla zainteresowanych - poszukać jakim algorytmem jest obliczana). Wartości do porównania…
import math
math.sqrt(4579)
67.66830868286867
Zadanie. Sprawdzić, że ten ciąg jest zbieżny do \(\sqrt{a}\). A jak być może pamiętamy: to (na ogół liczba niewymierna, a więc wymaga obliczeń na komputerze. A to czego jeszcze nie mówiliśmy: funkcja pierwiastkowa sprawi pewne problemy obliczeniowe i warto opracować specjalne algorytmy - zwłaszcza za pomocą ciągów rekurencyjnych!
Rozwiązanie. Zbadamy oczywiście ograniczoność i montoniczność tego ciągu. Zastanowimy się skąd ten algorytm. To proste: bierzemy prostokąt o polu \(a\) i bokach \(x_n\) oraz \(\frac{a}{x_n}\). Algorym zakłada dążenie do uzyskania kwadratu, a wówczas jego bok ma długość \(\sqrt{a}\).
…. rysunek - może być na tablicy ….
Mamy więc dwie liczby: \(x_n\) i \( \frac{a}{x_n}\), a (jak już przypominaliśmy) ich średnia arytmetyczna, czyli \(x_{n+1}\) jest ‘’pomiędzy nimi’’. Rozpatrzmy przypadek \(x_1 < \frac{a}{x_1}\) (odwrotny przypadek jest analogiczny - samodzielnie!). Wtedy
czyli ciąg \((x_n)\) jest rosnący i ograniczony z góry. Jest więc zbieżny (oznaczmy tę granicę przez \(x\)).
Tak jak we wcześniejszych przykładach przechodzimy do granicy z \(n \to \infty\) we wzorze rekurencyjnym i uzyskujemy
Rozwiązujemy równanie uzyskując
Wyjaśnienie źródeł pomysłu i komentarz do drugiego przypadku - pozostawionego do samodzielnego uzupełnienia:
czyli w każdym przypadku
jest mniejsze albo od \(\left|x_n - \sqrt{a}\right|\), albo od \(\left|\frac{a}{x_n} - \sqrt{a}\right|\).
Jeśli \(x_n\) leży blisko \(\sqrt{a}\), to \(\frac{a}{x_n}\) też leży blisko \(\sqrt{a}\); przy tym jeśli \(x_n\) leży po jednej stronie \(\sqrt{a}\), to \(\frac{a}{x_n}\) leży po drugiej stronie \(\sqrt{a}\). Jedna z liczb \(x_n\), \(\frac{a}{x_n}\) znajduje się bliżej \(\sqrt{a}\) niż druga, ale niezależnie od tego która, ich średnia \(\frac{1}{2}\,\left(x_n+\frac{a}{x_n}\right)\) znajdzie się bliżej \(\sqrt{a}\) od obu z nich.
Inne algorytmy. A jak programy obliczają wartości funkcji \(\sqrt{x}\)?
Czy jest ‘’najlepszy algorytm’’? Dla zainteresowanych przegląd algorytmów dla funkcji \(f(x) = \sqrt{x}\) można znaleźć tu: przegląd kilkunastu algorytmów
Może ograniczymy się do jednego algorytmu rekurencyjnego pozwalającego obliczać pierwiastki (tak naprawdę: ich przybliżone wartości) - ale co ważne - tylko za pomocą mnożenia i dodawania ({N. Wirth}):
gdzie \(a_0 = x, c_0 = 1-x , x \in (0,2)\).
Pozostawimy zbadanie granicy w tym zadaniu do samodzielnego rozwiązania…
Wskazówka.
Można pokazać, że \(a_n = \sqrt{x \cdot (1 - c_n)}\) , \(|c_0| < 1\) i \(c_n \to 0\) gdy \(n \to \infty\) i dalej podobnie jak w przypadku \(\frac{1}{x}\).
A może rekurencja dla innych typowych operacji w informatyce? {N. Wirth}
Obliczanie odwrotności liczby \(\frac{1}{x}\) dla rzeczywistych liczb \(x \in (0,2)\) (jedynie poprzez mnożenie i dodawanie) i za pomocą rekurencji…
Dane: \(a_0 = 1\), \(c_0 = 1 - x\) (\(x \not= 0\)). Definiujemy dwa ciągi rekurencyjne:
Wtedy (dlaczego?)
Ale najpierw (!!) wypadałoby sprawdzić, że te ciągi są zbieżne. Proszę sprawdzić te fakty.
Rozwiązanie. Po pierwsze zauważmy, że \(|c_0| < 1\) oraz, że \(c_1 = c_0^2\), \(c_2 = c_1^2 = c_0^{4}\) i ogólnie
Czyli jest to ciąg geometryczny o ilorazie \(c_0^2 < 1\), w szczególności \(\lim_{n \to \infty} c_n = 0\). Teraz zajmiemy się ciągem \((a_n)\):
Teraz zauważmy, że dla \(k = 1,2, \ldots , n\) mamy (z własności ciągu geometrycznego)
Podstawiając do wzoru i pamiętając, że \(c_0 = 1-x\) uzyskujemy:
A teraz można skorzystać z własności ciągów zbieżnych i przejść obustronnie do granicy (pamiętając, że zbieżność \((a_n)\) można też sprawdzić bezpośrednio):
Przykład (BIS): A teraz wrócimy do wspominanej wcześniej (zajęcia z liczb rzeczywistych) metody bisekcji rozwiązywania równań nieliniowych
Tam była taka metoda ‘’wspomagana graficznie’’, ale chodzi nam o algorytm, którym posłuży się sam program, bez oceny przez jego twórcę. Definiujemy dwa ciagi rekurencyjne: \(x_1 = a\), \(y_1 = b\) oraz
A teraz (najciekawsze (dla matematyka, a najważniejsze dla informatyka): to czy te ciągi są zbieżne i to do wspólnej granicy będącej miejscem zerowym funkcji \(f\) w przedziale \([a,b]\) zależy od własności funkcji \(f\). Czyli: konkretny algorytm metody ma swoje założenia - jak każde z twierdzeń…
Dokładniej da się to wprowadzić albo na metodach numerycznych, albo zajęciach z analizy matematycznej.
Rekurencja - kolejne zadanie. Dane są ciągi rekurencyjne \((a_n)\), \((b_n)\) i \((s_n)\):
Pytania: czy istnieje i jaka jest granica ciągu \((s_n)\)?
Odp. zbieżne do \(\log{x}\)
Kiedy istnieje (dla jakich wartości początkowych: rozpocznij od \(a_0 = x > 0\), \(b_0 = 1\) i \(s_0 = 0\))? Jak zakończyć obliczenia typu ‘’while do’’ (warunek stopu)?
Kolejny ciąg określamy rekurencyjnie:
przy czym \(0 < a < 1\). Wykazać, że \((c_n)\) jest ograniczony i \(c_n < 1 - \sqrt{1 - a}\) oraz, że jest zbieżny. Obliczyć jego granicę.
Czym różni się metoda jego rozwiązywania od tej z poprzedniego zadania?
Rekurencja liniowa: od wzoru rekurencyjnego do ogólnego.
Podamy jak sobie radzić w 2 najprostszych (ale typowych) przypadkach. Dotyczyć to będzie rekurencji liniowej I i II rzędu i wyjaśnimy też na czym polega trudność dla wyższych rzędów (dla przypadku ogólnego rekurencji liniowej). A dlaczego takie rekurencje? Z pewnością wszyscy poznają (lub poznali) algorytmy sortowania, złożoność czasowa takich algorytmów wyraża się w naturalny sposób rekurencjami liniowymi.
Zbadamy rekurencje o stałych współczynnikach.
Rekurencja liniowa I rzędu. Dotyczy to przypadku
dla pewnych stałych \(k\) i \(s\). Zobaczmy pierwsze wyrazy
Wygląda to na zasadę
Warto powtórzyć zasadę indukcji zupełnej - dowód prawdziwości powyższego wzoru proszę przeprowadzić samodzielnie poprzez indukcję matematyczną… Udało się więc zamienić wzór rekurencyjny na ogólny.
Kolejny ważny przypadek (dwa ciągi rekurencyjne - już takie napotkaliśmy):
Stosujemy ponownie rozumowanie krok po kroku
Oczywiście jako szczególny przypadek \(y_n = s\) mamy nasz pierwszy wzór.
Uwaga: działanie nieskończone. Procedury z ciagami rekurencyjnymi - niekoniecznie liniowymi - będą napotykane w trudniejszych problemach, tu jeszcze za wcześnie na wszystkie przypadki. Warto zwócić uwagę na:
(a) Ułamki łańcuchowe
\(n\)-ty redukt ułamka łańcuchowego
zakładamy przy tym \(a_n >0\). Wartością ułamka łańcuchowego nazywamy granicę
Ciekawy jest przypadek \([a_0; a_1, a_2, \ldots]\), gdy liczby \(a_n\) są całkowite. Liczby wymierne posiadają skończone rozwinięcie w taki ułamek łańcuchowy. Liczby niewymierne mogą mieć rozwinięcia okresowe.
Ułamek \(\frac{253}{48}\) zapisujemy w postaci ułamka łańcuchowego następująco:
Ćwiczenie. Rozwinąć w ułamek łańcuchowy liczbę \(\frac{11}{3}\).
(b) Nieskończone pierwiastki.
Wzór
gdzie \(x_0=0 , a > 0\) - ustalona liczba, opisuje \(n\)-te przybliżenie pierwiastka nieskończonego
Analogicznie
gdzie \(x_0=1 ,a > 0 , p>1\) - zadane liczby, opisuje \(n\)-te przybliżenie pierwiastka
Zadania (samodzielne).
(1) Znaleźć wzór ogólny dla ciągu rekurencyjnego
Oczywiście: nie posługujemy się wzorem ogólnym, tylko ćwiczymy całą procedurę!
(2) Rozwiązać równania rekurencyjne:
Rekurencja liniowa II rzędu.
Dotyczy to przypadku
dla pewnych stałych \(k, m, s\). Podamy tylko jedną z metod - zainteresowani znajdą inne. Teraz czeka nas zdecydowanie więcej pracy, ale za to mamy dobry algorytm. Będziemy szukali rozwiązań postaci \(a_n = x^n\) (nie będziemy tego uzasadniali - pozostawimy to zainteresowanym).
Rozpoczniemy (bez uzasadniania…) od poszukiwań \(a_n\) w postaci potęgi:
Przy przyjęciu usytalonych 2 wyrazów początkowych (a wiemy, że to istotne)
i po podstawieniu do równania uzyskujemy
i te ostatnie równanie nazwiemy równaniem charakterystycznym. To trójmian kwadratowy, więc ma 2 pierwiastki (niestety - być może zespolone, do czego wrócimy po wprowadzeniu liczb zespolonych) i rozpatrzymy te 3 przypadki:
a) 2 pierwiastki rzeczywiste,
b) 1 pierwiastek rzeczywisty podwójny,
c) dwa pierwiastki zespolone (sprzężone).
ad a) Skoro mamy 2 pierwiastki równania charakterystycznego \(\alpha\) i \(\beta\), to z liniowości wynika, że ich kombinacje liniowe
spełniają równanie. Pozostaje dobrać \(v\) i \(w\) tak, aby pierwsze wyrazy były uzyskane
i rozwiązujemy ten układ równań liniowych wyznaczając \(v\) i \(w\).
ad b) Teraz mamy tylko jeden pierwiastek (podwójny) \(\alpha\), a więc ciągi rozwiązań to \((\alpha)^n\) oraz \((n\cdot (\alpha)^n)\), czyli
Także tu dobieramy \(v\) i \(w\) w celu uzgodnienia pierwszych wyrazów:
łatwo to rozwiązujemy…
ad c) Uwaga - jeśli nie znamy jeszcze liczb zespolonych - pominąć ten przypadek i dokończyć te zadanie po ich wprowadzeniu!
Teraz skorzystamy, że trójmian ma 2 pierwiastki zespolone sprzężone: \(z = z_1 + i z_2\) oraz \(\bar{z} = z_1 - i z_2\). Bierzemy ich kombinację liniową o współczynnikach zespolonych (!):
To nie zmienia dalszego rozumowania, ponownie szukamy \(v\) i \(w\) tak, aby dwa pierwsze wyrazy były zgodne z danymi wejściowymi:
Jak widać - rozwiązujemy układ równań zespolonych, mogą się przydać np. wzór Moivre’a… O tym - w jednym z kolejnych ćwiczeń.
Wersja a): Rozpatrzmy ciąg rekurencyjny
Odpowiednie równanie charakterystyczne jest więc w postaci
Rozwiązujemy równanie: \(\Delta = 4 + 12 = 16\), czyli \(\sqrt{\Delta} = 4\), a więc
Rozwiązaniami są więc również funkcje postaci
Ponieważ \(a_0 = 5\), \(a_1 = 13\), to
Rozwiązujemy prosty układ równa’n:
Ostatecznie
Ćwiczenie (F). A teraz - na koniec proszę taką właśnie metodą znaleźć wyraz ogólny ciągu Fibonacciego (z równaniem charakterystycznym \(x^2 = x +1\))!
Wersja b): Rozpatrzmy ciąg rekurencyjny
Odpowiednie równanie charakterystyczne jest więc w postaci
Rozwiązaniem jest
Rozwiązaniami są więc również funkcje postaci
Ponieważ \(a_0 = 1\), \(a_1 = 2\), to
Ostatecznie
Wersja c): Uwaga - jeśli nie było jeszcze liczb zespolonych - pominąć ten przypadek i dokończyć te zadanie po ich wprowadzeniu!
Rozpatrzmy ciąg rekurencyjny
Odpowiednie równanie charakterystyczne jest więc w postaci
Rozwiązujemy równanie: \(\Delta = 1 - 8 = -7\), czyli \(\sqrt{\Delta} = i\cdot \sqrt{7}\), a więc
Rozwiązaniami są więc również funkcje postaci
Korzystamy ze znajomości pierwszych wyrazów ciągu:
czyli oczywiście
Ostatecznie
Ale teraz mamy kolejne zadanie: nasz ciąg składa się z wartości rzeczywistych, a więc powinniśmy z powyższego ciągu wyeliminować liczby zespolone. Co będzie potrzebne? Ponieważ potęgujemy liczby zespolone, to skorzystamy ze wzoró de Moivre’a.
Mamy \(\left|\frac{1-i\sqrt{7}}{2}\right| = \left|\frac{1+i\sqrt{7}}{2}\right| = \frac{\sqrt{53}}{2}\). Postać trygonometryczna to \(\frac{1-i\sqrt{7}}{2} = \frac{\sqrt{53}}{2} \cdot (\cos{ \phi} + i\sin{ \phi})\) oraz \(\frac{1+i\sqrt{7}}{2} = \frac{\sqrt{53}}{2} \cdot (\cos{ \phi} - i\sin{ \phi})\) dla pewnego kąta \(\phi\), gdzie możemy go wyliczyć w danych funkcji trygonometrycznych, nie obliczamy, to ćwiczenie z algebry…) Czyli
Zadania. Znajdź wzory ogólne ciągów rekurencyjnych:
a)
b)
c)
Przypadek ogólny.
To wskazuje, że w ogólnym przypadku \(a_{n+k} = F(a_1, ... , a_{n+k-1})\) uzyskamy
a takich (dowolnych) równań nie potrafimy rozwiązywać…
Na ogół ograniczamy się do sytaucji, gdy \(F\) jest wielomianem.
A tu wprowadzenie do równań rekurencyjnych w terminologii ciągów geometrycznych (a nie funkcji tworzących) jak kto woli… - autor: prof. J. Matkowski. a symulacje… ponownie przypomnę o ‘’Geogebrze’’. Tym razem ładny skrypt o rekurencji liniowej i to niejednorodnej… I może kolejny materiał .
Układy równań liniowych rekurencyjnych.
Jak się okaże - nawet na tym wykładzie często zamiast ciągu zadanego rekurencyjnie mamy np. dwa ciągi (choćby przy obliczeniach \(\sqrt{x}\) na komputerze).
Metoda: sprowadzić do jednego równania poprzez redukcję zmiennej.
Przykład. \(a_0 = 2, b_0 = 3, a_{n+1} = 6a_n + 4 b_n , b_{n+1} = a_n + 3b_n\).
Weźmy pierwsze równanie \(a_{n+1} = 6a_n + 4 b_n\) i liczymy
Ale z pierwszego równania \(a_{n+1} - 6a_n = 4 b_n\), czyli
skąd
i równanie charakterystyk jest postaci
Z trójmianu
uzyskujemy
a więc \(a_n = c\cdot 7^n + d\cdot 2^n \). Wstawiając \(a_0\) i \(a_1\) uzyskamy układ równań:
Ostatecznie \(c = 4\) i \(d = -2\), czyli
i dalej
Uwaga: można było inaczej, ale taka jest ogólna metoda…
Zauważmy, że metoda tu podawana ograniczyła się do przypadku rekurencji liniowych (o stałych współczynnikach). To ograniczenie pozwala na pominięcie całego aparatu matematyczny szeregów potęgowych (o tym: na analizie matematycznej)! Zamiast tego uzyskujemy wyłącznie wielomiany, a więc wystarczy badać ich pierwiastki. To i tak sprawia, że przydatne są liczby zespolone, albo musimy potrafić to zrobić wyłącznie dla wielomianów, dla których znajdziemy pierwiastki - a w ogólnym przypadku to nie jest możliwe!
Np. ciąg dany rekurencyjnie
prowadzi do równania charakterystycznego
ale to jest
Tu się uda, ale…
Ćwiczenie. (dodatkowe) Rozwiązać układ równań rekurencyjnych niejednorodnych:
Rozwiązanie. Przekształćmy pierwsze z równań:
i wstawiamy do drugiego
Równanie charakterystyczne problemu jednorodnego
Rozwiązanie problemu niejednorodnego jest więc postaci
gdzie \(c,d\) – stałe dowolne, a ciągi \((c_n )\) i \( (d_n)\) spełniają
Z pierwszego równania \(\Delta d_n\cdot (-6)^{n+1} = - \Delta c_n\) i wstawiamy do drugiego uzyskując:
Stąd
Jeśli np. ustalimy pierwszy wyarz \(c_0=\frac{3}{49} ,\) \(d_0=-\frac{3}{49}\), to dostajemy
Ćwiczenie samodzielne. Na wzór tej metody można łatwo rozwiązać wiele zadań. Np. takie:
Wyrazy pewnego ciągu geometrycznego \((a_n)\) spełniają warunki:
Aby wyznaczyć iloraz \(q\) tego ciągu, postąpimy następująco:
(1) Zapisujemy drugie równanie jak przy rekurencjach liniowych: \(q^{3}(a_1+a_2+a_3)=-2\). 2. Korzystając z równania pierwszego uzyskamy \(a_1+a_2+a_3=2\) 3. Teraz mamy: \(q^{3}=-1\). 4. Obliczmy, że \(q=-1\).
A teraz - wyznaczyć iloraz \(q\) ciągu geometrycznego \((b_n)\),o wyrazach \(b_3,b_4,\ldots,b_8\) spełniających:
Rekurencja - trudniejsze pytanie. Dane są ciągi:
Pytania: czy istnieje i jaka jest granica ciągu \((s_n)\)? Kiedy istnieje (dla jakich wartości początkowych: rozpocznij od \(a_0 = x > 0\), \(b_0 = 1\) i \(s_0 = 0\))? Jak zakończyć obliczenia (warunek stopu)?
Rekurencja jest silnie związana z zastosowaniem pętli bez wskazania liczby przebiegów, a raczej ze sprawdzeniem osiągnęcia założonego celu, czyli pętli ‘’while… do’’. I tu problem: obliczając symulacje istnienia i wartości granicy mamy dwa problemy: pierwszy, to nie możemy zweryfikować, czy granica istnieje (o czym mówiliśmy), a drugi, to kiedy zakończyć obliczenia (problem ‘’stopu’’). W tym drugim przypadku możemy uzyskać fałszywą sugestię odnośnie wartości granicy, a na ogół chcemy znać tę wartość z zadaną precyzją \(\varepsilon > 0\). Nie znając granicy \(g\) nie możemy sprawdzać w pętli warunku z definicji \(|a_n - g| < \varepsilon\).
Powinniśmy badać warunek Cauchyego, bo on nie wymaga znajomości granicy, a jedynie wyrazów ciągu. Niestety - wszystkich od pewnego miejsca. Tego się nie da, więc często sprawdzamy różnice \(|a_n - a_{n-1}| < \varepsilon\).
To za mało: proszę zrobić symulację np. dla \(a_n = \sum_{k=3}^n \frac{1}{k \ln k \ln (\ln k)} \) lub po prostu dla \(a_n = \ln{n}\). Problem jest otwarty, a pewne istniejące rozwiązania podamy na analizie matematycznej…
Proszę być świadomym ograniczeń obliczeń komputerowych:
Diagonal arguments are used to prove many fundamental results about the limitations of computation, such as the undecidability of the Halting Problem for programs and the inherent, unavoidable inefficiency (exponential time or worse) of procedures for other computational problems. So computer scientists do need to study diagonal arguments in order to understand the logical limits of computation. A well-educated computer scientist will be comfortable dealing with countable sets, finite as well as infinite. {Mathematics for Computer Science, Eric Lehman, F Thomson Leighton, Albert R Meyer}