Podstawowe elementy programu patrz:następne2 slajdy

Transkrypt

Podstawowe elementy programu patrz:następne2 slajdy
Podstawowe elementy programu
Zestaw komend stojący do dyspozycji programisty
• zależy od języka programowania;
• jest ograniczony;
• jest na tyle bogaty, że daje się z nich złożyć (jak z klocków) sensowne
programy.
Umiejętność programowania jest sztuką odpowiedniego układania tych klocków.
Do typowych komend należą:
patrz: n
astępne
2 slajdy
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 2
Podstawowe elementy programu
Komendy proste:
SCHEMAT
przypisanie
wartości
zmiennej
C
?
zmienna ← wartość
?
zmienna = wartość ;
Podstawowe elementy programu
Komendy złożone (strukturalne):
SCHEMAT
pętla
C
?
warunek | ¬warunek
?
ciało
while ( warunek ) {
ciało
}
?
rozgałęzienie
?
warunek | ¬warunek
?
?
instrukcja1 instrukcja2
if ( warunek ) {
instrukcja1
} else {
instrukcja2
}
?
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 4
Rozgałęzienie warunkowe
pełne
?
warunek | ¬warunek
?
?
instrukcja1 instrukcja2
?
uproszczone
?
warunek | ¬warunek
?
instrukcja1
?
?
if ( warunek ) {
instrukcja1
} else {
instrukcja2
}
if ( warunek ) {
instrukcja1
}
Budowa prostych programów
Zagnieżdżanie instrukcji:
?
war1 | ¬war1
?
war | ¬war2
2
?
?
instr1
instr2
while (war1 ) {
if (war2 ) {
instr1
}
else {
instr2
}
}
?
?
schemat
C
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 6
Przykład programu: największy wspólny dzielnik
a=A; b=B;
while (a != b) {
if (a > b) a = a-b;
else b = b-a;
}
!=
— oznaczenie relacji „nierówne” w języku C
A
180
180
180
180
180
180
180
180
B
a b
48
48 180 48
48 132 48
48 84 48
48 36 48
48 36 12
48 24 12
48 12 12
Przykład programu: NWD wielu liczb
nwd(a1 , a2 , a3 , a4 ) = nwd nwd nwd(a1 , a2 ), a3 , a4
nwd(a1 , a2 , . . . , an ) = nwd(nwd(nwd(a1 , a2 ), . . .), an )
wczytaj a; ile wczyt = 1;
while (ile wczyt < n){
wczytaj b; ile wczyt = ile wczyt+1;
while (a != b) {
if (a > b) a = a-b;
else b = b-a;
}
}
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 8
Poprawność algorytmów
Przykład: (potęgowanie przez wielokrotne mnożenie)
M
?
wynik ← 1; w ← wykładnik
wynik · podstawaw = podstawawykladnik
?
w>0 | w=0
wynik · podstawa · podstawaw−1 =
= podstawawykladnik
?
wynik ← wynik · podstawa
wynik · podstawaw−1 = podstawawykladnik
?
w ←w−1
?
wynik = podstawawykladnik
Metoda niezmienników
DEFINICJA:
M
Niezmiennik pętli while (war) instr — dowolna własność P zmiennych programu taka, że
jeśli przed wykonaniem instr spełnione jest P & war,
to po wykonaniu instr spełnione jest P
TWIERDZENIE:
M
Jeśli P jest niezmiennikiem pętli while (war) instr i po inicjalizacji
pętli jest spełniony, to na wyjściu z pętli jest spełnione P & ¬war .
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 10
Niezmienniki spoza informatyki
2 m/sek
-
....................
??? m/sek
6 ...........
......
...........
.
.
.
.
.
.
.
.
.
.
.
.
.
.....
6
12 m
......
.
.....
.
10 m
.
.
......... .........
.
.
.
.
.
.
?
?
.
.
.
.
.
.
.
.
.
··································
mv 2
+ mgh
energia = energia kinetyczna + energia potencjalna =
2
— jest stała.
v2
(2 m/sek)2
2
+ 10 m/sek · 12 m =
+ 10 m/sek2 · 10 m
2
2
√
v = 44 m/sek ≈ 6.63 m/sek
Metoda niezmienników
W trakcie obliczeń pętli wartości zmiennych stale się zmieniają, ale pozostaje
w mocy pewien związek między nimi — niezmiennik. Z tego faktu wynikają
własności pętli.
............. A
A — założenia wstępne
B — niezmiennik
C — niezmiennik + warunek
D — stan wynikowy
?
inicjalizacja
-
.............. B
?
warunek | ¬warunek
............. C
?
ciało
............. D
Trzeba zbadać:
1. przejście przez inicjalizację z A do B,
2. przejście przez ciało z C do B,
3. implikację B & warunek ⇒ C,
4. implikację B & ¬warunek ⇒ D.
?
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 12
Co liczy dany program?
?
n ← 500 000; a ← 0; b ← 0; c ← 1; d ← 6
B
?
b+c¬n | b+c>n
?
a ← a + 1; b ← b + c
?
c←c+d
?
d←d+6
?
Ręczna symulacja: wartości
zmiennych w B w kilku pierwszych
obrotach pętli:
a
b
c d
0
0
1 6
1
1
7 12
2
8 19 18
3 27 37 24
4 64 61 30
5 125 91 36
6 216 127 42
7 343 169 48
Zależności między wartościami
zmiennych:
b = a3
d = 6 · (a + 1)
3
c = (a + 1) − a3 = 3a2 + 3a + 1
Co liczy dany program?
Czy B jest niezmiennikiem?
?
n ← 500 000; a ← 0; b ← 0; c ← 1; d ← 6
3
b = a & d = 6(a + 1)
& c
= 3a2 + 3a + 1
B
?
b+c¬n | b+c>n
zmienne nieprimowane —
przed przejściem przez ciało pętli
zmienne primowane —
po przejściu przez ciało pętli
Wiemy:
b = a3 & d = 6(a + 1) &
c = 3a2 + 3a + 1 & b + c ¬ n
?
a ← a + 1; b ← b + c
oraz
a′ = a + 1
b′ = b + c
?
c←c+d
c′ = c + d
d′ = d + 6
Stąd wnioskujemy:
?
d←d+6
?
?
b′ =
a′ & d′ =
6(a′ + 1) &
2
?
3a′ + 3a′ + 1
c′ =
3
?
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 14
Co liczy dany program?
?
n ← 500 000; a ← 0; b ← 0; c ← 1; d ← 6
3
b = a & d = 6(a + 1)
& c
= 3a2 + 3a + 1
B
?
b+c¬n | b+c>n
?
a ← a + 1; b ← b + c
?
c←c+d
?
d←d+6
D
b = a3 & d = 6(a + 1) &
c = 3a2 + 3a + 1 & b + c > 500 000
D
& a3 ¬ 500 000 < (a + 1)3
D
√
& a ¬ 3 500 000 < a + 1
D
&a=
?
√
3
Program
oblicza
a=
j√
k
3
500 000
=
= ⌊79.37 . . .⌋
= 79
500 000
⌊x⌋ — część całkowita liczby rzeczywistej
Przykłady programów
/* A : m ­ 1 */
k=0; p=1; q=2;
/* B : p = 3k ¬ m & q = 2 · 3k */
while (p+q <= m) {
k=k+1; p=p+q; q=p+p;
}
/* D : k = ⌊log3 m⌋ */
Dowieść (zmienne primowane oznaczają nowe wartości):
1. m ­ 1 & k ′ = 0 & p′ = 1 & q ′ = 2
′
′
p′ = 3k ¬ m & q ′ = 2 · 3k
?
⇒
2. p = 3k ¬ m & q = 2 · 3k & p + q ¬ m &
k ′ = k + 1 & p′ = p + q & q ′ = p′ + p′
′
′
p′ = 3k ¬ m & q ′ = 2 · 3k
3. p = 3k ¬ m & q = 2 · 3k & p + q > m
?
⇒
?
⇒
k = ⌊log3 m⌋
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 16
Przykład programu: największy wspólny dzielnik
/* A > 0 & B > 0 */
a=A; b=B;
/* a > 0 & b > 0 & nwd(a, b) = nwd(A, B) */
while (a != b) {
if (a > b) a = a-b;
else b = b-a;
}
/* a = nwd(A, B) */
Przykłady programów
Dzielenie całkowite z resztą:
Dzielenie dokładne:
Dzielenie z resztą:
q jest ilorazem n przez k
⇐⇒
k·q =n
q jest ilorazem całkowitym a r jest resztą n przez k
⇐⇒
k·q+r =n&0¬r <k
Dzielenie z resztą łatwo zorganizować przez wielokrotne odejmowanie:
• znaleźć jakiekolwiek q i r spełniające k · q + r = n & 0 ¬ r ,
• tak długo odejmować dzielnik k od r, aż dodatkowo będzie spełnione
r < k (zakładamy k > 0).
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 18
Przykłady programów
Dzielenie całkowite z resztą (zał.: k > 0):
A
?
q ← 0; r ← n
n­0&k>0
1. Przejście
od A do B
-
k·q+r =n&0¬r
B
?
k¬r | r<k
k·q+r =n&0<k ¬r
k · (q + 1) + (r − k) = n & 0 ¬ r − k
C
C
?
r ←r−k
k · (q + 1) + r = n & 0 ¬ r
k·q+r =n&0¬r
E
B
?
q ←q+1
D
?
k·q+r =n&0¬r <k
2. Wynikanie
B&k¬r⇒C
3. Przejście
od C do B
(przez E)
4. Wynikanie
B&r<k⇒D
Przykłady programów
Dzielenie całkowite z resztą:
/* n ­ 0 & k > 0 */
q = 0; r = n;
/* n = k · q + r & 0 ¬ r */
while (r>=k) {
q = q+1; r = r-k;
}
/* n = k · q + r & 0 ¬ r < k */
Dla poprawności należy sprawdzić:
1. jeśli n ­ 0 & k > 0, to po wykonaniu q = 0; r = n;
jest n = k · q ′ + r′ & 0 ¬ r′
2. jeśli n = k · q + r & 0 ¬ r & r ­ k, to po wykonaniu
q = q+1; r = r-k; jest n = k · q ′ + r′ & 0 ¬ r′
3. jeśli n = k · q + r & 0 ¬ r & r < k,
to n = k · q ′ + r′ & 0 ¬ r′ < k
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 20
Przykład programu: pierwiastek kwadratowy
√
Napisać algorytm, który dla danej liczby naturalnej n oblicza ⌊ n⌋, czyli
część całkowitą pierwiastka kwadratowego z n.
/* n ­ 0 */
a=0;
h=1;
while (n >= h*h)
h = 2*h;
/* h ­ 1 & a2 ¬ n < (a + h)2 */
while (h>1) {
h = h/2;
if (n >= (a+h)*(a+h))
a = a+h;
}
2
/* a2 ¬ n
√< (a + 1) */
/* a = ⌊ n⌋ */
a2 ¬ n < (a√+ 1)2
⇒ a = ⌊ n⌋
h­1&
a2 ¬ n < (a + h)2 &
h¬1
⇒ a2 ¬ n < (a + 1)2
Niezmiennik pętli:
h ­ 1 & a2 ¬ n < (a + h)2
Przykład: pierwiastek kwadratowy
√
Napisać algorytm, który dla danej liczby naturalnej n oblicza ⌊ n⌋, czyli
część całkowitą pierwiastka kwadratowego z n.
/* n ­ 0 */
a=0;
h=1;
while (n >= h*h)
h = 2*h;
/* h ­ 1 & a2 ¬ n < (a + h)2 */
while (h>1) {
h = h/2;
if (n >= (a+h)*(a+h))
a = a+h;
}
2
/* a2 ¬ n
√< (a + 1) */
/* a = ⌊ n⌋ */
Żeby nie podnosić sumy do
kwadratu w każdym obrocie pętli, wprowadzamy nowe zmienne: x = a2 , y = a · h, z = h2 .
Wtedy:
(a + h) · (a + h)
=x+2·y+z
Nowy niezmiennik pętli:
h ­ 1 & a2 ¬ n < (a + h)2
& x = a2 & y = a · h
& x · z = y2
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 22
Przykład: pierwiastek kwadratowy
√
Napisać algorytm, który dla danej liczby naturalnej n oblicza ⌊ n⌋, czyli
część całkowitą pierwiastka kwadratowego z n.
/* n ­ 0 */
a=0; x=0; y=0;
h=1; z=1;
while (n >= h*h) {
h = 2*h; z = 4*z; }
/* h ­ 1 & a2 ¬ n < (a + h)2 & x = a2
& y = a · h & z = h2 & x · z = y 2 */
while (h>1) {
h = h/2; y=y/2; z=z/4;
if (n >= x+2*y+z) {
a = a+h; x = x+2*y+z; y = y+z; }
}
2
/* a2 ¬ n
√< (a + 1) */
/* a = ⌊ n⌋ */
Przykład: pierwiastek kwadratowy
√
Napisać algorytm, który dla danej liczby naturalnej n oblicza ⌊ n⌋, czyli
część całkowitą pierwiastka kwadratowego z n.
/* n ­ 0 */
a=0; x=0; y=0;
h=1; z=1;
while (n >= h*h) {
h = 2*h; z = 4*z; }
/* h ­ 1 & a2 ¬ n < (a + h)2 & x = a2
& y = a · h & z = h2 & x · z = y 2 */
while (h>1) {
h = h/2; y=y/2; z=z/4;
if (n >= x+2*y+z) {
a = a+h; x = x+2*y+z; y = y+z; }
}
2
/* a2 ¬ n
√< (a + 1) */
/* a = ⌊ n⌋ */
Przy takim niezmienniku:
n ­ h2 ⇐⇒ n ­ z
h ­ 1 ⇐⇒ z ­ 1
h=1 ⇒ y=a
więc zmienne a i h już
nie są potrzebne
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 24
Przykład: pierwiastek kwadratowy
√
Napisać algorytm, który dla danej liczby naturalnej n oblicza ⌊ n⌋, czyli
część całkowitą pierwiastka kwadratowego z n.
/* n ­ 0 */
a=0; x=0; y=0;
h=1; z=1;
while (n >= z) {
h = 2*h; z = 4*z; }
/* z ­ 1 & x ¬ n < x + 2 · y + z & x = a2
& y = a · h & z = h2 & x · z = y 2 */
while (z>1) {
h = h/2; y=y/2; z=z/4;
if (n >= x+2*y+z) {
a = a+h; x = x+2*y+z; y = y+z; }
}
/* y ¬ n√< (y + 1)2 */
/* y = ⌊ n⌋ */
Przykład: pierwiastek kwadratowy
√
Napisać algorytm, który dla danej liczby naturalnej n oblicza ⌊ n⌋, czyli
część całkowitą pierwiastka kwadratowego z n.
/* n ­ 0 */
x=0; y=0; z=1;
while (n >= z)
z = 4*z;
/* z ­ 1 & x ¬ n < x + 2 · y + z
& x · z = y 2 */
while (z>1) {
y=y/2; z=z/4;
if (n >= x+2*y+z) {
x = x+2*y+z; y = y+z;
}
}
/* y ¬ n√< (y + 1)2 */
/* y = ⌊ n⌋ */
Nowy program z dowodem poprawności, nadal liczący część całkowitą pierwiastka kwadratowego.
n
35
x
0
y
0
16
16
8
4
5
25
z
1
4
16
64
16
4
1
Wykład 2. INSTRUKCJE I NIEZMIENNIKI, str. 26
Jak pisać programy z dowodami?
• Z tego, że asercje rozmieszczone w programie są niezmiennikami,
wnioskujemy o jego poprawności. Np. w powyższym programie z niezmienniczości
asercji n ­ 0 na wejściu wynika niezmienniczość asercji
√
a = ⌊ n⌋ na wyjściu, czyli fakt, że program liczy część całkowitą pierwiastka z n.
• Konstruując program najpierw piszemy odpowiednie asercje; potem
tak dobieramy komendy, żeby te asercje były niezmiennicze.
• Program powstaje więc razem z dowodem swojej poprawności; dowód
zawsze „o pół kroku wcześniej”.
• Asercje mogą również pomóc w kontrolowanym transformowaniu programu do innej postaci.

Podobne dokumenty