Funkcje - wstęp
Przegląd zagadnień
Wyodrębnioną część programu, stanowiącą pewną całość, mającą ustalony
sposób wymiany danych (informacji) z pozostałymi częściami programu, która
jest reprezentowana przez jednoznaczną nazwę i może być wywołana dowolną
ilość razy w innej części programu nazywamy funkcją. Prościej można
powiedzieć, że funkcja to ciąg instrukcji, który posiada nazwę, czyli jest to
podprogram.
W języku C# funkcje możemy tylko definiować wewnątrz klasy lub struktury.
Funkcję zdefiniowaną w bloku kodu klasy lub struktury nazywamy metodą.
Używanie funkcji w programie posiada następujące zalety:
Możliwość wykorzystania wielokrotnie tego samego kodu bez
konieczności jego przepisania.
Uproszczenie kodu przez podział złożonego problemu na mniejsze i
spójne logicznie fragmenty.
Możliwość powtórnego użycia kodu w innym programie, dzięki
tworzeniu bibliotek funkcji.
Łatwiejsze testowanie i wykrywanie błędów logicznych - łatwiej
przetestować mniejsze kawałki kodu, które mają realizować konkretne
zadania.
Program staje się mniejszy, mniej linii kodu, przez co staje się
łatwiejszy do zrozumienia.
Możliwość rozdzielenia pracy przy tworzeniu programu wśród kilku
osób.
Zmniejszenie rozmiaru pliku wynikowego.
Po zakończeniu tego rozdziału studenci nauczą się:
Definiować metody w języku C#.
Wywoływać metodę.
Określać wartość przekazywaną przez metodę.
Wymieniać informację między metodami przy pomocy zmiennych
współdzielonych.
Rozumieć mechanizm obsługi wyjątków w przypadku zgłoszenia
wyjątku wewnątrz metody.
Tworzyć bibliotekę własnych metod przy pomocy Visual Studio i z
niej korzystać.
Uwaga:
W kursie tym omawiane jest tylko tworzenie metod statycznych. Metody nie
statyczne i różnice miedzy metodami statycznymi i nie statycznymi jest
dokładnie omówione w kursie "Programowanie obiektowe".
Definicja metody w języku C#
W celu zdefiniowania metody stosujemy następującą notację:
static typ_zwracany Nazwa(lista_argumentów)
{
//ciało metody
}
W powyższym zapisie jako typ_zwracany można podać dowolny typ,
zarówno typ wartości jak i typ referencyjny. Przekazywanie wartości przez
metodę zostanie dokładnie omówione w dalszej części tego rozdziału. Do tego
czasu będziemy zakładać, że funkcja nie zwraca żadnej wartości. Realizuje się
to przez podanie jako typ_zwracany słowa kluczowego void.
Słowo nazwa oznacza nazwę metody, która w jednoznaczny sposób
identyfikuje metodę. Nadawanie nazw metodom podlega tym samym regułom,
co tworzenie identyfikatorów zmiennych, czyli nazwa może składać się z cyfr,
liter i znaku podkreślenia, nazwa nie może rozpoczynać się od cyfry, nie może
być słowem kluczowym i musi być unikalna w danym bloku kodu. Ostatnia
reguła w przypadku metod ma jednak pewne wyjątki. Zostanie dokładnie to
omówione w następnym rozdziale przy omawianiu tematu "Przeciążenie nazwy
metody". Przy tworzeniu nazw metod należy stosować format PascalCase.
Po nazwie metody umieszczamy nawisy okrągłe. Jeżeli metoda przyjmuje
jakieś argumenty, to należy ich definicję umieści wewnątrz tych nawiasów.
Przekazywanie argumentów do funkcji zostanie przedstawione w rozdziale
dziewiątym " Przesyłanie argumentów do metody".
Następnie po nawiasach okrągłych umieszczana jest definicja - przepis, co
metoda ma realizować, czyli ciąg instrukcji które metoda wykonuje. Instrukcje
te umieszcza się w nawiasach klamrowych. Czynność tę wykonywałeś już
wielokrotnie definiując metodę Main.
W przedstawionej definicji metody występuje jeszcze słowo kluczowe
static
. Dokładna jego interpretacja zostanie przedstawiona w kursie
"Programowanie obiektowe". Na potrzeby tego kursu należy przyjąć, że musi
ono występować.
W przypadku metod, które będą wywoływane z metod definiowanych w innej
klasie przed słowem static należy umieścić jeszcze słowo kluczowe
public
. Dokładne znaczenie słowa kluczowego public zostanie równie
omówione w kursie "Programowanie obiektowe".
Poniżej przedstawiono przykładowy kod definiujący dwie metody: metodę
Main oraz metodę Powitanie.
class Program
{
static void Main()
{
//ciało metody Main
}
public static void Powitanie()
{
Console.WriteLine("Cześć!!!");
}
}
Wszystkie funkcje w języku C# są metodami, czyli muszą być definiowane
wewnątrz klasy lub struktury.
Metod nie wolno definiować wewnątrz innej metody, muszą być definiowane
bezpośrednio w bloku kodu klasy lub struktury.
Wywołanie metody
Wywołanie metody polega na wykonaniu ciągu instrukcji podanych w bloku
kodu metody w miejscu wywołania. Metodę wywołuje się przez podanie jej
nazwy zakończonej parą nawiasów okrągłych. W przypadku, gdy metoda
pobiera argumenty, odpowiednie wartości lub zmienne należy podać wewnątrz
nawiasów okrągłych. Więcej na temat przesyłania argumentów do metody
będzie podane w rozdziale dziewiątym "Przesyłanie argumentów do metody".
Przykład wywołania metody Powitanie w metodzie Main przedstawiono
poniżej.
class Program
{
static void Main()
{
Powitanie();
Console.ReadKey()
}
public static void Powitanie()
{
Console.WriteLine("Cześć!!!");
}
}
W wyniku działania powyższego programu na ekranie pojawi się napis:
Cześć!!!
W przypadku gdy metoda jest zdefiniowana w innej klasie niż metoda ją
wywołująca, przy wywołaniu nazwę metody należy poprzedzić nazwą klasy, w
której jest zdefiniowana. Między nazwą klasy, a nazwą metody umieszczamy
znak kropki (operator dostępu do składowej). Ilustruje to poniższy przykład.
class Program
{
static void Main()
{
KlasaPomocnicza.Powitanie();
Console.ReadKey()
}
}
class KlasaPomocnicza
{
public static void Powitanie()
{
Console.WriteLine("Cześć!!!");
}
}
Oczywiście, co już było wspominane wcześniej w tym rozdziale, w przypadku
metod które będą wywoływane z metod definiowanych w innej klasie, przed
słowem static koniecznie trzeba umieścić słowo kluczowe public.
W przypadku gdy definicja klasy znajduje się w innej przestrzeni nazw, należy
również uwzględnić nazwę przestrzeni nazw:
NazwaPrzestrzeniNazw.NazwaKlasy.NazwaMetody();
lub użyć dyrektywy using.
Wartość zwracana przez metodę
Wartość przekazana lub inaczej zwrócona przez metodę jest to wartość, która
jest wstawiana w miejscu wywołania metody i jest to wartość wyrażenia
występującego z prawej strony instrukcji return, należącej do instrukcji
danej metody. Nazwa typu umieszczona przed nazwą metody określa typ
wartości przekazanej. Typ wartości przekazanej musi być zgodny z typem
wyniku wyrażenia stojącego obok instrukcji return - musi być identyczny
lub musi istnieć konwersja niejawna z typu wyniku wyrażenia do typu wartości
zwracanej. Rozważmy to na przykładzie. Napiszmy metodę, która przekazuje
liczbę lat, które upłynęły od chrztu Polski. W celu uzyskania bieżącego roku
użyjemy następującej konstrukcji: DateTime.Now.Year. Metoda
przekazuje liczbę całkowitą i jej definicja może wyglądać następująco:
static int LiczbaLat()
//brak średnika!!!
{
int iloscLat = DateTime.Now.Year - 966;
return iloscLat;
}
Metoda LiczbaLat przekazuje liczbę całkowitą i obok instrukcji return
stoi zmienna typu całkowitego. Powyższą funkcję można zapisać krócej:
static int LiczbaLat()
{
return DateTime.Now.Year - 966;
}
Powyższą metodę możemy wykorzystać w następujący sposób:
int n = LiczbaLat();
Console.WriteLine("Liczba lat od chrztu Polski: {0}",
n);
lub krócej:
Console.WriteLine("Liczba lat od chrztu Polski: {0}",
LiczbaLat());
W obu przypadkach na ekranie pojawi się napis (zakładając że obecny rok to
2006)
Liczba lat od chrztu Polski: 1040
Funkcję również możemy wywołać wewnątrz wyrażenia. Załóżmy, że od
chrztu Polski rozpoczęto usypywać kopiec i co roku do kopca dodawano 243
kamienie. W celu wypisania na ekranie z ilu kamieni aktualnie składa się
kopiec możemy użyć następującego kodu.
int liczbaKamieni = 243 * LiczbaLat();
Console.WriteLine("Ilość komieni z których składa się
¬kopiec wynosi: {0}", liczbaKamieni);
lub krócej
Console.WriteLine("Ilość komieni z których składa się
¬kopiec wynosi: {0}", 243 * LiczbaLat());
Instrukcja return oprócz zwrócenia wartości powoduje natychmiastowe
wyjście z funkcji. Rozważmy na przykład funkcję obliczającą silnię. Można ją
zaimplementować w następujący sposób:
Uwaga:
Silnia dla liczby n całkowitej nieujemnej oznaczamy znakiem wykrzyknika i
określamy następującym wzorem:
static long Silnia()
{
uint n;
Console.Write("Podaj n: ");
n = Convert. ToUInt32(Console.ReadLine());
if(n<2)
return 1;
long iloczyn = 1;
for(uint i = 2;i <= n; i++)
{
iloczyn *= i;
}
return iloczyn;
}
W powyższym przykładzie, jeżeli użytkownik nada zmiennej n wartość jeden
lub zero, to metoda wykona instrukcję return 1, która spowoduje wyjście z
metody oraz przekazanie wartości 1 przez metodę. Instrukcje zaznaczone
czcionką pogrubioną nie zostaną wykonane.
,...
3
,
2
,
1
*
)
1
(
*
...
*
2
*
1
0
1
!
n
dla
n
n
n
dla
n
W przypadku gdy jako nazwa typu przekazywanego przez metodę pojawi się
słowo void, przyjmuje się, że metoda nie zwraca żadnej wartości. W bloku
kodu "metody void" może pojawić się instrukcja return. Oznacza ona tylko
wyjście z metody i nie może obok niej pojawić się żadne wyrażenie. Za słowem
return trzeba od razu postawić średnik.
Zmienne współdzielone i lokalne
Zmienne zdefiniowane wewnątrz bloku metody lub jej podblokach noszą nazwę
zmiennych lokalnych. Zmienne lokalne są dostępne tylko w bloku metody
gdzie zostały zdefiniowane, a dokładniej można je używać od miejsca definicji
do końca bloku gdzie zostały zdefiniowane.
static void Metoda()
{
...
int x = 2;
...
{
...
int y = 1;
...
}
...
}
W miejscu końca bloku kodu, pamięć zajmowana przez zmienne lokalne
zdefiniowane w danym bloku zostaje zwolniona, dlatego też często fragment
kodu od miejsca definicji zmiennej do końca bloku, w którym została
zdefiniowana, nazywamy czasem życia zmiennej. Należy pamiętać, że
zwolnienie pamięci zajmowanej przez zmienną typu referencyjnego, nie jest
równoznaczne z zwolnieniem obiektu, do którego zmienna zawierała
odwołanie.
Zmienne możemy również definiować bezpośrednio w bloku klasy lub
struktury. Zmienne takie definiujemy podobnie jak zmienne lokalne, z tym że
całą definicję poprzedzamy słowem static. Zmienne te są wspólne dla
"Czas życia"
zmiennej y
"Czas życia"
zmiennej x
wszystkich metod danej klasy, dlatego można je nazwać zmiennymi
współdzielonymi. Troszeczkę upraszczając możemy założyć, że zmienne
współdzielone są dostępne od początku działania programu do jego końca we
wszystkich metodach danej klasy. Mogą służyć one do wymiany informacji
między różnymi metodami.
...
class Program
{
static int Main(string[] args)
{
Console.Write("Podaj liczbę n: ");
n = Convert.ToUInt32(Console.ReadLine());
Console.WriteLine("{0}! = {1}",n,Silnia());
Console.ReadKey();
return 0;
}
static uint n; //definicja zmiennej współdzielonej
static ulong Silnia()
{
ulong iloczyn = 1;
for(uint i = 2;i<=n;i++)
iloczyn*=i;
return iloczyn;
}
}
W powyższym przykładzie zmienna współdzielona n jest używana zarówno w
metodzie Silnia jak i metodzie Main. Jak widać nie ważna jest kolejność
definicji metody i zmiennej współdzielonej. Zmienna współdzielona jest
dostępna dla wszystkich metod danej klasy.
Zmienna współdzielona może być również dostępna dla metod innych klas.
Definicję takiej zmiennej należy wtedy poprzedzić słowem kluczowym
public
. Odwołując się do zmiennej współdzielonej zdefiniowanej w innej
klasie, jej nazwę należy poprzedzić nazwą klasy, w której jest zdefiniowana i
znakiem kropki. W przypadku gdy klasy znajdują się w różnych przestrzeniach
nazw nie wolni zapomnieć o nazwie przestrzeni nazw lub jej "zaimportowaniu"
przy pomocy dyrektywy using .
NazwaPrzestrzeni.NazwaKlasy.NazwaZmiennej;
Zmienna lokalna może mieć tą samą nazwę co zmienna współdzielona.
Jest to wyjątek od zasady, że w danym bloku kodu, dotyczy to również bloków
zagnieżdżonych, nie można nadać jednego identyfikatora dwóm różnym
elementom. Nadanie zmiennej lokalnej nazwy takiej samej jak nazwa zmiennej
współdzielonej nazywamy przesłonięciem nazwy. W metodzie wewnątrz której
zdefiniowana jest zmienna lokalna o identycznym identyfikatorze, jaki ma
zmienna współdzielona, w celu odwołania się do zmiennej współdzielonej
należy użyć konstrukcji:
NazwaKlasy.NazwaZmiennejWspoldzielonej.
class Klasa
{
...
static int nazwa = 10;
...
static int Metoda()
{
...
int nazwa = 200;
Console.WriteLine(nazwa);
//200
Console.WriteLine(Klasa.nazwa);
//10
...
}
}
Uwaga:
Zmienne współdzielone najczęściej nazywane są polami statycznymi. Pola
statyczne i ich prawdziwa istota i zastosowanie zostanie dokładnie omówione w
kursie "Programowanie obiektowe".
Zgłoszenie wyjątku w metodzie
W przypadku gdy wewnątrz metody zostanie zgłoszony wyjątek, na początku
sprawdzane jest, czy instrukcja powodująca zgłoszenie wyjątku znajduje się w
bloku try i z tym blokiem związany jest blok catch obsługujący zgłoszony
wyjątek. Jeżeli taki blok istnieje wyjątek zostaje obsłużony. Natomiast gdy
instrukcja powodująca wyjątek nie znajduje się w żadnym bloku try lub z
żadnym blokiem try w którym znajduje się kod zgłaszający wyjątek nie jest
skojarzony blok catch obsługujący dany wyjątek, program wraca w miejsce
wywołania danej metody i traktuje instrukcję wywołania metody, jako
instrukcję powodującą zgłoszenie wyjątku. Podczas powrotu do miejsca
wywołania metody, wszystkie zmienne lokalne danej metody są usuwane -
pamięć przez nie zajmowana jest zwalniana. Poszukiwanie bloku catch
obsługującego zgłoszony wyjątek, odbywa się przez łańcuch funkcji
wywołujących aż do metody Main. Jeżeli również w metodzie Main
zgłoszony wyjątek nie jest przechwycony program kończy działanie.
Proces przeglądania łańcucha wywołań funkcji w celu znalezienia
odpowiedniego bloku catch, wraz ze zwolnieniem pamięci zajmowanej przez
zmienne lokalne poszczególnych funkcji nazywamy zwijaniem stosu.
Pytania sprawdzające
1. Co to jest metoda?
Odp.
Najprościej metoda to funkcja zdefiniowana w klasie, czyli jest to
wyodrębnioną część programu, stanowiącą pewną całość, mającą ustalony
sposób wymiany danych (informacji) z pozostałymi częściami programu,
która jest reprezentowana przez jednoznaczną nazwę i może być wywołana
dowolną ilość razy w innej części programu oraz jest składową klasy lub
struktury.
2. Kiedy zwalniana jest pamięć zajmowana przez zmienne lokalne?
Odp.
Pamięć zajmowana przez zmienne lokalne, zwalniana jest na końcu bloku w
którym zdefiniowano daną zmienną.
3. Do czego służy instrukcja return?
Odp.
Instrukcja return ma dwa cele. Pierwszy, przekazanie do metody
wywołującej wartości, drugi wyjście z (zakończenie) metody.
4. Jakim słowem oznaczamy, że funkcja nie przekazuje żadnej wartości?
Odp.
Jako typ zwracany w przypadku gdy metoda nie przekazuje żadnej wartości,
używamy słowa void.
5. Jak wywołujemy metodę która jest zdefiniowana w innej klasie?
Odp.
W przypadku gdy definicja metody znajduje się w innej klasie, aby ją
wywołać, trzeba jej nazwę poprzedzić nazwą klasy w której jest
zdefiniowana i znakiem kropki. Dodatkowo jeśli klasa, w której
zdefiniowano metodę, znajduje się w innej przestrzeni nazw niż klasa
metody wywołującej, nazwę klasy poprzedzamy nazwą przestrzeni nazw i
znakiem kropki.
6. Co to jest proces zwijania stosu?
Odp.
Proces przeglądania łańcucha wywołań funkcji w celu znalezienia
odpowiedniego bloku catch, wraz ze zwolnieniem pamięci zajmowanej
przez zmienne lokalne poszczególnych funkcji nazywamy zwijaniem stosu.
Laboratorium
Ćwiczenie 1:
Napisz program wspierający pracę kasjera. Program pobiera cenę towaru
zakupionego przez klienta oraz kwotę którą wpłaca klient, następnie wypisuje
cenę brutto i kwotę podatku od danej ceny brutto oraz minimalną ilość
banknotów i monet którą należy wydać klientowi w postaci reszty. Program
podziel na metody:
metodę pobierającą cenę netto i obliczającą cenę brutto. Po obliczeniu
ceny brutto wypisuje ją na ekranie i pobiera kwotę wpłaconą przez
klienta. W przypadku gdy cena brutto towaru jest większa od kwoty
wpłaconej zgłoś wyjątek. Stawkę podatku przechowuj w stałej
nazwanej StawkaPodatku.
metodę wypisującą na ekranie cenę brutto, cenę netto, kwotę wpłaconą
przez klienta i kwotę podatku.
metodę wypisującą jak wydać resztę klientowi. Zakładamy, że chcemy
resztę wydać przy użyciu minimalnej ilości banknotów i monet.
Najpierw wydajemy banknot lub monetę o największym
dopuszczalnym nominale. Czynność powtarzamy, aż do wydania nic
nie pozostanie. Algorytm powyższy funkcjonuje na zasadzie, że
wykonuje się działanie, które wydaje się najlepsze w danej chwili, nie
uwzględniając tego, jak to wpłynie na wynik(wydajność) w
przyszłości. Algorytmy działające według tej zasady nazywamy
algorytmami zachłannymi (greedy algorithm).
metody Main, która wywołuje w pętli powyższe metody. Metoda
Main również obsługuje wyjątek zgłoszony przez metodę obliczającą
cenę brutto towaru.
1. Uruchom Visual Studio
Naciśnij przycisk Start systemu Windows, wybierz Wszystkie Programy
następnie Microsoft Visual Studio 2005/ Microsoft Visual Studio 2005.
2. Utwórz nowy projekt
a. Z menu File wybierz New/Project...
b. W oknie dialogowym New Project określ następujące właściwości:
i. typu projektu: Visual C#/Windows
ii. szablon: Console Application
iii. lokalizacja: Moje Dokumenty\Visual Studio 2005\Projects\
iv. nazwa projektu: Kasjer.
v. nazwa rozwiązania: Lab8
3. Zdefiniuj trzy zmienne współdzielone typu decimal: cenaBrutto i
kwotaWplacona, cenaNetto.
static decimal cenaBrutto,kwotaWplacona, cenaNetto;
4. Zdefiniuj stałą nazwaną współdzieloną StawkaPodatku typu decimal
i nadaj jej wartość 0,22.
const decimal StawkaPodatku = 0.22m;
Uwaga:
Stał nazwane współdzielone definiujemy bez słowa static!!!
5.
Utwórz metodę Pobierz, która będzie pobierać od użytkownika cenę netto
towaru i obliczać cenę brutto. Następnie wypisze cenę brutto i pobierze
kwotę wpłaconą przez klienta. Jeżeli cena towaru brutto jest większa od
kwoty wpłaconej przez użytkownika zgłoś wyjątek. Po pobraniu obu
wartości (ceny netto i kwoty podanej przez klienta) oraz po obliczeniu ceny
brutto zaokrąglij wszystkie wartości do dwóch miejsc po przecinku przy
pomocy metody Round struktury Decimal.
cenaNetto =
Decimal
.Round(cenaNetto, 2);
Pilnuj aby wartości wprowadzone były większe od zera.
static void Pobierz()
{
do
{
Console.Write("\nPodaj cenę (netto) towaru
¬zakupionego przez klienta: ");
cenaNetto =
¬Convert.ToDecimal(Console.ReadLine());
}
while (cenaNetto <= 0);
cenaNetto = Decimal.Round(cenaNetto, 2);
cenaBrutto = Decimal.Round(
cenaNetto * ( 1 + StawkaPodatku),2);
Console.WriteLine("Cena brutto wynosi: {0:C}",
cenaBrutto);
do
{
Console.Write("\nPodaj kwotę wpłaconą przez
¬klienta: ");
kwotaWplacona =
Convert.ToDecimal(Console.ReadLine());
}
while (kwotaWplacona <= 0);
kwotaWplacona = Decimal.Round(kwotaWplacona, 2);
if (cenaBrutto > kwotaWplacona)
throw new Exception("Cena towaru nie może być
¬większa od kwoty wpłaconej przez
¬klienta!!!");
}
6. Utwórz metodę Wypisz, która wypisuje na ekranie kwotę wpłaconą przez
klienta, cenę brutto, cenę netto, kwotę podatku.
static void Wypisz()
{
Console.WriteLine("\n\n\n*******************");
Console.WriteLine("\nKwota wpłacona przez
¬klienta: {0:C}", kwotaWplacona);
Console.WriteLine("\nCena netto: {0:C}",
cenaNetto);
Console.WriteLine("\nCena brutto: {0:C}",
cenaBrutto);
Console.WriteLine("\nWartość podatku: {0:C}",
cenaBrutto - cenaNetto);
}
7. Utwórz metodę Reszta, która wypisuje na ekranie ilość poszczególnych
banknotów i monet, które trzeba dać klientowi, aby wydać mu resztę.
Rozpocznij od obliczenia ilości banknotów 100 zł, następnie 20 zł, 10 zł itd.
static void Reszta()
{
decimal reszta = kwotaWplacona - cenaBrutto;
int ilosc = 0;
Console.WriteLine("\nWartość reszty należnej
¬klientowi: {0:C}", reszta);
while (100 <= reszta)
{
ilosc++;
reszta -= 100;
}
if (ilosc != 0)
{
Console.WriteLine("\tLiczba banknotów {0:C}:
¬{1}", 100, ilosc);
ilosc = 0;
}
while (50 <= reszta)
{
ilosc++;
reszta -= 50;
}
if (ilosc != 0)
{
Console.WriteLine("\tLiczba banknotów {0:C}:
¬{1}", 50, ilosc);
ilosc = 0;
}
...
...
...
}
8. W metodzie Main wywołuj, póki jest klient do obsłużenia, powyżej
zdefiniowane metody. Obsłuż również wyjątek zgłaszany w metodzie
Pobierz.
static void Main(string[] args)
{
char c='t';
do
{
try
{
Pobierz();
Wypisz();
Reszta();
Console.WriteLine("\n\nCzy jest jeszcze
¬jakiś klient?");
c = Console.ReadKey().KeyChar;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
while (c == 't' || c == 'T');
}
9. Skompiluj i uruchom program.
Ćwiczenie 2:
Napisz program obliczający całkę oznaczoną z funkcji nieujemnej i całkowalnej
na zadanym przedziale np. f(x) = x
4
+ x
3
+ 2. Użytkownik ma do
wyboru:
metodę (metoda prostokątów lub metoda trapezów)
przedział całkowania
liczbę podziałów (podprzedziałów)
Polecenie powyższe jest identyczne z poleceniem do laboratorium w rozdziale
5, gdzie jest również opisany algorytm obliczenia całki metodą trapezów i
prostokątów. W odróżnieniu od poprzedniego laboratorium w poniższym
zastosuj następujący podział na metody:
Utwórz oddzielną klasę MetodyCalkowania zawierającą następujące
elementy:
o
Definicję typu wyliczeniowego Metody, który ma dwa elementy
Prostokatow=1 oraz Trapezow=2
o
Zmienne współdzielone zawierające wartość początku przedziału
całkowania, końca przedziału całkowania, liczbę podziałów oraz
zmienną pomocniczą, dla której jest obliczana wartość funkcji
całkowanej w kolejnych iteracjach.
o
Metodę obliczającej wartość dla funkcji całkowanej:
f(x) = x
4
+ x
3
+ 2
i ją zwracającą do programu
Funkcja ta korzysta z współdzielonej zmiennej pomocniczej.
o Metodę obliczającej wartość całki metodą trapezów i zwracającą ją do
programu.
o
Metodę obliczającej wartość całki metodą prostokątów i zwracającą ją
do programu.
o
Metodę ustawiającej koniec i początek przedziału.
o
Metodę zmieniającej ilość podziałów.
Do klasy Program dodaj następujące elementy:
o
Zmienną współdzieloną zawierającą informacje o aktualnie wybranej
metodzie całkowania.
o
Metodę wyświetlającą menu i przekazującą pozycję menu wybraną
przez użytkownika.
o
Metodę dającą użytkownikowi możliwość wyboru metody całkowania
i przekazującą wybór użytkownika do programu.
o
Metody obliczającej całkę metodą wybraną przez użytkownika (wybór
jest zawarty w zmiennej współdzielonej) i wypisującą jej wartość na
ekranie.
W metodzie Main w pętli wyświetl menu, a następnie w zależności od
wyboru użytkownika wywołaj odpowiednią metodę.
1. Dodaj do bieżącego rozwiązania nowy projekt
a. Z menu File wybierz Add/New Project...
b. W oknie dialogowym Add New Project określ następujące
właściwości:
i. typu projektu: Visual C#/Windows
ii. szablon: Console Application
iii. nazwa projektu: Calka
2. Uczyń nowo utworzony projekt projektem startowym
a. Zaznacz projekt Calka w okienku Solution Explorer i z menu
kontekstowego wybierz Set as StartUp Project.
albo, gdy rozpoczynasz laboratorium od tego ćwiczenia
1. Uruchom Visual Studio
Naciśnij przycisk Start systemu Windows, wybierz Wszystkie Programy
następnie Microsoft Visual Studio 2005/ Microsoft Visual Studio 2005.
2. Utwórz nowy projekt
a. Z menu File wybierz New/Project...
b. W oknie dialogowym New Project określ następujące właściwości:
i. typu projektu: Visual C#/Windows
ii. szablon: Console Application
iii. lokalizacja: Moje Dokumenty\Visual Studio 2005\Projects\
iv. nazwa projektu: Calka.
v. nazwa rozwiązania: Lab8
3.
Wewnątrz przestrzeni nazwa Calka, utwórz oddzielną klasę
MetodyCalkowania zawierającą następujące elementy:
namespace Calka
{
....
class MetodyCalkowania
{
...
//definicja poszczególnych elementów
}
}
a. Definicję typu wyliczeniowego Metody, który ma dwa elementy
Prostokatow=1 oraz Trapezow=2
public enum Metody{Prostokatow=1, Trapezow=2}
b. Zmienne współdzielone zawierające wartość początku przedziału
całkowania - PoczatekPrzedzialu, końca przedziału całkowania
- KoniecPrzedzialu, liczbę podziałów - LiczbaPodzialow
oraz zmienną pomocniczą - x, dla której jest obliczana wartość funkcji
całkowanej w kolejnych iteracjach. Nadaj wartości: zmiennej
reprezentującej początek przedziału wartość zero, zmiennej
reprezentującej koniec przedziału wartość 1, zmiennej reprezentującej
liczbę podziałów wartość 10.
public static double PoczatekPrzedzialu = 0;
public static double KoniecPrzedzialu = 1;
public static uint LiczbaPodzialow = 10;
static double x;
c. Metodę f obliczającej wartość dla funkcji całkowanej:
f(x) = x
4
+ x
3
+ 2
i ją zwracającą do programu
Funkcja ta korzysta z współdzielonej zmiennej pomocniczej.
static double f()
{
return x * x * x * (x + 1) + 2;
}
d. Metodę Trapezow obliczającej wartość całki metodą trapezów i
zwracającą ją do programu. Opis algorytmu obliczającego całkę
metodą trapezów znajduje się w laboratorium w rozdziale 5. W celu
obliczenia wartości funkcji w danym punkcie, wywołuj metodę
zdefiniowaną w kroku poprzednim. Pamiętaj jednak, aby wcześniej
ustawić odpowiednią wartość pomocniczej zmiennej współdzielonej -
x.
public static double Trapezow()
{
double suma = 0;
double dx = (KoniecPrzedzialu -
PoczatekPrzedzialu) / LiczbaPodzialow;
x = PoczatekPrzedzialu;
for (int i = 1; i < LiczbaPodzialow; i++)
{
x += dx;
suma += f();
}
x = PoczatekPrzedzialu;
double tmp = f();
x = KoniecPrzedzialu;
tmp += f();
suma += tmp / 2;
suma *= dx;
return suma;
}
e. Metodę Prostokatow obliczającej wartość całki metodą
prostokątów i zwracającą ją do programu. Opis algorytmu
obliczającego całkę metodąprostokątów znajduje się w laboratorium w
rozdziale 5. W celu obliczenia wartości funkcji w danym punkcie,
wywołuj metodę zdefiniowaną w dwa kroki wcześniej. Pamiętaj
jednak, aby wcześniej ustawić odpowiednią wartość pomocniczej
zmiennej współdzielonej.
public static double Prostokatow()
{
double suma = 0;
double dx = (KoniecPrzedzialu -
PoczatekPrzedzialu) / LiczbaPodzialow;
double x = PoczatekPrzedzialu;
for (int i = 0; i < LiczbaPodzialow; i++)
{
x += dx;
suma += f();
}
suma *= dx;
return suma;
}
f. Metodę UstawPrzedzial ustawiającej koniec i początek
przedziału. Pilnuj, aby koniec przedziału miał większą wartość niż
początek.
public static void UstawPrzedzial()
{
do
{
if(PoczatekPrzedzialu > KoniecPrzedzialu)
{
Console.Write("\nPoczątek musi być
¬mniejszy od końca: ");
}
Console.Write("\nPodaj początek
¬przedziału: ");
PoczatekPrzedzialu =
Convert.ToDouble(Console.ReadLine());
Console.Write("Podaj koniec przedziału:
¬ ");
KoniecPrzedzialu =
Convert.ToDouble(Console.ReadLine());
}
while(PoczatekPrzedzialu>KoniecPrzedzialu);
}
g. Metodę zmieniającej ilość podziałów. Pilnuj, aby wartość liczby
podziałów była większa od zera.
public static void UstawLiczbePodzialow()
{
Console.Write("\nPodaj liczbę podziałów: ");
LiczbaPodzialow =
Convert.ToUInt32(Console.ReadLine());
if (LiczbaPodzialow == 0)
throw new Exception("Liczba podziałów
¬musi być większa od zera");
}
4. Do klasy Program, klasy wygenerowanej automatycznie przez Visual
Studio, dodaj następujące elementy:
a. Zmienną współdzieloną zawierającą informacje o aktualnie wybranej
metodzie całkowania. Nadaj zmiennej wartość.
static MetodyCalkowania.Metody metoda =
MetodyCalkowania.Metody.Prostokatow;
b. Metodę wyświetlającą menu i przekazującą pozycję menu wybraną
przez użytkownika.
static char Menu()
{
Console.WriteLine("\nPrzedział całkowania:
¬<{0}; {1}>",
MetodyCalkowania.PoczatekPrzedzialu,
MetodyCalkowania.KoniecPrzedzialu);
Console.WriteLine("Liczba podziałów: {0}",
MetodyCalkowania.LiczbaPodzialow);
Console.WriteLine("Metoda całkowania: {0}",
metoda);
Console.WriteLine("\t\t\tA - Zmiana
przedziału");
Console.WriteLine("\t\t\tB - Zmiana liczby
podziałów");
Console.WriteLine("\t\t\tC - Zmiana metody
całkowania");
Console.WriteLine("\t\t\tD - Policz całkę");
Console.WriteLine("\t\t\tK - Koniec");
return Console.ReadKey(true).KeyChar;
}
c. Metodę dającą użytkownikowi możliwość wyboru metody całkowania
i przekazującą wybór użytkownika do programu.
static MetodyCalkowania.Metody
UstawMetodeCalkowania()
{
int m = 1;
do
{
if (m != 1)
{
Console.WriteLine("\nNaciśnij 1 lub 2:
¬");
}
Console.WriteLine("\nPodaj metodę
¬liczenia całki : ");
Console.WriteLine("\t1 - Metoda
¬prostokątów");
Console.WriteLine("\t2 - Metoda trapezów:
¬");
m = Convert.ToInt32(Console.ReadLine());
}
while (!(m == 1 || m == 2));
return (MetodyCalkowania.Metody)m;
}
d. Metody obliczającej całkę metodą wybraną przez użytkownika (wybór
jest zawarty w zmiennej współdzielonej) i wypisującą jej wartość na
ekranie. W celu obliczenia wartości całki wywołaj odpowiednie
metody z klasy MetodyCalkowania.
static void ObliczCalke()
{
double calka = 0;
switch (metoda)
{
case MetodyCalkowania.Metody.Prostokatow:
calka = MetodyCalkowania.Prostokatow();
break;
case MetodyCalkowania.Metody.Trapezow:
calka = MetodyCalkowania.Trapezow();
break;
}
Console.Write("\nPrzybliżona wartość całki
¬funkcji f(x) w przedziale <{0}; {1}>
¬wynosi: {2}",
MetodyCalkowania.PoczatekPrzedzialu,
MetodyCalkowania.KoniecPrzedzialu, calka);
Console.ReadKey(true);
}
5. W metodzie Main w pętli wyświetl menu, a następnie w zależności od
wyboru użytkownika wywołaj odpowiednią metodę.
static void Main(string[] args)
{
char c;
do
{
c = Menu();
switch (c)
{
case 'a':
case 'A':
MetodyCalkowania.UstawPrzedzial();
break;
case 'b':
case 'B':
MetodyCalkowania.UstawLiczbePodzialow();
break;
case 'c':
case 'C':
metoda = UstawMetodeCalkowania();
break;
case 'd':
case 'D':
ObliczCalke();
break;
}
}
while (!(c == 'k' || c == 'K'));
}
6. Skompiluj i uruchom program.