Wykład 2
Transkrypt
Wykład 2
Podstawy programowania Doskonalimy umiejętności Idzie lato, czas na siłownię. Współczynnik BMI (nieaktualny ;) ) 𝐵𝑀𝐼 < = 𝑚𝑎𝑠𝑎 [𝑘𝑔] 𝑤𝑧𝑟𝑜𝑠𝑡 2 [𝑚] 16,0 – wygłodzenie 16,0–16,99 – wychudzenie 17,0–18,49 – niedowagę 18,5–24,99 – wartość prawidłową 25,0–29,99 – nadwagę 30,0–34,99 – I stopień otyłości 35,0–39,99 – II stopień otyłości ≥ 40,0 – III stopień otyłości No to piszemy program Gdyby babcia miała wąsy… Instrukcja if – sposób na sprawdzanie warunków Konstrukcja: if(warunek) { instrukcje gdy warunek spełniony} else {instrukcje gdy warunek NIE spełniony} Gdyby babcia miała wąsy… Część z else jest opcjonalna: if(warunek) { instrukcje gdy warunek spełniony} Podobnie jak nawiasy klamrowe {}. Bez nich wewnątrz if-a wykonana zostanie jedna instrukcja! Gdyby babcia miała wąsy… … if(liczba > 0) cout << „Liczba dodatnia”; cout << „Liczba większa od zera”; Wynik Część „Liczba większa od zera” wykona się zawsze! Niezależnie od wartości zmiennej liczba. Jak to naprawić? Gdyby babcia miała wąsy… … if(liczba > 0) { cout << „Liczba dodatnia”; cout << „Liczba większa od zera”; } Poprawna wersja. Gdyby babcia miała wąsy… Instrukcje if można zagnieżdżać: if(liczba > 5) if(liczba < 10) cout << „Liczba z przedziału (5;10); Gdyby babcia miała wąsy… Ale każdy szanujący się programista zrobi to w ten sposób: if (liczba > 5 && liczba < 10) cout << „Liczba z przedziału (5;10); Dzięki temu maleje ryzyko błędu. Gdyby babcia miała wąsy… To nie zadziała tak, jak nam się wydaje: if(liczba > 5) if(liczba < 10) cout << „Liczba z przedziału (5;10); else cout << „Liczba spoza przedziału”; Gdyby babcia miała wąsy… To nie zadziała tak, jak nam się wydaje: if(liczba > 5) if(liczba < 10) cout << „Liczba z przedziału (5;10); else cout << „Liczba spoza przedziału”; else tyczy się wewnętrznej instrukcji. Gdyby babcia miała wąsy… Jaka jest różnica pomiędzy tymi dwoma podejściami? 1) if (liczba > 0) cout << „Liczba > 0”; if (liczba > 1) cout << „Liczba > 1”; 2) if (liczba > 0) cout << „Liczba > 0”; else if (liczba > 1) cout << „Liczba > 1”; Gdyby babcia miała wąsy… Jaka jest różnica pomiędzy tymi dwoma podejściami? 1) Dla liczba=5: if (liczba > 0) cout << „Liczba > 0”; 1): Wyświetli oba if (liczba > 1) komunikaty cout << „Liczba > 1”; 2) if (liczba > 0) cout << „Liczba > 0”; else if (liczba > 1) cout << „Liczba > 1”; 2): Wyświetli tylko pierwszy komunikat. I będzie szybsze. Instrukcja if – sposób na sprawdzanie warunków Konstrukcja: if(warunek) { instrukcje gdy warunek spełniony} else {instrukcje gdy warunek NIE spełniony} Gdyby babcia miała wąsy… Operator warunkowy Operator warunkowy jest postaci: warunek ? wartość1 : wartość2; Co należy rozmieć jako: jeśli warunek jest prawdziwy to podstaw za wartość wyrażenia wartość1, w przeciwnym wypadku podstaw za wartość wyrażenia wartość2. Można go traktować jako skróconą wersję instrukcji warunkowej if. Przykład: O czytaniu z klawiatury No to piszemy program lepiej Ale i tak do kitu Ma być mniej więcej tak Pętla while Pętla while wykonuje daną instrukcję lub blok instrukcji tak długo jak długo warunek jest spełniony (ma wartość true). Ogólna postać pętli while jest następująca: while (warunek) instrukcja; Pętla while bada prawdziwość warunku jeszcze przed wykonaniem dalszego kodu (na samym jej początku), dlatego też, jeśli warunek ma wartość false to instrukcje zawarte w tej pętli nigdy nie zostaną wykonane. Pętla while - przykład Pętla do while Pętla do while jest odmianą pętli while, a jej ogólna postać jest następująca: do instrukcja; while(warunek); Co należy rozumieć jako: Wykonuj instrukcję dopóki warunek jest prawdziwy. Jako, iż warunek pętli sprawdzany jest na końcu, wykona się ona zawsze przynajmniej raz! Fragment kodu Fragment kodu Wykonuj dopóki warunek jest prawdziwy. A nie przerwij, kiedy warunek! Stąd: dopóki wzrost > 2.4 m LUB wzrost < 0 Pętla for Ogólna postać pętli for jest następująca: for (wyrażenie początkowe; wyrażenie warunkowe; wyrażenie modyfikujące) instrukcja_do_wykonania; W miejsce wyrażenia początkowego wstawiane jest wyrażenie stosowane do zainicjalizowania zmiennej służącej jako licznik wykonań pętli. Wyrażenie warunkowe określa jaki warunek musi być spełniony by przejść do kolejnego przebiegu pętli. Wyrażenie modyfikujące natomiast używane jest do modyfikacji wartości zmiennej będącej licznikiem pętli. Zainicjowanie licznika warunkuje jak daleko jest on widoczny! Instrukcja break Instrukcja break powoduje przerwanie wykonywania pętli i opuszczenie jej bloku. Instrukcja continue Instrukcja continue powoduje przejście do kolejnej iteracji danej pętli (chyba, że była to jej ostatnia iteracja). Doskonalimy nasz żart Zgadnij moją liczbę Program losuje liczbę z przedziału od 1 do 100. Zadaniem użytkownika jest odgadnięcie wylosowanej liczby — wpisuje swoją propozycję a program stwierdza, czy proponowana liczba jest równa, mniejsza lub większa od wylosowanej. Zgadnij moją liczbę Zgadnij moją liczbę Będzie 1. 2. 3. 4. nam potrzeba: Wylosować liczbę. Odczytać liczbę od użytkownika Porównać liczby. I wykonywać to, aż zgadnie Piszemy program Pamiętaj o zerowaniu zmiennych. Zmienne nazywamy tak, aby wiedzieć jakie wartości przechowują. Piszemy program Pamiętasz \”Hansa Klosa\” ? Losujemy liczbę Losujemy liczbę Komputery nie są dobre w losowaniu i wymyślaniu losowych numerów. Stąd liczby losowe i tak muszą zostać „wyliczane”. Ale tak, że zwykły człowiek nie jest w stanie przewidzieć kolejnej liczby. Przed erą komputerów za liczby losowe brano końcówki numerów telefonów w książce telefonicznej. Piszemy program Inicjalizacja Losowanie Losujemy liczby srand(666); To inicjalizacja generatora liczb pseudolosowych (tzw. zalążek). Dla testowania programów – ustawiamy na stałą wartość (np. 666). Dzięki temu co uruchomienie programu otrzymamy ten sam zestaw liczb pseudolosowych. Ale w programach produkcyjnych zwykle chcemy mieć pełną losowość. Losujemy liczby srand( int (unsigned) time( NULL )); wylosowana = rand() % 100 + 1 Ograniczamy do 100 liczb (reszta z dzielenia przez 100 to liczby 0, 1, 2,…,99) Dodajemy 1, aby przesunąć przedział losowania. Losujemy liczby srand( (unsigned) time( NULL )); Takie coś za każdym razem ustali nam zalążek na aktualną wartość zegara systemowego (ściślej: liczbę sekund, jaka upłynęła od 1 stycznia 1970 r.) Ale dalej nie działa, jak chcemy, bo rand() losuje liczby z przedziału 0…32767 (co najmniej) Jak to ograniczyć? Ulepszamy program Nowe nagłówki Lepsze losowanie Lepsze losowanie Poznaj swój kompilator CodeBlocks martwi się, że mamy zmienne, których nie wykorzystujemy. Te informacje tutaj pozawalają na zmniejszenie liczby wyrwanych włosów przy naprawianiu programu! Poznaj swój kompilator Dodajemy pętlę Dopóki liczba jest nieodgadnięta … Dodajemy pętlę Wczytuj nową liczbę od użytkownika Dodajemy pętlę Porównuj wczytywaną z wylosowaną No to kolejne wyzwanie Napisać program symulujący działanie kalkulatora. Możliwe operacje (dwuargumentowe): Dodawanie Dzielenie (ze sprawdzeniem, czy nie dzielimy przez 0) Mnożenie Odejmowanie No to kolejne wyzwanie No to kolejne wyzwanie 1. 2. Zapytaj użytkownika o pierwszą liczbę i ją zapamiętaj. Zapytaj użytkownika o działanie 1. 3. Zapytaj użytkownika o drugą liczbę i ją zapamiętaj. 1. 4. 5. Jeśli działanie będzie niedozwolone, wyświetl błąd i powtórz. Jeśli ta liczba to 0 ORAZ działanie to dzielenie, wyświetl błąd i zakończ program. Wyświetl wynik. Zapytaj użytkownika, czy chce liczyć raz jeszcze. Które zmienne są lepsze? int a int b int c double pierwsza double druga double wynik float pierwsza float druga float wynik Które zmienne są lepsze? int a int b int c float pierwsza float druga float wynik double pierwsza double druga double wynik 1. Nazwy zmiennych „mówią”, czym one są (kod samokomentujący się) 2. Skoro dzielimy, to musimy użyć typu zmiennoprzecinkowego. Pierwsza przymiarka Pierwsza przymiarka Apostrofy, bo to znak! Pierwsza przymiarka Sposób na zatrzymanie programu. Pierwsza przymiarka Ale ten kod jest brzydki! Instrukcja wyboru switch Instrukcja switch pozwala w wygodny sposób sprawdzić ciąg warunków i wykonać różny kod w zależności od tego czy są one fałszywe czy prawdziwe. Jej postać jest następująca: Druga przymiarka Jaka zmienna „rozdziela” program break jest cholernie istotny! Gdyby nie było breaków Wykonały się wszystkie instrukcje Coś i tak popsuliśmy Brakuje komunikatu o błędzie Trzecie i ostatnie podejście default zwykle umieszczamy na końcu. A jak wykonywać obliczenia wiele razy? do { … } while(wybor == ’p’ || wybor == ’P’) Zabezpieczenie przed małymi/wielkimi literami. Kto chce być milionerem? Gramy w Lotto 1. 2. 3. 4. Przywitajmy użytkownika. Spytajmy ile liczb obstawia Wylosuj tyle liczb ile trzeba (i z odpowiedniego zakresu). Zapytaj użytkownika, czy chce losować dalej. Ogólny sposób losowania liczb rand() % DŁUGOŚĆ_PRZEDZIAŁU + POCZĄTEK DŁUGOŚĆ_PRZEDZIAŁU = ile liczb jest możliwych do wylosowania POCZĄTEK Mały = gdzie zaczynamy haczyk – co jest, jeśli przedział przechodzi przez 0? const – oznacza stałą. To taka zmienne, tylko jej nie da się zmienić w programie. Nie zapomnijmy o inicjowaniu generatora liczb pseudolosowych! Jak być milionerem na serio W pętli for możemy korzystać ze zmiennych. Dzięki temu nie musimy znać liczby przebiegów przy projektowaniu programu Czemu użyłem stałych? Jak być milionerem na serio W pętli for możemy korzystać ze zmiennych. Dzięki temu nie musimy znać liczby przebiegów przy projektowaniu programu Czemu użyłem stałych? Żeby program móc łatwo przerobić np. na Multi Lotka. Jak być milionerem na serio Jak być milionerem na serio Jak być milionerem na serio Na co warto iść do kina? Lubię kino. Ale nie wiem, na co iść do kina. Jest sporo serwisów z ocenami, ale który tak naprawdę daje radę? Poza tym – zmieniają się często, więc nie wiem ile ich jest. Jak tutaj sobie poradzić i policzyć średnią? A przy okazji mieć informację o maksymalnej i minimalnej ocenie? Liczymy średnią ocen Zaczynamy standardowo. Witamy użytkownika i deklarujemy zmienne. Liczymy średnią ocen W pętli dopóki nie 0: pytamy, czytamy, dodajemy i liczymy Liczymy średnią ocen Na końcu liczymy średnią i ją wyświetlamy. Fajne? Tyle, że nie działa: Fajne? Tyle, że nie działa: 1. Liczenie średniej do chrzanu. 2. Numer oceny do kitu. Liczymy średnią ocen Do nieokreślonej wartości dodajemy coś. Więc wynik jest też nieokreślony! Liczymy średnią ocen Tak lepiej. Liczymy średnią ocen Tak lepiej. Ale dalej źle. Liczymy średnią ocen A tak najlepiej: Korzystamy z operatora ++ I dzielimy przez (ileOcen-1) aby nie liczyć ostatniego zera. Liczymy średnią ocen nan = Not A Number. A po polsku – symbol nieoznaczony. Pozostał tylko jeden problem, ale jego już możecie rozwiązać sami. A może przy okazji policzymy min oraz max? Aby to zrobić najpierw trzeba by pamiętać, jakie są maksymalne i minimalne wartości możliwe do zapisania w odpowiednich typach danych. Pamiętacie? A może przy okazji policzymy min oraz max? Aby to zrobić najpierw trzeba by pamiętać, jakie są maksymalne i minimalne wartości możliwe do zapisania w odpowiednich typach danych. Pamiętacie? Ja też nie. Bo i po co? A może przy okazji policzymy min oraz max? Dodajemy nagłówek: #include <limits> A następnie korzystamy z konstrukcji: numeric_limits < double >::max(); numeric_limits < double >::min(); A może przy okazji policzymy min oraz max? Dodajemy nagłówek: #include <limits> A następnie korzystamy z konstrukcji: numeric_limits < double >::max(); numeric_limits < double >::min(); Zamiast double może być float, int, cokolwiek. A może przy okazji policzymy min oraz max? Algorytm wyznaczania max jest następujący: 1. 2. 3. Za aktualne maksimum przypisz jakąś małą liczbę. Porównuj kolejne liczby z aktualnym maksimum. Jeśli liczba jest większa, to zamień aktualne maksimum. Algorytm max 1 -3 5 15 0 Algorytm max 1 -3 5 MAX: -100 15 0 Algorytm max 1 -3 5 1 >? MAX MAX: -100 15 0 Algorytm max 1 -3 5 1 > MAX MAX: 1 15 0 Algorytm max 1 -3 5 -3 >? 1 MAX: 1 15 0 Algorytm max 1 -3 5 15 5 >? 1 MAX: 1 0 Algorytm max 1 -3 5 15 5>1 MAX: 5 0 Algorytm max 1 -3 5 15 >? 5 MAX: 5 15 0 Algorytm max 1 -3 5 15 > 5 MAX: 15 15 0 Algorytm max 1 -3 5 15 0 0 >? 5 MAX: 15 Algorytm max 1 -3 5 MAX: 15 15 0 Uzupełniamy kod o min i max Niejako przy okazji – widzimy łańcuchowanie operatora strumieniowego << Pobawimy się we wróżkę Pamiętacie program „zgadnij moją liczbę”? Gdzie komputer losował liczbę i podawał „za dużo” lub „za mało”, a my zgadywaliśmy liczbę? A może by tak zrobić mu psikus? I odwrócić rolę? Napiszmy program, gdzie to człowiek wymyśla liczbę, a komputer ją odgaduje*. * Zakładając, że użytkownik nie oszukuje Pobawimy się we wróżkę Czyżbyśmy Algorytm 1. 2. 3. 4. 5. znowu zaprzęgli randoma do roboty? może wyglądać tak: Każ użytkownikowi wymyślić sobie liczbę. Wylosuj liczbę z przedziału. Spytaj użytkownika, czy to ta Jeśli tak – otwórz szampana. Jeśli nie – zgaduj do skutku. Pobawimy się we wróżkę Pobawimy się we wróżkę Pętla nieskończona while(true) może być zakończona przez instrukcję break. Pobawimy się we wróżkę Pobawimy się we wróżkę To się może nigdy nie skończyć! Pobawimy się we wróżkę A jak to zrobić lepiej? Odpowiedzią (BST). jest drzewo poszukiwań binarnych Pobawimy się we wróżkę 42 Czy Twoja liczba to 50? Pobawimy się we wróżkę 42 Czy Twoja liczba to 50? Nie, za dużo! Pobawimy się we wróżkę Czy Twoja liczba to (0+50)/2 = 25? 42 Pobawimy się we wróżkę Czy Twoja liczba to (0+50)/2 = 25? Nie, za mało! 42 Pobawimy się we wróżkę Czy Twoja liczba to (25+50)/2 = 37? 42 Pobawimy się we wróżkę Czy Twoja liczba to (25+50)/2 = 37? Nie, za mało! 42 Pobawimy się we wróżkę Czy Twoja liczba to (37+50)/2 = 43? 42 Pobawimy się we wróżkę Czy Twoja liczba to (37+50)/2 = 43? Nie, za dużo! 42 Pobawimy się we wróżkę Czy Twoja liczba to (37+43)/2 = 40? 42 Pobawimy się we wróżkę Czy Twoja liczba to (37+43)/2 = 40? Nie, za mało! 42 Pobawimy się we wróżkę Czy Twoja liczba to (40+43)/2 = 41? 42 Pobawimy się we wróżkę Czy Twoja liczba to (40+43)/2 = 41? Nie, za mało! 42 Pobawimy się we wróżkę Czy Twoja liczba to (41+43)/2 = 42? 42 Pobawimy się we wróżkę Czy Twoja liczba to (41+43)/2 = 42? Tak, zgadza się! 42 Pobawimy się we wróżkę Zawsze pytamy o połowę dostępnego przedziału. Ale jak to zrealizować w C++? 42 Pobawimy się we wróżkę