Przed zajęciami laboratoryjnymi zapoznaj się z następującymi pozycjami literatury:
1. Wykład z przedmiotu „Podstawy programowania”
2. J. Grębosz „Symfonia C++” tom 1. Oficyna Kallimach, Kraków, 1999
Rozdziały: 2.3, 2.4, 2.5 , 2.7, 2.9, 2.10, 4.1.
Przygotowując się do laboratorium przeanalizuj podane poniżej przykłady, odpowiedz na pytania, rozwiąż testy i napisz odpowiednie programy. Po zajęciach zrób zadania podane w ostatnim punkcie tego opracowania.
Przykłady i pytania
1. Instrukcje iteracyjne - trzy rodzaje pętli: while, do-while, for
Przykład L3_F0_P1 Przeanalizuj program i odpowiedz na pytania
// L3_F0_P1.cpp
// Program wypisuje liczby od 1 do 20 uzywajac petli while
#include<iostream>
using namespace std;
int main()
{
int i = 1; // definicja i inicjalizacja zmiennej i
while( i <= 20 ) // poczatek petli while
{
cout << i << " "; // wypisanie wartosci zmiennej i oraz spacji
i++; // zwiekszenie i. Rownowazne z i = i + 1; albo i +=1;
} // koniec petli while
cout << endl; // przejscie do nowej linii
system("pause");
return 0;
}
Pytania
a) Jak zastąpić blok ITERACJA przez równoważną instrukcję do-while?
b) Jak zastąpić blok ITERACJA przez równoważną instrukcję for( pole1 ; pole2 ; pole3 ). Wypełnij pola.
c) Jak zastąpić blok ITERACJA przez równoważną pętlę nieskończoną while(1) i instrukcję break.
d) Jak zastąpić blok ITERACJA instrukcją for oraz instrukcją continue, tak aby program wypisywał liczby od 20
do 1 z pominięciem liczby 13.
Skompiluj i uruchom programy i sprawdź poprawność odpowiedzi.
Odpowiedzi
a) do {cout << i << " "; i++; } while( i <= 20 );
b) for( ; i<=20; cout << i << " ", i++);
c) while(1){ cout << i << " "; if (i==20) break; i++;}
d) for( i=20; i>= 1; i--) { if (i==13) continue; cout << i << " ";}
S t r o n a | 1 WETI Politechnika Gdańska, POP v.1.5.2
2. Błędy numeryczne w obliczeniach na liczbach zmiennoprzecinkowych
Przykład L3_F0_P2 Przeanalizuj program i odpowiedz na pytania
/*
* L3_F0_P2.cpp
*
* PROGRAM DWUKROTNIE OBLICZA SKONCZONA SUME CIAGU:
* S = 1./1 + 1./2 + 1./3 + 1./4 + ... + 1./n gdzie n=100000000
* Kropki po jedynkach we wzorze wskazuja, ze nie sa to obliczenia na liczbach
* calkowitych ( dla nich wynik bylby staly S=1 ).
* W pierwszej petli for sumowanie rozpoczyna się od najwiekszego skladnika sumy.
* W drugiej petli for sumowanie rozpoczyna się od najmniejszego skladnika sumy.
*/
#include<iostream>
using namespace std;
int main()
{
float fx = 0;
for (long int i=1; i<=100000000; i++)
{
fx = fx + 1./i;
}
cout << fx << endl;
float fy = 0;
for (long int i=100000000; i>=1; i--)
{
fy = fy + 1./i;
}
cout << fy << endl;
system("pause");
return 0;
}
Pytania
a) Sprawdź w Literaturze, jak są reprezentowane liczby zmiennoprzecinkowe. Czy wszystkie liczby rzeczywiste są dokładnie reprezentowane w zapisie binarnym używanym w komputerze?
b) Skompiluj, uruchom program i porównaj obliczone sumy. Czy obie sumy są równe? Jeżeli nie są równe, to dlaczego?
c) Zastąp typ float typem double, ponownie skompiluj i uruchom program. Porównaj wyniki. Który z użytych typów liczb zmiennoprzecinkowych dokładniej reprezentuje liczby rzeczywiste?
Odpowiedzi
a) Nie.
b) Nie. Z powodu kumulujących się błędów numerycznych.
c) Typ double.
S t r o n a | 2 WETI Politechnika Gdańska, POP v.1.5.2
3. Pętle zagnieżdżone (pętle wewnątrz innych pętli)
Przykład L3_F0_P3 Program rysuje brzeg prostokąta znakami ’x’. Długości boków użytkownik podaje na standardowym wejściu jako liczby całkowite z przedziału [2, 60].
Przeanalizuj program i odpowiedz na pytania
// L3_F0_P3.cpp
/* Program rysuje brzeg prostokąta znakami ’x’.
xxxxxxxxxxxxxxxxxxxxx
x x
x x b
x x
xxxxxxxxxxxxxxxxxxxxx
a
*/
#include<iostream>
using namespace std;
int main()
{
int a; // dlugosc boku a
int b; // dlugosc boku b
// wczytaj boki: a oraz b
cout << "Podaj dlugosc boku a [2,60]: ";
cin >> a;
cout << "Podaj dlugosc boku b [2,60]: ";
cin >> b;
// zakładamy ze podane dane sa poprawne
for(int i = 1; i <= a; i++)
cout << 'x'; // rysowanie gornej linii
cout << endl;
for(int j = 2; j <= b-1; j++) // petla kolejnych wierszy - rysowanie linii bocznych
{
cout << 'x'; // znak ’x’ na lewym brzegu
for(int i = 2; i < a; i++) // wypisanie a-2 spacji we wnętrzu j-tego wiersza
cout << ' ';
cout << 'x' << endl; // znak ’x’ na prawym brzegu
}
for(int i = 1; i <= a; i++)
cout << 'x' ; // rysowanie dolnej linii
cout << endl;
system("pause");
return 0;
}
Pytania
a) Skompiluj i uruchom program dla ( a = 60, b = 20) oraz ( a = 2, b = 2). Jaka jest kolejność wypisywania znaków na ekranie?
b) W programie użyto 4 pętli for, przy czym pętla druga jest zagnieżdżona w pętli trzeciej. Czy ilość zagnieżdżeń jest ograniczona? Czy można zagnieżdżać w sobie pętle różnego typu?
c) Napisz program L3_F0_P3.cpp tak, aby użyć tylko dwóch instrukcji iteracji (można dodatkowo użyć instrukcji warunkowych). Ponownie skompiluj i uruchom program.
Odpowiedzi
a) Wierszami, z góry na dół. W wierszu, od lewej do prawej.
b) Nie. Tak.
S t r o n a | 3 WETI Politechnika Gdańska, POP v.1.5.2
//-------------------------------------------------------------rysowanie--------
for(int y = 1; y <= b; y++) // petla wierszy
{
for(int x = 1; x <= a; x++) // petla kolumn
{
if( (y == 1) || (y == b) ) // pierwszy i ostatni wiersz rysujemy
cout << 'x'; // jako linie ciagla ( znaki ‘x’)
else
if( (x == 1) || (x == a) ) // pierwsza i ostatnia kolumne rowniez
cout << 'x'; // rysujemy jako linia ciagla ( znaki ‘x’)
else
cout << ' '; // pozostaly obszar wypelniamy spacjami
} // koniec petli kolumn
cout << endl; // po kazdym wierszu przejscie do nowej linii
}
//--------------------------------------------------------------------------------
Testy
1. Co wypiszą na ekranie następujące iteracje?
a) int i=5;
while (i >= 0) {
cout << i+1 << ' ';
i--;
}
cout << endl;
b) int j=8;
do {
cout << '-';
j--;
if (j<5) continue;
cout << '+';
} while (j);
cout << endl;
c) int x=1, max=1;
for (int k=0; k<3 ; k+=1){
while (x <= max) cout << x++;
cout << endl;
max++;
x=1;
}
2. Czy poniższe pętle są równoważne, w sensie wypisywanych wyników, z iteracją z Testu 1 a)?
a) for (int i=7, k=2 ; ; k++){
cout << i-k+1 << ' ';
if (k > i-1) break;
}
b) int i=5;
do {
cout << i+1 << ' '; i-=1;
} while (i);
c) int k=2;
for (k--, k--; k<6; cout << 6-k << ' ', k+=1);
3. Które pętle kompilator uzna za nieprawidłowe ze względu na błędy syntaktyczne?
a) for(;0;)for(;1;)for(;2;);
b) for(int a=11, b=a+4; ; b-=1, cout<<b);
c) for(int a=2,,a++) if(a==2) break;
d) while(1)(cout << "hello\n"; break;)
e) do {cout << "witaj\n"; break;} while{1};
S t r o n a | 4 WETI Politechnika Gdańska, POP v.1.5.2
4. Wskaż pętle, które nigdy się nie kończą:
Pętla 1:
int k = 12; while (k){ cout << "Jupi!\n"; }
Pętla 2:
for (int i = 0; i < 100; i = i-2)
cout << ":) ";
Pętla 3:
int progress = 1;
cout << "Loading, please wait";
do {
cout << ".";
if (progress == 100) break;
progress = progress + 2;
} while (1);
Pętla 4:
int j = 15;
do {
if (j%2 == 0) j = j-2;
else j = j-1;
} while (j);
Pętla 5:
int j = 15;
do {
if (j%2 == 0) j = j-2;
else j = j-1;
} while (j = 8);
5. Podaj liczby, jakie należy wczytać w poniższych pętlach, aby pętle zakończyły się:
a) int c, d;
do {
cin >> c >> d;
d = d+1;
} while ( !(c==d-3 and d==5));
b) int m, n;
do {
cin >> m >> n;
} while ( n!=m-2 or m!=5);
Odpowiedzi
Test 1:
a)
6 5 4 3 2 1
b)
-+-+-+-----
c)
1
12
123
Test 2: a) tak, b) nie, c) tak.
Test 3: a), b) – prawidłowe; c), d), e) – nieprawidłowe.
Test 4: Pętle 1, 2, 3 i 5 nie kończą się. Pętla 4 kończy się dla każdej początkowej dodatniej liczby j .
Test 5: a) c = 2, d = 4, b) m = 5, n = 3.
S t r o n a | 5 WETI Politechnika Gdańska, POP v.1.5.2
Zadania przygotowujące do laboratorium
Napisz, uruchom i przetestuj następujące programy
Zadanie L3_F0_Z1
Napisz program wyznaczający sumę n iloczynów liczb naturalnych o postaci:
= 1 ∙ 2 + 2 ∙ 3 + ⋯ + ( + 1)
gdzie n jest podawane z klawiatury przez użytkownika.
Program nie wykonuje obliczeń i podaje komunikat "Zła wartość n", gdy n nie należy do przedziału [2, 100].
Przykład:
dla n = 2 wynik jest w postaci:
= 1 ∙ 2 + 2 ∙ 3 = 6
dla n = 10 wynik jest w postaci:
= 1 ∙ 2 + 2 ∙ 3 + ⋯ + 10 ∙ 11 = 440
Polecenie: W podanym niżej szkielecie programu L3_F1_S1.cpp uzupełnij linie oznaczone przez //$$$. Nie zmieniaj pozostałych części szkieletu.
// L3_F0_S1.cpp Suma iloczynow – Iteracja ograniczona
#include<iostream>
using namespace std;
int main()
{
int i; // licznik petli
int n; // dana wejsciowa n
int suma ; // suma iloczynow
//---------------------------------------------------------------------------------
cout << "Program wyznacza sume 1*2+2*3+...+n*(n+1)" << endl;
cout << endl << "Podaj wartosc n: "; //$$$ wczytanie n
if ( ) { //$$$ czy n jest poprawne?
suma = ; //$$$
i = ; //$$$
while( ) { //$$$ petla - obliczanie sumy
suma = //$$$
i++; // to samo co i=i+1; albo i += 1;
}
cout << endl << " 1*2+...+" << << '*' << << " = " << << endl; //$$$
}
else
cout << endl << << endl; //$$$
//---------------------------------------------------------------------------------
cout << endl;
system ("pause");
return 0;
}
S t r o n a | 6 WETI Politechnika Gdańska, POP v.1.5.2
// L3_F0_Z1.cpp Suma iloczynow – Iteracja ograniczona
#include<iostream>
using namespace std;
int main()
{
int i; // indeks petli
int n; // dana wejsciowa n
int suma ; // suma iloczynow
//-----------------------------------------------------------------------------------
cout << "Program wyznacza sume 1*2+2*3+...+n*(n+1)" << endl;
cout << endl << "Podaj wartosc n: "; cin >> n; //$$$
if ( n >= 2 && n <= 100 ) { //$$$
suma = 0 ; //$$$
i = 1 ; //$$$
while( i <= n ) { //$$$
suma = suma + i*(i+1);
i++;
}
cout << endl << " 1*2+...+" << n << '*' << n+1 << " = " << suma << endl; //$$$
}
else cout << endl << "Zla wartosc n" << endl; //$$$
//------------------------------------------------------------------------------------
cout << endl;
system ("pause");
return 0;
}
Zadanie L3_F0_Z2
Napisz program, który na przemian dodaje i odejmuje kolejno wczytane liczby całkowite, aż do wczytania liczby zero. Po podaniu każdej kolejnej liczby program wyświetla aktualną sumę.
// L3_F0_Z2.cpp Program dodaje i odejmuje (na przemian) liczby - Iteracja warunkowa
#include<iostream>
using namespace std;
int main( )
{
int liczba;
int suma = 0;
int znak = 1;
do {
if (znak > 0) cout << "Dodaj ";
else cout << "Odejmij ";
cout << "liczbe calkowita: ";
cin >> liczba;
suma = suma + znak*liczba;
cout << "Suma: "<< suma << endl << endl;
znak = -znak;
} while( liczba != 0 );
system("pause");
return 0;
}
S t r o n a | 7 WETI Politechnika Gdańska, POP v.1.5.2
Napisz program rysujący trójkąt prostokątny równoramienny za pomocą znaku ’o’. Długość przyprostokątnych zadaje użytkownik jako liczbę całkowitą w zakresie od 1 do 30. Program sprawdza poprawność wczytanej liczby.
Przykład: Wynik działania programu dla n = 7
ooooooo
oooooo
ooooo
oooo
ooo
oo
o
// L3_F0_Z3.cpp Rysowanie Trojkata - Petle zagniezdzone
#include<iostream>
using namespace std;
int main()
{
char znak = 'o';
int n; // licznik linii = dlugosc przyprostokatnej
cout << "Podaj dlugosc przyprostokatnej [1, 30]: ";
cin >> n;
if( (n < 1) || (n > 30) )
{
cout << "Blad: dlugosc przyprostokatnej spoza zakresu" << endl;
system("pause");
exit(0);
}
// ----------------------------------------------------------rysowanie-------
while (n) { // petla liczaca linie, petla trwa dopoki n rozne od zera
for(int i = 1; i <= n; i++)
cout << znak; // petla rysujaca jedna linie
cout << endl; // przejdz do nastepnej linii
n--; // zmniejsz licznik n = n-1;
}
system("pause");
return 0;
}
Zadanie L3_F0_Z4
Niech
= 1
oraz
1
=
+
Dla danego n (liczba naturalna, 0 < n < 11) obliczyć n pierwszych wyrazów ciągu liczb rzeczywistych
, … , oraz
wyświetlić je w kolejnych liniach na ekranie z dokładnością 4 miejsc po przecinku.
Przykład:
Wejście:
Wyjście:
3
2.0000
4.5000
13.8333
S t r o n a | 8 WETI Politechnika Gdańska, POP v.1.5.2
//L3_F0_Z4.cpp - Wypisywanie wyrazow ciagu wg wzoru
#include<iostream>
#include<iomanip>
using namespace std;
int main ()
{
int n, i=1;
double a=1;
cout << "Podaj n : " ;
cin >> n;
if( n<=0 || n>=11 )
{
cout << "zle dane\n\n";
system("PAUSE");
exit(0);
}
cout << fixed << setprecision(4);
while (n--)
{ // wartosc a po prawej stronie wyrazenia jest elem. ciagu z poprzedniej iteracji, a = a*i + 1./i; // natomiast po lewej stronie jest elementem ciagu wyznaczanym w biezacej iteracji i = i + 1;
cout << setw(15) << a << endl;
}
system("PAUSE");
return 0;
}
Zadania do samodzielnego rozwiązania po laboratorium
Zadanie L3_F3_Z1
Oblicz przybliżoną wartość funkcji sinus dla kąta xr podanego w radianach jako liczba rzeczywista. Przybliżenie wartości funkcji wyznacz na podstawie jej rozwinięcia w szereg potęgowy:
( ) = 1 − 3! + 5! −...=
= # + #$ + # + …
Iteracje są kontynuowane dopóki wyraz wi szeregu jest większy od zadanej dokładności eps. Skorzystaj z faktu, że
'(
= 1
# = &
2
*
−1 ∙ #
−1 (2 − 2)(2 − 1) '(
> 1
co oznacza, że kolejny wyraz szeregu można obliczyć na podstawie wartości wyrazu poprzedniego.
Wejście: xr oraz eps (obie liczby rzeczywiste np. xr = 30.0, eps = 1e-8).
Wyjście: wartości funkcji sinus wyznaczone odpowiednio na podstawie szeregu oraz przy pomocy funkcji sin z biblioteki <cmath>. Obie liczby wypisz w formacie wykładniczym (10 miejsc po przecinku). Podaj liczbę wyrazów szeregu większych od eps.
Testując program porównaj wyniki dla różnych wartości eps.
S t r o n a | 9 WETI Politechnika Gdańska, POP v.1.5.2
Napisz program tablicujący funkcję sinus w zakresie od 0 do 360 stopni z krokiem 5 stopni. Obok wartości kąta w stopniach oraz wartości funkcji wypisywanych w równych kolumnach, z lewej strony ekranu należy dodatkowo rysować szkic wykresu funkcji wykorzystując znak ’*’ (patrz rysunek). Przesunięcie gwiazdki o odpowiednią ilość znaków wylicz na podstawie wartości funkcji. Przyjmij, że przedział [-1,1], do którego należą wartości funkcji, odpowiada 60 znakom na ekranie.
Przykład:
x sin(x) -1 0 1
-----------------------------------------------------------------------------
0.000 0.000 *
5.000 0.087 *
10.000 0.174 *
15.000 0.259 *
20.000 0.342 *
25.000 0.423 *
30.000 0.500 *
. . . .
. . .
Zadanie L3_F3_Z3
Ciąg Collatz’a jest ciągiem danym następującym wzorem
1
+
*
, = - 2 +
.'/ + 01 2 3 45/ 2
3+ + 1 .'/ + 01 2 13 45/ 2
Zauważ, że kolejne wyrazy ciągu Collatz’a mogą przyjmować różne wartości w zależności od wartości pierwszego wyrazu c 0.
Przykład:
c 0 = 20 C20 = (20, 10, 5, 16, 8, 4, 2, 1)
c 0 = 19 C19 = (19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, . . . , 1)
c 0 = 18 C18 = (18, 9, 28, 14, 7, 22, . . . , 1)
Napisz program, który wypisuje elementy ciągu Collatz’a zaczynającego się od podanej na wejściu programu liczby całkowitej c 0 będącej pierwszym wyrazem ciągu. Program powinien zakończyć wypisywanie, gdy wartość kolejnego wyrazu będzie miała wartość równą 1.
Zadanie L3_F3_Z4
Hipoteza Collatz’a mówi, że niezależnie od jakiej liczby c 0 zaczniemy, zawsze dojdziemy do wyrazu o wartości równej 1. Napisz program, który dla każdego 1 < c 0 < 104 sprawdza, czy hipoteza Collatz’a jest prawdziwa.
Hipotezę udowodniono dotychczas dla liczb mniejszych niż 20*258. Program powinien wyznaczyć c 0, z podanego powyżej zakresu, dla którego wygenerowany ciąg ma najwięcej elementów oraz podać liczbę tych elementów.
Zastanów się czy jest gwarancja, że program, który napisałeś w zadaniu L3_F3_Z3 jest poprawny? Czy zatrzyma się on dla każdych danych wejściowych? Jeżeli nie, to jak można zabezpieczyć się przed jego ewentualnym
„zapętleniem”, czyli nieskończonym działaniem?
S t r o n a | 10 WETI Politechnika Gdańska, POP v.1.5.2