Dr. Kai-Friederike Oelbermann Dipl.-Math. Alina Bondarava Wintersemester 2015/16 OVGU Magdeburg Übungen zur Algorithmischen Mathematik Blatt 4 1. Ersetzen Sie die geschachtelten if-else-Anweisungen in dem Programm Taschenrechner1.c aus der Vorlesung durch switch-case. Die Wahl der Rechenart soll mit a-s-m-d gesteuert werden. 2. Ziel dieser Aufgabe ist es, das Sieb des Eratosthenes zu programmieren. Das Sieb findet alle Primzahlen bis zu einer vorgegebenen Grenze N 2 N. Dafür stelle man sich vor, dass alle Zahlen bis N aufgelistet sind. Zuerst wird die Eins gestrichen, sie ist keine Primzahl. Danach werden alle Vielfachen der Zwei gestrichen, da diese keine Primzahlen sein können. Auch alle Vielfachen der Drei werden als zusammengesetzte Zahlen gestrichen. Diese Prozedur wird mit allen Vielfachen der nächsten ungestrichenen (Prim-)Zahl kleiner gleich N wiederholt. Übrig bleiben nur noch die Primzahlen. p (a) Beweisen Sie, dass es ausreicht die Vielfachen aller Primzahlen kleiner oder gleich N zu streichen, um alle Primzahlen bis N 2 N auszusieben. (b) Programmieren Sie das Sieb des Eratosthenes. Listen Sie dazu die natürlichen Zahlen in einem array der Maximallänge auf, die Ihr Computer Ihnen ermöglicht, d.h. Ihr Sieb soll auch nur alle Primzahlen bis zu dieser Grenze finden können. (c) Erweitern Sie Ihr Programm aus (b) so, dass es auch alle Primzahlzwillinge, -drillinge und -vierlinge findet. Hinweis: Primzahlzwillinge sind zwei aufeinanderfolgende Primzahlen pn und pn+1 mit pn+1 pn = 2. Primzahldrillinge sind Primzahlen von der Form p, p + 2 und p + 6 sowie der spezielle Drilling 3, 5 und 7. Entsprechend sind Primzahlvierlinge Primzahlen von der Form p, p + 2, p + 6 und p + 8. 3. (F5 PunkteF) (a) Schreiben Sie ein Programm, welches die Fakultätsfunktion rekursiv berechnet, d.h. für die Berechnung von (n 1)! in n! = n(n 1)! soll die Funktion selbst wieder aufgerufen werden. (b) Sei n 2 N gerade. Beweisen Sie folgende Ungleichung n! Hinweis: Ordnen Sie n! = n(n 1)(n ⇣n⌘n 2 2 . 2) · . . . · 3 · 2 · 1 geschickt um. 4. (F5 PunkteF) Schreiben Sie ein naives Programm, welches zu zwei natürlichen Zahlen den ggT (größten gemeinsamen Teiler) findet. Die Beispielprogramme aus der Vorlesung und die Aufgabenblätter finden Sie unter http: // kai-friederike. de/ wise2015algmathe. html . Die mit F gekennzeichneten Aufgaben sind Hausaufgaben. Abgabe der Lösungen: 12.11.2015 vor der Vorlesung. Beachten Sie die Hinweise zur Abgabe von Programmieraufgaben unter dem Link: http: // kai-friederike. de/ wise2015algmathe. html 1 Musterlösungen 1. Der folgende Programmcode zeigt exemplarisch, wie man den switch-case Befehl verwendet. 1 #include <s t d i o . h> 2 3 4 5 6 double a d d i t i o n ( double a , double b ) { return ( a+b ) ; } 7 8 9 10 11 double s u b t r a k t i o n ( double a , double b ) { return ( a b ) ; } 12 13 14 15 16 double m u l t i p l i k a t i o n ( double a , double b ) { return ( a ⇤b ) ; } 17 18 19 20 21 22 23 24 25 26 27 28 29 double d i v i s i o n ( double a , double b , short ⇤w) { i f ( b <0.00000001 && b > 0.00000001) { ⇤w=1; return ( 0 ) ; } else { return ( a /b ) ; } } 30 31 32 33 34 35 i n t main ( void ) { double z a h l 1 , z a h l 2 , e r g e b n i s ; short warnung =0; char wahl ; 36 37 38 39 p r i n t f ( " D i e s e s Programm kann e i n e d e r v i e r Grundrechenarten a u f z w e i \ r e e l l e Zahlen anwenden . \ n\ Geben S i e b i t t e I h r e e r s t e Zahl e i n : " ) ; 40 41 s c a n f ( "%l f " ,& z a h l 1 ) ; 42 43 p r i n t f ( "Geben S i e nun b i t t e I h r e z w e i t e Zahl e i n : " ) ; 44 45 46 s c a n f ( "%l f " ,& z a h l 2 ) ; getchar ( ) ; 47 48 49 50 51 52 53 p r i n t f ( "Nun kommt d i e Wahl d e r Rechenart . B i t t e geben S i e e i n : \ n\ a f u e r Addition , \ n\ s f u e r S u b t r a k t i o n , \ n\ m f u e r M u l t i p l i k a t i o n , \ n\ d f u e r D i v i s i o n . \ n I h r e Wahl : " ) ; s c a n f ( "%c " ,& wahl ) ; 54 55 56 57 58 59 60 61 62 switch ( wahl ) { case ’ a ’ : e r g e b n i s=a d d i t i o n ( z a h l 1 , z a h l 2 ) ; break ; case ’ s ’ : e r g e b n i s=s u b t r a k t i o n ( z a h l 1 , z a h l 2 ) ; break ; case ’m ’ : e r g e b n i s=m u l t i p l i k a t i o n ( z a h l 1 , z a h l 2 ) ; break ; case ’ d ’ : e r g e b n i s=d i v i s i o n ( z a h l 1 , z a h l 2 ,& warnung ) ; break ; default : p r i n t f ( "Wegen I h r e r u n z u l a e s s i g e n Wahl wird das Programm\ b e e n d e t . \ n" ) ; return ( 1 ) ; break ; 2 } 63 64 65 66 67 68 i f ( warnung==0) { 69 p r i n t f ( "Das E r g e b n i s d e r " ) ; 70 71 switch ( wahl ) { case ’ a ’ : p r i n t f ( " A d d i t i o n " ) ; break ; case ’ s ’ : p r i n t f ( " S u b t r a k t i o n " ) ; break ; case ’m ’ : p r i n t f ( " M u l t i p l i k a t i o n " ) ; break ; case ’ d ’ : p r i n t f ( " D i v i s i o n " ) ; break ; } 72 73 74 75 76 77 78 79 p r i n t f ( " von %10.10 l f und %10.10 l f l a u t e t : %10.10 l f . \ n\n" , z a h l 1 , z a h l 2 , e r g e b n i s ) ; 80 81 i f ( z a h l 1 >100000000 | | ( z a h l 1 <0.00000001 && z a h l 1 > 0.00000001 ) | | \ z a h l 1 < 100000000 | | z a h l 2 >100000000 | | ( z a h l 2 <0.00000001 && \ z a h l 2 > 0.00000001 ) | | z a h l 2 < 100000000 ) { p r i n t f ( " S i e muessen damit rechnen , d a s s d i e s e s E r g e b n i s wegen \ d e r G r o e s s e d e r Zahlen \ nmit R u n d u n g s f e h l e r n b e h a f t e t i s t . \ n" ) ; } else { p r i n t f ( " D i e s e s E r g e b n i s wird durch R u n d u n g s f e h l e r \ n i c h t w e s e n t l i c h v e r f a e l s c h t . \ n" ) ; } } else { p r i n t f ( " Die D i v i s i o n konnte wegen e i n e s zu k l e i n e n Nenners \ n i c h t d u r c h g e f u e h r t werden . \ n" ) ; } 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 return ( 0 ) ; 101 102 103 } 2. (a) Sei a ein Teiler von n, sodass n = ab mit a, b 2 N und a b. Dann gilt p a2 ab = n =) a n. Damit muss mindestens ein Primfaktor einer zusammengesetzten Zahl immer kleiner gleich der Wurzel der Zahl sein muss. Also ist es ausreichend, nur die Vielfachen von Zahlen zu streichen, die kleiner oder gleich der Wurzel von N sind. (b) Folgendes Programm gibt alle Primzahlen aus, die kleiner gleich einer eingegebenen Zahl N sind. 1 2 #include <s t d i o . h> #define MAXLAENGE 2000000 3 4 5 6 7 8 9 i n t main ( void ) { unsigned i n t n=2 , i =0 , l =1 ,p=2 , a n z a h l =0; unsigned i n t PF [MAXLAENGE] ; char wahl =10; 10 11 12 /⇤ I n i t i a l i s i e r e Array mit Einsen ⇤/ 3 13 14 15 16 f o r ( i =0; i <MAXLAENGE; i ++) { PF [ i ] = 1 ; } 17 18 19 20 p r i n t f ( "Wir suchen a l l e Primzahlen k l e i n e r g l e i c h e i n e r \ n a t u e r l i c h e n Zahl N e c h t \n g r o e s s e r a l s 1 und k l e i n e r a l s %u . \ n \ B i t t e geben S i e e i n e s o l c h e Zahl e i n : " , MAXLAENGE) ; 21 22 23 s c a n f ( "%u" ,&n ) ; getchar ( ) ; 24 25 26 27 28 while ( n<2 | | n> MAXLAENGE) { p r i n t f ( " B i t t e geben S i e e i n e Zahl g r o e s s e r a l s 1 und \ k l e i n e r a l s %u e i n : " ,MAXLAENGE ) ; 29 s c a n f ( "%u" ,&n ) ; getchar ( ) ; 30 31 } 32 33 34 /⇤ S c h r e i b e i n das Array a l l e Z a h l e n von 2 b i s n⇤/ 35 36 37 38 39 40 41 i =0; while ( i<=n 2) { PF [ i ]= i +2; i ++; } 42 43 44 45 46 47 /⇤ S i e b d e s E r a t o s t h e n e s ⇤/ f o r ( i =0;( i +2)⇤( i +2)<=n ; i ++) { p=PF [ i ] ; 48 i f ( p !=1) { 49 50 51 f o r ( l =2; l ⇤p<=n ; l ++) { PF [ ( l ⇤p 2)]=1; } 52 53 54 55 56 } 57 58 } 59 60 61 62 63 /⇤ A u s g a b e s c h l e i f e mit Anzahl d e r Primz ahlen ⇤/ p r i n t f ( " \ n A l l e Primzahlen k l e i n e r g l e i c h %u s i n d : \ n" , n ) ; 64 65 66 f o r ( i =0; i <MAXLAENGE; i ++) { 67 68 69 70 71 72 73 } i f (PF [ i ] ! = 1 ) { p r i n t f ( " %u " ,PF [ i ] ) ; a n z a h l=a n z a h l +1; } 74 75 p r i n t f ( " \n\ nAnzahl d e r Primzahlen : %u\n\n" , a n z a h l ) ; 76 77 /⇤ Frage nach P r i m z a h l h a e u f u n g e n ⇤/ 4 78 p r i n t f ( " Wollen S i e auch a l l e P r i m z a h l z w i l l i n g e , d r i l l i n g e und v i e r l i n g e \ k l e i n e r g l e i c h %u ausgeben ?\ n Fuer Z w i l l i n g e geben S i e b i t t e <z >, \ D r i l l i n g e <d>, V i e r l i n g e <v> und zum Beenden e i n \n\ anderes b e l i e b i g e s Zeichen ein : " ,n ) ; 79 80 81 82 83 s c a n f ( "%c " ,& wahl ) ; 84 85 /⇤ Z w i l l i n g e ⇤/ 86 87 i f ( wahl==’ z ’ ) { f o r ( i =0; i +2<MAXLAENGE; i ++) { 88 89 90 91 92 93 94 95 96 97 } 98 } i f (PF [ i ] ! = 1 && PF [ i +2]!=1) { p r i n t f ( " %u , %u ; \ n" ,PF [ i ] , PF [ i + 2 ] ) ; } 99 /⇤ D r i l l i n g e ⇤/ 100 101 i f ( wahl==’ d ’ ) { 102 103 104 i f ( n>=7) p r i n t f ( " 3 , 5 , 7 ; \ n" ) ; 105 106 f o r ( i =0; i +6<MAXLAENGE; i ++) { 107 108 109 i f (PF [ i ] ! = 1 && PF [ i +2]!=1 && PF [ i +6]!=1) { 110 111 112 113 } 114 115 } 116 } p r i n t f ( " %u , %u , %u ; \ n" ,PF [ i ] , PF [ i +2] ,PF [ i + 6 ] ) ; 117 /⇤ V i e r l i n g e ⇤/ 118 119 i f ( wahl==’ v ’ ) { f o r ( i =0; i +8<MAXLAENGE; i ++) { 120 121 122 123 124 i f (PF [ i ] ! = 1 && PF [ i +2]!=1 && PF [ i +6]!=1&& PF [ i +8]!=1) { 125 126 127 128 } 129 130 131 132 133 134 } p r i n t f ( " %u , %u , %u , %u ; \ n" ,PF [ i ] , PF [ i +2] ,PF [ i +6] ,PF [ i + 8 ] ) ; } } p r i n t f ( " \n" ) ; return ( 0 ) ; 3. Dieses Programm berechnet der Fakultätsfunktion rekursiv 1 #include <s t d i o . h> 2 3 4 5 6 long f a k u l t a e t ( short a ) { long e r g e b n i s =1; short i =1; 5 7 8 9 10 11 12 13 14 } i f ( a==0 | | a==1) { return ( 1 ) ; } e r g e b n i s=f a k u l t a e t ( a 1)⇤ a ; return ( e r g e b n i s ) ; 15 16 17 18 i n t main ( void ) { short v a r i a b l e =0; 19 p r i n t f ( " D i e s e s Programm b e r e c h n e t den Wert d e r F a k u l t a e t s f u n k t i o n zu einem \ von Ihnen e i n g e g e b e n e n Wert . \ n B i t t e geben S i e I h r e n Wert e i n : " ) ; 20 21 22 s c a n f ( "%h i " , &v a r i a b l e ) ; 23 24 i f ( v a r i a b l e <0) { p r i n t f ( " D i e s e r Wert i s t u n z u l a e s s i g . Wir beenden das Programm . \ n\n" ) ; return ( 1 ) ; } 25 26 27 28 29 30 31 32 33 34 35 36 i f ( v a r i a b l e >19) { p r i n t f ( " Die e i n g e g e b e n e Zahl i s t zu g r o s s ; das kann u n s e r Computer n i c h t . \ n\ Wir beenden das Programm . \ n\n" ) ; return ( 1 ) ; } 37 p r i n t f ( " Die F a k u l t a e t von %h i l a u t e t : \ n %l i . \ n\n" , variable , fakultaet ( variable ) ) ; 38 39 40 41 42 } return ( 0 ) ; Wir beweisen nun die Ungleichung n! n! = n(n | 1)(n (n/2)n/2 für gerade n 2 N. Zunächst gilt 2) · · · (n/2 + 1) (n/2)(n/2 1) · · · 1 {z }| {z } n/2 Faktoren n/2 Faktoren, 1 n (n 1) (n 2) · · · (n/2 + 1) (n/2 Faktoren) |{z} | {z } | {z } | {z } n/2 (n/2) n/2 n/2 n/2 n/2 . 4. Dieses Programm berechnet den größten gemeinsamen Teiler zweier natürlicher Zahlen ohne den Euklidischen Algorithmus 1 #include <s t d i o . h> 2 3 4 5 i n t main ( void ) { unsigned z a h l 1 =1, z a h l 2 =1 , g g t =1, i =1; 6 7 8 p r i n t f ( " D i e s e s Programm b e r e c h n e t den g r o e s s t e n gemeinsamen T e i l e r \ z w e i e r n a t u e r l i c h e r Zahlen . \ n B i t t e geben S i e I h r e e r s t e Zahl e i n : " ) ; 9 10 s c a n f ( "%u" ,& z a h l 1 ) ; 11 12 p r i n t f ( " B i t t e geben S i e nun I h r e z w e i t e Zahl e i n : " ) ; 13 14 s c a n f ( "%u" ,& z a h l 2 ) ; 15 6 /⇤ P r o b i e r e a l l e p o t e n t i e l l e n T e i l e r durch ⇤/ 16 17 while ( i<=z a h l 1 && i<=z a h l 2 ) { i f ( z a h l 1%i ==0 && z a h l 2%i ==0) { g g t=i ; } i ++; } 18 19 20 21 22 23 24 25 26 p r i n t f ( " Der g r o e s s t e gemeinsame T e i l e r von %u und %u i s t %u . " , z a h l 1 , z a h l 2 , g g t ) ; 27 28 p r i n t f ( " \n\n" ) ; 29 30 31 32 } return ( 0 ) ; 7