Diszkrét matematika 7. előadás Sapientia Egyetem, Műszaki és Humántudományok Tanszék Marosvásárhely, Románia mgyongyi@ms.sapientia.ro 2016, őszi félév
Miről volt szó az elmúlt előadáson? az ord, chr függvények az index metódus bitműveletek a base64 kódolás bináris állomány hexa formátuma
Miről lesz szó? a Fibonacci számsorozat a Fibonacci számrendszer beolvasási lehetőségek: a split és join függvények prímszámok
A Fibonacci számsorozat A számsorozat: 0, 1, 1, 2, 3, 5, 8, 13,..., A rekurziós képlet: F 0 = 0, F 1 = 1, F n = F n 1 + F n 2, léteznek hatékonyabb rekurziós összefüggések, alkalmazásuk: kombinatorika, algoritmusok futási idejének elemzése, minden pozitív egész szám feĺırható Fibonacci számok összegeként, aranymetszés, zene, művészetek, természet. A Lucas számok, ugyanaz az összefüggés a számok között, más a két kezdeti érték: A számsorozat: 2, 1, 3, 4, 7, 11, 18, 29, 47,..., A rekurziós képlet: L 0 = 2, L 1 = 1, L n = L n 1 + L n 2,
A Fibonacci számsorozat A klasszikus rekurzív megoldás, nem hatékony, exponenciális: def fibr1 (n): if n == 0: return 0 if n == 1: return 1 return fibr1 (n-1) + fibr1 (n-2) A következő algoritmus futási ideje lineáris: def sfib(a, b, n): if n == 1: return a return sfib(b, a + b, n-1) def fibr2(n): return sfib(1, 1, n) >>> fibr2(100) 354224848179261915075 Mi lesz az algoritmus iterativ változata?
A Fibonacci számsorozat Létezik logaritmikus futási idejű algoritmus: a feladat visszavezethető a gyorshatványozás algoritmusára: [ ] n 1 [ ] 4 [ ] 1 1 1 1 5 3 F n =, F 1 0 5 = = 1 0 3 2 ahol meg kell tehát határozni két 2 2 mátrix szorzatát: [ ] [ ] [ a 1 a 2 b 1 b 2 a 1 b 1 + a 2 b 3 a 1 b 2 + a 2 b 4 = a 3 a 4 b 3 b 4 a 3 b 1 + a 4 b 3 a 3 b 2 + a 4 b 4 A hatékonyság végett a mátrixot egy számhármassal is lehet ábrázolni, mert az a 2 és a 3 elemek megegyeznek. ]
A Fibonacci számsorozat A két 2x2-es mátrix szorzata: def mszt((a1, a2, a3, a4), (b1, b2, b3, b4)): c1 = a1 * b1 + a2 * b3 c2 = a1 * b2 + a2 * b4 c3 = a3 * b1 + a4 * b3 c4 = a3 * b2 + a4 * b4 return (c1, c2, c3, c4) Feladat: felhasználva a fenti algoritmust határozzuk meg a n-ik Fibonacci számot, a gyorshatványozás algoritmusára visszavezetve. Hogyan lehet még hatékonyabbá tenni az algoritmust?
A Fibonacci számsorozat, összefüggések Fennáll a következő: Bizonyítás, vázlat: F n+1 lim = ϕ n F n F n+1 F n + F n 1 lim = lim = 1 + lim n F n n F n n fennáll tehát: x = 1 + 1 F n+1, ahol a lim x n F n jelölést alkalmaztuk. = lim n 1 F n F n 1 F n F n 1 = x megoldva a x = 1 + 1 egyenletet kapjuk, a kért összefüggést x Binet formula (bizonyítás matematikai indukcióval): F n = ϕn ˆϕ n 5 = (1 + 5) n (1 5) n 2 n 5
A Fibonacci számsorozat, összefüggések F n = ( 1+ 5 ) n ( 1 5 2 5 2 ) n = (1 + 5) n (1 5) n 2 n 5 from math import sqrt def fibn1 (n): temp = pow((1 + sqrt(5))/2, n) - pow ((1 - sqrt(5))/2, n) return int( temp / sqrt(5)) def fibn2 (n): temp = ((1 + sqrt(5))/2) ** n - ((1 - sqrt(5))/2) ** n return int( temp / sqrt(5))
A Fibonacci számsorozat Adott n értékig, egy számsorozatba határozzuk meg két egymás melletti Fibonacci szám arányát: def fibrate(nr): n, L = fibl(nr) fr = [] for i in range(1, n): fr += [ float(l[i]) / L[i-1] ] return fr >>> fibrate(500) [1.0, 2.0, 1.5, 1.6666666666666667, 1.6, 1.625, 1.6153846153846154, 1.619047619047619, 1.6176470588235294, 1.6181818181818182, 1.6179775280898876, 1.6180555555555556, 1.6180257510729614] A fibl függvény meghatározza nr-nél kisebb Fibonacci számok számát, illetve a Fibonacci számok listáját. Írjuk meg ezt a függvényt!!
A Fibonacci számsorozat Határozzuk meg egy szám Fibonacci számrendszerbeli alakját. Az eredményt egy string típusú változóba generáljuk ki: def fibbasestr(nr): n, L = fibl(nr) #print L[n:0:-1] bl = i = n - 1 while i > 1: nr -= L[i] bl += str(1) i -= 1 while L[i] > nr and i > 1: bl += str(0) i -= 1 print bl >>> fibbasestr(100) 1000010100
A split és join függvények >>> mstr = Sapientia EMTE Kolozsvar, 2016/2017 >>> Lstr = mstr.split() >>> Lstr [ Sapientia, EMTE, Kolozsvar,, 2016/2017 ] >>>.join(lstr) SapientiaEMTEKolozsvar,2016/2017 >>>.join(lstr) Sapientia EMTE Kolozsvar, 2016/2017 >>> Lstr = mstr.split(, ) >>> Lstr [ Sapientia EMTE Kolozsvar, 2016/2017 ] >>>.join(lstr) Sapientia EMTE Kolozsvar 2016/2017
A split és join függvények >>> mstr = http://www.ms.sapientia.ro/~mgyongyi/diszkretmat/feladatok5.html >>> Lstr = mstr.split( / ) >>> Lstr [ http:,, www.ms.sapientia.ro, ~mgyongyi, DiszkretMat, feladatok5.html ] >>>.join(lstr) http:www.ms.sapientia.ro~mgyongyidiszkretmatfeladatok5.html >>> /.join(lstr) http://www.ms.sapientia.ro/~mgyongyi/diszkretmat/feladatok5.html >>> mstr[7:].split( / ) [ www.ms.sapientia.ro, ~mgyongyi, DiszkretMat, feladatok5.html ]
A split és join függvények >>> ido = 12:30:45 >>> o, p, mp = ido.split( : ) >>> print o, p, mp 12 30 45 >>> o, p = ido.split( :, 1) >>> print o, p 12 30:45 Az enter mentén osztjuk fel az állomány tartalmát, meghatározzuk az állomány sorainak számát: def filesplit1(fnev): inf = open(fnev, rt ) mstr = inf.read() inf.close() nstr = mstr.split( \ n ) print len(nstr) >>> filesplit( labor6.py )
Beolvasási lehetőségek def beolv1(): x = raw_input() return x >>> beolv1() 12 67 8 90 12 67 8 90 def beolv2(): x = raw_input().split() return x >>> beolv2() 12 3 56 78 901 [ 12, 3, 56, 78, 901 ]
Beolvasási lehetőségek def beolv3(): y = [] x = raw_input().split() for elem in x: y += [int(elem)] return y >>> beolv3() 12 4 5 67 890 [12, 4, 5, 67, 890] def beolv4(): x = map(int, raw_input().split()) return x >>> beolv4() 1 0 1 0 1 1 0 1 [1, 0, 1, 0, 1, 1, 0, 1]
Beolvasási lehetőségek def beolv5(): x = raw_input() return map(int, list(x)) >>> beolv5() 101011 [1, 0, 1, 0, 1, 1] def beolv6(): x = raw_input() return map(str, list(x)) >>> beolv6() aed454e [ a, e, d, 4, 5, 4, e ]
Beolvasási lehetőségek def beolv7(): y = [] x = raw_input() xstr = map(str, list(x)) for e in xstr: if e in 0123456789 : y += [int(e)] elif e in abcdef : y += [ord(e) - 97 + 10] elif e in ABCDEF : y += [ord(e) - 65 + 10] else: print bad chars return return y >>> beolv7() aed55a [10, 14, 13, 5, 5, 10]
Prímszámok 1. tétel Prímszámok: azok az 1-nél nagyobb egész számok, amelyek nem oszthatóak, csak 1-el és önmagukkal. Összetett számok: azok az 1-nél nagyobb egész számok, amelyek nem prímszámok. Minden 1-nél nagyobb pozitív egész számnak van egy prímosztója. A bizonyítás indirekt bizonyítási módszerrel történik: tegyük fel az ellenkezőjét, azaz létezik egy olyan szám amelyiknek nincs prímosztója; ezek a számok meghatároznak egy nem üres halmazt. A természetes számok jólrendzettség tulajdonsága alapján ebben a halmazban van egy legkisebb ilyen elem, legyen ez n. Mivel n-nek nincs primosztója, de n osztja n-t, következik, hogy n nem prímszám. Azaz n = a b, 1 < a < n, 1 < b < n. Mivel a < n következik, hogy a-nak van primosztója. De a bármely osztója osztja n-t, ez pedig ellentmondás.
Prímszámok 2. tétel Végtelen sok prímszám létezik. Egyik bizonyítási módszer Eukleidész, Elemek című könyvében található: feltételezzük, hogy a prímszámok halmaza véges. Legyenek ezek p 1, p 2,..., p n. Előálĺıtható Q = p 1 p 2... p n + 1. Bebizonyítható, hogy Q-nak viszont van egy olyan prímosztója amelyik nem szerepel a fenti prímszámok listájában. Legyen ez q és feltételezzük, hogy megegyezik valamelyik p j -vel. Ez azonban azt jelenti hogy q osztja Q p 1 p 2... p n = 1, azaz 1-t. Ez ellentmondás, mert egy prímszám nem oszthatja az 1-et. Pl. Ha összeszorozzuk az első 6 prímszámot, akkor kapunk egy olyan számot, amelynek biztosan lesz egy új prímszám osztója: 2 3 5 7 11 13 + 1 = 30031 = 59 509 Hendrik Lenstra: Végtelen sok összetett szám létezik. Ahhoz, hogy egy új összetett számot kapjunk szorozzuk össze az első n összetett számot és ne adjunk hozzá 1-et.
Prímszámok 3. tétel Ha n egy összetett szám, akkor n-nek van egy olyan prímosztója, amelyik kisebb vagy egyenlő mint n. Bizonyítása a 1. tétel alapján történik. Ha n összetett, akkor n = a b, ahol 1 < a b < n. Fenn kell álljon, hogy a n, mert másképp n < a b n = n n < a b. Az 1. tétel alapján a-nak van egy prímosztója, amelyik n-nek is prímosztója, amelyik tehát n. A tétel alapján algoritmusok adhatóak meg a prímszámok vizsgálatára: osztási próba módszere (trial division): állapítsuk meg egy adott számról, hogy prímszám-e, Eratosztenész szitája: határozzuk meg egy adott n-ig az összes prímszámot, hatékonyabb algoritmusok: Miller-Rabin prímteszt, Solovay-Strassen prímteszt, AKS prímteszt, stb.
Prímszámok Vizsgáljuk meg az osztási próba módszerével, hogy 101 prímszám-e: a cél: minél kevesebb osztást végezzünk az oszthatóság eldöntéséhez, a 11-el már nem kell megvizsgálni az oszthatóságot, mert 11 11 = 121 > 101, vagy 101 < 11 milyen számokkal vizsgáljuk az oszthatóságot? csak a páratlan számokkal vizsgáljuk az oszthatóságot, mert a 2-nél nagyobb prímszámoknak nem lehet páros osztójuk, 101 nem osztható 3, 5, 7, 9 101 prímszám.
Algoritmusok Pythonban Vizsgáljuk meg az osztási próba módszerével, hogy n prímszám-e def triald1(n): if n == 2: return True if n % 2 == 0: return False i = 3 while i*i <= n: if n % i == 0: return False i += 2 return True def triald2(n): i = 3 while i*i <= n: if n % i == 0: return False i += 2 return True Ha bemenetnek csak páratlan számot adhatunk, akkor a triald2(n) függvénnyel dolgozunk.