User Tools

Site Tools


dydaktyka:cprog:2016:loops-solutions

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
dydaktyka:cprog:2016:loops-solutions [2016/10/27 12:30]
pkleczek
— (current)
Line 1: Line 1:
-====== Pętla for, pętla "​while"​ - rozwiązania i odpowiedzi ====== 
- 
-Laboratorium:​ [[dydaktyka:​cprog:​2016:​loops]] 
- 
-===== Pętla "​for"​ ===== 
- 
-==== Zadanie FOR-1 ==== 
- 
-<code c for-1.c> 
-/* Program oblicza sume liczb naturalnych 1,2,...,10. */ 
- 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int i = 0; 
-    int suma = 0; 
- 
-    for (i = 1; i <= 10; i = i + 1) { 
-        suma = suma + i; 
-    } 
-    ​ 
-    printf("​suma = %d\n", suma); 
- 
-    return 0; 
-} 
-</​code>​ 
- 
-Zwróć uwagę, że równie dobrze można zastosować następującą pętlę ''​for'':​ 
-<code c> 
-    for (i = 0; i < 11; i = i + 1) { 
-        suma = suma + i; 
-    } 
-</​code>​ 
-gdyż dodanie $0$ do zmiennej ''​suma''​ nie zmieni jej wartości, a warunki $i \leq 10$ oraz $i < 11$ są równoważne \\ 
-ALE \\ 
-:!: pierwszy sposób ($i_0 = 0$, $i \leq 10$) lepiej przekazuje **intencję** programisty,​ przez co kod jest bardziej zrozumiały! 
- 
-==== Zadanie FOR-2 ==== 
- 
-<code c for-2.c> 
-/* Program oblicza sume liczb calkowitych z przedzialu <​a,​b>​. */ 
- 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int a = 0; 
-    int b = 0; 
-    int suma = 0; 
- 
-    int i; 
- 
-    printf("​Podaj liczby `a` i `b`: "); 
-    scanf("​%d %d", &a, &b); 
- 
-    for (i = a; i <= b; i = i + 1) { 
-        suma = suma + i; 
-    } 
- 
-    printf("​suma = %d\n", suma); 
- 
-    return 0; 
-} 
-</​code>​ 
-W powyższym przykładzie zmienna ''​i''​ oznacza aktualnie sumowaną liczbę. 
- 
- 
-Zwróć uwagę, że równie dobrze można zastosować następującą pętlę ''​for'':​ 
-<code c> 
-    for (i = 0; i <= b - a; i = i + 1) { 
-        suma = suma + (i + a); 
-    } 
-</​code>​ 
-w którym zmienna ''​i''​ oznacza **indeks** aktualnie sumowanej liczby -- bądź inaczej mówiąc //​odległość aktualnie sumowanej liczby od lewego krańca przedziału (czyli od $a$)//. 
- 
-Podobnie jak w przypadku zadania FOR-1, pierwszy sposób lepiej przekazuje **intencję** programisty,​ jest prostszy do zrozumienia i (w moim odczuciu) bardziej intuicyjny. 
- 
-===== Priorytety operatorów ===== 
- 
-==== Zadanie PRIOR-1 ==== 
- 
-W wyrażeniu ''​3 < x < 6''​ mamy dwa operatory o tym samym priorytecie,​ a kierunek wiązania dla operatora ''<''​ to od-lewej-do-prawej (czyli najpierw obliczana jest wartość tego, co stoi po lewej stronie operatora, a następnie tego co po prawej) -- możemy zatem zapisać ''​3 < x < 6''​ jako ''​(3 < x) < 6''​. 
- 
-W języku C wartość wyrażenia logicznego to albo ''​1''​ albo ''​0''​ (typu całkowitego),​ zatem dla $x = 2$ mamy: \\ 
-''​(3 < 2) < 6''​ ⇔ ''​0 < 6''​ ⇔ ''​1''​ 
- 
-Widać zatem, że w przypadku programowania intuicja matematyczna czasem zawodzi -- o czym zresztą ostrzega nas kompilator: 
-<​code>​ 
-D:​\cb_projects\sample\main.c|10|warning:​ comparisons like '​X<​=Y<​=Z'​ do not have their mathematical meaning [-Wparentheses]| 
-</​code>​ 
- 
-===== Pętla "​while"​ ===== 
- 
-==== Zadanie WHILE-1 ==== 
- 
- 
-<code c while-1_1.c>​ 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int n = 5; 
-    int k = 3; 
-    int iloczyn = 0; 
-    int i = 0;   // ilosc dotychczas zsumowanych `n` 
- 
-    while (i < k) { 
-        iloczyn = iloczyn + n; 
-        i = i + 1; 
-    } 
- 
-    printf("​%d * %d = %d\n", n, k, iloczyn); 
- 
-    return 0; 
-} 
-</​code>​ 
- 
-Inny sposób -- tu zmienna ''​k''​ określa to, ile razy musimy jeszcze dodać ''​n''​! 
-<code c while-1_2.c>​ 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int n = 5; 
-    int k = 3; 
-    int iloczyn = 0; 
-    int k0 = k; // zapamietaj wartosc `k`, bo bedziemy ja modyfikowac... 
- 
-    // tu `k` okresla ile `n` pozostalo nam jeszcze do zsumowania! 
- 
-    while (k > 0) { 
-        iloczyn = iloczyn + n; 
-        k = k - 1; 
-    } 
- 
-    printf("​%d * %d = %d\n", n, k0, iloczyn); 
- 
-    return 0; 
-} 
-</​code>​ 
- 
-===== Pętla "​do-while"​ ===== 
- 
-==== Zadanie DOWHILE-1 ==== 
- 
-<code c dowhile-1.c>​ 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int n; 
- 
-    do { 
-        printf("​Podaj liczbe dodatnia: "); 
-        scanf("​%d",​ &n); 
-    } while (n <= 0); 
- 
-    printf("​OK,​ wpisano %d.\n",​ n); 
- 
-    return 0; 
-} 
-</​code>​ 
- 
-==== Zadanie DOWHILE-2 ==== 
- 
-Na początek kilka słów wstępu: 
- 
-Pętla ''​do-while''​ (podobnie jak każda inna pętla -- ''​for'',​ ''​while''​) wykonuje się dopóki warunek __jest__ spełniony. Nam zależy na wylosowaniu liczby __należącej__ do przedziału $\langle 10, 15 \rangle$, zatem chcemy wykonywać pętlę dopóki wylosowana liczba __nie będzie należeć__ do przedziału $\langle 10, 15 \rangle$. 
- 
-Pseudokod (czyli ogólny schemat) naszego programu wygląda zatem następująco:​ 
-<​code>​ 
-losuj liczbę `n` DOPÓKI `n` spoza przedziału <​10,​15>​ 
-wypisz `n` 
-</​code>​ 
- 
-Najpierw zastanówmy się, jak wygląda zapis $n \in \langle 10, 15 \rangle$ w języku C. Jak już wiesz, nie możemy napisać ''​10 <= n <= 15''​ -- musimy rozbić to na dwie części, ''​10 <= n && n <= 15''​. 
-Jak zatem zapisać warunek //spoza przedziału $\langle 10, 15 \rangle$//? Można na dwa sposoby: 
-  - Skorzystać z operatora negacji: ''​!(10 <= n && n <= 15)''​ 
-  - Skorzystać z [[https://​pl.wikipedia.org/​wiki/​Prawa_De_Morgana#​Logika|I prawa de Morgana]]: $\neg(10 \leq n \leq 15) \Leftrightarrow \neg(10 \leq n \wedge n \leq 15) \Leftrightarrow \neg(10 \leq n) \vee \neg(n \leq 15) \Leftrightarrow 10 > n \vee n > 15$ otrzymując w języku C ''​10 > n || n > 15''​. 
- 
-Przykład programu z wykorzystującego sposób #1: 
-<code c dowhile-2.c>​ 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int n; 
- 
-    do { 
-        n = rand() % 101; 
-        printf("​Wylosowano %d.\n",​ n); 
-    } while (!(10 <= n && n <= 15)); 
- 
-    printf("​OK,​ wylosowano %d.\n",​ n); 
- 
-    return 0; 
-} 
-</​code>​ 
- 
-PS. Nie przejmuj się, że powyższy program zawsze losuje te same liczby w tej samej kolejności -- to działanie celowe :) 
- 
-===== Zadania podsumowujące ===== 
- 
-==== Zadanie STAIRS ==== 
- 
-<code c stairs.c>​ 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int n = 3;  // ilosc stopni 
-    int i_levels, i_dollars; 
- 
-    for (i_levels = 1; i_levels <= n; i_levels = i_levels + 1) { 
-        for (i_dollars = 1; i_dollars <= i_levels; i_dollars = i_dollars + 1) { 
-            printf("​$"​);​ 
-        } 
-        printf("​\n"​);​ 
-    } 
- 
-    return 0; 
-} 
-</​code>​ 
-W powyższym zadaniu zmienne oznaczają: 
-  * ''​i_levels''​ -- który z kolei stopień wyświetlamy w danym obiegu pętli (licząc od góry) 
-  * ''​i_dollars''​ -- który z kolei dolar danego aktualnie "​budowanego"​ stopnia wyświetlamy w danym obiegu pętli (licząc od lewej) 
- 
-==== Zadanie BOX ==== 
- 
-Do tego zadania możemy podejść w następujący sposób -- traktujemy pudełko jak kartkę w kratkę o wymiarze $n \times n$ i uzupełniamy kratki wierszami, zaczynając od lewego górnego rogu, wpisując w kratkę ''​*''​ bądź ''​ ''​. 
- 
-Zatem wyświetlamy ''​*'',​ gdy zachodzi __dowolny__ z poniższych warunków: 
-  * uzupełniamy pierwszy rząd 
-  * uzupełniamy ostatni rząd 
-  * uzupełniamy pierwszą kolumnę 
-  * uzupełniamy ostatnią kolumnę 
-  * uzupełniamy kratkę leżącą na przekątnej naszej kartki 
- 
-W języku C taki sposób rozwiązania wygląda następująco:​ 
-<code c box.c> 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int n = 5;      // rozmiar pudelka (dlugosc krawedzi) 
-    int i_row; ​     // numer aktualnie uzupelnianego rzedu 
-    int i_cell; ​    // numer aktualnie uzupelnianej komorki 
- 
-    for (i_row = 1; i_row <= n; i_row = i_row + 1) { 
-        for (i_cell = 1; i_cell <= n; i_cell = i_cell + 1) { 
-            if (i_row == 1 || i_row == n || i_cell == 1 || i_cell == i_row || i_cell == n) { 
-                printf("​*"​);​ 
-            } else { 
-                printf("​ "); 
-            } 
-        } 
-        printf("​\n"​);​ 
-    } 
- 
-    return 0; 
-} 
-</​code>​ 
- 
-==== Zadanie DIGSUM ==== 
- 
-Pomysł polega na tym, aby sumować cyfry zaczynając od jedności (z użyciem operatora //modulo//) i następnie "​obcinać"​ po jednej pozycji -- właśnie zaczynając od jedności (z użyciem operatora dzielenia): 
-  - $\mod(196, 10) = 6$; w języku C ''​196 / 10''​ wynosi ''​19''​ 
-  - $\mod(19, 10) = 9$; w języku C ''​19 / 10''​ wynosi ''​9''​ 
-  - $\mod(1, 10) = 1$; w języku C ''​1 / 10''​ wynosi ''​0''​ 
- 
-Gdy po (kolejnym) dzieleniu dostaniemy wartość ''​0''​ -- wiemy, że nie zostało już więcej cyfr do sumowania. 
- 
-<code c digsum.c>​ 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int n = 196; 
-    int n0 = n; 
- 
-    // POMYSŁ: "​Odcinaj"​ po jednej cyfrze od końca i zobacz, co 
-    // wlasciwie odcinasz ;) 
- 
-    int sum = 0; 
-    while (n > 0) { 
-        sum = sum + n % 10; // dodaj wartość ostatniej cyfry "​głowy"​ 
-        n = n / 10; // obetnij ostatnią cyfrę "​głowy"​ 
-    } 
- 
-    printf("​Suma cyfr liczby %d to %d.\n",​ n0, sum); 
- 
-    return 0; 
-} 
-</​code>​ 
- 
-==== Zadanie PRIME ==== 
- 
-Krótkie przypomnienie z gimnazjum: [[http://​www.math.edu.pl/​czy-pierwsza|Jak rozpoznać czy liczba naturalna jest pierwsza?]] \\ 
-(W poniższym przykładzie nie bawimy się w warunek $i < \sqrt{n}$, czyli równoważnie $i^2 < n$, tylko po prostu sprawdzamy wszystkie liczby naturalne z przedziału $[2,n-1]$ -- to nie wypływa na poprawność rozwiązania,​ po prostu poniższy warunek jest mniej wydajny, gdyż należy sprawdzić większą liczbę liczb.) 
- 
-<code c prime.c> 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int n; 
-    int i; 
- 
-    printf("​Podaj liczbe calkowita: "); 
-    scanf("​%d",​ &n); 
- 
-    for (i = 2; (i < n) && (n % i != 0); i = i + 1) 
-        ; /* po prostu sprawdz kolejna liczbe... */ 
- 
-    if (i == n) { 
-        // Cala petla zostala wykonana, wiec liczba N nie byla podzielna 
-        // przez zadna z liczb 2, 3, ..., N-1. 
-        printf("​Liczba %d jest pierwsza.\n",​ n); 
-    } else { 
-        printf("​Liczba %d NIE jest pierwsza.\n",​ n); 
-    } 
- 
-    return 0; 
-} 
-</​code>​ 
- 
- 
-==== Zadanie BABSQRT ==== 
- 
-<code c babsqrt.c>​ 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
-int main () 
-{ 
-    double S = 5.0; 
-    double x = S; // krok (1) 
-    double x_prev; ​ // wartość `x` w poprzedniej iteracji 
-    double accuracy = -10e-3; ​  // pozadana dokladnosc obliczen 
- 
-    do { 
-        x_prev = x; 
-        x = (x_prev + S / x_prev) / 2; // krok (2) 
-        printf("​%.6f\n",​ x); 
-    } while (x - x_prev < accuracy);​ //​ krok (3) 
- 
-    printf("​sqrt(%.2f) ~= %.6f\n",​ S, x); 
- 
-    return 0; 
-} 
-</​code>​ 
- 
- 
-==== Zadanie SQUARE ==== 
- 
-<code c square.c>​ 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int row, col; 
- 
-    for (row = 0; row < 3; row++) { 
-        for (col = 0; col < 3; col++) { 
-            printf("​%d",​ (row + col) % 3 + 1); 
-        } 
-        printf("​\n"​);​ 
-    } 
- 
-    return 0; 
-} 
-</​code>​ 
- 
- 
- 
- 
  
dydaktyka/cprog/2016/loops-solutions.1477564219.txt.gz · Last modified: 2020/03/25 11:46 (external edit)