Programowanie w języku Java. Zbiór zadań z (p)odpowiedziami 9788324663668, 9788324643196, 8324643192, 8324663665

Gdy przegląda się oferty pracy dla programistów, trudno nie natknąć się na słowo "Java". Ten obiektowy, niezal

187 114 5MB

Polish Pages 440 [436] Year 2012

Report DMCA / Copyright

DOWNLOAD PDF FILE

Table of contents :
Spis treści
Od autora
Rozdział 1. Pierwszy krok — rozpoczynamy naukę programowania w języku Java
1. Historia Javy i pierwsze zadania
2. JDK, Notatnik i klasyczny przykład „Hello World”
3. Znaki, tablice znaków i klasa String
4. Klasa String — operacje na tekstach
5. Tablica argumentów aplikacji
6. Prawda czy fałsz — logiczny typ danych
7. Liczby całkowite typu int i klasa Integer
8. Inne typy liczb całkowitych w Javie
9. Typy liczb zmiennoprzecinkowych
Rozdział 2. Drugi krok — operacje wejścia-wyjścia i instrukcje sterujące w Javie
10. Wyświetlanie sformatowanych wyników w konsoli. Stałe i metody z klasy Math
11. Wczytywanie danych — klasa Scanner
12. Operacje na tekstach — klasy StringBuffer i StringBuilder
13. Instrukcje warunkowe i instrukcja selekcji
14. Instrukcja pętli typu do-while
15. Instrukcja pętli typu while
16. Instrukcja pętli typu for
Rozdział 3. Trzeci krok — budujemy własne metody i klasy
17. Obsługa wyjątków
18. Liczby pseudolosowe i tablice jednowymiarowe — budujemy metody statyczne
19. Dokumentacja klasy
20. Działania na ułamkach — budujemy klasę Fraction
21. Klasa opakowująca Angle — miara kąta i funkcje trygonometryczne
22. Liczby rzymskie i klasa Roman
23. Trójmian kwadratowy i klasa QuadratPoly
24. Liczby zespolone — budujemy klasę Complex
Rozdział 4. Czwarty krok — pliki, tablice i macierze
25. Operacje na plikach tekstowych
26. Tablice jednowymiarowe i wielomiany
27. Obliczenia statystyczne
28. Tablice wielowymiarowe i macierze
29. Obliczanie wartości funkcji, rekurencja i inne zadania
Rozdział 5. Rozwiązania zadań z rozdziału 1.
1. Historia Javy i pierwsze zadania
2. JDK, Notatnik i klasyczny przykład „Hello World”
3. Znaki, tablice znaków i klasa String
4. Klasa String — operacje na tekstach
5. Tablica argumentów aplikacji
6. Prawda czy fałsz — logiczny typ danych
7. Liczby całkowite typu int i klasa Integer
8. Inne typy liczb całkowitych w Javie
9. Typy liczb zmiennoprzecinkowych
Rozdział 6. Rozwiązania zadań z rozdziału 2.
10. Wyświetlanie sformatowanych wyników w konsoli. Stałe i metody z klasy Math
11. Wczytywanie danych — klasa Scanner
12. Operacje na tekstach — klasy StringBuffer i StringBuilder
13. Instrukcje warunkowe i instrukcja selekcji
14. Instrukcja pętli typu do-while
15. Instrukcja pętli typu while
16. Instrukcja pętli typu for
Rozdział 7. Rozwiązania zadań z rozdziału 3.
17. Obsługa wyjątków
18. Liczby pseudolosowe i tablice jednowymiarowe — budujemy metody statyczne
19. Dokumentacja klasy
20. Działania na ułamkach — budujemy klasę Fraction
21. Klasa opakowująca Angle — miara kąta i funkcje trygonometryczne
22. Liczby rzymskie i klasa Roman
23. Trójmian kwadratowy i klasa QuadratPoly
24. Rozwiązania zadań — liczby zespolone
Rozdział 8. Rozwiązania zadań z rozdziału 4.
25. Operacje na plikach tekstowych
26. Tablice jednowymiarowe i wielomiany
27. Obliczenia statystyczne
28. Tablice wielowymiarowe i macierze
29. Obliczanie wartości funkcji, rekurencja i inne zadania
Recommend Papers

Programowanie w języku Java. Zbiór zadań z (p)odpowiedziami
 9788324663668, 9788324643196, 8324643192, 8324663665

  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
File loading please wait...
Citation preview

Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Redaktor prowadzący: Ewelina Burska Projekt okładki: Studio Gravite/Olsztyn Obarek, Pokoński, Pazdrijowski, Zaprucki Materiały graficzne na okładce zostały wykorzystane za zgodą Shutterstock.

Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: [email protected] WWW: http://helion.pl (księgarnia internetowa, katalog książek) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie?projaz_ebook Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Materiały do książki można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/projaz.zip ISBN: 978-83-246-6366-8 Copyright © Helion 2012 Printed in Poland. • Poleć książkę na Facebook.com

• Księgarnia internetowa

• Kup w wersji papierowej

• Lubię to! » Nasza społeczność

• Oceń książkę

Spis treci Od autora . ....................................................................................... 5 Rozdzia 1. Pierwszy krok — rozpoczynamy nauk programowania w jzyku Java . ............................................... 7 1. Historia Javy i pierwsze zadania .................................................................................... 7 2. JDK, Notatnik i klasyczny przykad „Hello World” . .................................................... 9 3. Znaki, tablice znaków i klasa String ............................................................................ 11 4. Klasa String — operacje na tekstach ........................................................................... 15 5. Tablica argumentów aplikacji ...................................................................................... 18 6. Prawda czy fasz — logiczny typ danych .................................................................... 19 7. Liczby cakowite typu int i klasa Integer ..................................................................... 22 8. Inne typy liczb cakowitych w Javie ............................................................................ 25 9. Typy liczb zmiennoprzecinkowych ............................................................................. 27

Rozdzia 2. Drugi krok — operacje wejcia-wyjcia i instrukcje sterujce w Javie . 31 10. Wywietlanie sformatowanych wyników w konsoli. Stae i metody z klasy Math ...................................................................................... 31 11. Wczytywanie danych — klasa Scanner ..................................................................... 34 12. Operacje na tekstach — klasy StringBuffer i StringBuilder . .................................... 36 13. Instrukcje warunkowe i instrukcja selekcji . .............................................................. 38 14. Instrukcja ptli typu do-while .................................................................................... 41 15. Instrukcja ptli typu while . ........................................................................................ 42 16. Instrukcja ptli typu for . ............................................................................................ 44

Rozdzia 3. Trzeci krok — budujemy wasne metody i klasy . ............................. 47 17. Obsuga wyjtków ................. 47 18. Liczby pseudolosowe i tablice jednowymiarowe — budujemy metody statyczne ................................................................................. 48 19. Dokumentacja klasy . ................................................................................................. 53 20. Dziaania na uamkach — budujemy klas Fraction . ................................................ 55 21. Klasa opakowujca Angle — miara kta i funkcje trygonometryczne ..................... 61 22. Liczby rzymskie i klasa Roman ................................................................................. 64 23. Trójmian kwadratowy i klasa QuadratPoly . ............................................................. 66 24. Liczby zespolone — budujemy klas Complex . ....................................................... 69

4

Programowanie w jzyku Java

Rozdzia 4. Czwarty krok — pliki, tablice i macierze . ....................................... 77 25. Operacje na plikach tekstowych ................................................................................ 77 26. Tablice jednowymiarowe i wielomiany ..................................................................... 80 27. Obliczenia statystyczne . ............................................................................................ 82 28. Tablice wielowymiarowe i macierze ......................................................................... 87 29. Obliczanie wartoci funkcji, rekurencja i inne zadania . ............................................ 92

Rozdzia 5. Rozwizania zada z rozdziau 1 . .................................................... 97 1. Historia Javy i pierwsze zadania .................................................................................. 97 2. JDK, Notatnik i klasyczny przykad „Hello World” . ................................................ 101 3. Znaki, tablice znaków i klasa String .......................................................................... 104 4. Klasa String — operacje na tekstach ......................................................................... 111 5. Tablica argumentów aplikacji .................................................................................... 117 6. Prawda czy fasz — logiczny typ danych . ................................................................ 120 7. Liczby cakowite typu int i klasa Integer . ................................................................. 129 8. Inne typy liczb cakowitych w Javie .......................................................................... 135 9. Typy liczb zmiennoprzecinkowych ........................................................................... 140

Rozdzia 6. Rozwizania zada z rozdziau 2 . .................................................. 147 10. Wywietlanie sformatowanych wyników w konsoli. Stae i metody z klasy Math .................................................................................... 147 11. Wczytywanie danych — klasa Scanner . ................................................................. 152 12. Operacje na tekstach — klasy StringBuffer i StringBuilder . .................................. 157 13. Instrukcje warunkowe i instrukcja selekcji . ............................................................ 162 14. Instrukcja ptli typu do-while .................................................................................. 179 15. Instrukcja ptli typu while ....................................................................................... 187 16. Instrukcja ptli typu for . .......................................................................................... 193

Rozdzia 7. Rozwizania zada z rozdziau 3 . .................................................. 201 17. Obsuga wyjtków ............... 201 18. Liczby pseudolosowe i tablice jednowymiarowe — budujemy metody statyczne ............................................................................... 206 19. Dokumentacja klasy . ............................................................................................... 221 20. Dziaania na uamkach — budujemy klas Fraction . .............................................. 237 21. Klasa opakowujca Angle — miara kta i funkcje trygonometryczne ................... 269 22. Liczby rzymskie i klasa Roman ............................................................................... 290 23. Trójmian kwadratowy i klasa QuadratPoly . ........................................................... 301 24. Rozwizania zada — liczby zespolone . ................................................................ 318

Rozdzia 8. Rozwizania zada z rozdziau 4 . .................................................. 347 25. Operacje na plikach tekstowych .............................................................................. 347 26. Tablice jednowymiarowe i wielomiany . ................................................................. 358 27. Obliczenia statystyczne . .......................................................................................... 370 28. Tablice wielowymiarowe i macierze ....................................................................... 385 29. Obliczanie wartoci funkcji, rekurencja i inne zadania . .......................................... 420

Od autora Niniejszy zbiór zada jest propozycj dla rozpoczynajcych nauk programowania w jzyku Java. Jak sugeruje tytu (moe nieco dziwnie zbudowany), Czytelnik znajdzie tutaj zadania z zakresu programowania i podpowiedzi (wskazówki) dotyczce tego, jak zabra si do ich rozwizywania. Jeli informacja zawarta w treci zadania i ewentualna podpowied (wskazówka, uwaga) oka si niewystarczajce, to mona sign do odpowiedzi, gdzie zawarto dodatkowe wskazówki, istotne fragmenty rozwizania lub kompletne listingi kodów ródowych. Kady dzia jest poprzedzony krótkim wprowadzeniem teoretycznym, przykadem lub linkiem do odpowiedniego fragmentu dokumentacji jzyka zamieszczonej w internecie. W pocztkowych rozdziaach umieszczono w tekcie zada sugerowane nazwy plików ródowych (np. w zadaniu 2.3 zaproponowano nazw pliku Adres.java). Rozwizujc zadanie, Czytelnik powinien pamita, e nazwa klasy musi by identyczna z nazw pliku (bez rozszerzenia). Sugerowanie nazw plików (a przy tym nazw klas) ma na celu przyzwyczajenie Czytelnika do dobierania nazw klas odpowiednich do treci zadania. Ponadto róne nazwy plików (klas) umoliwiaj gromadzenie rozwiza kilku zada w tym samym folderze. W dalszej czci zbioru zaproponowano nazwy plików zgodne z numerami zada, np. rozwizanie zadania 13.8 zapisano w pliku Z13_8.java, a inny wariant rozwizania tego zadania zapisano w pliku Z13_8a.java. Aby uatwi Czytelnikowi poszukiwanie plików z rozwizaniami, rozwizanie na przykad zadania 2.3 (i innych pocztkowych zada) zawarto dodatkowo w pliku Z02_3.java. Wszystkie pliki ródowe umieszczono na serwerze ftp://ftp.helion.pl/przyklady/projaz.zip).

6

Programowanie w jzyku Java

Rozdzia 1.

Pierwszy krok — rozpoczynamy nauk programowania w jzyku Java 1. Historia Javy i pierwsze zadania Zespó inynierów z firmy Sun, pracujc pod kierownictwem Jamesa Goslinga, rozpocz w 1991 roku projekt pod nazw Green. Celem projektu byo utworzenie jzyka programowania dla niewielkich urzdze elektronicznych. Jzyk mia by niezaleny od platformy sprztowej. Doprowadzio to do utworzenia kodu poredniego dla maszyny wirtualnej, który mona uruchamia w kadym urzdzeniu wyposaonym w odpowiedni interpreter. Przez kilka lat projekt rozwija si, ale produkt nie uzyskiwa podanej popularnoci. Jzyk pocztkowo nazwano Oak (db), ale gdy okazao si, e ta nazwa jest ju zajta, zmieniono j na Java. Przeomem w rozwoju tego jzyka stao si napisanie w nim przegldarki internetowej HotJava. Umoliwiaa ona uruchamianie kodu wbudowanego w strony internetowe, czyli tzw. apletów. Efekty pracy opublikowano w maju 1995 roku w magazynie „Sun Word” i odtd Java zacza zyskiwa popularno. Na pocztku 1996 roku ukazaa si pierwsza oficjalna wersja jzyka — Java 1.0. Hasem promujcym Jav byo zdanie Write Once, Run Anywhere („Napisz raz, uruchamiaj wszdzie”). W kolejnych wersjach uzupeniano zauwaone braki i dodawano nowe funkcjonalnoci. Systematycznie rosa liczba klas i interfejsów:

Programowanie w języku Java

8

ł JDK1 1.0 ( 23stycznia 1996 r.-211klas i interfejsów)-pierwsza oficjalna wersja Javy.

ł JDK 1.1 ( 19lutego 1997r.-477klas i interfejsów).

ł J2SE2 1.2 ( 8grudnia 1998r.-1524klasy i interfejsy)-nazwa kodowa Playground. ł J2SE 1.3 ( 8maja 2000r.-1840klas i interfejsów)-nazwa kodowa Kestrel. ł J2SE 1.4 ( 6 lutego 2002r.-2723klasy i interfejsy)-nazwa kodowa Merlin. ł J2SE 5.03 ( 30września 2004r.- 3270klas i interfejsów)- nazwa kodowa Tiger. ł Java SE 64 ( 11 grudnia 2006 r.-3777klas i interfejsów)-nazwa kodowa Mustang. ł Java SE 7 ( 28lipca 2011r.)-nazwa kodowa Dolp

$

��



:będą dostępne na licencji W 2007roku firma Sun ogłosiła, że kolejne wers GPL i taka jest właśnie licencja dla wersji Ja�� erAutor podczas pracy nad zbio­ rem zadań używał wersji Java SE 6. Wsz t ;i�edstawione rozwiązania nie będą sprawiać problemów w Java SE 7. Od 2 nia 2010 roku nowym właścicielem Javy jest firma Oracle, która kupiła firme icrosystems. Zadanie 1.1.

�O

Przygotuj komputer do progra�)Jia w języku Java.

f)

Wskazówka

Zadanie 1. .

Sprawdź, czy środowisko JDK do programowania w języku Java jest poprawnie zain­ stalowane na Twoim komputerze. Jaką wersję środowiska masz zainstalowaną? Java Development Kit- pakiet udostępniający kod bajtowy wszystkich klas standardowych, maszynę wirtualną do ich uruchamiania oraz źródła klas i narzędzia niezbędne do programowania w języku Java (m.in. kompilator, paker, debuger). Java 2 Platfmm, Standard Edition - podstawowa wersja platformy Java, pozwalająca tworzyć i uru­ chamiać aplikacje napisane w języku Java na komputerach stacjonarnych i serwerach. Od tego wyda­ nia Java rozwija się w trzech wersjach: J2SE, J2EE (Java 2 Platfmm, Enterprise Edition- setwerowa platforma programistyczna języka Java) i J2ME (Java 2 Platform Micro Edition- uproszczona wer­ sja platfmmy Java, zaprojektowana z myślą o tworzeniu aplikacji mobilnych dla urządzeń o bardzo ograniczonych zasobach). Dotychczasową numerację 1.5 zmieniono na 5.0. 4

J2SE zastąpiono Java SE, a z numeracji usunięto O. Nadal jednak używa się również oznaczenia 1.6.

Rozdział 1.



Wskazówka

+

Pierwszy krok - rozpoczynamy naukę programowania w języku Java

9

Sprawdź w oknie konsoli (praca w trybie MS-DOS) działanie poleceń java i javac.

�------�

Zadanie 1.3.

Przygotuj "ściągawkę" z instrukcją uruchamiania wirtualnej maszyny Javy (JVM).



Wskazówka

�------� Skorzystaj z opcji pomocy, jaką oferuje program java.exe.

Zadanie 1.4.

Przygotuj "ściągawkę" z instrukcją uruchamiania kompilatora Javy (javac.exe). Metoda zastosowana w rozwiązaniu zadania 1.3 nie sprawd i się w tym przypadku. Informacje są zawsze wyświetlane na ekranie. Należy poszuk innego rozwiązania.

Uwaga



Zadanie 1.5.

Przygotuj folder, w którym będziesz zapisyw �s wsadowych ułatwiających dalszą pracę.

� � l'







ody źródłowe, i kilka plików

lności nam wystarczą. Autor nie jest Na początek tak przygotowane narzędzi zwolennikiem strzelania z armaty do X� (generalnie uważa, że strzelanie do wró­ _ oponuje Czytelnikowi użycia skomplikowa­ bli nie jest wskazane), wobec tego n� nych zintegrowanych środowisk �mistycznych (IDE) i wieloplikowych projektów do kompilowania i uruchamia � linijek kodu. Po wykonaniu tych zadań możesz kontynuować naukę pro o 1l.a w języku Java.

�� �

�nik i klasyczny przyklaW,,H eno World"

2. JDK, No

Ten przykład jest powielany w wielu podręcznikach i ma swoje odpowiedniki praw­ dopodobnie we wszystkich językach programowania. Listing

1.

Hellojava public class Hello { public static void main(String args[J) System.out.println("Hello World") :

Zadanie 2.1.

Przepisz dokładnie kod źródłowy podany na listingu l . Skompiluj go i uruchom.

Programowanie w języku Java

10

f)

Wskazówka

Skorzystaj z przygotowanych wcześniej plików wsadowych i dysku X:.

�------�

Zadanie 2.2.

Napisz polskojęzyczną wersję klasycznego przykładu z zadania 2.1. Klasę nazwij Wltam; uruchomiona aplikacja powinna wyświetlić w konsoli napis (w dwóch wierszach): Wltaj, śwlecle. Uczę slę programować w języku Java.

f)

Wskazówka

W systemie Windows kod źródłowy pisany jest w Notatniku (strona kodowa 1250), a efekty pracy programu wyświetlane są w konsoli (strona kodowa 852). Powoduje to nieprawidłowe wyświetlanie liter z polskimi znakami diakrytycznymi. Możliwe są dwa rozwiązania:

� 2. Uruchamianie aplikacji poleceniem: java -Dfll e. ecod ��52 NazwaKl asy. W obu przypadkach w konsoli powinna być ustawi a ci•�a TT Lucida Conso/e. 1. Zmiana strony kodowej w konsoli poleceniem: chcp 12

Zadanie 2.3.

'i)ytO� �

Napisz program, który wyświetli na ekran pisałbyś go na kopercie (plik źródłowy:

f)

Wskazówka

Użyj kilka razy instrukcji Sys cały adres w jednym łańcuc ny \n, oznaczający przej' ie



j adres w kilku wierszach, tak jak na­ sjava).

t. prln t l n ( "... ");. Możesz również zapisać

ltlY.wstawiając we właściwych miejscach znak specjal­

Zadanie 2.4.



�owego wiersza (ang. new line).

n4 ��

Napisz progra óry wyświetli na ekranie etykietkę zawierającą Twoje imię i na­ y: Etykietajava). Jako wzór (niekoniecznie do wiernego odtwo­ zwisko (plik ź rzenia) przyjmij podany przykład: ******* Programowanle *******

* oblektowe w języku Java * * * Jan Nowak *****************************

f)

Wskazówka

W tym zadaniu i zadaniach podobnych wyświetlenie wiersza tekstu (z przejściem do następnego wiersza) możesz zrealizować na kilka sposobów, dających dokład­ nie taki sam rezultat: System.out.println("Wlersz tekstu... "): System.out.prlnt("Wl ersz tekstu... \n"): System.out.prlnt("Wl ersz tekstu...") : System. out.println();

Element odpowiedzialny za przejście do nowego wiersza w kodzie wyróżniono po­ grubieniem czcionki.

Rozdział 1.

+

Pierwszy krok - rozpoczynamy naukę programowania w języku Java

11

3. Znaki, tablice znaków i klasa String Do reprezentacji znaków (liter, cyfr, znaków interpunkcyjnych i wielu innych symbo­ li) służy typ char. Do zapisania jednego znaku potrzeba 16 bitów (dwa bajty) i stoso­ wany jest standard Unicode. Klasa Character opakowuje prosty typ char w obiekt; posiada jedno pole typu char i szereg metod działających na znakach. Najczęściej posługujemy się stałymi znakowymi, np. 'A' jest znakiem o kodzie 65. W ten sposób możemy zapisywać wszystkie znaki widoczne na klawiaturze. Znaki specjalne posiadają symbole zastępcze: \b- backspace, \t- tabulator, \n- przej­ ście do nowego wiersza, \r - powrót karetki (przejście na początek wiersza), \" znak cudzysłowu, \ ' -znak apostrofu, \\- znak lewego ukośnika (ang. slash). Znaki Unieode możemy zapisywać w notacji szesnastkowej- wa�ci od \uOOOO do \uFFFF (65 536 znaków)5. W konsoli będą wyświetlone poprawni�}j.. zdefiniowane w wy­ branej czcionce, pozostałe znaki zostaną zastąpione �kie�apytania (?). Oto kilka operacji na zmiennych typu char:

� Iw� �� �� �

char a: 1/deklaracja zmiennej a = 'A' ; /l przypisanie do zmiennej a znaku 'A' (�talej char b = 'B'; //zadeklarowanie zmiennej b i .: b = a ; 11 przypisanie zmiennej b wartości zmien char alfa = '\u03Bl'; 1/grecka litera alfa



'A') a ze jej wartością 'B'

(rf!:)V Przy okazji poznałeś komentarz l.in�ierszowy) stosowany w kodach źródłowych. Tekst od znaków do końca �j�st komentarzem (objaśnieniem dla programi­ ll

sty) i kompilator go ignoruje.

� � �

\()

Zwykle pojedyncze zna1r..; �ie wystarczają, więc tworzymy tablice znaków. Zmien­ tablicę znaków) możemy zadeklarować na dwa sposoby: ną tablicową (w tym r char[] znak l lub nakl[]. Słowo znakl jest identyfikatorem (nazwą) zmiennej, natomiast char MTą typu danych przechowywanych w tablicy. Tablicami zawierającymi dane róż ch typów będziemy posługiwali się wielokrotnie. Na razie zadekla­ rowaliśmy zmienną znakl. Teraz możemy utworzyć tablicę za pomocą operatora new: znaki = new char[l5]:

Tablica znakl może przechowywać maksymalnie 15 elementów (taką wartość podali­ śmy w chwili tworzenia tablicy) i są one indeksowane liczbami całkowitymi od O do 14 (o l mniej od rozmiaru tablicy). Mamy zatem dostęp do elementów tablicy za po­ średnictwem zmiennych: znakl[O], znakl[1], ... , znakl[14]. Pozostaje wypełnić tablicę wartościami, np.: znakl[0] ' W ', znakl[l] 'l ' itd. (pa­ miętajmy o zakresie indeksów; przekroczenie zakresu zakończy się zgłoszeniem wy­ jątku Array I ndexOutOfBounds ). =

5

=

Na tym etapie ta informacja w zupełności wystarczy. Obecnie standard Unieode umożliwia zakodowa­ nie większej liczby znaków. Zastosowano siedemnaście tzw. przestrzeni numeracyjnych. My ograniczy­ my się do podstawowej przestrzeni numeracyjnej.

Programowanie w języku Java

12

Tablicę znaków możemy również wypełnić wartościami (zainicjować) w trakcie defi­ niowania: char napis[] = { 'W'. 'i'. 't'. 'a'.

'j'}:

Rozmiar tej tablicy jest równy 5, a indeksy elementów zawierają się w przedziale od O do 4. Tablica jest strukturą danych stanowiących zestaw elementów tego samego typu. Mamy dwie równoważne deklaracje zmiennej tablicowej: typ_danych[J nazwaTablicy: typ_danych nazwaTablicy[]:

Tablicę możemy zainicjować listą watiości umieszczoną w nawiasach { } . Rozmiar tablicy będzie równy liczbie podanych elementów: typ_danych nazwaTabl1cy[] � { element_!. element_Z

... .



n}

� �tablicę, należy określić """t.'\, .. � � "'r

Tablicę możemy utworzyć za pomocą operatora new, or liczbę elementów:

��

11 zmienna nazwaTablicy była wcześniej zadeklarowan nazwaTablicy = new typ_danych[liczba_ele en ó 11 deklaracja ż tworzenie tablicy elementów typ_danych[J nazwaTablicy = new typ_da ·czba_elementów]:



Rozmiar tablicy można odczytać za

�cą odwołania nazwaTabl lcy. l ength6.

Indeksy elementów tablicy są l gdzie n jest liczbą eleme

całkowitymi i należą do przedziału od O do n-l, iarem) tablicy.

� �t �

\� �awierającą napis Dzień dobry. Napisz aplikację (plik źródło­ Utwórz tablic� � Zadanie 3.1.

"--

�ra wyświetli napis w konsoli.

wy: Witajjava,



Wskazówka

Parametrem wywołania metody prlnt() lub prlntl n() (obiektu out z klasy System) może być wartość typu char lub char[].

Zadanie 3.2. Utwórz tablicę zawierającą znaki słowa Informatyka. Napisz program wyświetlający znaki zawarte w tablicy w następujący sposób (plik źródłowy: Informatykajava): a) pionowo-każdy znak w odrębnym wierszu, b) poziomo-znaki rozdzielone dodatkowymi odstępami (tzw. spacjowanie lub rozstrzelenie tekstu). 6

Tablica jest obiektem, któty posiada pole (własność) length. Pojęcie to wkrótce będzie wyjaśnione dokładniej.

Rozdział 1.

+

Pierwszy krok - rozpoczynamy naukę programowania w języku Java

13

c) poziomo- wielkimi literami, d) poziomo-małymi literami.

f)

Wskazówka

Parametrem metody prlnt() (prl ntl n() ) może być zmienna typu char. Przydatna okaże się również klasa java. l ang. Character opakowująca typ prosty char. Obiekt typu Character posiada jedno pole typu cha r oraz szereg metod przetwarzają­ cych znaki (zob. http:jjdownload.orac/e.comjjavasej1.4.2jdocsjapijjavaj/angj Character.htmn. Zamiany wartości zmiennej znak typu char na wielką literę można dokonać z wykorzystaniem metody Character. toUpperCase(znak). Zwrócony wy­ nik (obiekt typu Character) może być parametrem metody prl nt(). Zamiany na małe litery dokonamy przy użyciu metody Character. tolowerCase(znak). Do po­ bierania znaków z tablicy można zastosować pętlę typu for each.



Zadanie 3.3.

Utwórz tablicę zawierającą znaki słowa programowanie. c� z�wartość tablicy i wyświetlający efekty tych zmian (pl nze.Java): a) zamień pierwszą literę na wielką, b) zamień wszystkie litery na wielkie.

f)

Wskazówka



� "'r ��

- z program zmieniają­ z ódłowy: Programowa-



Tym razem pętla typu for each nie w czy. Przeglądając tablicę, musimy mieć modyfikować znak, należy znać jego indeks. możliwość modyfikowania znaków. dane uzyskamy, stosując pętlę typu for: Dostęp do wszystkich znaków

� �lt1

):{

for(int i=O: i< dane.len�; i) { ne z elementem dane[i] 11 tu wykonaj przeksztalcen ·e zw

� .

}

� �

Zadanie 3.4.

Utwórz tablic erającą znaki słowa programowanie. Napisz program wyświetla­ jący znaki zawarte w tablicy w kolejności odwrotnej-od końca do początku (plik źródłowy: Wspakl java)

f)

Wskazówka

Uwaga

.

Można zastosować pętlę for, w której następuje odliczanie w dół (od wartości więk­ szych do mniejszych for(lnt l=dane. l ength-1; l >= O; --l) . . . .

Do przeglądania (odczytu) zawartości tablicy możemy wykorzystać pętlę typ for each: for(typ_danych z

:

tablica) instrukcja:

Zmienna z przyjmuje kolejno wartości wszystkich elementów tablicy (od początku do końca). Do przeglądania (odczytu) lub modyfikowania (zapisu) zawartości tablicy możemy wykorzystać pętlę typu for: for(int i = 0: i< tablica.length: ++i) instrukcja:

/*Odliczaniewgórę*l

14

Programowanie w jzyku Java

lub: for(int i = tablica.length-1; i >= 0; --i) instrukcja; /* Odliczanie w dó */

Zadanie 3.5. Utwórz tablic zawierajc znaki sowa programowanie. Napisz program odwracajcy kolejno znaków w tablicy (plik ródowy: Wspak2.java). Przestawiaj kolejno pary elementów tablicy: pierwszy z ostatnim, drugi z przedostatnim — a dojdziesz do rodka tablicy.

Zadanie 3.6. Przeanalizuj kod podany na listingu 2. Przepisz kod i uruchom t aplikacj. Sprawd , czy wyniki na ekranie s zgodne z Twoimi oczekiwaniami. Na podstawie tego kodu i dokumentacji klasy Character napisz wasn aplikacj pokazujc dziaanie wybranej metody lub wartoci zdefiniowanych staych. Listing 2. DemoCharacter.java import static java.lang.System.*; public class DemoCharacter { public static void main(String args[]) { /* Informacje o metodzie */ out.println("Klasa: java.lang.Character"); out.println("Metoda statyczna: digit\n"); out.println("static int digit(int ch, int radix)"); out.println("Returns the numeric value of the character ch in the specified radix."); out.println(); /* Przykadowa tablica znaków */ char znak[] = {'E', 'u', 'r', 'o', ' ', '2', '0', '1', '2'}; /* Demonstracja dziaania metody */ out.println("Warto znaku jako cyfry w ukadzie dziesitkowym (radix = 10)"); for(char z : znak) out.println("Znak: "+z+" Cyfra: "+Character.digit(z, 10)); out.println("Uwaga: -1 oznacza, e znak nie jest cyfr w tym ukadzie liczbowym."); out.println(); out.println("Warto znaku jako cyfry w ukadzie szesnastkowym (radix = 16)"); for(char z : znak) out.println("Znak: "+z+" Cyfra: "+Character.digit(z, 16)); out.println("Uwaga: -1 oznacza, e znak nie jest cyfr w tym ukadzie liczbowym."); } }

Rozdzia 1. i Pierwszy krok — rozpoczynamy nauk programowania w jzyku Java

15

Zadanie 3.7. Napisz program, który utworzy dziesicioelementow tablic znaków i wypeni j cyframi od 0 do 9 (plik ródowy: Cyfry.java). Zadeklaruj tablic znaków o odpowiednim wymiarze. Wykorzystaj tabel kodów ASCII i moliwo zamiany kodu znaku na odpowiadajcy mu znak np. przez rzutowanie: (char)65 zamienia liczb 65 na znak o kodzie 65, czyli wielk liter 'A'.

Zadanie 3.8. Napisz program, który utworzy szesnastoelementow tablic znaków i wypeni j cyframi ukadu szesnastkowego (plik ródowy: Cyfry16.java). Moesz postpi podobnie jak w zadaniu 3.7 lub wykorzysta statyczn metod forDigit() z klasy Character.

4. Klasa String — operacje na tekstach W Javie nie ma wbudowanego typu prostego do przechowywania cigów (acuchów) znaków. Kady acuch znaków jest obiektem klasy String nalecej do standardowej biblioteki. Klasa String oferuje kilka konstruktorów i szereg metod (ponad 50) do przetwarzania acuchów. Literay acuchowe zapisujemy w cudzysowie, np. "Zadania z programowania". Ten litera jest obiektem i na jego przykadzie zostanie pokazanych kilka metod klasy String.

Zadanie 4.1. Uruchom aplikacj, której kod ródowy przedstawiono na listingu 3. Na podstawie obserwacji wyników dziaania programu opisz dziaanie uytych metod klasy String. W przypadku wtpliwoci zajrzyj do dokumentacji jzyka Java (np. http://download. oracle.com/javase/6/docs/api/java/lang/String.html). Listing 3. TestString.java public class TestString { public static void main(String args[]) { System.out.println("Zadania z programowania."); System.out.println("Zadania z programowania.".charAt(0)); System.out.println("Zadania z programowania.".length()); System.out.println("Zadania z programowania.".charAt(23)); System.out.println("Zadania z programowania.".toUpperCase()); System.out.println("Zadania z programowania.".toLowerCase()); System.out.println("Zadania z programowania.".indexOf('z')); System.out.println("Zadania z programowania.".indexOf("prog")); System.out.println("Zadania z programowania.".replace('.', '?'));

16

Programowanie w jzyku Java System.out.println("Zadania z programowania.". replace("adania", "dania")); System.out.println("Zadania z programowania.". replaceAll("ania", "anka")); System.out.println("Zadania z programowania.". replaceFirst("ania", "anka")); System.out.println("Zadania z programowania.".substring(10)); System.out.println("Zadania z programowania.".substring(10, 17)); System.out.println("Zadania z programowania.". concat("\b z podpowiedziami.")); System.out.println("Zadania z programowania."+"\b"+ " z odpowiedziami."); } }

Oczywicie moemy tworzy zmienne typu obiektowego String. Poniewa raz utworzony acuch znaków (ang. string) nie moe by zmieniany, to kada operacja powoduje tworzenie nowego acucha. Zmienna jest referencj do acucha znaków, wic moemy przypisa jej inny acuch (w szczególnoci zmieniony obraz acucha, który wskazywaa wczeniej). Nie powoduje to problemów z pamici, gdy zbdne obiekty w Javie s automatycznie usuwane. Utworzon zmienn naley zainicjowa: String napis = "Zadania z programowania.";

lub: String napis = new String("Zadania z programowania.");

acuch moemy równie utworzy z tablicy znaków, np.: char[] znaki = {'z', 'a', 'd', 'a', 'n', 'i', 'e'}; String napis = new String(znaki);

Zadanie 4.2. Napisz program z listingu 3., wykorzystujc zamiast literaów zmienne reprezentujce obiekty typu String lub zmienne typu char. Klas nazwij DemoString. Aby kod by czytelny, wprowad odpowiednie nazwy zmiennych, np. char kropka = '.'; itp.

Rozwiemy teraz kilka zada podobnych do zada z rozdziau 3. Zastpimy tablic znaków odpowiednim acuchem. Naley jednak pamita, e pomimo jednakowej zawartoci te obiekty si róni. Moemy dokonywa konwersji w obie strony pomidzy tablic i acuchem znaków.

Zadanie 4.3. Utwórz acuch zawierajcy napis Dzie dobry. Napisz aplikacj (plik ródowy: WitajStr. java), która wywietli napis w konsoli: a) pionowo — kady znak w odrbnym wierszu,

Rozdzia 1. i Pierwszy krok — rozpoczynamy nauk programowania w jzyku Java

17

b) poziomo — znaki rozdzielone dodatkowymi odstpami (tzw. spacjowanie

lub rozstrzelenie tekstu), c) poziomo — wielkimi literami, d) poziomo — maymi literami. W podpunktach a) i b) moesz skorzysta z ptli typu for i metody charAt(). Mona te dokona konwersji acucha na tablic znaków (metoda toCharArray() z klasy String) i dalej postpowa wedug rozwizania zadania 3.2.

Zadanie 4.4. Utwórz acuch znaków zawierajcy sowo programowanie. Napisz program zmieniajcy zawarto acucha i wywietlajcy efekty tych zmian (plik ródowy: ProgramowanieStr.java): a) zamie pierwsz liter na wielk, b) zamie wszystkie litery na wielkie. Moemy utworzy nowy acuch, speniajcy warunki zadania, i przypisa jego warto tej samej zmiennej. Dotychczasowa warto zostanie usunita z pamici w chwili, gdy nie bdzie ju dalej potrzebna.

Zadanie 4.5. Utwórz acuch znaków zawierajcy sowo programowanie. Napisz program, który znaki zawarte w acuchu bdzie wywietla w kolejnoci odwrotnej, od koca do pocztku (plik ródowy: WspakStr1.java).

Zadanie 4.6. Utwórz acuch znaków zawierajcy sowo programowanie. Napisz program odwracajcy kolejno znaków w acuchu (plik ródowy: WspakStr2.java). Zob. wskazówk do zadania 4.4.

Zadanie 4.7. Napisz program, który utworzy acuch znaków wypeniony cyframi od 0 do 9 (plik ródowy: CyfryStr.java). Rozwizanie tego zadania jest zupenie banalne — poprawna odpowied to: String cyfry = "0123456789";. Spróbuj jednak zbudowa ten acuch z poszczególnych znaków (zob. zadanie 3.7). Takie podejcie do zagadnienia moe w przyszoci si przyda .

18

Programowanie w jzyku Java

Zadanie 4.8. Napisz program, który utworzy acuch znaków wypeniony cyframi ukadu szesnastkowego (plik ródowy: CyfryStr16.java). Zob. wskazówk do zadania 4.7.

5. Tablica argumentów aplikacji W nagówku metody main()jest zadeklarowana tablica argumentów String args[] lub String[] args. W tablicy zawarte s referencje do obiektów typu String przekazanych przez system operacyjny podczas uruchomienia aplikacji poleceniem: java NazwaKlasy parametr1 parametr2 ... parametrN

Pole args.length zawiera liczb przekazanych argumentów. Argumenty w programie s dostpne przy uyciu indeksów od 0 do args.length–1: args[0], args[1], …, args[N–1], gdzie N oznacza liczb argumentów. Jeli aplikacj wywoamy bez dodatkowych parametrów (java NazwaKlasy), czyli liczba argumentów bdzie równa 0, to wtedy tablica args bdzie pusta (nie bdzie zawiera adnego elementu). W kolejnych zadaniach wykorzystamy tablic argumentów do przekazywania danych do aplikacji.

Zadanie 5.1. Napisz program, który wywietli na ekranie liczb argumentów wywoania aplikacji oraz podane argumenty. Kady argument powinien by wywietlony w odrbnym wierszu (plik ródowy: Argumenty.java). Do przegldania zawartoci tablicy wykorzystaj ptle typu for lub for each (zob. zadanie 3.2).

Zadanie 5.2. Napisz program (plik ródowy: Osoba.java), który uruchamiany z dwoma parametrami, imi i nazwisko, wywietli na ekranie w kolejnych wierszach te dane wedug schematu: Nazwisko: Kowalska Imi: Maria Nazwisko i imi: KOWALSKA Maria

Rozdzia 1. i Pierwszy krok — rozpoczynamy nauk programowania w jzyku Java

19

Inicjay: MK Login: KOmar

Wielkoci liter na wydruku powinny by zgodne z przykadem, niezalenie od tego, jakie wielkoci liter wykorzysta uytkownik, podajc imi i nazwisko. Wypisz bdy, które powstan podczas uruchomienia aplikacji z niewaciw liczb parametrów.

Zadanie 5.3. Napisz program (plik ródowy: ArgsWspak.java), który uruchomiony z kilkoma argumentami wypisze list argumentów, oddzielonych odstpami, w odwrotnej kolejnoci.

Zadanie 5.4. Napisz program (plik ródowy: ArgWspak.java), który uruchomiony z kilkoma argumentami wypisze kady argument w odrbnym wierszu, odwracajc przy tym kolejno znaków w argumencie. Naley uy dwóch ptli, stosujc tzw. zagniedanie ptli. Zewntrzna ptla powinna odczyta kolejno wszystkie argumenty, a wpisana w jej ciele wewntrzna ptla ma za zadanie odwróci kolejno znaków w biecym argumencie.

Zadanie 5.5. Napisz program, który wywietli na ekranie etykietk zawierajc imi i nazwisko podane jako parametry wywoania aplikacji (plik ródowy: EtykietaArg.java). Zmodyfikuj odpowiednio rozwizanie zadania 2.4. Oblicz dugo tekstu (imienia i nazwiska razem z odstpem midzy nimi), liczb odstpów pomidzy midzy znakiem * a tekstem oraz po tekcie przed znakiem *. Stosown liczb odstpów moesz wywietli w ptli lub wyci jako podacuch z acucha zoonego z okrelonej liczby odstpów. Ze wzgldu na konieczno oblicze zadanie wyprzedza nieco omawian teori.

6. Prawda czy fasz — logiczny typ danych Prosty typ danych boolean moe przyjmowa jedn z dwóch wartoci: false (fasz) i true (prawda). Te dwie wartoci su do oceny logicznej rónych zda (warunków) i s podstaw do dziaania instrukcji sterujcych przebiegiem programu (instrukcji warunkowych, instrukcji wyboru i ptli). Klasa Boolean opakowuje prosty typ boolean.

20

Programowanie w jzyku Java

Zadanie 6.1. Napisz program, który w formie tabeli przedstawi dziaanie operatorów logicznych (plik ródowy: OperatoryLogiczne.java). Moesz zbudowa dwuelementow tablic wartoci logicznych i uy ptli typu for each do pobierania wartoci z tej tablicy. Dziki zagniedeniu ptli moesz w atwy sposób przetestowa wszystkie wartoci dla dwóch i wikszej liczby zda logicznych. Do dyspozycji masz trzy operatory:  ! — negacj (NOT),  & lub && — koniunkcj (iloczyn logiczny, AND),  | lub || — alternatyw (sum logiczn, OR).

Zadanie 6.2. Napisz program (plik ródowy: PrawaLogiczne.java), który w formie tabeli przedstawi dowód nastpujcych praw logicznych: a) prawo wyczonego rodka p › ™p , b) prawo niesprzecznoci ™ p š ™p , c) prawo podwójnego przeczenia ™ ™p œ p . W zapisie matematycznym wyrae logicznych zastosowano nastpujce symbole: ™ — negacja, š — koniunkcja, › — alternatywa, œ — równowano . Równowano moemy w programie zastpi operatorem jest równe (== — dwa znaki równoci obok siebie). Wynikiem porównania dwóch wartoci nalecych do typu prostego jest warto logiczna.

Zadanie 6.3. Napisz program (plik ródowy: PrawaDeMorgana.java), który w formie tabeli przedstawi dowód praw De Morgana: a) I prawo De Morgana — prawo zaprzeczenia koniunkcji

™ p š q œ ™p › ™q ,

b) II prawo De Morgana — prawo zaprzeczenia alternatywy

™ p › q œ ™p š ™q .

Zadanie 6.4. Napisz program, który przedstawi tabel wartoci logicznych implikacji (plik ródowy: Implikacja.java).

Rozdzia 1. i Pierwszy krok — rozpoczynamy nauk programowania w jzyku Java

21

Przyjmijmy, e wartoci logiczne s uporzdkowane i false poprzedza true. Implikacja jest faszywa tylko w jednym przypadku true Ÿ false (z prawdziwych zaoe nie mona udowodni tezy faszywej), w pozostaych przypadkach jest prawdziwa (z prawdy wynika prawda, na podstawie faszywych zaoe mona udowodni zarówno prawd, jak i fasz). Zauwamy, e stosujc operator mniejsze lub równe ( p › q š r @ œ > p › q š p › r @ ,

c) prawo rozdzielnoci koniunkcji wzgldem alternatywy

> p š q › r @ œ > p š q › p š r @ , d) prawo odrywania > p Ÿ q š q @ Ÿ q , e) prawo eliminacji implikacji p Ÿ q œ ™p › q .

W prawach zawierajcych implikacj (podpunkty a), d) i e)) skorzystaj z metody statycznej impl(), zdefiniowanej w rozwizaniu zadania 6.4. Uproci to w istotny sposób zapis zadania. Mona te wprowadzi dodatkowe zmienne typu boolean, przechowujce wartoci wyrae stojcych po lewej i prawej stronie badanych równowanoci.

22

Programowanie w jzyku Java

Zadanie 6.7. W klasie String (od wersji Javy 1.6) dostpna jest metoda isEmpty(), zwracajca warto true, gdy dugo acucha znaków jest równa 0, oraz warto false w pozostaych przypadkach. Napisz prost aplikacj (plik ródowy: StringIsEmpty.java) pokazujc dziaanie tej metody. Ustal warto acucha, a nastpnie wywietl na ekranie ten acuch, jego dugo i warto zwrócon przez metod isEmpty().

Zadanie 6.8. Napisz program (plik ródowy: TestChar.java) demonstrujcy dziaanie metod isDigit(), isLetter(), isLetterOrDigit(), isLowerCase(), isSpaceChar(), isUpperCase() i isWhiteSpace(). Wyniki przedstaw w postaci tabeli. Zadanie wykonaj dla zestawu znaków zapisanego w acuchu: a) "A\240b3&4\040", b) "o_0+\t", c) "#\"\304\\\344\b\n".

7. Liczby cakowite typu int i klasa Integer Prosty typ danych int pozwala na przechowywanie czterobajtowych (32-bitowych) liczb cakowitych ze znakiem. Klasa Integer opakowuje prosty typ int i oferuje dwa konstruktory budujce obiekt na podstawie liczby cakowitej lub acucha znaków. Zawiera m.in. szereg metod przeznaczonych do konwersji obiektów klasy Integer na inne typy liczbowe lub acuchy znaków.

Zadanie 7.1. Uruchom aplikacj, której kod ródowy przedstawiono na listingu 4. Na podstawie obserwacji wyników dziaania programu opisz przeznaczenie uytych staych i metod statycznych klasy Integer. W kodzie ródowym programu, w miejscu trzech kropek, wpisz odpowiednie teksty objaniajce wywietlane wyniki. W przypadku wtpliwoci zajrzyj do dokumentacji jzyka Java (np. http://download.oracle.com/javase/1.5.0/ docs/api/java/lang/Integer.html). Listing 4. StaticInteger.java public class StaticInteger { public static void main(String args[]) { System.out.println("Wybrane stae i metody statyczne klasy Integer\n");

Rozdzia 1. i Pierwszy krok — rozpoczynamy nauk programowania w jzyku Java

23

System.out.println("...: "+Integer.MIN_VALUE); System.out.println("...: "+Integer.MAX_VALUE); System.out.println("...: "+Integer.SIZE); int a = 179; System.out.println("a = "+a); System.out.println("...: "+Integer.toBinaryString(a)); System.out.println("...: "+Integer.toOctalString(a)); System.out.println("...: "+Integer.toHexString(a)); System.out.println("...: "+Integer.toString(a)); System.out.println("...: "+Integer.toString(a, 4)); int b = Integer.parseInt("-177"); System.out.println("b = "+b); int c = Integer.parseInt("1000", 8); System.out.println("c = "+c); System.out.println("...: "+Integer.signum(a)); System.out.println("...: "+Integer.signum(b)); System.out.println("...: "+Integer.signum(0)); } }

Zadanie 7.2. Uruchom aplikacj przedstawion na listingu 5. Na podstawie uzyskanych wyników i dokumentacji objanij (w postaci komentarza) uyte metody klasy Integer. Listing 5. ObjectInteger.java public class ObjectInteger { public static void main(String args[]) { System.out.println("Wybrane metody obiektów klasy Integer\n"); /* tworzenie obiektów */ Integer a = new Integer(1024); Integer b = new Integer("02000"); Integer c = Integer.decode("02000"); Integer d = Integer.decode("0x2000"); System.out.println("a = "+a); System.out.println("b = "+b); System.out.println("c = "+c); System.out.println("d = "+d); /* porównania obiektów */ System.out.println("...? "+a.equals(b)); System.out.println("...? "+a.equals(c)); System.out.println("...? "+a.compareTo(c)); System.out.println("...? "+c.compareTo(d)); System.out.println("...? "+d.compareTo(c)); /* zmiana wartoci obiektu */ a = Integer.valueOf(1000); b = Integer.valueOf("1000"); c = Integer.valueOf("1000", 2); d = Integer.valueOf("1000", 16); System.out.println("a = "+a); System.out.println("b = "+b); System.out.println("c = "+c); System.out.println("d = "+d); } }

24

Programowanie w jzyku Java

Zmienne i stae (literay) typu int mog by wykorzystane do wykonywania oblicze w zbiorze liczb cakowitych, w zakresie ograniczonym 32-bitowym rozmiarem typu (od –231 do 231–1). Do dyspozycji mamy cztery podstawowe operatory: dodawanie +, odejmowanie –, mnoenie * i dzielenie (cakowite) / oraz operator %, sucy do obliczania reszty z dzielenia dwóch liczb cakowitych. Warto cakowit (potrzebn do oblicze) zawart w obiekcie moemy uzyska przy uyciu metody intValue().

Zadanie 7.3. Dla dwóch dowolnie wybranych liczb cakowitych typu int napisz aplikacj pokazujc dziaanie operatora + (plik ródowy: Dodawanie.java). Wynik wywietlaj w postaci: a = 3, b = 15 a + b = 18

Zadeklaruj i zainicjuj dwie zmienne typu int, np. int a = 2451, b = 375;. Wyraenia wykonujce obliczenia moesz umieci jako parametry w metodzie println().

Zwró uwag na kolejno wykonywania dziaa, gdy operatora + uywasz do oblicze i czenia tekstów!

Zadanie 7.4. Dla dwóch dowolnie wybranych liczb cakowitych typu int napisz aplikacje pokazujce dziaanie pozostaych operatorów arytmetycznych: a) odejmowanie – (plik ródowy: Odejmowanie.java), b) mnoenie * (plik ródowy: Mnoenie.java), c) dzielenie / (plik ródowy: Dzielenie.java), d) reszta z dzielenia % (plik ródowy: Reszta.java).

Wyniki wywietlaj podobnie jak w zadaniu 7.3.

Zadanie 7.5. Napisz aplikacj (plik ródowy: Dzielenie2.java) demonstrujc dzielenie z reszt dla liczb cakowitych o rónych znakach. Wyniki wywietlaj w postaci znanej z lekcji matematyki, np. 13 : 2 = 6 r. 1.

Zadanie 7.6. Napisz aplikacj (plik ródowy: Suma.java), która obliczy sum dwóch liczb naturalnych podanych jako parametry wywoania. Wynik wywietl na ekranie. Parametry s przekazywane do programu jako acuchy znaków. Potrzebna bdzie zamiana acucha na liczb cakowit. Mona uy odpowiedniej metody statycznej lub posuy si obiektami klasy Integer.

Rozdzia 1. i Pierwszy krok — rozpoczynamy nauk programowania w jzyku Java

25

Zadanie 7.7. Napisz aplikacj (plik ródowy: Sumuj.java), która obliczy sum serii liczb naturalnych podanych jako parametry wywoania aplikacji. Wynik wywietl na ekranie. Wprowad zmienn suma typu int i zainicjuj j wartoci 0. Korzystajc z ptli typu for each, przegldaj tablic argumentów, zamieniaj argument (acuch znaków) na liczb cakowit i dodawaj j do sumy. Po przejrzeniu caej tablicy wywietl wynik.

Zadanie 7.8. Napisz aplikacj (plik ródowy: Zamiana.java), która na podstawie dwóch parametrów cakowitych — podstawy systemu liczbowego od 2 do 36 i liczby dziesitnej — wywietli na ekranie liczb zapisan we wskazanym systemie wedug podanego wzoru: 102[10] = 123[9].

Zadanie 7.9. Napisz aplikacj (plik ródowy: Zamiana2.java), która na podstawie dwóch parametrów — podstawy systemu liczbowego od 2 do 36 i liczby zapisanej w systemie o podstawie podanej jako pierwszy parametr — wywietli na ekranie t liczb zapisan w systemie dziesitnym wedug podanego wzoru: 123[9] = 102[10].

8. Inne typy liczb cakowitych w Javie Do zapisywania liczb cakowitych w pamici komputera najczciej uywamy 1, 2, 4 lub 8 bajtów (odpowiednio 8, 16, 32 lub 64 bitów). Odpowiada to nastpujcym typom liczb cakowitych ze znakiem w jzyku Java: byte, short, int lub long. Z kadym z wymienionych typów prostych zwizana jest klasa opakowujca — Byte, Short, Integer lub Long. Klasy te dziedzicz z klasy abstrakcyjnej java.lang.Number. Zmianie ulegaj jedynie zakresy dostpnych wartoci, natomiast metody maj identyczne nazwy i analogiczny sposób dziaania. Kada z wymienionych klas posiada metody zwracajce warto reprezentowan przez obiekt jako warto jednego z pozostaych typów cakowitych.

Zadanie 8.1. Przepisz i uruchom kod ródowy przedstawiony na listingu 6. Opisz krótko zastosowane metody. Uzasadnij otrzymane rezultaty. Powtórz wiczenie, zmieniajc warto liczby n na minimaln dostpn warto typu long. Listing 6. LongNumber.java public class LongNumber { public static void main(String args[]) { long n = Long.MAX_VALUE;

26

Programowanie w jzyku Java System.out.println("n = "+n); System.out.println("BIN: "+Long.toBinaryString(n)); System.out.println("HEX: "+Long.toHexString(n)); long m = n+1; System.out.println("m = "+m); System.out.println("BIN: "+Long.toBinaryString(m)); System.out.println("HEX: "+Long.toHexString(m)); Long max = new Long(n); System.out.println("Zamiana na typ int, m = "+max.intValue()); System.out.println("BIN: "+ Integer.toBinaryString(max.intValue())); System.out.println("HEX: "+Integer.toHexString(max.intValue())); System.out.println("Zamiana na typ int, m = "+(int)m); System.out.println("BIN: "+Integer.toBinaryString((int)m)); System.out.println("HEX: "+Integer.toHexString((int)m)); } }

Zadanie 8.2. Napisz program (plik ródowy: MinMax.java) wywietlajcy minimalne i maksymalne wartoci liczb cakowitych typu byte, short, int i long. Wyniki wywietl w postaci: nazwa typu . Wykorzystaj stae MIN_VALUE i MAX_VALUE z klas opakowujcych typy proste.

Zadanie 8.3. Napisz program (plik ródowy: MaxPositive.java) wywietlajcy maksymalne wartoci liczb cakowitych typu byte, short, int i long. Wyniki wywietl w postaci binarnej i szesnastkowej. Klasy opakowujce Integer i Long zawieraj metody toBinaryString() i toHexString() — tych metod nie ma w klasach Byte i Short.

Zadanie 8.4. Napisz program (plik ródowy: Kodowanie.java) zamieniajcy acuch znaków (np. sowo kodowanie) na cig bajtów odpowiadajcych tym znakom. Poszukaj odpowiedniej metody w klasie String.

Zadanie 8.5. Napisz program (plik ródowy: Dekodowanie.java) zamieniajcy cig bajtów (np. {115, 122, 121, 102, 114}) na acuch znaków odpowiadajcych tym liczbom.

Rozdzia 1. i Pierwszy krok — rozpoczynamy nauk programowania w jzyku Java

27

Jeden z konstruktorów klasy String tworzy acuch znaków na podstawie tablicy bajtów.

Zadanie 8.6. Napisz program (plik ródowy: DodajCyfry.java) obliczajcy sum cyfr liczby cakowitej dodatniej podanej: a) w postaci tekstu — acucha znaków (cyfr) reprezentujcych t liczb, b) jako warto typu long. Skorzystaj z rozwizania zadania 8.4 i pamitaj, e kody cyfr s równe: 0 — 48, 1 — 49, 2 — 51 itd. Liczb moesz zamieni na acuch znaków.

Zadanie 8.7. Napisz program (plik ródowy: Txt2Hex.java) zamieniajcy acuch znaków ASCII na acuch cyfr szesnastkowych odpowiadajcych tym znakom. Zamie tekst na cig bajtów, a nastpnie przedstaw bajty w postaci szesnastkowej. Na jeden bajt (znak ASCII) przypadn dwie cyfry szesnastkowe.

Zadanie 8.8. Napisz program (plik ródowy: Hex2Txt.java) zamieniajcy acuch cyfr szesnastkowych na odpowiadajcy mu acuch znaków ASCII (dwie cyfry przypadaj na jeden znak).

9. Typy liczb zmiennoprzecinkowych Typy zmiennoprzecinkowe su do przechowywania liczb z czci uamkow. Java oferuje dwa typy zmiennoprzecinkowe zgodne ze standardem IEEE 754:  float — dane zmiennoprzecinkowe 32-bitowe pojedynczej precyzji

o dokadnoci 7 – 8 cyfr znaczcych,  double — dane zmiennoprzecinkowe 64-bitowe podwójnej precyzji

o dokadnoci 15 cyfr znaczcych.

Zadanie 9.1. Przepisz i uruchom kod ródowy przedstawiony na listingu 7. Zobacz efekty dziaania programu. Czy na podstawie zapisu kodu ródowego (bez czytania dokumentacji) moesz okreli dziaanie uytych metod? Sporzd krótki opis kodu i efektów jego dziaania.

28

Programowanie w jzyku Java

Listing 7. DemoDouble.java public class DemoDouble { public static void main(String[] args) { double a = Double.MIN_VALUE; System.out.println("Minimalna warto dodatnia: "+a); System.out.println("BIN: "+Long.toBinaryString(Double. doubleToLongBits(a))); System.out.println("HEX: "+Double.toHexString(a)); a = -a; System.out.println("Liczba przeciwna: "+a); System.out.println("BIN: "+Long.toBinaryString(Double. doubleToLongBits(a))); System.out.println("HEX: "+Double.toHexString(a)); } }

Zadanie 9.2. Przedstaw w postaci sowa 64-bitowego reprezentacj binarn kilku wybranych liczb typu double (plik ródowy: DoubleBin.java). Z cigu 64 bitów wyodrbnij bit znaku, cech i mantys. a) 0,25; 0,5; 1,0; 2,0; 512,0; b) 0,01; 0,1; 1,0; 10,0; 100,0; c) 1,367; 1367; 13,67; –13,67; 1,367e–12; 1,367e12; d) symbole specjalne: Double.NaN (ang. Not-a-Number), np. wynik pierwiastkowania liczby ujemnej, Double.NEGATIVE_INFINITY ( f — ujemna nieskoczono, np. wynik dzielenia –1/0,0), Double.POSITIVE_INFINITY ( f

— dodatnia nieskoczono, np. wynik dzielenia 1/0,0). e) dwie reprezentacje zmiennoprzecinkowe zera 0.0 i –0.0 oraz wartoci ekstremalne Double.MIN_VALUE, Double.MAX_VALUE i 2.2250738585072014e-308. Moemy zastosowa metod statyczn doubleToLongBits() z klasy Double i zamieni liczb zmiennoprzecinkow typu double na liczb cakowit typu long o identycznej reprezentacji binarnej. W dalszej kolejnoci zamienimy liczb typu long na odpowiadajcy jej cig cyfr binarnych. Niestety, metoda statyczna toBinaryString() z klasy Long, tworzc cig cyfr binarnych odpowiadajcych liczbie typu long, pomija zera nieznaczce. Uzupenimy te zera do 64 znaków w acuchu, wycinajc je jako podcig o odpowiedniej dugoci z cigu (acucha) zoonego z 64 cyfr 0 i dodajc do cigu zer uzyskan posta binarn liczby. Musimy pamita , e indeksy znaków w acuchu s liczone od strony lewej do prawej, natomiast bity w liczbie binarnej s numerowane od strony prawej (najmodszy bit to 0) do lewej (najstarszy bit to 63). Znaczenie poszczególnych bitów w reprezentacji binarnej liczby typu double jest nastpujce: bit nr 63 — bit znaku, bity o numerach od 52 do 62 — cecha liczby (11 bitów), bity o numerach od 0 do 51 (52 bity) — cz uamkowa mantysy.

Rozdzia 1. i Pierwszy krok — rozpoczynamy nauk programowania w jzyku Java

29

Zadanie 9.3. Cig bitów 111110000011110000111000110010 reprezentuje pewn liczb zmiennoprzecinkow pojedynczej precyzji (zera nieznaczce pominito). Jak warto dziesitn ma ta liczba? Napisz program (plik ródowy: Bin2Float.java) wyznaczajcy t warto. Liczby typu int i float zajmuj w pamici 32 bity. Znajd liczb cakowit posiadajc podan reprezentacj binarn i skorzystaj z metody intBitsToFloat() z klasy Float.

Zadanie 9.4. Cig bitów 111110000011110000111000110010 reprezentuje pewn liczb zmiennoprzecinkow podwójnej precyzji (zera nieznaczce pominito). Jak warto dziesitn ma ta liczba? Napisz program (plik ródowy: Bin2Double.java) wyznaczajcy t warto. Liczby typu long i double zajmuj w pamici 64 bity.

Zadanie 9.5. Napisz binarne reprezentacje symboli specjalnych ( rf , NaN) dla liczb zmiennoprzecinkowych pojedynczej precyzji. Utwórz aplikacj (plik ródowy: TestBinFloat.java), która odkoduje liczb binarn podan jako parametr wywoania i wywietli odpowiadajc jej warto typu float. Wykorzystaj t aplikacj do sprawdzenia poprawnoci swoich odpowiedzi. Reprezentacja binarna liczby zmiennoprzecinkowej pojedynczej precyzji skada si z bitu znaku, 8 bitów cechy i 23 bitów mantysy (razem 32 bity). Cecha symbolu specjalnego ma wszystkie bity równe 1.

30

Programowanie w jzyku Java

Rozdzia 2.

Drugi krok — operacje wejcia-wyjcia i instrukcje sterujce w Javie 10. Wywietlanie sformatowanych wyników w konsoli. Stae i metody z klasy Math Do formatowania wywietlanych wyników w konsoli moemy uy metody printf() na obiekcie out klasy System: System.out.printf(acuch_formatujcy, lista_argumentów);

Pierwszy parametr (acuch_formatujcy) jest acuchem znaków (obiektem klasy String) zawierajcym znaczniki formatujce w postaci: %[indeks_argumentu$][flaga][szeroko][.precyzja]znak_konwersji

Drugi parametr (lista_argumentów) jest list zmiennych lub staych oddzielonych przecinkami — wartoci tych argumentów bd podstawiane w miejsce znaczników formatujcych w acuchu formatujcym zgodnie z kolejnoci wystpowania lub w miejscu okrelonym przez opcjonalny indeks_argumentu$. Pozostae opcjonalne parametry okrelaj:  flaga — znak okrelajcy dodatkowe cechy sformatowanego wyniku, np. + oznacza, e przed liczb zawsze wywietlany jest znak + lub –.

32

Programowanie w jzyku Java  szeroko — okrela szeroko pola, czyli liczb znaków przeznaczonych

do wywietlenia wartoci argumentu (jeli warto nie mieci si w tym polu, to jego rozmiar zostanie automatycznie poszerzony).  precyzja — okrela liczb miejsc po przecinku (domylnie 6) dla wywietlanych

liczb zmiennoprzecinkowych. Znacznik formatujcy rozpoczyna si znakiem % i koczy (obowizkowym) znakiem (znak_konwersji) okrelajcym typ formatowanych danych, np.: c — znak, d — liczba cakowita dziesitna, f — liczba zmiennoprzecinkowa, s — acuch znaków. Wicej szczegóów znajdziemy w dokumentacji klasy Formater: http://docs.oracle.com/ javase/1.5.0/docs/api/java/util/Formatter.html. Klasa Math zawiera zestaw funkcji matematycznych i dwie stae (pola klasy) — przyblienie liczby S i podstawy logarytmu naturalnego e. Wszystkie funkcje zostay zdefiniowane jako metody statyczne, wic nie tworzymy obiektów klasy Math, a jedynie wywoujemy zdefiniowane metody, np. Math.sqrt(2) zwróci warto (przyblion) pierwiastka kwadratowego z liczby 2. Wykaz funkcji znajdziemy w dokumentacji: http://docs.oracle.com/javase/6/docs/api/java/lang/Math.html.

Zadanie 10.1. Przedstaw uamek

4 7

z dokadnoci do 5 miejsc po przecinku.

Dzielc 4 przez 7, otrzymasz uamek dziesitny, o ile co najmniej jedn z tych liczb zamienisz na liczb zmiennoprzecinkow, np. stosujc tzw. rzutowanie double x = (double) 4. Do sformatowania wyniku moesz uy metody System.out.printf().

Zadanie 10.2. Wywietl w konsoli z dokadnoci do 10 miejsc po przecinku nastpujce liczby niewymierne: e, S i M (liczba Fibonacciego). Liczby poprzed komentarzem sownym i ustaw w kolumnie wyrównanej do prawej strony. Liczby e i S s zdefiniowane w klasie Math jako stae, natomiast M

1 5 . 2

Zadanie 10.3. Napisz aplikacj, która wywietli w konsoli w trzech kolumnach liczby naturalne 2, 3, 5, 7, 11, 13 i 17, pierwiastki kwadratowe i pierwiastki szecienne z tych liczb. Wartoci pierwiastków wywietlaj z dokadnoci do 8 miejsc po przecinku, w kolumnach o szerokoci 15 znaków. Liczby 2, 3, 5, 7, 11, 13 i 17 umie w tablicy. Zastosuj ptl typu for each do przegldania tablicy, oblicze i wywietlania pierwiastków.

Rozdzia 2. i Drugi krok — operacje wejcia-wyjcia i instrukcje sterujce w Javie

33

Zadanie 10.4. Napisz aplikacj, która wywietli w konsoli pierwiastki arytmetyczne od stopnia 2. do 10. z liczby 5 z dokadnoci do 6 miejsc po przecinku. 1

Zgodnie z definicj n x x n , wic do obliczania pierwiastków mona wykorzysta metod Math.pow(podstawa, wykadnik).

Zadanie 10.5. Wywietl w konsoli kody ósemkowe, dziesitkowe i szesnastkowe wielkich liter alfabetu aciskiego. W pierwszym wierszu umie opisy poszczególnych kolumn: Znak, OCT, DEC i HEX. Wykorzystaj specyfikatory %o, %d i %x w acuchu formatujcym.

Zadanie 10.6. Wywietl w konsoli miar kta o rozwartoci 1 radiana w stopniach (z maksymaln moliw precyzj), w stopniach i minutach ktowych oraz w stopniach, minutach i sekundach ktowych. W klasie Math znajdziesz metody zamieniajce radiany na stopnie i stopnie na radiany. Pozostaje opracowa samodzielnie zamian czci dziesitnych stopnia na minuty (1° = 60') i sekundy ktowe (1' = 60").

Zadanie 10.7. Wywietl w konsoli miary któw 1°, 1' i 1" w radianach z dokadnoci do 15 miejsc po przecinku.

Zadanie 10.8. Oblicz kty ostre w trójkcie egipskim (trójkcie prostoktnym o proporcji boków 3:4:5). Wyniki podaj: a) w radianach, z dokadnoci do 4 miejsc po przecinku, b) w stopniach, z dokadnoci do 1 miejsca po przecinku, c) w stopniach i minutach ktowych, z dokadnoci do 1', d) w stopniach, minutach i sekundach ktowych z dokadnoci do 1". W klasie Math znajdziesz funkcje trygonometryczne (argumenty w radianach) oraz funkcje do nich odwrotne (wartoci w radianach).

34

Programowanie w jzyku Java

11. Wczytywanie danych — klasa Scanner Pobieranie danych ze standardowego strumienia wejciowego System.in moemy zrealizowa za pomoc obiektu klasy Scanner: Scanner input = new Scanner(System.in);

Klasa Scanner oferuje m.in. metody testujce, czy w strumieniu znajduje si kolejny token okrelonego typu, oraz metody odczytujce jego warto ze strumienia:  hasNextLine() — zwraca warto true, gdy w strumieniu znajduje si wiersz danych, w przeciwnym wypadku zwraca warto false;  nextLine() — odczytuje jeden wiersz danych;  hasNext() — zwraca warto true, gdy w strumieniu znajduje si nastpny

token (np. sowo ograniczone spacjami);  next() — odczytuje ze strumienia jeden token (jedno sowo);  hasNextInt() — zwraca warto true, gdy kolejny token w strumieniu

reprezentuje liczb cakowit;  nextInt() — odczytuje ze strumienia kolejny token, interpretujc go jako

liczb cakowit. Podobne metody zdefiniowano dla pozostaych prostych typów danych. Szczegóowe informacje znajdziemy w dokumentacji pod adresem http://docs.oracle.com/javase/ 1.5.0/docs/api/java/util/Scanner.html.

Zadanie 11.1. Napisz program zamieniajcy temperatur podan w stopniach Celsjusza na temperatur wyraon w stopniach Fahrenheita. Dane wejciowe wprowadzamy z klawiatury w postaci liczby dziesitnej; wynik naley obliczy i wywietli z dokadnoci do 0,1 stopnia. Wzór do zamiany temperatury ze skali Celsjusza na skal Fahrenheita: °F = °C·1,8+32.

Zadanie 11.2. Napisz program zamieniajcy temperatur podan w stopniach Fahrenheita na temperatur wyraon w stopniach Celsjusza. Dane wejciowe wprowadzamy z klawiatury w postaci liczby cakowitej, wynik naley obliczy i wywietli z dokadnoci do 0,1 stopnia. Przekszta wzór podany w zadaniu 11.1.

Rozdzia 2. i Drugi krok — operacje wejcia-wyjcia i instrukcje sterujce w Javie

35

Zadanie 11.3. Napisz program obliczajcy dugo przeciwprostoktnej w trójkcie prostoktnym, majc dane: a) dugoci przyprostoktnych, b) dugo przyprostoktnej i miar kta ostrego (podan w stopniach) lecego

naprzeciw tej przyprostoktnej. Dane uytkownik wprowadza z klawiatury. Wyniki naley wywietli z dokadnoci do 0,001.

Zadanie 11.4. Napisz program, który odczyta z konsoli dwie liczby zapisane w naturalnym kodzie binarnym, obliczy ich sum i wywietli wynik w postaci binarnej. Zaproponuj ograniczenie liczby cyfr binarnych stosownie do przyjtej metody oblicze i uytych zmiennych. Odczytaj cigi cyfr binarnych i zamie je na liczby cakowite, dodaj uzyskane rezultaty i przedstaw wynik w postaci binarnej. Póniej wykonamy te obliczenia na cigach cyfr, bez konwersji na liczby.

Zadanie 11.5. Napisz program, który zamieni uamek zwyky na procent. Uamek zwyky wprowadzamy z klawiatury w postaci acucha znaków zoonego z dwóch liczb cakowitych (licznika i mianownika) oddzielonych znakiem / (bez odstpów). Wynik naley wywietli z dokadnoci do 0,1%.

Zadanie 11.6.

acuch znaków zawiera oddzielone odstpami imi i nazwisko pracownika, liczb przepracowanych godzin i stawk godzinow. Napisz program obliczajcy na tej podstawie wynagrodzenie nalene pracownikowi. Wykorzystaj metody klasy Scanner do przeczytania danych z acucha znaków.

Zadanie 11.7. Plik tekstowy dane.txt zawiera wiersz tekstu, a w nim oddzielone odstpami imi i nazwisko pracownika, liczb przepracowanych godzin i stawk godzinow. Napisz program obliczajcy na tej podstawie wynagrodzenie nalene pracownikowi. Wykorzystaj metody klasy Scanner do przeczytania danych z pliku tekstowego.

36

Programowanie w jzyku Java

12. Operacje na tekstach — klasy StringBuffer i StringBuilder Skadanie acucha znaków z krótszych acuchów moemy zrealizowa przy uyciu obiektu klasy StringBuffer lub StringBuilder (od wersji JDK 5.0). Obie klasy maj ten sam interfejs. Podstawowe metody to: append() (dodawanie znaków na kocu acucha — dane rónych typów s konwertowane na typ String i doczane do budowanego obiektu), delete() (usuwanie znaków z acucha), insert() (wstawianie znaków do acucha), replace() (zastpowanie znaków w acuchu). W budowanym obiekcie mamy dostp do odczytu pojedynczych znaków (metoda charAt()) i podacuchów (metoda substring()) oraz moliwo zmiany pojedynczego znaku (setCharAt()). Wicej informacji mona znale  w dokumentacji: http://docs.oracle.com/javase/1.5.0/ docs/api/java/lang/StringBuffer.html.

Zadanie 12.1. Wykresem funkcji kwadratowej f ( x) ax 2  bx  c, a z 0 jest parabola o wierzchoku §  b  ' · . Napisz program, który obliczy i wywietli w konsoli wspórzdne wierz, ¨ ¸ © 2 a 4a ¹

choka paraboli. Zakadamy, e uytkownik bdzie podawa poprawne wspóczynniki trójmianu. Wykorzystaj obiekt klasy StringBuffer lub StringBuilder i metod append() do zbudowania acucha znaków przedstawiajcego wspórzdne wierzchoka. Metoda append() dodaje na kocu acucha znaki, acuchy znaków, wartoci wbudowanych typów danych zamienione na acuch znaków lub obiekty zamienione na acuch znaków.

Zadanie 12.2. Rozwi zadanie 12.1, stosujc obiekt i metod insert() klasy StringBuffer lub StringBuilder. Zacznij od zbudowania acucha znaków "(, )", do którego nastpnie wstawisz obliczone wartoci wspórzdnych wierzchoka paraboli. Zwró uwag na kolejno wstawiania tych wartoci do pocztkowego acucha.

Rozdzia 2. i Drugi krok — operacje wejcia-wyjcia i instrukcje sterujce w Javie

37

Zadanie 12.3. Rozwi zadanie 12.1, stosujc obiekt i metod replace() klasy StringBuffer lub StringBuilder. Zacznij od zbudowania acucha znaków "(#1, #2)". Podacuchy "#1" i "#2" (o dugoci 2 znaków) wskazuj miejsca, w których zastpisz te podacuchy obliczonymi wartociami wspórzdnych wierzchoka paraboli. Aby znale miejsca wstawiania obliczonych wartoci, zastosuj metod indexOf().

Zadanie 12.4. Napisz program, który obliczy rónic liczby cakowitej dodatniej wprowadzonej z konsoli i liczby zapisanej tymi samymi cyframi w odwrotnej kolejnoci. Wynik wywietl w postaci caego wyraenia, np.: 452-254 = 198. W klasie StringBuffer lub StringBuilder znajdziesz metod reverse() odwracajc kolejno znaków w acuchu oraz metod toString() konwertujc budowany acuch na obiekt klasy String.

Zadanie 12.5. Symbol [a, b] w geometrii analitycznej oznacza wektor o wspórzdnych a i b (w przestrzeni dwuwymiarowej, czyli na paszczy nie). Napisz program obliczajcy dugo wektora [a, b] wprowadzonego przez uytkownika z klawiatury w postaci acucha znaków, np. [2.5, -4]. Zakadamy, e uytkownik bdzie podawa poprawn posta danych (nawiasy prostoktne, przecinek i liczby dziesitne w notacji z kropk). Z acucha znaków naley wydoby podacuchy reprezentujce liczby a i b (wspórzdne wektora), zamieni je na liczby i obliczy dugo wektora ze wzoru

u

a2  b2 .

Zadanie 12.6. Napisz program obliczajcy dugo wektora [a, b, c] (w przestrzeni trójwymiarowej) wprowadzonego przez uytkownika z klawiatury w postaci acucha znaków. Zakadamy, e uytkownik bdzie podawa poprawn posta danych (nawiasy prostoktne, dwa przecinki oddzielajce wspórzdne i trzy liczby dziesitne w notacji z kropk).

Dugo wektora obliczymy ze wzoru u

a 2  b2  c2 .

38

Programowanie w jzyku Java

13. Instrukcje warunkowe i instrukcja selekcji Instrukcje warunkowe stosujemy w sytuacji, gdy dalszy przebieg programu zaley od spenienia pewnego warunku (wyraenia logicznego o wyniku typu boolean). Instrukcja warunkowa ma posta if (wyraenie) instrukcja;

lub if (wyraenie) instrukcja1; else instrukcja2;

Najpierw obliczana jest warto wyraenia logicznego. Jeeli wyraenie ma warto true, to wykonywana jest instrukcja (lub instrukcja1 w drugiej postaci instrukcji warunkowej). Je eli wyra enie ma warto false, to wykonanie instrukcji w pierwszym przypadku jest pomijane, a w drugim przypadku wykonywana jest instrukcja2. Instrukcje mog by instrukcjami prostymi, z o onymi (cig instrukcji ujtych w nawiasy klamrowe {}, tzw. blok) lub instrukcjami warunkowymi (tzw. zagnie d anie instrukcji warunkowych). Instrukcja selekcji pozwala na wybór jednego z kilku wariantów. Skadnia instrukcji jest nastpujca: switch (wyraenie) { case warto1: instrukcja1; break; case warto2: instrukcja2; break; case warto3: instrukcja3; break; // itd. ....default: instrukcja; break; }

Wyraenie przyjmuje wartoci cakowite. Instrukcja (switch) porównuje warto wyra enia z wartociami warto1, warto2 itd. Jeli jedna z nich jest równa wartoci obliczonego wyraenia, to wykonywana jest odpowiednia instrukcja z ciaa instrukcji switch. Instrukcja break powoduje natychmiastowe zakoczenie instrukcji switch. Pominicie instrukcji break jest dopuszczalne, ale spowoduje wykonywanie kolejnych instrukcji wystpujcych po wybranej instrukcji (do koca instrukcji selekcji lub wystpienia break). Jeli wyraenie nie przyjmuje adnej z podanych wartoci, to wykonywana jest instrukcja domylna (default). Instrukcja domylna jest opcjonalna i moemy j pomin. Instrukcje selekcji mona zagnieda.

Rozdzia 2. i Drugi krok — operacje wejcia-wyjcia i instrukcje sterujce w Javie

39

Zadanie 13.1. Napisz program, który zapyta uytkownika o imi, a nastpnie wykorzystujc podane imi, wywietli w konsoli napis w postaci: "Jan jest mczyzn." lub "Anna jest kobiet.". Wykorzystaj fakt, e typowe polskie imiona eskie s zakoczone na liter a.

Zadanie 13.2. Napisz program obliczajcy pole powierzchni i obwód kwadratu. Dugo boku kwadratu uytkownik wprowadzi z klawiatury. Program powinien sprawdzi, czy wprowadzona dugo boku jest poprawna (dodatnia).

Zadanie 13.3. Uytkownik wprowadza z klawiatury dwie liczby rzeczywiste a i b. Napisz program, który wywietli (zapisany w sposób symboliczny) zbiór zoony z tych liczb oraz wszystkich liczb zawartych midzy nimi. Jeli liczby s równe, to otrzymamy zbiór jednoelementowy {a}, w przeciwnym razie szukanym zbiorem bdzie przedzia domknity.

Zadanie 13.4. Uytkownik wprowadza z klawiatury wspóczynniki funkcji kwadratowej f ( x)

ax 2  bx  c

Napisz program, który wyznaczy zbiór wartoci tej funkcji lub wywietli komunikat, e podane wspóczynniki nie s poprawne (przypadek a 0 ). Do zapisania zbioru wartoci funkcji, który jest przedziaem nieograniczonym, bdzie potrzebny symbol f . W konsoli moemy ten symbol „zoy ” z dwóch znaków oo, co w poczeniu ze znakiem + lub — bdzie wystarczajco czytelne (–oo lub +oo).

Zadanie 13.5. Uytkownik wprowadza z klawiatury wspóczynniki funkcji kwadratowej f ( x)

ax 2  bx  c

Napisz program, który wyznaczy przedziay monotonicznoci i ekstremum tej funkcji.

40

Programowanie w jzyku Java

Zadanie 13.6. Napisz program rozwizujcy równanie liniowe ax  b 0 . Wspóczynniki równania uytkownik wprowadzi z klawiatury. Rozwa wszystkie moliwe przypadki dla wspóczynników równania.

Zadanie 13.7. Uytkownik wprowadza z klawiatury trzy liczby a, b i c. Napisz program, który wywietli najmniejsz (lub najwiksz) z tych liczb. Nie wprowadzaj dodatkowych zmiennych.

Zadanie 13.8. Uytkownik wprowadza z klawiatury trzy liczby a, b i c. Napisz program, który wywietli te liczby w sposób uporzdkowany, w kolejnoci od najmniejszej do najwikszej (lub od najwikszej do najmniejszej). Nie wprowadzaj dodatkowych zmiennych.

Zadanie 13.9. Stosujc instrukcj selekcji, napisz program, który liczb naturaln jednocyfrow zapisze sownie.

Zadanie 13.10. Napisz program, który podan liczb naturaln mniejsz od 100 zapisze sowami.

Zadanie 13.11. Napisz program, który podan liczb naturaln mniejsz od 1000 zapisze sowami.

Zadanie 13.12. Napisz program, który sprawdzi poprawno daty z obecnego wieku, zapisanej w postaci dd.mm.rrrr, i wywietli odpowiedni komunikat.

Zadanie 13.13. Napisz program, który dat podan w postaci dd.mm.rrrr zapisze w formacie rrrr-mm-dd. Przyjmij, e wprowadzana data jest poprawna (np. sprawdzona programem z zadania 13.12).

Zadanie 13.14. Napisz program, który dat podan w formacie dd.mm.rrrr zapisze w postaci tradycyjnej: a) z miesicem zapisanym sownie, np. 15 marca 2012; b) z miesicem zapisanym w systemie rzymskim, np. 15 III 2012.

Przyjmij, e wprowadzona przez uytkownika data jest poprawna.

Rozdzia 2. i Drugi krok — operacje wejcia-wyjcia i instrukcje sterujce w Javie

41

Zadanie 13.15. Napisz program, który na podstawie daty podanej w formacie dd.mm.rrrr okreli, jaki to dzie tygodnia. Przyjmij, e wprowadzona przez uytkownika data jest poprawna. Poszukaj informacji na temat wzoru Zellera.

14. Instrukcja ptli typu do-while Ptla ze sprawdzaniem warunku na kocu ma posta: do instrukcja; while(warunek);

Najpierw jest wykonywana instrukcja, potem obliczana jest warto wyraenia logicznego (warunek). Jeli warunek ma warto true, to powracamy do wykonywania instrukcji, i cykl si powtarza. Cech charakterystyczn tej ptli jest to, e instrukcja wykona si co najmniej raz (do instrukcja; while(false);). Naley zwróci uwag, aby instrukcja miaa wpyw na badany warunek, poniewa moemy uzyska ptl nieskoczon (do instrukcja; while(true);). Ptl nieskoczon, utworzon wiadomie, moemy przerwa, uywajc w ciele ptli instrukcji warunkowej i instrukcji break.

Zadanie 14.1. Uytkownik wprowadza z klawiatury seri liczb rónych od zera, zero natomiast jest sygnaem zakoczenia wprowadzania danych. Napisz program, który obliczy sum tych liczb.

Zadanie 14.2. Podczas wprowadzania danych niejednokrotnie potrzebujemy liczb speniajcych okrelone warunki, np. dodatnich. Napisz program, który przyjmie z konsoli wycznie warto dodatni zmiennej. Jeli uytkownik poda liczb ujemn lub zero, to program powinien ponowi danie podania waciwej wartoci. Wczytywanie wartoci zmiennej umie w ptli ze sprawdzaniem warunku na kocu.

Zadanie 14.3. Napisz program, który wywietli w konsoli wielokrotnoci liczby 7 mniejsze od 100.

42

Programowanie w jzyku Java

Zadanie 14.4. Napisz program obliczajcy pole powierzchni koa. Promie koa uytkownik wprowadza z klawiatury. Program powinien zasygnalizowa bdne dane (liczb ujemn lub zero) i ponownie zapyta o dugo promienia.

Zadanie 14.5. Napisz program obliczajcy pole powierzchni piercienia koowego o promieniu zewntrznym R i wewntrznym r. Dugoci promieni uytkownik wprowadza z klawiatury. Program powinien zasygnalizowa bdne dane i ponownie zapyta o potrzebn warto.

Zadanie 14.6. Napisz program wywietlajcy w konsoli cig liczb Fibonacciego mniejszych od 1000. Cig liczb Fibonacciego okrelamy w nastpujcy sposób: F(1) = 1, F(2) = 1, F(n) = F(n–1)+F(n–2) dla n =3, 4, 5…. Pomimo rekurencyjnego charakteru wzoru moemy zrealizowa obliczenia w sposób iteracyjny, uywajc trzech zmiennych i odpowiednio przestawiajc w nich wartoci trzech kolejnych liczb cigu Fibonacciego.

Zadanie 14.7. Napisz program obliczajcy, ile jest liczb w cigu Fibonacciego mniejszych od podanej przez uytkownika liczby cakowitej n.

Zadanie 14.8. Napisz program obliczajcy pole powierzchni trójkta równobocznego i umoliwiajcy wielokrotne powtarzanie oblicze. Jako znak zakoczenia oblicze przyjmij podanie dugoci boku równej 0. Dla wartoci ujemnych wywietl stosowny komunikat i ponów pytanie o dugo boku.

Zadanie 14.9. Napisz program umoliwiajcy wielokrotne wykonywanie oblicze (np. dugoci okrgu). Po wykonaniu oblicze program powinien wywietli pytanie Czy obliczamy dalej (t/n)?. W pytaniu zawarta jest sugestia sposobu udzielenia odpowiedzi: t — tak, n — nie (inne odpowiedzi powinny by ignorowane).

15. Instrukcja ptli typu while Ptla ze sprawdzaniem warunku na pocztku ma posta: while(warunek) instrukcja;

Rozdzia 2. i Drugi krok — operacje wejcia-wyjcia i instrukcje sterujce w Javie

43

Najpierw obliczana jest warto wyraenia logicznego warunek. Jeeli warunek ma warto true, to wykonywana jest instrukcja i nastpuje powrót do badania warunku (cykl si powtarza). Jeeli warunek przyjmie warto false, to dziaanie ptli zostanie zakoczone. Cech charakterystyczn tej ptli jest to, e instrukcja moe nie wykona si ani razu (while(false) instrukcja;). Naley zwróci uwag, aby instrukcja miaa wpyw na badany warunek, gdy moemy uzyska ptl nieskoczon (while(true) instrukcja;). Poniewa skadnia ptli dopuszcza uycie instrukcji pustej, powstaje moliwo przypadkowego utworzenia ptli nieskoczonej w postaci while(true); instrukcja; (wstawienie znaku rednika pomidzy warunek i instrukcj).

Zadanie 15.1. Uytkownik wprowadza z klawiatury dwie liczby naturalne. Nie korzystajc z operatora dodawania (+), oblicz sum tych liczb. Napisz program obliczajcy sum tych liczb, majc do dyspozycji operatory inkrementacji (++) i dekrementacji (––). Wyobra sobie dwa stosy patyczków. Dodawanie realizujesz, przekadajc po jednym patyczku z jednego stosu na drugi. Wykorzystaj ten pomys do rozwizania zadania.

Zadanie 15.2. Uytkownik wprowadza z klawiatury dwie liczby cakowite. Napisz program obliczajcy sum tych liczb, korzystajc z operatorów inkrementacji (++) i dekrementacji (––).

Zadanie 15.3. Napisz program obliczajcy iloczyn liczb cakowitych, nie korzystajc z operatora *. Do dyspozycji masz operatory + i ––. Zadanie rozwi: a) dla pary liczb cakowitych dodatnich, b) dla pary dowolnych liczb cakowitych. W zadaniu b rozwa wszystkie moliwe przypadki i sprowad je ewentualnie do przypadku z zadania a.

Zadanie 15.4. Korzystajc z operatora odejmowania (–), napisz program obliczajcy iloraz cakowity pary liczb cakowitych.

Zadanie 15.5. Korzystajc z operatora odejmowania (–), napisz program obliczajcy reszt z dzielenia pary liczb cakowitych.

44

Programowanie w jzyku Java

Zadanie 15.6. Napisz program obliczajcy cakowity pierwiastek kwadratowy z podanej liczby naturalnej. Nie korzystaj przy tym z funkcji bibliotecznych oraz innych metod przyblionego obliczania pierwiastka kwadratowego i zaokrglenia otrzymanego wyniku zmiennoprzecinkowego do liczby cakowitej. Cakowity pierwiastek kwadratowy z liczby n jest najwiksz liczb naturaln p spe2 niajc nierówno p d n .

Zadanie 15.7. Napisz program wyznaczajcy najmniejsz wspóln wielokrotno (NWW) dla pary liczb cakowitych dodatnich. Obliczaj wielokrotnoci jednej liczby i sprawdzaj, czy obliczona wielokrotno jest wielokrotnoci drugiej liczby (czy dzieli si bez reszty przez drug liczb).

Zadanie 15.8. Korzystajc z algorytmu Euklidesa, napisz program wyznaczajcy najwikszy wspólny dzielnik (NWD) pary liczb cakowitych dodatnich.

Zadanie 15.9. Mamy dwie róne liczby cakowite dodatnie. Bierzemy mniejsz z nich i obliczamy jej wielokrotno do chwili, gdy wielokrotno osignie lub przekroczy warto drugiej liczby. W przypadku równoci mamy ju gotowy wynik. Jeli jednak wielokrotno pierwszej liczby przekroczya warto drugiej liczby, to zaczynamy liczy wielokrotnoci drugiej liczby i porównywa wyniki z obliczon wielokrotnoci pierwszej liczby. Naprzemienne liczenie kolejnych wielokrotnoci zakoczymy w chwili, gdy obie wielokrotnoci bd równe. Uzasadnij, e to postpowanie si zakoczy. Napisz na tej podstawie program wyznaczajcy najmniejsz wspóln wielokrotno (NWW) pary liczb cakowitych dodatnich.

16. Instrukcja ptli typu for Instrukcja ptli typu for ma skadni: for(instrukcja_inicjujca; wyraenie_logiczne; instrukcja_modyfikujca) instrukcja;

Na pocztku wykonywana jest (tylko raz) instrukcja_inicjujca. Nastpnie obliczana jest warto wyraenia logicznego (wyraenie_logiczne). Jeeli wyraenie logiczne ma warto true, to wykonywana jest instrukcja, w przeciwnym razie (gdy wyraenie logiczne ma warto false) ptla zostaje zakoczona. Po wykonaniu instrukcji

Rozdzia 2. i Drugi krok — operacje wejcia-wyjcia i instrukcje sterujce w Javie

45

(instrukcja) wykonywana jest instrukcja_modyfikujca i nastpuje powrót do obliczania wartoci wyraenia logicznego (cykl jest kontynuowany). Instrukcja for czsto przyjmuje posta (n jest ustalon liczb naturaln): for(int i = 0; i < n; ++i) instrukcja; // odliczanie w gór

lub: for(int i = n; i > 0; --i) instrukcja; // odliczanie w dó

W obu przypadkach instrukcja zostanie wykonana n razy, przy czym w pierwszym przypadku zmienna i (zwana czsto zmienn sterujc lub licznikiem) przyjmie kolejno wartoci 0, 1, 2 … n-1, a w drugim przypadku n, n–1, … 1. W kadym cyklu instrukcja_modyfikujca zmienia warto zmiennej i (++i — inkrementacja, czyli zwikszenie wartoci zmiennej i o 1, lub ––i — dekrementacja, czyli zmniejszenie zmiennej i o 1). Ptla for nie ogranicza si do przedstawionych wyej zastosowa. W uzasadnionych sytuacjach mona poszczególne instrukcje pomija. W skrajnym przypadku uzyskamy nieskoczon ptl w postaci for(;;);, wykonujc instrukcj pust.

Zadanie 16.1. Napisz program, który nie wykonujc mnoenia, obliczy kwadrat liczby naturalnej. Wykorzystaj fakt, e suma kolejnych liczb nieparzystych jest kwadratem liczby naturalnej: 1 12 , 1  3

4

22 , 1  3  5 9

32 itd.

Zadanie 16.2. Napisz program, który sprawdzi, czy wprowadzone z klawiatury sowo jest palindromem, czyli brzmi tak samo czytane od strony lewej do prawej i od prawej do lewej. Przykadem palindromu jest sowo kajak lub imi Anna (bez rozróniania wielkoci liter). Moesz porównywa podany tekst z tekstem zapisanym tymi samymi znakami w odwrotnej kolejnoci lub porównywa pierwszy znak z ostatnim, drugi z przedostatnim itd.

Zadanie 16.3. Napisz program, który sprawdzi, czy wprowadzone z klawiatury zdanie jest palindromem, czyli brzmi tak samo czytane od strony lewej do prawej i od prawej do lewej. Przykadem zdania-palindromu jest Kobya ma may bok (bez rozróniania wielkoci liter i uwzgldniania odstpów midzy sowami).

Zadanie 16.4. Napisz program wywietlajcy na ekranie tabliczk mnoenia.

46

Programowanie w jzyku Java

Zadanie 16.5. Napisz program wywietlajcy na ekranie tabliczk dodawania i tabliczk mnoenia w pitkowym ukadzie pozycyjnym.

Zadanie 16.6. Napisz program obliczajcy sum n pocztkowych wyrazów cigu harmonicznego. Liczb n uytkownik wprowadza z klawiatury.

Zadanie 16.7. Napisz program obliczajcy silni liczby naturalnej n. Liczb n uytkownik wprowadza z klawiatury.

Zadanie 16.8. Napisz program umoliwiajcy wielokrotne obliczanie potg o wykadniku naturalnym n i podstawie rzeczywistej a. Nie korzystaj z funkcji klasy Math. Podanie wykadnika –1 powinno przerwa dziaanie programu.

Rozdzia 3.

Trzeci krok — budujemy wasne metody i klasy 17. Obsuga wyjtków Wyjtek (ang. exception) — nietypowa sytuacja pojawiajca si podczas dziaania programu. Kady wyjtek w Javie jest obiektem okrelonego typu, przekazywanym do metody, której dziaanie doprowadzio do pojawienia si bdu. Metoda moe przechwyci wyjtek i wykona instrukcje zapobiegajce przerwaniu dziaania programu. Konstrukcja obsugi wyjtków przedstawia si nastpujco: try { instrukcja } catch (typ_wyjtku_1 e) { instrukcja_obsugi_wyjtku_1 } catch (typ_wyjtku_2 e) { instrukcja_obsugi_wyjtku_2 } ... catch (typ_wyjtku_n e) { instrukcja_obsugi_wyjtku_n } [finally { instrukcja }]

Opcjonalny blok finally jest zawsze wykonywany przed powrotem do instrukcji wystpujcej za konstrukcj try-catch. W kodzie programu moemy generowa wyjtki, stosujc instrukcj throw.

Zadanie 17.1. Podczas wprowadzania danych liczbowych uytkownik moe wiadomie lub przez pomyk wprowadzi cig znaków niebdcy poprawnie zapisan liczb. Spowoduje to przerwanie pracy programu. Napisz program umoliwiajcy wczytywanie z klawiatury liczby zmiennoprzecinkowej typu double przy uyciu metody nextDouble() z klasy Scanner i reagujcy poprawnie na popeniony bd. Naley przechwyci i obsuy wyjtek InputMismatchException (pakiet java.util), a nastpnie ponowi proces wczytywania liczby.

48

Programowanie w jzyku Java

Zadanie 17.2. Dane liczbowe ze standardowego wejcia moemy wczytywa w postaci acucha znaków, a nastpnie konwertowa je na liczby odpowiedniego typu. Napisz program, który w ten sposób wczyta z klawiatury liczb zmiennoprzecinkow i zareaguje poprawnie na popenione bdy. Podczas konwersji acucha na liczb moe wystpi wyjtek NumberFormatException. Naley przechwyci i obsuy ten wyjtek, a nastpnie ponowi proces wczytywania danych.

Zadanie 17.3. Napisz program, który odczyta i obliczy sum piciu liczb cakowitych, wprowadzonych ze standardowego wejcia. Pomi liczby zmiennoprzecinkowe i acuchy znaków niebdce liczbami. Wykorzystaj wyjtki lub informacj, e klasa Scanner oferuje metody sprawdzajce, jaki kolejny token znajduje si w strumieniu. Na przykad metoda hasNextInt() sprawdza, czy kolejny token jest liczb cakowit typu int.

Zadanie 17.4. Napisz program obliczajcy odwrotno liczby cakowitej wprowadzonej z klawiatury. a) Przechwy i obsu wszystkie wyjtki, jakie mog pojawi si podczas

wczytywania danych i wykonywania oblicze. b) Zrealizuj zadanie bez obsugi wyjtków.

Zadanie 17.5. Napisz program obliczajcy wynik dzielenia z reszt dwóch liczb cakowitych wprowadzonych z klawiatury. Przechwy i obsu wyjtki, jakie mog pojawi si podczas wczytywania danych i wykonywania oblicze.

18. Liczby pseudolosowe i tablice jednowymiarowe — budujemy metody statyczne Liczby losowe powstaj w wyniku dziaania mechanizmu losujcego (rzut kostk do gry, losowanie ponumerowanych kul z urny itp.) — rozkad tych liczb jest nieregularny i trudny do przewidzenia. Otrzymywanie liczb losowych w programach komputerowych jest bardzo skomplikowane, wic czsto zastpuje si je liczbami pseudoloso-

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

49

wymi (rozkad tych liczb ma pewne regularnoci, które w wielu zastosowaniach moemy pomin). Do generowania liczb pseudolosowych moemy stosowa statyczn metod java.lang. Math.random(), zwracajc liczb typu double z przedziau 0, 1 , lub obiekt klasy java. util.Random i jedn z dostpnych w klasie metod.

Tablica jednowymiarowa — struktura danych do przechowywania okrelonej liczby danych jednego typu. Ogólna definicja tablicy przedstawia si nastpujco: typ_danych [] nazwa_tablicy = new typ_danych[rozmiar_tablicy];

natomiast tablica zainicjowana podanymi wartociami to: typ_danych [] nazwa_tablicy = { warto_1, warto_2, ..., warto_n };

W Javie tablica jest obiektem. Rozmiar tablicy zapisany jest w polu length. Indeksowanie elementów tablicy rozpoczyna si od 0. Jeli podamy indeks spoza zakresu (0..rozmiar_tablicy-1), to zostanie wygenerowany wyjtek java.lang.ArrayIndexOutOfBoundsException. Metody statyczne, dostpne w klasie java.util.Arrays pozwalaj na wykonywanie podstawowych operacji na tablicy — sortowanie, wyszukiwanie binarne, kopiowanie itp.

Zadanie 18.1. Napisz program, który przeprowadzi symulacj 100 rzutów kostk i wywietli wyniki w konsoli.

Zadanie 18.2. Napisz program, który przeprowadzi symulacj 1000 rzutów kostk i sporzdzi zestawienie wyników. Nie zapamituj wyników kolejnych rzutów — wystarczy, e bdziesz na bieco zlicza, ile razy wypad dany wynik. Rol licznika moe odgrywa tablica.

Zadanie 18.3. Dwukrotnie rzucamy kostk do gry i zapisujemy sum wyrzuconych oczek. Napisz program, który przeprowadzi symulacj 3000 powtórze dowiadczenia i sporzdzi zestawienie wyników.

Zadanie 18.4. Utwórz funkcj rand() z dwoma parametrami a i b, losujc liczb rzeczywist nalec do przedziau a, b , gdzie a i b s liczbami cakowitymi i a < b. Wynik losowania powinien by podany z precyzj do 0,1. Napisz program demonstrujcy dziaanie tej funkcji.

50

Programowanie w jzyku Java

Zadanie 18.5. Napisz program losujcy 500 liczb rzeczywistych z przedziau 0, 5 . Przedstaw rozkad wylosowanych liczb w przedziaach o dugoci 1.

Zadanie 18.6. Utwórz funkcj (metod statyczn) lotto() losujc 6 rónych liczb z 49 i zwracajc wynik w postaci tablicy liczb cakowitych. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 18.7. Utwórz funkcj (metod statyczn) lotto() z dwoma parametrami m i n, losujc m rónych liczb sporód liczb od 1 do n i zwracajc wynik w postaci tablicy liczb cakowitych. Napisz program demonstrujcy dziaanie tej metody. Rozwizujc kolejne zadania (18.8 – 18.18), zbudujemy klas MyRandomArray, gromadzc metody umoliwiajce tworzenie jednowymiarowych tablic wypenionych pseudolosowymi liczbami typu cakowitego int lub zmiennoprzecinkowego double.

Zadanie 18.8. Utwórz statyczn metod int[] rndArray(int n, int m) suc do budowania tablicy liczb cakowitych o podanym wymiarze n, wypenionej pseudolosowymi wartociami z zakresu 0, 1, …, m-1. Zdefiniuj metody uatwiajce wywietlanie elementów tablicy oddzielonych odstpem void arrayPrint(int[] tab) i void arrayPrintln(int[] tab) — nazwy sugeruj rónic w dziaaniu tych metod. Utwórz równie metod dodajc do wszystkich elementów tablicy okrelon warto void addToArray(int[] tab, int d). Napisz program demonstrujcy dziaanie tych metod. Tworzone metody skopiuj do pliku MyRandomArray.java w biecym folderze. import java.util.Random; public class MyRandomArray { /* Tu skopiuj kody metod */ }

Bdziesz móg z nich korzysta podczas rozwizywania innych zada, np. kod: int[] los = MyRandomArray.rndArray(6, 49); MyRandomArray.addToArray(los, 1); MyRandomArray.arrayPrintln(los);

stanowi przykad losowania 6 liczb z 49 (podobnie jak w rozwizaniu zadania 18.6 — w tym przypadku jednak liczby mog si powtarza ) przy uyciu metod statycznych z klasy MyRandomArray.

Zadanie 18.9. Utwórz statyczn metod int[] rndUniqueArray(int n, int m) suc do budowania tablicy liczb cakowitych o podanym wymiarze (n) i niepowtarzajcych si elemen-

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

51

tach, wypenionej pseudolosowymi wartociami z okrelonego zakresu 0, 1, …, m-1. Napisz program demonstrujcy dziaanie tej metody. Docz j do klasy MyRandomArray. Skorzystaj z rozwizania zadania 18.6.

Zadanie 18.10. Utwórz statyczne metody int[] rndSortArray(int n, int m) i int[] rndSortUniqueArray(int n, int m), które bd suy do budowania posortowanych tablic liczb cakowitych o podanym wymiarze (n), wypenionych pseudolosowymi wartociami z zakresu 0, 1, …, m-1. Druga metoda powinna zwraca tablic o niepowtarzajcych si elementach. Napisz program demonstrujcy dziaanie tych metod. Docz je do klasy MyRandomArray. Skorzystaj z rozwizania zadania 18.9 oraz metody sortujcej z klasy Arrays.

Zadanie 18.11. Utwórz statyczn metod double[] rndArray(int n, double a), która bdzie suy do budowania tablicy liczb zmiennoprzecinkowych typu double o podanym wymiarze (n), wypenionej pseudolosowymi wartociami z przedziau 0, a . Zdefiniuj metody uatwiajce wywietlanie elementów tablicy oddzielonych odstpem void arrayPrint(double[] tab), void arrayPrintln(double[] tab) i void arrayPrintf(String spec, double[] tab) — nazwy sugeruj sposób dziaania tych metod. Ponadto utwórz metod dodajc do wszystkich elementów tablicy okrelon warto void addToArray(double[] tab, double d). Napisz program demonstrujcy dziaanie tych metod. Skorzystaj z rozwizania zadania 18.8.

Metody te maj nazwy takie same jak metody istniejce w klasie MyRandomArray, ale róni si typami parametrów wywoania. Moemy wic te metody dodawa do klasy MyRandomArray — wykorzystujemy tutaj moliwo przeciania metod.

Zadanie 18.12. Utwórz statyczn metod double[] rndUniqueArray(int n, double a), która bdzie suy do budowania tablicy liczb zmiennoprzecinkowych o podanym wymiarze (n) i niepowtarzajcych si elementach, wypenionej pseudolosowymi wartociami z przedziau 0, a . Napisz program demonstrujcy dziaanie tej metody. Docz j do klasy MyRandomArray. Skorzystaj z rozwizania zadania 18.9.

52

Programowanie w jzyku Java

Zadanie 18.13. Utwórz statyczne metody double[] rndSortArray(int n, double a) i double[] rndSortUniqueArray(int n, double a), które bd suy do budowania posortowanych tablic liczb zmiennoprzecinkowych o podanym wymiarze (n), wypenionych pseudolosowymi wartociami z przedziau 0, a . Druga metoda powinna zwraca tablic o niepowtarzajcych si elementach. Napisz program demonstrujcy dziaanie tych metod. Docz je do klasy MyRandomArray. Skorzystaj z rozwizania zadania 18.10.

Zadanie 18.14. Utwórz statyczn metod void roundArray(double[] tab, int prec), która bdzie zaokrgla wszystkie liczby w tablicy tab do okrelonej liczby miejsc po przecinku (parametr prec). Napisz program demonstrujcy dziaanie tej metody. Docz j do klasy MyRandomArray.

Zadanie 18.15. Utwórz statyczn metod double[] rndArray(int n, double a, int prec), która bdzie suy do budowania tablicy liczb zmiennoprzecinkowych o podanym rozmiarze (n) i wartociach z przedziau 0, a oraz o okrelonej liczbie miejsc po przecinku (parametr prec). Napisz program demonstrujcy dziaanie tej metody. Docz j do klasy MyRandomArray.

Zadanie 18.16. Utwórz statyczn metod double[] rndArray(int n, double a, double step), która bdzie suy do budowania tablicy liczb zmiennoprzecinkowych o podanym rozmiarze (n) i wartociach z przedziau 0, a bdcych wielokrotnoci parametru step. Napisz program demonstrujcy dziaanie tej metody. Docz j do klasy MyRandomArray.

Zadanie 18.17. Utwórz statyczne metody void inputArray(int[] tab) i void inputArray(double[] tab), które bd umoliwia wprowadzanie danych z klawiatury do tablicy odpowiedniego typu. Napisz program demonstrujcy dziaanie tych metod. Utwórz klas MyArray i umie w niej te dwie metody oraz wczeniej zdefiniowane metody suce do wywietlania zawartoci tablic jednowymiarowych i do zaokrglania wartoci w tablicy liczb typu double (z klasy MyRandomArray).

Zadanie 18.18. Utwórz statyczn metod konwertujc tablic liczb cakowitych na tablic liczb zmiennoprzecinkowych (double[] intArrayToDouble(int[] tab)) oraz metod (int[] doubleArrayToInt(double[] tab)) dziaajc odwrotnie.

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

53

Utwórz drug tablic o takim samym rozmiarze, z odpowiednim typem danych, i przepisz do niej elementy z pierwszej tablicy, stosujc rzutowanie typów.

19. Dokumentacja klasy JDK zawiera narzdzie javadoc, generujce na podstawie komentarzy dokumentacyjnych w plikach ródowych dokumentacj w formie plików HTML. W komentarzach mona umieszcza dowolny tekst, znaczniki jzyka HTML oraz specjalne znaczniki dokumentacyjne (zaczynajce si od znaku @). Komentarz dokumentacyjny zaczyna si od znaku /** i koczy si znakiem */. Komentarze blokowe /* ... */ i liniowe // ... s podczas tworzenia dokumentacji pomijane. W kolejnych zadaniach poznasz wybrane przykady z zakresu tworzenia dokumentacji.

Zadanie 19.1. Przygotuj „cigawk” z instrukcj obsugi aplikacji javadoc.exe dla uywanego rodowiska JDK. W konsoli wykonaj polecenie javadoc –help > opis.txt. W pliku opis.txt znajdziesz wszystkie opcje aplikacji javadoc.exe.

Zadanie 19.2. Utwórz plik ródowy Z19_2.java, który bdzie zawiera nastpujcy kod: public class Z19_2 { private static final String HELLO = "Hello World!"; static String hello() { return HELLO; } public static void main(String args[]) { System.out.println(hello()); } }

Skompiluj i uruchom przykad. Dokumentacj klasy Z19_2 moesz sporzdzi, postpujc wedug schematu:  otwórz konsol,  przejd do folderu z plikiem Z19_2.java,

54

Programowanie w jzyku Java  wykonaj polecenie: javadoc Z19_2.java (zapoznaj si z treci uwagi),  otwórz plik index.html i obejrzyj dokumentacj klasy.

Powtórz zadanie, tworzc kilka wersji dokumentacji — zapamitaj znaczenie uytych opcji: a) javadoc –d Z19_2a -nohelp Z19_2.java b) javadoc –d Z19_2b -notree Z19_2.java c) javadoc –d Z19_2c -noindex Z19_2.java d) javadoc –d Z19_2d -nodeprecatedlist Z19_2.java e) javadoc –d Z19_2e –nodeprecatedlist -noindex -notree -nohelp –private Z19_2.java Aby unikn kolizji pomidzy plikami dokumentacji (nadpisywanie plików), przyjmij za zasad tworzenie dokumentacji dla poszczególnych zada w odrbnych folderach. Nazwy folderów niech zawieraj numer zadania. W zwizku z tym ju od tego zadania uywaj opcji –d, wskazujc folder, w którym zostanie zapisana dokumentacja. Zatem zamiast polecenia javadoc Z19_2.java zastosuj polecenie javadoc –d Z19_2 Z19_2.java. Dokumentacja klasy zostanie zapisana w biecym folderze, w podfolderze Z19_2.

Zadanie 19.3. Utwórz plik ródowy Z19_3.java, który bdzie zawiera kod z zadania 19.2. Wstaw komentarze w postaci /** tekst komentarza */ przed kodem klasy, definicj staej i definicjami metod. W komentarzach zawrzyj zwize opisy przedstawianych elementów. Sporzd dokumentacj i przeanalizuj otrzymany dokument. Zastosuj opcje –d i –private.

Zadanie 19.4. Rozwizujc zadania 18.8, 18.11, 18.17 i 18.18, utworzylimy kilka statycznych metod uatwiajcych prac z jednowymiarowymi tablicami liczb cakowitych typu int i tablicami liczb zmiennoprzecinkowych typu double. Metody zostay zgromadzone w klasie MyArray. Na tej podstawie utwórz klas MyIntArray, która bdzie zawiera metody dziaajce na tablicach liczb cakowitych (moesz zmieni nazwy metod lub doda dodatkowe metody), i sporzd dokumentacj tej klasy (dokumentacj zapisz w folderze MyIntArray). W dokumentacji umie informacje o autorze i wersji klasy. W komentarzu do klasy wykorzystaj znaczniki @author i @version. Dokumentacj utwórz z opcjami –author i –version.

Zadanie 19.5. Na podstawie rozwiza zada 18.8, 18.11, 18.17, 18.18 i 19.4 zbuduj klas MyDoubleArray, która bdzie zawiera statyczne metody uatwiajce prac z jednowymiarowy-

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

55

mi tablicami liczb typu double. Sporzd dokumentacj klasy i zapisz j w folderze MyDoubleArray.

Zadanie 19.6. Na podstawie rozwizania zadania 19.5 zbuduj klas MyFloatArray, która bdzie zawiera statyczne metody uatwiajce prac z jednowymiarowymi tablicami liczb typu float. Sporzd dokumentacj klasy i zapisz j w folderze MyFloatArray. Utwórz wspóln dokumentacj klas MyIntArray, MyDoubleArray i MyFloatArray w folderze MyArrays.

Zadanie 19.7. W pliku MyRandomArray.java, utworzonym podczas rozwizywania zada z rozdziau 18., wpisz komentarze dokumentacyjne. Utwórz dokumentacj klasy MyRandomArray i zapisz t dokumentacj w folderze o tej samej nazwie.

20. Dziaania na uamkach — budujemy klas Fraction Rozwizujc systematycznie kolejne zadania, bdziemy tworzy wasn klas Fraction (uamki) oraz programy ukazujce moliwoci tej klasy. Na bieco zbudujemy dokumentacj klasy.

Zadanie 20.1. Zbuduj klas Fraction, która bdzie zawiera dwa prywatne pola reprezentujce licznik i mianownik uamka. W klasie tej umie konstruktor z dwoma parametrami, który bdzie budowa uamek na podstawie dwóch liczb cakowitych (licznika i mianownika), oraz publiczn metod toString(), zwracajc uamek w postaci acucha znaków, np. "4/13" (licznik, kreska uamkowa / i mianownik). Napisz program pokazujcy dziaanie konstruktora i zdefiniowanej metody.

Zadanie 20.2. Dodaj do klasy Fraction konstruktor bezparametrowy budujcy uamek odpowiadajcy liczbie 0 oraz konstruktor z jednym parametrem cakowitym m budujcy uamek m/1. Napisz program pokazujcy dziaanie tych konstruktorów.

Zadanie 20.3. Utwórz w klasie Fraction konstruktor kopiujcy i napisz program pokazujcy dziaanie tego konstruktora.

56

Programowanie w jzyku Java

Zadanie 20.4. Zauwamy, e obiekty new Fraction(-3, 4) i new Fraction(3, -4) reprezentuj ten 3 4

sam uamek  . Po zamianie obiektów na acuchy znaków (metod toString()) otrzymamy odpowiednio "-3/4" i "3/-4". Podobnie wygldaaby sytuacja dla obiektów new Fraction(2, 5) i new Fraction(-2, -5) reprezentujcych uamek 2/5. Zapis uamka w postaci "3/-4" lub "-2/-5" nie wyglda korzystnie (lepszy bdzie zapis "-3/4" lub "2/5"). Mona przyj, e bdziemy zapamitywali zawsze dodatni mianownik, a znak licznika zadecyduje o znaku uamka. Dodaj do klasy Fraction prywatn metod, która wywoana wewntrz konstruktora skoryguje licznik i mianownik uamka zgodnie z przyjt umow. Napisz program pokazujcy skutki dziaania tej metody. Metod nazwij correction() (poprawka). Bdzie ona przydatna podczas wyznaczania odwrotnoci ujemnego uamka lub dzielenia przez taki uamek.

Zadanie 20.5. Zauwamy, e obiekty new Fraction(3, 4) i new Fraction(15, 20) reprezentuj ten sam uamek 3/4. Dodaj do klasy Fraction publiczne metody suce do skracania uamka (przez najwikszy wspólny dzielnik licznika i mianownika lub inn podan warto) oraz publiczn metod pozwalajc na rozszerzanie uamka. Napisz program pokazujcy dziaanie tych metod. Metod skracajc uamek nazwij reduce() (ang. reducing fraction — skraca uamek). Do realizacji tej metody niezbdna bdzie prywatna metoda obliczajca najmniejszy wspólny dzielnik (ang. Greatest Common Factor — GCF). Proponujemy w tym przypadku uycie polskiego skrótu nwd. Metod rozszerzajc uamek nazwij equivalent() (ang. equivalent fraction — uamek).

Zadanie 20.6. W klasie Fraction utwórz metody zwracajce nowy obiekt Fraction, bdcy iloczynem uamka reprezentowanego przez ten obiekt i inny obiekt lub liczb cakowit. Napisz program pokazujcy dziaanie tych metod. Dziki moliwoci przeciania nazw metod obie metody mog mie t sam nazw mult() (ang. multiplication — mnoenie).

Zadanie 20.7. W klasie Fraction utwórz metody statyczne (o nazwie product(), ang. product — iloczyn) zwracajce obiekt Fraction, bdcy iloczynem dwóch uamków, uamka i liczby cakowitej lub dwóch liczb cakowitych. Napisz program demonstrujcy dziaanie tych metod.

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

57

Zadanie 20.8. W klasie Fraction utwórz metod zwracajc nowy obiekt Fraction, reprezentujcy uamek odwrotny do uamka zawartego w obiekcie wywoujcym t metod. Utwórz metod statyczn o podobnej funkcjonalnoci. Napisz program pokazujcy dziaanie tych metod. Wykorzystaj odwrotno do obliczenia ilorazu dwóch uamków. Metodom nadaj nazw multInv(), pochodzc od okrelenia ang. multiplicative inverse — odwrotno (liczby).

Zadanie 20.9. W klasie Fraction utwórz metody zwracajce nowy obiekt Fraction, bdcy ilorazem uamka reprezentowanego przez ten obiekt i inny obiekt lub liczb cakowit. Metodom nadaj nazw div() (ang. division — dzielenie).

Zadanie 20.10. W klasie Fraction utwórz metody statyczne (o nazwie quot(), ang. quotient — iloraz) zwracajce obiekt Fraction, bdcy ilorazem dwóch uamków, uamka i liczby cakowitej lub dwóch liczb cakowitych. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 20.11. W klasie Fraction utwórz metody (o nazwie add(), ang. addition — dodawanie) zwracajce nowy obiekt Fraction, bdcy sum uamka reprezentowanego przez ten obiekt i inny obiekt lub liczb cakowit. Napisz program pokazujcy dziaanie tych metod. Podczas dodawania uamków o rónych mianownikach niezbdne jest sprowadzenie uamków do wspólnego mianownika. Wspólnym mianownikiem moe by iloczyn mianowników, czyli dodawanie moemy wykona wedug wzoru

a c  b d

ad bc  bd bd

ad  bc . Korzystniej bdzie jednak bd

obliczy najmniejsz wspóln wielokrotno (NWW(b, d)) mianowników i t liczb przyj jako wspólny mianownik (zob. rozwizania zada 15.7 lub 15.9). Prywatn metod nww() dodaj do klasy Fraction.

Zadanie 20.12. W klasie Fraction utwórz metody statyczne (o nazwie sum(), ang. sum — suma) zwracajce obiekt Fraction, bdcy sum dwóch uamków lub uamka i liczby cakowitej. Napisz program demonstrujcy dziaanie tych metod.

58

Programowanie w jzyku Java

Zadanie 20.13. W klasie Fraction utwórz metod zwracajc nowy obiekt Fraction, reprezentujcy uamek przeciwny do uamka zawartego w obiekcie wywoujcym t metod. Utwórz metod statyczn o podobnej funkcjonalnoci. Napisz program pokazujcy dziaanie tych metod. Wykorzystaj uamek przeciwny do obliczenia rónicy dwóch uamków. Metodom nadaj nazw addInv(), pochodzc od okrelenia ang. additive inverse — liczba przeciwna.

Zadanie 20.14. W klasie Fraction utwórz metody (o nazwie sub(), ang. subtraction — odejmowanie) zwracajce nowy obiekt Fraction, bdcy rónic uamka reprezentowanego przez ten obiekt i inny obiekt lub liczb cakowit. Napisz program pokazujcy dziaanie tych metod.

Odejmowanie moemy wykona wedug wzoru

a c  b d

ad bc  bd bd

ad  bc lub bd

stosujc jako wspólny mianownik NWW(b, d). Proponujemy uproci spraw i zastpi odejmowanie dodawaniem liczby przeciwnej:

a c  b d

a c  . b d

Zadanie 20.15. W klasie Fraction utwórz metody statyczne (o nazwie diff(), ang. difference — rónica) zwracajce obiekt Fraction, bdcy rónic dwóch uamków lub uamka i liczby cakowitej. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 20.16. Dodaj do klasy Fraction metody (getNum() i getDen()) pozwalajce na odczytanie wartoci prywatnych pól obiektu (licznika i mianownika uamka reprezentowanego przez obiekt). Napisz program demonstrujcy dziaanie tych metod.

Zadanie 20.17. Dopuszcza si zmiany wartoci prywatnych pól obiektu (przy uyciu metod) w celu zmiany jego wartoci bez tworzenia nowej instancji obiektu. Zdefiniuj w klasie Fraction metody setNum(int), setDen(int) i setFrac(int, int), które bd zmienia warto licznika, mianownika lub jednoczenie licznika i mianownika uamka (obiektu). Napisz program demonstrujcy dziaanie tych metod.

Zadanie 20.18. Metoda Object.equals() jest dziedziczona przez wszystkie klasy i pozwala ustali, czy dwa obiekty s identyczne. W klasie Fraction za równe uznamy te obiekty, które reprezentuj ten sam uamek. Utwórz i docz do klasy metod equals(), przesania-

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

59

jc metod Object.equals(), oraz napisz program testujcy poprawno dziaania zbudowanej metody.

Do porównania uamków wykorzystaj zaleno

a b

c œ ad d

bc . Metoda ta

zawiedzie, gdy warto iloczynów (ad lub bc) przekroczy zakres liczb cakowitych. Bezpieczniejszym rozwizaniem byoby doprowadzenie obu uamków do postaci nieskracalnej — takie uamki bd równe wtedy i tylko wtedy, gdy bd miay równe liczniki i równe mianowniki, np.

12 27

4 20 i 9 45

4 12 , wic 9 27

20 . 45

Metoda equals() powinna by zwrotna, symetryczna i przechodnia (cechy relacji równowanoci). Ponadto powinna by spójna, czyli wielokrotne wywoywanie x.equals(y) musi konsekwentnie zwraca t sam warto (albo true, albo false), o ile nie zostaa zmodyfikowana adna dana wykorzystywana do porównywania (w naszym przypadku skracanie lub rozszerzanie uamka nie moe mie wpywu na wynik porównania). Jeli x jest niepust referencj (wskazuje obiekt), to x.equals (null) musi zwraca warto false. Jeli w klasie przedefiniujemy metod equals(), to naley równie przedefiniowa metod hashCode(). Jest to konieczne do prawidowej wspópracy klasy z kolekcjami korzystajcymi z kodowania mieszajcego (np. HashSet).

Zadanie 20.19. Dodaj do klasy Fraction metody zwracajce warto dziesitn uamka reprezentowanego przez obiekt. Napisz program demonstrujcy dziaanie tych metod. Podziel licznik przez mianownik, pamitajc o tym, aby co najmniej jedn z liczb rzutowa przed wykonaniem dzielenia na typ zmiennoprzecinkowy. Sugerowane nazwy metod to doubleValue() i floatValue(); dla metod statycznych: toDouble(Fraction), toFloat(Fraction).

Zadanie 20.20. Uamek moe by przedstawiony jako acuch znaków w postaci "4/7" (uamek zwyky), "5" (liczba cakowita odpowiadajca uamkowi 5/1), "2.45" (uamek dziesitny odpowiadajcy uamkowi 245/100) lub "2,45" (wedug zasad zapisu obowizujcych w Polsce). Zbuduj konstruktor, który na podstawie acucha znaków utworzy odpowiedni obiekt klasy Fraction lub zgosi wyjtek, gdy acuch znaków nie bdzie przedstawia uamka. Napisz program demonstrujcy dziaanie tego konstruktora.

Zadanie 20.21. Zbuduj kilka metod statycznych o nazwie valueOf() z jednym parametrem (typu float, double, int, String) lub dwoma parametrami (typu int), zwracajcych obiekt Fraction

60

Programowanie w jzyku Java

reprezentujcy uamek o wartoci odpowiadajcej podanemu parametrowi. Napisz program demonstrujcy dziaanie tych metod. W kolejnych zadaniach (20.22 – 20.27) wykorzystamy obiekty i metody klasy Fraction, uzyskujc wyniki oblicze w postaci dokadnej, wyraonej uamkami zwykymi.

Zadanie 20.22. Okrelamy nieskoczony cig liczbowy w nastpujcy sposób: a1 1 , a2 1  1 , 1

a3

1 , 1 1 a4 1 1

1

1 1

…. Korzystajc z obiektów i metod klasy Fraction, na1

1

1 1

pisz program obliczajcy 15 pocztkowych wyrazów cigu. Ile maksymalnie wyrazów tego cigu mógby w tym programie obliczy?

Zadanie 20.23. Korzystajc z obiektów i metod klasy Fraction, napisz program obliczajcy sumy czciowe nieskoczonego szeregu 1  1  1  1  1  ... . 2

4

8

16

Zadanie 20.24. Korzystajc z obiektów i metod klasy Fraction, napisz program obliczajcy sumy czciowe nieskoczonego szeregu 1  1  1  1  1  ... . 2

4

8

16

Zadanie 20.25. Napisz program rozwizujcy równanie o postaci ax  b 0 w zbiorze liczb wymiernych, posugujc si obiektami i metodami klasy Fraction.

Zadanie 20.26. Napisz program rozwizujcy metod wyznaczników ukad dwóch równa liniowych z dwiema niewiadomymi w zbiorze liczb wymiernych. Wykorzystaj obiekty i metody klasy Fraction. Utwórz metod det(), która bdzie oblicza wyznacznik, oraz metod inputFraction() do wprowadzania z klawiatury wartoci obiektów klasy Fraction. Wygodnie jest zbudowa metod inputFraction() z jednym parametrem typu String, bdcym opisem poprzedzajcym wprowadzanie (tzw. znak zachty). Wprowadzenie wartoci obiektu a moe wyglda tak: Fraction a = inputFraction ("a = "); — w konsoli pojawi si napis a = i migajcy kursor; uytkownik wpisuje warto i naciska klawisz Enter. Z konsoli pobierzemy tekst i zamienimy go na obiekt Fraction, stosujc metod valueOf(). Pozwoli to na poprawne zinterpretowanie danych o postaci "2,45", "2.45", "-5" lub "2/3".

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

61

Zadanie 20.27. Pierwiastek drugiego stopnia z liczby nieujemnej a moemy obliczy ze wzoru iteracyjnego x

1§ a· ¨ x  ¸ , biorc warto pocztkow x = 1. Korzystajc z obiektów i me2© x¹

tod klasy Fraction, napisz program obliczajcy przyblienie liczby zwykego.

5 w postaci uamka

Ten proces iteracyjny jest szybko zbieny i 4 – 5 iteracji wystarczy do wyznaczenia wyniku. Wiksza liczba iteracji nie jest moliwa do wykonania przy uyciu klasy Fraction (zbyt szybko rosncy licznik i mianownik uamka).

21. Klasa opakowujca Angle — miara kta i funkcje trygonometryczne Zadanie 21.1. Utwórz klas Angle zawierajc jedno pole prywatne x typu double przechowujce miar kta podan w radianach. W klasie zbuduj konstruktor z jednym parametrem double (miara kta w radianach) i sze metod zwracajcych wartoci funkcji trygonometrycznych kta reprezentowanego przez obiekt. Napisz program demonstrujcy dziaanie konstruktora i utworzonych metod. Oprócz powszechnie znanych funkcji trygonometrycznych sinus, cosinus tangens 1 ) i cotangens w klasie Angle uwzgldnimy mniej popularne funkcje secans ( sec x cos x 1 ). i cosecans ( csc x sin x

Zadanie 21.2. Docz do klasy Angle publiczne metody (radian() i degree()) zwracajce liczb typu double, miar kta reprezentowanego przez obiekt wyraon w radianach i stopniach. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 21.3. Docz do klasy Angle publiczn metod toString(), która bdzie zwraca acuch znaków (o postaci 45°30'15") przedstawiajcy miar kta reprezentowanego przez obiekt wyraon w stopniach, minutach i sekundach. Napisz program demonstrujcy dziaanie tej metody.

62

Programowanie w jzyku Java

Metoda toString() przesoni metod o tej samej nazwie, dziedziczon z klasy Object. Metod t naley zdefiniowa z adnotacj Override (@Override).

Zadanie 21.4. Docz do klasy Angle trzy konstruktory — z jednym, dwoma lub trzema parametrami typu int — umoliwiajce zbudowanie obiektu reprezentujcego kt o podanej liczbie stopni, stopni i minut lub stopni, minut i sekund. Ogranicz liczb stopni do zakresu od 0° do 360°, a liczb minut i sekund do zakresu od 0 do 60. Napisz program demonstrujcy dziaanie tych konstruktorów.

Zadanie 21.5. Cig znaków o postaci 105°30'15" przedstawia miar kta w stopniach, minutach i sekundach ktowych. Utwórz konstruktor w klasie Angle, który zbuduje obiekt reprezentujcy kt o podanej w ten sposób mierze. Napisz program demonstrujcy dziaanie tego konstruktora.

Zadanie 21.6. Utwórz w klasie Angle sze metod o nazwie setOfXxx, gdzie Xxx oznacza nazw funkcji trygonometrycznej, ustawiajcych miar kta reprezentowanego przez obiekt na podstawie podanej wartoci odpowiedniej funkcji (metody te odpowiadaj funkcjom odwrotnym do funkcji trygonometrycznych). Metody zmieniaj warto obiektu, ale nie zwracaj adnej wartoci. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 21.7. Na paszczy nie z ukadem wspórzdnych czsto potrzebujemy wyznaczy miar kta nachylenia prostej przechodzcej przez pocztek ukadu wspórzdnych i punkt P(x, y) do osi OX. Utwórz w klasie Angle metod o nazwie setOfPoint(), ustawiajc miar tego kta jako warto obiektu. Napisz program demonstrujcy dziaanie metody setOfPoint().

Zadanie 21.8. Utwórz w klasie Angle konstruktor z dwoma parametrami typu double, tworzcy nowy obiekt reprezentujcy miar kta nachylenia prostej przechodzcej przez pocztek ukadu wspórzdnych i punkt P(x, y) do osi OX. Napisz program demonstrujcy dziaanie tego konstruktora.

Zadanie 21.9. Zbuduj w klasie Angle statyczne funkcje o nazwie valueOf(), o rónych parametrach (takich samych jak konstruktory zbudowane w zadaniach 21.1, 21.4, 21.5 i 21.8), zwracajce obiekt klasy Angle odpowiadajcy ktowi o podanych parametrach. Napisz program demonstrujcy dziaanie tych metod.

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

63

Zadanie 21.10. Na miarach któw moemy wykonywa dodawanie i odejmowanie. Dodaj do klasy Angle metody add() (sub()), które bd zwraca nowy obiekt, bdcy sum (rónic) miary kta reprezentowanego przez obiekt wywoujcy metod i miary kta w obiekcie podanym jako parametr. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 21.11. Docz do klasy Angle statyczne metody sum() (diff()), które bd oblicza sum (rónic) dwóch obiektów podanych jako parametry (miar któw reprezentowanych przez te obiekty). Wynik powinien by obiektem klasy Angle. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 21.12. Miary któw mona mnoy (dzieli) przez liczb. Napisz metod mult() (div()), która bdzie zwraca nowy obiekt, reprezentujcy kt o mierze bdcej iloczynem (ilorazem) miary kta reprezentowanego przez obiekt i liczby podanej jako parametr (cakowitej lub zmiennoprzecinkowej). Napisz program demonstrujcy dziaanie tych metod.

Zadanie 21.13. Napisz metod prod() (quot()), która bdzie zwraca obiekt klasy Angle, reprezentujcy kt o mierze bdcej iloczynem (ilorazem) miary kta (obiektu) podanego jako parametr i liczby podanej jako drugi parametr. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 21.14. Docz do klasy Angle statyczne pola przechowujce stae wartoci obiektów reprezentujcych wybrane kty: RIGHT_ANGLE (kt prosty), STRAIGHT_ANGLE (kt pópeny) i FULL_ANGLE (kt peny), RADIAN (1 radian), DEGREE (1 stopie), ARCMINUTE (1 minuta ktowa) i ARCSECOND (1 sekunda ktowa). Napisz program pokazujcy wartoci tych staych. Stae w Javie s waciwie zmiennymi deklarowanymi ze sowem kluczowym final. Wartoci staych w czasie dziaania programu nie moemy zmieni .

Zadanie 21.15. Dodaj do klasy Angle metod compl() (ang. complementary angle — kt dopeniajcy), zwracajc obiekt reprezentujcy dopenienie kta (obiektu) podanego jako parametr, i metod suppl() (ang. supplementary angle — kt przylegy), zwracajc obiekt reprezentujcy miar kta przylegego do kta (obiektu) podanego jako parametr. Napisz program demonstrujcy dziaanie tych metod. Klasa Angle jest ju dostatecznie rozbudowana. W kilku kolejnych zadaniach pokaemy przykady wykorzystania pochodzcych z niej obiektów i metod.

64

Programowanie w jzyku Java

Zadanie 21.16. Utwórz metod inputAngle() z jednym parametrem typu String (przeznaczonym do opisania wprowadzanej wielkoci), zwracajc obiekt Angle reprezentujcy kt o mierze podanej w stopniach. Metoda ta powinna poprawnie interpretowa takie dane: liczba cakowita stopni, liczba rzeczywista (uamek dziesitny) bez podawania symbolu stopnia oraz cig znaków zawierajcych stopnie, minuty i sekundy ktowe z odpowiednimi symbolami jednostek (np. 24°30'15"). Napisz program rozwizujcy nastpujce zadanie: W trójkcie równoramiennym kt przy wierzchoku ma miar D . Oblicz miar kta E przylegego do podstawy tego trójkta. Sprawd obliczenia, dodajc miary wszystkich któw wewntrznych trójkta. Podczas wprowadzania danych symbol stopnia (°) moesz uzyska , wpisujc Alt+0176 (przytrzymaj lewy klawisz Alt i wprowad kod 0176 z klawiatury numerycznej). Symbole minuty i sekundy to apostrof i cudzysów (dostpne bezporednio na klawiaturze). Miary któw speniaj zaleno D  2E 180q .

Zadanie 21.17. Napisz program rozwizujcy zadanie: W trójkcie równoramiennym kt przylegy do podstawy ma miar E . Oblicz miar kta D lecego naprzeciw podstawy tego trójkta. Sprawd obliczenia, dodajc miary wszystkich któw wewntrznych trójkta.

Zadanie 21.18. Napisz program rozwizujcy zadanie: Oblicz miary któw w trójkcie równoramiennym o podstawie a i ramieniu dugoci b. Sprawd obliczenia, dodajc miary wszystkich któw wewntrznych trójkta.

Zadanie 21.19. Napisz program rozwizujcy zadanie: Oblicz miary któw w trójkcie równoramiennym o podstawie a i wysokoci (opuszczonej na podstaw) h. Sprawd obliczenia, dodajc miary wszystkich któw wewntrznych trójkta.

Zadanie 21.20. Napisz program rozwizujcy zadanie: Oblicz miary któw w trójkcie o bokach a, b i c. Sprawd obliczenia, dodajc miary wszystkich któw wewntrznych trójkta.

22. Liczby rzymskie i klasa Roman Zadanie 22.1. Napisz program zamieniajcy liczby naturalne podawane z klawiatury w postaci dziesitnej na liczby zapisane w systemie rzymskim. Warunkiem zakoczenia programu powinno by podanie liczby 0.

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

65

Stosujc symbole I, V, X, L, C, D i M oraz reguy zapisu liczb rzymskich, moemy zapisa liczb naturaln z zakresu od 0 do 3999.

Zadanie 22.2. Napisz program odczytujcy warto dziesitn liczby zapisanej znakami rzymskimi. Dane wprowadzamy z klawiatury. Warunkiem zakoczenia programu powinno by wprowadzenie pustego acucha znaków.

Zadanie 22.3. Utwórz metod statyczn decToRoman(), która bdzie zamienia liczb naturaln z zakresu od 1 do 3999 na liczb w zapisie rzymskim. Napisz program demonstrujcy dziaanie tej metody. Skorzystaj z tablic zbudowanych w rozwizaniu zadania 22.1.

Zadanie 22.4. W procesie kodowania liczb rzymskich stosujemy dwie tablice — tablic z wartociami wybranych liczb rzymskich i tablic z odpowiadajcymi im wartociami dziesitnymi. Utwórz klas RN (ang. roman numbers), która bdzie zawiera dwa pola: pole typu String (symbol rzymski) oraz pole typu int (warto dziesitna tej liczby rzymskiej). Klasa powinna udostpnia jedynie tablic z parami wartoci ("M", 1000), ("CM", 900) itd. Zmodyfikuj metod decToRoman() (z zadania 22.3) tak, aby wykorzystywaa tablic z klasy RN.

Zadanie 22.5. Utwórz metod statyczn romanToDec(), która bdzie zamienia liczb zapisan w systemie rzymskim na liczb dziesitn. Napisz program demonstrujcy dziaanie tej metody. Skorzystaj z rozwiza zada 22.2 i 22.4.

Zadanie 22.6. Utwórz klas Roman, która bdzie mie jedno pole typu int zawierajce liczb naturaln z zakresu od 1 do 3999. W klasie tej zbuduj konstruktory tworzce obiekt na podstawie parametru bdcego liczb cakowit lub acuchem znaków przedstawiajcym liczb w zapisie rzymskim. Docz do klasy inne metody przydatne do pracy z liczbami rzymskimi. Napisz program demonstrujcy moliwoci tej klasy. Skorzystaj z rozwiza zada 22.1 – 22.5 oraz dowiadcze zdobytych podczas tworzenia klasy Angle.

66

Programowanie w jzyku Java

Zadanie 22.7. Korzystajc z klasy Roman, napisz aplikacj sprawdzajc umiejtno odczytywania wartoci liczb rzymskich. Liczba pyta powinna by z góry ustalona, a wartoci liczb powinny by losowane z podanego zakresu. Do losowania liczb mona uy metod z klasy MyRandomArray.

Zadanie 22.8. Korzystajc z klasy Roman, napisz aplikacj sprawdzajc umiejtno zapisywania liczb w systemie rzymskim. Liczba pyta powinna by z góry ustalona, a wartoci liczb powinny by losowane z podanego zakresu.

23. Trójmian kwadratowy i klasa QuadratPoly Zadanie 23.1. Zbuduj klas QuadratPoly (ang. quadratic polynomial — trójmian kwadratowy) umoliwiajc rozwizywanie rónych zada dotyczcych trójmianu kwadratowego ( ax 2  bx  c, a z 0 ) o wspóczynnikach cakowitych. W klasie tej utwórz konstruktor z trzema parametrami i metod value() z jednym parametrem, zwracajc warto trójmianu kwadratowego dla podanego argumentu. Napisz program demonstrujcy dziaanie konstruktora i zdefiniowanej metody.

Zadanie 23.2. Dodaj do klasy QuadratPoly pole delta przechowujce warto wyrónika trójmianu kwadratowego ( ' b 2  4ac ) i metod getDelta() zwracajc warto wyrónika trójmianu. Obliczenie wyrónika powinno by zrealizowane w konstruktorze podczas tworzenia nowego obiektu. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 23.3. Utwórz i docz do klasy QuadratPoly metod toString() zwracajc trójmian w postaci tekstowej, np. "2x^2-x+3". Napisz program demonstrujcy dziaanie tej metody. Zwró uwag na sposób przedstawiania wspóczynników –1, 1 i 0 — pomi liczby -1 i 1 przed wyraeniem x^2 lub x, pozostawiajc odpowiedni znak; nie wypisuj wyraenia 0x oraz wyrazu wolnego 0.

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

67

Zadanie 23.4. Utwórz w klasie QuadratPoly metod sgnDelta() zwracajc znak wyrónika trójmianu. Od znaku wyrónika zaley liczba pierwiastków trójmianu. Napisz program informujcy o liczbie rzeczywistych pierwiastków trójmianu kwadratowego. Funkcja sgn (ac. signum — znak) zwraca –1, gdy argument jest ujemny, 1, gdy argument jest dodatni, oraz 0 dla wartoci zero.

Zadanie 23.5. Docz do klasy QuadratPoly metody getX1() i getX2() zwracajce pierwiastki trójmianu kwadratowego reprezentowanego przez obiekt. Jeli trójmian nie ma pierwiastków rzeczywistych, to metody mog zwraca warto NaN. Korzystajc z tych metod, napisz program rozwizujcy równanie kwadratowe o wspóczynnikach cakowitych, wprowadzonych z klawiatury.

Zadanie 23.6. Wykresem trójmianu kwadratowego ax 2  bx  c, a z 0 jest parabola. Charakterystycznym punktem paraboli jest jej wierzchoek, czyli punkt o wspórzdnych (p, q), gdzie p  b i q  ' . Docz do klasy QuadratPoly metody getP() i getQ() zwra2a

4a

cajce wspórzdne wierzchoka paraboli. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 23.7. Docz do klasy QuadratPoly metod isAPositve() zwracajc warto true, gdy a jest dodatnie, i false, gdy a jest ujemne. Napisz program wyznaczajcy zbiór wartoci dla podanego trójmianu kwadratowego. 2 Jeli a > 0, to zbiorem wartoci trójmianu ax  bx  c jest przedzia q,  f , a dla

a < 0 — przedzia  f, q .

Zadanie 23.8. Napisz program, który dla danego trójmianu kwadratowego okreli jego warto ekstremaln (minimum lub maksimum). Dane trójmianu uytkownik wprowadzi z klawiatury.

Zadanie 23.9. Docz do klasy QuadratPoly metod getVertex() (ang. vertex — wierzchoek), która bdzie zwraca wspórzdne wierzchoka paraboli bdcej wykresem trójmianu reprezentowanego przez obiekt. Wynik powinien by podany w postaci acucha znaków. Napisz program demonstrujcy dziaanie tej metody.

68

Programowanie w jzyku Java

Zadanie 23.10. Docz do klasy QuadratPoly metod getCodomain() (ang. codomain — przeciwdziedzina funkcji), która bdzie zwraca zbiór wartoci trójmianu (przedzia liczbowy) zapisany w postaci acucha znaków. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 23.11. Napisz program sporzdzajcy opis przebiegu zmiennoci funkcji kwadratowej f ( x ) ax 2  bx  c, a z 0 . Opis zredaguj w punktach. Umie w opisie dziedzin funkcji, zbiór wartoci, monotoniczno , ekstremum, miejsca zerowe i krótkie objanienie wykresu.

Zadanie 23.12. Napisz program rozwizujcy nierówno kwadratow ax 2  bx  c ! 0, a z 0 .

Zadanie 23.13. Napisz program rozwizujcy nierówno kwadratow ax 2  bx  c t 0, a z 0 .

Zadanie 23.14. Docz do klasy QuadratPoly metod mult() z parametrem bdcym liczb cakowit rón od zera, która zwraca nowy obiekt, iloczyn tej liczby i trójmianu reprezentowanego przez obiekt wywoujcy t metod. Napisz program demonstrujcy jej dziaanie.

Zadanie 23.15. Docz do klasy QuadratPoly metod solutionOfQE() (ang. solution — rozwizanie), która bdzie zwraca rozwizanie równania kwadratowego w postaci zbioru pierwiastków (acuch znaków), np. {–2, 0.5}, {–3} lub {} (odpowiednio: dwa róne pierwiastki, pierwiastek dwukrotny lub brak pierwiastków rzeczywistych — zbiór pusty). Napisz program demonstrujcy dziaanie tej metody. W zestawie znaków dla konsoli nie znajdziemy symbolu zbioru pustego (‡), wic proponujemy zastpienie go pust par nawiasów klamrowych {}.

Zadanie 23.16. Docz do klasy QuadratPoly dwie prywatne metody: solutionQIe1() i solutionQIe2(), które bd zwraca zbiór rozwiza nierównoci kwadratowej ax 2  bx  c ! 0, a z 0 (pierwsza metoda) i ax 2  bx  c t 0, a z 0 (druga metoda). Wynik powinien by podany w postaci acucha znaków. Korzystajc z tych metod, zbuduj publiczn metod solutionQIe() (ang. quadratic inequality — nierówno kwadratowa) z jednym

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

69

parametrem (typu String) o postaci "=", okrelajcym typ nierównoci. Napisz program demonstrujcy rozwizywanie nierównoci kwadratowych. Wykorzystaj zbudowane metody prywatne i fakt, e nierówno ax  bx  c 2

( ax  bx  c d 0 ) 2

jest

równowana

nierównoci

0  ax  bx  c ! 0 2

(  ax  bx  c t 0 ). 2

Zadanie 23.17. Napisz program rozwizujcy równanie dwukwadratowe o wspóczynnikach cakowitych ( ax 4  bx 2  c 0, a z 0 ).

Zadanie 23.18. Trójmiany kwadratowe mona dodawa lub odejmowa. Wynik nie zawsze jednak bdzie trójmianem kwadratowym. Docz do klasy metody add() i sub(), które bd zwraca nowy obiekt QuadratPoly, odpowiednio sum i rónic obiektu wywoujcego metod i obiektu przekazanego jako parametr.

Zadanie 23.19. Zbuduj klas FloatQP lub DoubleQP (ang. quadratic polynomial — trójmian kwadratowy), która bdzie umoliwia rozwizywanie rónych zada dotyczcych trójmianu kwadratowego ( ax 2  bx  c, a z 0 ) o wspóczynnikach zmiennoprzecinkowych (typu float lub double). Jeli wynik nie jest obiektem klasy, to zgo wyjtek. Do klasy dodaj metod div() zwracajc nowy obiekt, wynik dzielenia trójmianu przez liczb rón od zera. Napisz program demonstrujcy dziaanie konstruktora i wybranych metod.

24. Liczby zespolone — budujemy klas Complex Brak rozwizania równania kwadratowego x 2 1 w zbiorze liczb rzeczywistych doprowadzi do odkrycia jednostki urojonej i — takiej, e i 2 1 — oraz liczb urojonych (bdcych iloczynami liczby rzeczywistej i jednostki urojonej — ai). W konsekwencji doprowadzio to do powstania teorii liczb zespolonych. Liczb zespolon moemy zapisywa w postaci pary liczb rzeczywistych (a, b), gdzie a oznacza cz rzeczywist liczby zespolonej, b — cz urojon. T par liczb moemy interpretowa jako wspórzdne punktu na paszczy nie (tzw. paszczyzna zespolona). Inn moliwoci jest zapis a+bi, czyli posta kanoniczna liczby zespolonej.

70

Programowanie w jzyku Java

Zadanie 24.1. Zbuduj klas Complex, której obiekty bd reprezentoway liczby zespolone. Klasa powinna posiada dwa prywatne pola typu double, co najmniej jeden konstruktor z dwoma parametrami (typu double), metody ustawiajce warto czci rzeczywistej i urojonej oraz moliwo przedstawienia liczby w postaci algebraicznej (kanonicznej). Napisz aplikacj pokazujc dziaanie konstruktorów metod tej klasy. Prywatne pola klasy Complex oznaczmy identyfikatorami re (ang. real — cz rzeczywista liczby zespolonej) i im (ang. imaginary — cz urojona). Metody setRe (double x) i setIm(double y) powinny umoliwi zmian wartoci liczby zespolonej reprezentowanej przez obiekt, natomiast metoda toString() zwróci acuch znaków reprezentujcy posta kanoniczn liczby.

Zadanie 24.2. Napisz aplikacj rozwizujc równanie kwadratowe o wspóczynnikach rzeczywistych w zbiorze liczb zespolonych. Algorytm rozwizywania równania jest taki sam jak w zbiorze liczb rzeczywistych. Jedynie w przypadku, gdy wyrónik jest ujemny ( ' 0 ), rozwizaniem równania bdzie para liczb zespolonych, poniewa '  'i .

Zadanie 24.3. Docz do klasy Complex metody zwracajce sum (add() — ang. addition) i rónic (sub() — ang. subtraction) wartoci zespolonej reprezentowanej przez obiekt i wartoci podanej jako parametr. Napisz aplikacj pokazujc dziaanie tych metod.

Zadanie 24.4. Docz do klasy Complex metody zwracajce liczb zespolon przeciwn (opp() — ang. opposite lub additive inverse), sprzon (conj() — ang. conjugate) i odwrotn (rec() — ang. reciprocal lub multiplicative inverse) do wartoci zespolonej reprezentowanej przez obiekt. Napisz aplikacj pokazujc dziaanie tych metod.

Zadanie 24.5. Docz do klasy Complex metody zwracajce iloczyn (mult() — ang. multiplication) i iloraz (div() — ang. division) wartoci zespolonej reprezentowanej przez obiekt i wartoci podanej jako parametr. Napisz aplikacj pokazujc dziaanie tych metod.

Zadanie 24.6. Dodaj do klasy Complex stae ZERO (zero), ONE (jeden), I (jednostka urojona i — ang. imaginary unit). Napisz aplikacj pokazujc znaczenie tych staych.

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

71

Staa ZERO jest elementem neutralnym dla dodawania, a staa ONE stanowi element neutralny dla mnoenia. Korzystajc ze staej I, moemy pokaza potgi jednostki urojonej.

Zadanie 24.7. Docz do klasy Complex metody zwracajce bezwzgldn warto (modu) liczby zespolonej (abs() — ang. absolute value) i argument gówny liczby zespolonej (arg()) reprezentowanej przez obiekt. Napisz aplikacj pokazujc dziaanie tych metod.

Zadanie 24.8. Docz do klasy Complex metody zwracajce cz rzeczywist (getRe()) i cz urojon (getIm()) liczby zespolonej reprezentowanej przez obiekt. Napisz aplikacj pokazujc dziaanie tych metod.

Zadanie 24.9. Dodaj do klasy Complex bezparametrowe metody print() i println() wywietlajce posta kanoniczn liczby zespolonej w konsoli. Zbuduj te metody równie z jednym parametrem typu String. Podany acuch znaków powinien poprzedza wywietlan liczb zespolon. Napisz aplikacj pokazujc dziaanie tych metod. Zaproponowane metody skróc nam zapis wielu rozwiza zada. Rónica w dziaaniu metody println() i print() jest oczywista i w naszej implementacji nie powinna odbiega od przyjtego standardu.

Zadanie 24.10. Docz do klasy Complex konstruktor kopiujcy oraz metod umoliwiajc porównywanie obiektu wywoujcego t metod z innym obiektem podanym jako parametr. Napisz aplikacj pokazujc porównywanie obiektów.

Zadanie 24.11. Docz do klasy Complex konstruktor tworzcy obiekt na podstawie acucha znaków przedstawiajcego liczb zespolon w postaci "–3.4+2.75i". Napisz aplikacj pokazujc dziaanie tego konstruktora. Konstruktor powinien poprawnie przetwarza acuchy o postaci: "1", "–2.5", "+3.5", "i", "+i", "–i", "2+3i", "–2.3+3i", "2–3i", "–2.3+3i", "+2–3.7i", "+2+3.7i", "1+i", "2.1–i". Aby zbytnio nie komplikowa kodu, zrezygnujemy z zapisywania liczb w notacji naukowej.

Zadanie 24.12. Zbuduj w klasie Complex metod statyczn parseComplex() zamieniajc acuch znaków na liczb zespolon. Napisz aplikacj pokazujc dziaanie tej metody.

72

Programowanie w jzyku Java

Zastosuj konstruktor zbudowany w rozwizaniu zadania 24.11.

Zadanie 24.13. Utwórz poza klas Complex funkcj power() obliczajc potg o wykadniku cakowitym dla dowolnej liczby zespolonej. Napisz aplikacj pokazujc dziaanie tej funkcji.

Zadanie 24.14. Dodaj opracowan w zadaniu 24.13 funkcj power() do klasy Complex jako metod statyczn oraz niestatyczn. Napisz aplikacj pokazujc dziaanie metod power(). W metodzie statycznej podstawa potgi przekazywana jest jako parametr wywoania, natomiast w metodzie niestatycznej podstaw potgi stanie si warto obiektu wywoujcego t metod (wykorzystaj sowo kluczowe this).

Zadanie 24.15. Docz do klasy Complex metody obliczajce kwadrat liczby zespolonej (sqr()) i pierwiastek kwadratowy (sqrt()) z liczby zespolonej. Napisz aplikacj pokazujc dziaanie tych metod. W zbiorze liczb zespolonych okrelamy dwa pierwiastki drugiego stopnia. S one liczbami przeciwnymi. Podczas rozwizywania zada naley o tym pamita . Mona utworzy metod nextSqrt(), wyznaczajc drugi pierwiastek z liczby zespolonej, lub poda w metodzie sqrt()parametr, wskazujcy, który z tych pierwiastków chcemy obliczy .

Zadanie 24.16. Docz do klasy Complex metody printf() i printlnf(), które bd wywietla w konsoli liczb zespolon z okrelon precyzj domyln (6 miejsc po przecinku). Napisz program demonstrujcy dziaanie tych metod. Zob. rozwizanie zadania 24.9.

Zadanie 24.17. Napisz program rozwizujcy w zbiorze liczb zespolonych równanie kwadratowe o wspóczynnikach zespolonych, np.: 1  2i z 2  iz  1 0 .

Zadanie 24.18. Docz do klasy Complex cztery metody statyczne (sum(), diff(), prod() i quot()), które bd realizowa cztery podstawowe dziaania (dodawanie, odejmowanie, mnoenie i dzielenie) w zbiorze liczb zespolonych.

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

Liczb zespolon z

x  yi moemy przeksztaci na posta z

73

z ˜ (sin M  i cos M )

nazywan postaci trygonometryczn liczby zespolonej ( z — modu, M — argument liczby z). Posta trygonometryczn liczby zespolonej moemy skojarzy z biegunowym ukadem wspórzdnych — liczb zespolon moemy przedstawia jako par r , M , gdzie r jest (promieniem) odlegoci punktu P(x, y) od pocztku ukadu wspórzdnych, a M jest ktem pomidzy promieniem i osi X ukadu wspórzdnych.

Zadanie 24.19. Utwórz klas PolarComplex, której obiekty bd reprezentoway liczby zespolone podane we wspórzdnych biegunowych (ang. polar coordinates). Zbuduj podstawowe konstruktory klasy PolarComplex, metod zamieniajc obiekt klasy PolarComplex na obiekt Complex i metod toString() zamieniajc obiekt na acuch znaków, np. "[r=1,500000; fi=1,000000]". Napisz program demonstrujcy dziaanie tych konstruktorów i metod. Podany cig znaków "[r=1,500000; fi=1,000000]" jest propozycj, z któr Czytelnik niekoniecznie musi si zgadza . Nie ma w tym przypadku standardu zapisu liczb podobnego do postaci kanonicznej liczby zespolonej i atwego do zapisania w postaci acucha znaków. Posta trygonometryczna liczby zespolonej z r sin M  i cos M i posta wykadnicza z re iM wykorzystuj elementy pary r , M , ale do tego celu niezbyt si nadaj. Pozostamy zatem przy zaproponowanej w zadaniu postaci acucha.

Zadanie 24.20. Docz do klasy PolarComplex konstruktor kopiujcy i konstruktor z parametrem typu Complex. Napisz program demonstrujcy dziaanie tych konstruktorów.

Zadanie 24.21. Docz do klasy Complex konstruktor z parametrem typu PolarComplex i metod toPolarComplex(), która bdzie zwraca obiekt klasy PolarComplex odpowiadajcy obiektowi Complex. Napisz program demonstrujcy dziaanie tego konstruktora i tej metody.

Zadanie 24.22. Docz do klasy PolarComplex metod mult(), która bdzie zwraca iloczyn liczby zespolonej reprezentowanej przez obiekt i liczby przekazanej jako parametr. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 24.23. Docz do klasy PolarComplex metod div(), która bdzie zwraca iloraz liczby zespolonej reprezentowanej przez obiekt i liczby przekazanej jako parametr. Napisz program demonstrujcy dziaanie tej metody.

74

Programowanie w jzyku Java

Zadanie 24.24. Docz do klasy PolarComplex metody sqr() i cube(), które bd zwraca kwadrat i szecian liczby zespolonej reprezentowanej przez obiekt. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 24.25. Docz do klasy PolarComplex metod power() z jednym parametrem n typu cakowitego (int), która bdzie zwraca potg o wykadniku n liczby zespolonej reprezentowanej przez obiekt. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 24.26. Liczba zespolona ma dwa pierwiastki kwadratowe. Docz do klasy PolarComplex metod sqrt() z jednym parametrem k typu int, która bdzie zwraca obiekt PolarComplex wskazany przez parametr k — pierwiastek kwadratowy z liczby zespolonej. Napisz program demonstrujcy dziaanie tej metody. Wyznacz reszt z dzielenia k przez 2 (k%2) — reszta 0 lub 1 wskae numer pierwiastka.

Zadanie 24.27. Liczba zespolona ma trzy pierwiastki szecienne (trzeciego stopnia). Docz do klasy PolarComplex metod cbrt() z jednym parametrem k typu int, która bdzie zwraca obiekt PolarComplex wskazany przez parametr k, pierwiastek trzeciego stopnia z liczby zespolonej. Napisz program demonstrujcy dziaanie tej metody. Wyznacz reszt z dzielenia k przez 3 (k%3) — reszta 0, 1 lub 2 wskae numer pierwiastka.

Zadanie 24.28. Docz do klasy PolarComplex bezparametrowe metody sqrt() i cbrt(), które bd zwraca pierwiastki kwadratowe i szecienne z liczby reprezentowanej przez obiekt w postaci tablicy obiektów klasy Complex. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 24.29. Napisz program rozwizujcy w zbiorze liczb zespolonych równanie o wspóczynnikach rzeczywistych: a) az  c 2

b) z  a 3

0, a z 0 , 0.

Rozdzia 3. i Trzeci krok — budujemy wasne metody i klasy

75

Zadanie 24.30. Napisz program rozwizujcy w zbiorze liczb zespolonych równanie o wspóczynnikach zespolonych: a) az  c 2

b) z  a 3

0 , a z 0  0i , 0.

Zadanie 24.31. Liczba zespolona ma n pierwiastków n-tego stopnia. Docz do klasy PolarComplex metod root() z dwoma parametrami n i k typu int, która bdzie zwraca obiekt PolarComplex wskazany przez parametr k — pierwiastek n-tego stopnia z liczby zespolonej. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 24.32. Docz do klasy PolarComplex metod root() z jednym parametrem n okrelajcym stopie pierwiastka, która bdzie zwraca tablic obiektów klasy Complex z pierwiastkami n-tego stopnia z liczby zespolonej reprezentowanej przez obiekt (wywoujcy metod). Napisz program demonstrujcy dziaanie tej metody.

Zadanie 24.33. Napisz program wyznaczajcy dla liczby naturalnej n podanej przez uytkownika z klawiatury wszystkie pierwiastki równania: a) z n  1

0,

b) z  i

0,

n

c) z

2n

 iz n  1 0 .

76

Programowanie w jzyku Java

Rozdzia 4.

Czwarty krok — pliki, tablice i macierze 25. Operacje na plikach tekstowych Zadanie 25.1. Korzystajc z obiektów i metod klasy FileWriter, napisz program zapisujcy do pliku tekstowego tekst.txt jeden wiersz tekstu: Programowanie obiektowe.

Zadanie 25.2. Plik tekstowy tekst.txt zawiera jeden wiersz tekstu: Programowanie obiektowe. Korzystajc z obiektu i metod klasy FileWriter, napisz program dopisujcy do tego pliku w pierwszym wierszu tekst: w jzyku Java, a w kolejnym wierszu tekst: jest bardzo interesujce. W systemie Windows koniec wiersza w pliku tekstowym skada si z dwóch znaków CR (ang. carriage return, warto ASCII 13, znak '\r') i LF (ang. line feed warto ASCII 10, znak '\n'). W systemach UNIX i Linux kocem wiersza jest LF, a w systemie Mac OS — znak CR.

Zadanie 25.3. Korzystajc z obiektu i metod klasy FileWriter, napisz program obliczajcy i zapisujcy w pliku silnia.txt wartoci n! (n silnia) dla n = 1, 2, …, 12. Kady wynik zapisz w odrbnym wierszu, w postaci 12! = 479001600. Przypomnijmy znaczenie symbolu n!: 1! = 1, 2! = 1!·2 = 1·2, 3! = 2!·3 = 1·2·3 itd.

78

Programowanie w jzyku Java

W tym zadaniu i zadaniach podobnych starajmy si, aby plik wyjciowy nie zawiera na kocu pustego wiersza (jeli obecno tego ostatniego wiersza nie jest zamierzona). Taki wiersz moe nam sprawi róne niespodzianki, gdy plik bdzie odczytywany.

Zadanie 25.4. Napisz program zapisujcy w pliku pierwiastki.txt wartoci pierwiastków kwadratowych i szeciennych dla liczb naturalnych od 2 do 15. Kady wiersz pliku powinien zawiera trzy liczby oddzielone znakami tabulatora — liczb naturaln, pierwiastek kwadratowy z tej liczby i pierwiastek szecienny. Pierwiastki podaj z precyzj do 8 miejsc po przecinku. Do formatowania wyników uyj metody format() z klasy String.

Zadanie 25.5. Napisz program zapisujcy w pliku tekstowym sto.txt sto liczb cakowitych wylosowanych z zakresu od 1 do 20. Liczby w pliku powinny by oddzielone odstpami.

Zadanie 25.6. Napisz program zapisujcy w pliku tekstowym dane.txt 50 par liczb. Kada para liczb powinna by umieszczona w odrbnym wierszu. Pierwsza liczba w parze powinna by rzeczywista, dodatnia i nie wiksza od 10 oraz podana z dokadnoci do dwóch miejsc po przecinku, druga liczba powinna by cakowita i ma nalee do przedziau 2, 8 . Liczby w wierszu oddzielamy odstpem. Po rozwizaniu zada 25.1 – 25.6 bdziemy mieli w biecym folderze pi plików: tekst.txt, silnia.txt, pierwiastki.txt, sto.txt i dane.txt. Zawarto tych plików bdziemy odczytywali w kolejnych zadaniach.

Zadanie 25.7. Korzystajc z obiektu i metod klasy FileReader, napisz program odczytujcy zawarto pliku tekstowego i wywietlajcy jego zawarto w konsoli. Bezparametrowa metoda read() z klasy FileReader odczytuje z pliku jeden znak i zwraca jego kod, liczb typu int z zakresu od 0 do 65 535 lub liczb –1, gdy nie mona odczyta znaku. Metoda ready() zwraca warto logiczn true, gdy z pliku mona odczyta kolejny znak, i false w przeciwnym wypadku.

Rozdzia 4. i Czwarty krok — pliki, tablice i macierze

79

Zadanie 25.8. Korzystajc z obiektu i metod klasy FileReader, utwórz metod (readLine()) odczytujc wiersz pliku tekstowego. Napisz program odczytujcy i wywietlajcy w konsoli wszystkie wiersze pliku tekstowego. Klasa FileReader nie zawiera metody readLine(), wic musisz j sam zbudowa . Plik tekstowy otwórz przed wywoaniem metody, obiekt (klasy FileReader) skojarzony z plikiem przeka jako parametr do metody readLine(), która przeczytany z pliku wiersz tekstu zwróci w postaci acucha znaków.

Zadanie 25.9. Napisz program wywietlajcy w konsoli kod ródowy programu w jzyku Java wraz z numerami linii. Nazw pliku (bez rozszerzenia) uytkownik powinien podawa z klawiatury. Jeli w okrelonej lokalizacji nie ma wskazanego pliku, to program powinien wywietli odpowiedni komunikat. Do wprowadzenia nazwy pliku z konsoli oraz do odczytania wierszy tekstu z pliku wykorzystaj obiekty klasy BufferedReader i metod readLine() z tej klasy. Obecno pliku moesz sprawdzi , stosujc metod exists() z klasy File.

Zadanie 25.10. Napisz program zapisujcy do pliku kod ródowy programu w jzyku Java wraz z numerami linii. Nazw pliku (bez rozszerzenia) uytkownik powinien podawa z klawiatury. Jeli w okrelonej lokalizacji nie ma wskazanego pliku, to program powinien wywietli odpowiedni komunikat. Nazwa pliku wyjciowego powinna by taka jak nazwa pliku ródowego, rozszerzenie java zamienimy na rozszerzenie txt. Do wprowadzenia nazwy pliku z konsoli oraz do odczytania wierszy tekstu z pliku wykorzystaj obiekty klasy Scanner. Do zapisania pliku wyjciowego uyj metod klasy PrintWriter.

Zadanie 25.11. W pliku tekstowym wpisany jest cig liczb cakowitych oddzielonych odstpami. Napisz program, który odczyta i wywietli w konsoli liczby z pliku oraz obliczy ich sum. Do testów moesz uy pliku sto.txt (rozwizanie zadania 25.5). Nie wykorzystuj jednak faktu, e znasz ilo liczb zapisanych w tym pliku.

80

Programowanie w jzyku Java

Zadanie 25.12. W pliku tekstowym wpisany jest cig liczb cakowitych oddzielonych odstpami. Napisz program, który znajdzie najmniejsz liczb w tym pliku oraz obliczy, ile razy ta liczba w tym pliku wystpuje. Do testów moesz uy pliku sto.txt (rozwizanie zadania 25.5). Nie wykorzystuj jednak faktu, e znasz ilo liczb zapisanych w pliku.

Zadanie 25.13. W pliku tekstowym zapisane s w kolejnych wierszach pary liczb — liczba zmiennoprzecinkowa i liczba cakowita. Napisz program, który odczytuje pary liczb z pliku, oblicza iloczyn kadej pary i sumuje iloczyny. Wynik oblicze naley wypisa w konsoli i zapisa w ostatnim wierszu pliku z danymi. Do testów moesz uy pliku dane.txt (rozwizanie zadania 25.6).

26. Tablice jednowymiarowe i wielomiany Jednym z zastosowa tablic jednowymiarowych moe by przechowywanie wspóczynników wielomianu. Wielomian n-tego stopnia jednej zmiennej w( x) a n x n  a n 1 x n 1  ...  a1 x  a 0 ma n+1 wspóczynników, które moemy zapisa w tablicy double[] a = {a0, a1, ..., an};.

Zadanie 26.1. Napisz program obliczajcy wartoci wielomianu. Stopie wielomianu, wspóczynniki i kolejne wartoci argumentu uytkownik bdzie wprowadza z klawiatury. Podanie argumentu x = 0 bdzie sygnaem do zakoczenia pracy programu. Do obliczenia wartoci wielomianu wykorzystaj schemat Hornera.

Zadanie 26.2. Napisz program, który obliczy i zapisze w pliku tekstowym (wielomian.txt) tablic wartoci wielomianu w( x) 2 x 3  5 x 2  x  3 w przedziale  2, 3 z krokiem h = 0,125. Plik powinien zawiera trzy wiersze z informacjami o rozwizywanym zadaniu, wedug schematu: stopie wielomianu (pierwszy wiersz), wspóczynniki wielomianu oddzielone odstpami w drugim wierszu (zaczynajc od wyrazu wolnego) i krace

Rozdzia 4. i Czwarty krok — pliki, tablice i macierze

81

przedziau oraz krok w trzecim wierszu. W kolejnych wierszach umiecimy pary liczb (argument i warto) oddzielone odstpem.

Zadanie 26.3. Napisz program, który obliczy i wywietli w konsoli sum dwóch wielomianów. Skorzystaj z metod dostpnych w klasie Arrays. Przyjmij, e wywietlajc wynik lub prezentujc dane, wielomian w( x) a n x n  a n 1 x n 1  ...  a1 x  a 0 zapiszemy w postaci acucha znaków "w = [a0, a1, ... an]", gdzie a0, a1, …, an s liczbami wyraajcymi wspóczynniki wielomianu.

Zadanie 26.4. Napisz program, który obliczy i wywietli w konsoli rónic dwóch wielomianów. Zob. wskazówk do zadania 26.3.

Zadanie 26.5. Napisz program, który obliczy i wywietli w konsoli iloczyn wielomianu przez liczb.

Zadanie 26.6. Napisz program, który obliczy i wywietli w konsoli iloczyn dwóch wielomianów.

Zadanie 26.7. Napisz program, który obliczy i wywietli w konsoli pochodn wielomianu.

Zadanie 26.8. Napisz program, który obliczy i wywietli w konsoli cak nieoznaczon (funkcj pierwotn) wielomianu.

Zadanie 26.9. Utwórz klas Polynomial (plik Polynomial.java) umoliwiajc wykonywanie podstawowych dziaa na wielomianach zapisanych w postaci tablicy wspóczynników. Napisz aplikacj prezentujc moliwoci utworzonych metod i konstruktorów.

Zadanie 26.10. Napisz program wykonujcy dzielenie wielomianu w( x)

a n x n  a n 1 x n 1  ...  a1 x  a 0

przez dwumian o postaci (x–c).

82

Programowanie w jzyku Java

Zadanie 26.11. Docz do klasy Polynomial dwie metody — division() i remainder() — obliczajce iloraz i reszt z dzielenia wielomianu reprezentowanego przez obiekt wywoujcy metod przez dwumian (x-c), gdzie liczba c typu double jest parametrem wywoania metody. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 26.12. b

³ w( x)dx dla wielomianu

Napisz program obliczajcy cak oznaczon s

a

w( x)

a n x n  a n 1 x n 1  ...  a1 x  a 0

Wszystkie potrzebne dane uytkownik powinien wprowadzi z klawiatury — najpierw dane wielomianu (stopie i wspóczynniki), a pó niej granice cakowania. Do wyznaczenia funkcji pierwotnej uyj metody (integral()) opracowanej w rozwizab

niach zada 26.8 i 26.9, a nastpnie skorzystaj ze wzoru

³ w( x)dx

F (b)  F (a) .

a

Zadanie 26.13. Majc dane wszystkie pierwiastki rzeczywiste wielomianu ( x1 , x2 , ..., xn ), napisz program wyznaczajcy wspóczynniki wielomianu.

27. Obliczenia statystyczne Zadania 27.1 – 27.19 wykonamy dla n-elementowej próbki zapisanej w tablicy: double[] x = {1.35, 2.45, 2.05, 1.20, 2.15, 1.70, 1.45, 1.95, 2.00, 1.65, 1.65, 2.05, 1.75, 1.25, 2.25, 1.40};

Czytelnik moe samodzielnie zmieni zestaw danych lub sposób ich pobierania przez program — wprowadzanie danych z klawiatury lub odczytywanie z pliku. Naley zwróci uwag na rozbienoci pomidzy zakresem indeksów. W tablicach w jzyku Java indeksowanie rozpoczynamy od 0 i koczymy na indeksie o 1 mniejszym od rozmiaru tablicy, natomiast we wzorach statystyki opisowej indeksy wartoci próbki bd w granicach od 1 do n. W zadaniach bardzo czsto bdziemy mieli do czynienia z obliczaniem sumy cigu n

liczb x1, x2, …, xn (oznaczanej symbolem

¦ x ) zapisanego w tablicy x[0], x[1], …, i

i 1

x[n–1]. Zrealizujemy to przy uyciu instrukcji ptli: double suma = 0; for(double xi: x) suma += xi;

Rozdzia 4. i Czwarty krok — pliki, tablice i macierze

83

lub: double suma = 0; for(int i = 0; i < n; ++i)) suma += x[i];

Zadanie 27.1. Dla podanej próbki n-elementowej x1, …, xn wyznacz najmniejsz i najwiksz warto w cigu oraz rozstp badanej cechy. Rozstpem badanej cechy jest rónica pomidzy wartoci maksymaln i minimaln

R

xmax  xmin .

Zadanie 27.2. Dla podanej próbki n-elementowej x1, …, xn wyznacz redni arytmetyczn.

redni arytmetyczn liczb x1, …, xn nazywamy liczb

x

1 n ¦ xi ni1

.

Zadanie 27.3. Dla podanej próbki n-elementowej x1, …, xn wyznacz redni geometryczn. n

redni geometryczn dodatnich liczb x1, …, xn nazywamy liczb

g

n

–x

i

.

i 1

Jeeli wszystkie xi > 0, to

log g

1 n ¦ log xi ni1

.

Zadanie 27.4. Dla podanej próbki n-elementowej x1, …, xn wyznacz redni harmoniczn. redni harmoniczn rónych od zera liczb x1, …, xn nazywamy liczb

h

§1 n 1 · ¨¨ ¦ ¸¸ © n i 1 xi ¹

1

n

, gdy

¦

i 1

1 z 0 xi

(odwrotno redniej arytmetycznej

odwrotnoci tych liczb).

Zadanie 27.5. Dla podanej próbki n-elementowej x1, …, xn wyznacz redni potgow rzdu r. Obliczenia wykonaj dla r = 2 i r = 3.

84

Programowanie w jzyku Java

redni potgow rzdu r dodatnich liczb x1, …, xn nazywamy liczb

p (r )

r

1 n

n

¦x

r i

. Dla r

1 otrzymujemy redni harmoniczn ( p ( 1)

1 redni arytmetyczn ( p (1)

a dla r

h ),

i 1

x ).

Zadanie 27.6. Dla podanej próbki n-elementowej x1, …, xn wyznacz median. Posortuj tablic z danymi i wybierz element rodkowy, gdy n jest nieparzyste, lub oblicz redni arytmetyczn dwóch rodkowych liczb, gdy n jest parzyste:

me

­ x n1 , gdy n jest nieparzyste °° 2 ®1 § · ° ¨¨ x n  x n ¸¸, gdy n jest parzyste 1 °¯ 2 © 2 2 ¹

Naley pamita o przesuniciu indeksu wynikajcego z rónicy pomidzy indeksami we wzorach a indeksami w tablicach.

Zadanie 27.7. Wyznacz warto modaln (dominant) n-elementowej próbki x1, …, xn. Wartoci modaln (dominant, mod) próbki x1, …, xn o powtarzajcych si wartociach nazywamy najczciej powtarzajc si warto , o ile taka istnieje. Ponadto warto ta nie moe by wartoci minimaln lub maksymaln.

Zadanie 27.8. Oblicz wariancj n-elementowej próbki x1, …, xn. Wykorzystaj wszystkie niej podane wzory i porównaj uzyskane wyniki. Wariancj s2 (dyspersj) próbki x1, …, xn nazywamy redni arytmetyczn kwadratów odchyle wartoci xi od redniej arytmetycznej x próbki: s 2 Mona zastosowa wzory równowane s 2

s

2

1 n

n

1 n

n

¦x

2 i

 x 2 lub

i 1

¦ x  a  x  a , gdzie a jest dowoln sta. 2

i

i 1

2

1 n

n

¦ x  x

2

i

i 1

.

Rozdzia 4. i Czwarty krok — pliki, tablice i macierze

85

Zadanie 27.9. Oblicz odchylenie standardowe n-elementowej próbki x1, …, xn. Odchylenie standardowe s próbki x1, …, xn jest równe pierwiastkowi kwadratowemu z wariancji s2 (zob. zadanie 27.8).

Zadanie 27.10. Oblicz odchylenie przecitne d próbki x1, …, xn od staej a. Obliczenia wykonaj dla a = 2. Odchyleniem przecitnym d od staej a próbki x1, …, xn nazywamy redni arytmetyczn wartoci bezwzgldnych odchyle poszczególnych wartoci xi od staej a:

d

1 n

n

¦ x a . i

i 1

Zadanie 27.11. Oblicz odchylenie przecitne d1 próbki x1, …, xn od wartoci redniej x .

Zadanie 27.12. Oblicz odchylenie przecitne d2 próbki x1, …, xn od mediany me .

Zadanie 27.13. Wyznacz kwartyl dolny Q1 i kwartyl górny Q3 próbki x1, …, xn. Oblicz odchylenie wiartkowe Q. Wartoci uporzdkowanej próbki dzielimy na dwie grupy: wartoci mniejsze od mediany i median oraz median i wartoci wiksze od mediany. Kwartylem dolnym (Q1) jest mediana pierwszej grupy, a górnym (Q3) mediana drugiej grupy. OdchyleQ3  Q1 nie wiartkowe Q obliczamy ze wzoru Q . 2

Zadanie 27.14. Oblicz moment zwyky ml rzdu l próbki x1, …, xn. Obliczenia wykonaj dla l = 2, 3 i 4.

Wzór ml

1 n

n

¦x , l i

i 1

lN .

86

Programowanie w jzyku Java

Zadanie 27.15. Oblicz moment centralny Ml rzdu l próbki x1, …, xn. Obliczenia wykonaj dla l = 2, 3 i 4. n

¦ (x  x) ,

1 n

Wzór M l

l

i

l  N . Z wasnoci redniej arytmetycznej wynika, e

i 1

M1 = 0, natomiast M2 jest wariancj.

Zadanie 27.16. Oblicz moment absolutny zwyky al rzdu l próbki x1, …, xn. Obliczenia wykonaj dla l = 2, 3 i 4. 1 n

Wzór al

n

¦| x | , l

i

lN .

i 1

Zadanie 27.17. Oblicz moment absolutny centralny bl rzdu l próbki x1, …, xn. Obliczenia wykonaj dla l = 2, 3 i 4. 1 n

Wzór bl

n

¦| x  x | , l

i

l  N . Absolutny moment centralny rzdu pierwszego

i 1

jest odchyleniem przecitnym od redniej arytmetycznej.

Zadanie 27.18. Oblicz wspóczynnik zmiennoci v próbki x1, …, xn.

Wzór v

s ˜ 100% , gdzie s jest odchyleniem standardowym, a x redni arytmex

tyczn próbki.

Zadanie 27.19. Oblicz wspóczynnik nierównomiernoci H próbki x1, …, xn.

Wzór H tycznej x .

d1 ˜ 100% , gdzie d1 jest odchyleniem przecitnym od redniej arytmex

Rozdzia 4. i Czwarty krok — pliki, tablice i macierze

87

W zadaniach 27.1 – 27.19 przedstawiono podstawowe wzory zwizane z obliczeniami statystyki opisowej dla pojedynczej próbki, zwykle nieprzekraczajcej 30 elementów. Czytelnik moe samodzielnie na podstawie rozwiza tych zada konstruowa programy majce na celu rozwizywanie problemów z zakresu statystyki.

Zadanie 27.20. Na podstawie problemów zawartych w zadaniach 27.1 – 27.19 utwórz klas Stat zawierajc metody statyczne do oblicze statystycznych. Napisz aplikacj konsolow pokazujc dziaanie wybranych metod z klasy Stat. Sporzd dokumentacj tej klasy.

Zadanie 27.21. Na podstawie problemów zawartych w zadaniach 27.1 – 27.19 utwórz klas Statpr umoliwiajc utworzenie obiektu (próbki) zawierajcego metody do rozwizywania tych problemów. Napisz aplikacj konsolow pokazujc dziaanie wybranych metod z klasy Statpr. Sporzd dokumentacj tej klasy.

28. Tablice wielowymiarowe i macierze Zadanie 28.1. Utwórz dwuwymiarow tablic liczb cakowitych o trzech wierszach. W pierwszym wierszu tablicy umie liczby od 1 do 10, w drugim kwadraty tych liczb, a w trzecim szeciany liczb z pierwszego wiersza. Napisz program tworzcy i wywietlajcy t tablic w konsoli.

Zadanie 28.2. W tablicy dwuwymiarowej nie wszystkie wiersze musz mie ten sam rozmiar. Napisz program, który utworzy tablic liczb cakowitych o dziesiciu wierszach. Wypenij tablic kolejnymi liczbami naturalnymi, zaczynajc od liczby 1. W pierwszym wierszu umie jedn liczb, w drugim dwie liczby, w trzecim trzy itd. — w dziesitym dziesi liczb. Oblicz sumy liczb w kolejnych wierszach i sum wszystkich liczb zapisanych w tablicy. Wywietl w konsoli tablic liczb oraz obliczone sumy.

Zadanie 28.3. Utwórz klas TInt, która bdzie zawiera metody statyczne input() i print() umoliwiajce wprowadzanie danych z konsoli do tablicy lub wywietlanie danych z tablicy w konsoli. Parametrem wywoania tych metod powinna by tablica liczb cakowitych jedno- lub dwuwymiarowa. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 28.4. Utwórz w klasie TInt metod statyczn setRandom(), która wypeni tablic liczb cakowitych wartociami wylosowanymi z zakresu od 0 do n (liczba cakowita n > 0).

88

Programowanie w jzyku Java

Tablic oraz zakres wartoci podaj jako parametry metody. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.5. Dodaj do klasy TInt metod statyczn printf() wywietlajc tablic liczb cakowitych w konsoli. Metoda ta powinna mie dwa parametry: acuch formatujcy i identyfikator tablicy. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.6. Na podstawie zada 28.3, 28.4 i 28.5 utwórz klas TDouble z metodami statycznymi input(), print(), printf() i setRandom(), uatwiajcymi pobieranie i wypisywanie danych oraz losowe ustawianie wartoci w jedno- i dwuwymiarowych tablicach liczb zmiennoprzecinkowych typu double. Napisz program pokazujcy dziaanie wybranych metod z tej klasy. Macierz jest uporzdkowan prostoktn tablic liczb, dla której zdefiniowane s dziaania algebraiczne dodawania (odejmowania) i mnoenia:  Dodawanie (odejmowanie) dwóch macierzy jest moliwe tylko dla macierzy

o jednakowych liczbach kolumn (n) i wierszy (m). Suma (rónica) macierzy A i B jest macierz C tak, e cij aij  bij ( cij aij  bij ).  Mnoenie macierzy jest moliwe, gdy liczba kolumn pierwszej macierzy (m)

jest równa liczbie wierszy drugiej macierzy. Iloczyn macierzy A i B jest m

macierz C tak, e cij

¦ aik bkj . Mnoenie macierzy nie jest przemienne. k 1

 Zawsze okrelone jest mnoenie macierzy przez liczb O , polegajce na

pomnoeniu kadego elementu macierzy przez t liczb ( cij

Oaij ).

Macierze moemy przedstawia w programach jako tablice dwuwymiarowe. Naley pamita, e tablice s indeksowane od zera, a indeksy macierzy rozpoczynamy od jedynki.

Zadanie 28.7. Utwórz metod sum() dodajc dwie macierze zapisane w postaci tablic dwuwymiarowych. Napisz program demonstrujcy dziaanie metody sum(). W tym i kolejnych zadaniach do wprowadzania danych uywaj metod z klasy TInt lub TDouble.

Zadanie 28.8. Utwórz metod difference() obliczajc rónic dwóch macierzy zapisanych w postaci tablic dwuwymiarowych. Napisz program demonstrujcy dziaanie metody difference().

Rozdzia 4. i Czwarty krok — pliki, tablice i macierze

89

Zadanie 28.9. Utwórz metod product() obliczajc iloczyn dwóch macierzy zapisanych w postaci tablic dwuwymiarowych. Napisz program demonstrujcy dziaanie metody product().

Zadanie 28.10. Utwórz metod product() obliczajc iloczyn macierzy zapisanej w postaci tablicy dwuwymiarowych przez liczb. Napisz program demonstrujcy dziaanie metody product().

Zadanie 28.11. Zbuduj metod transp() tworzc macierz transponowan z macierzy podanej jako parametr metody. Napisz program demonstrujcy dziaanie metody transp(). Macierz transponowana (przestawiona) powstaje z danej macierzy poprzez zamian jej wierszy na kolumny i kolumn na wiersze.

Zadanie 28.12. Utwórz metod statyczn toDouble() konwertujc macierz o elementach cakowitych na macierz o elementach zmiennoprzecinkowych. Napisz program demonstrujcy dziaanie tej metody. Docz j do klasy TInt.

Zadanie 28.13. Docz do klasy TDouble metod statyczn o nazwie valueOf(), zwracajc tablic (macierz) z elementami typu double o elementach odpowiadajcych elementom tablicy (macierzy) liczb cakowitych. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.14. W klasie TDouble utwórz statyczn metod toInt(), która bdzie zwraca tablic (macierz) o wartociach cakowitych, odpowiadajcych (zamiana przez rzutowanie) tablicy liczb zmiennoprzecinkowych podanej jako parametr. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.15. W klasie TInt utwórz statyczn metod valueOf(), która bdzie budowa tablic (macierz) o wartociach cakowitych, odpowiadajcych (zamiana przez rzutowanie) tablicy liczb zmiennoprzecinkowych podanej jako parametr. Napisz program demonstrujcy dziaanie tej metody. Macierze, w których liczba wierszy jest równa liczbie kolumn, nazywamy macierzami kwadratowymi. Z macierzami kwadratowymi zwizany jest szereg poj, takich jak: lad macierzy, wyznacznik macierzy, macierz diagonalna, macierz trójktna, macierz jednostkowa i macierz odwrotna.

90

Programowanie w jzyku Java

Zadanie 28.16. Utwórz statyczn metod trace() wyznaczajc lad macierzy. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.17. Utwórz statyczn metod getI() zwracajc macierz jednostkow stopnia n (stopie podamy jako parametr wywoania metody). Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.18. Utwórz statyczn metod setI() tworzc z macierzy kwadratowej podanej jako parametr macierz jednostkow. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.19. Utwórz metod statyczn det() obliczajc wyznacznik macierzy kwadratowej. Do obliczenia wyznacznika uyj rozwinicia Laplace’a. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.20. Utwórz metod statyczn upperTriangular() przeksztacajc macierz kwadratow podan jako parametr na macierz trójktn górn. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.21. Utwórz metod statyczn lowerTriangular() przeksztacajc macierz kwadratow podan jako parametr na macierz trójktn doln. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.22. Utwórz metod statyczn diagonal() przeksztacajc macierz kwadratow podan jako parametr na macierz diagonaln. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.23. Utwórz metod statyczn inverse() obliczajc i zwracajc macierz odwrotn do macierzy kwadratowej podanej jako parametr. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.24. Napisz program rozwizujcy ukad n-równa liniowych z n niewiadomymi (n < 10). Ukad równa rozwi, stosujc metod wyznaczników. Wszystkie niezbdne metody umie w klasie programu.

Rozdzia 4. i Czwarty krok — pliki, tablice i macierze

91

Zadanie 28.25. Napisz program rozwizujcy ukad n-równa liniowych z n niewiadomymi. Ukad równa rozwi, stosujc rachunek macierzy: A ˜ X B , X A 1 ˜ B , gdzie A — macierz podstawowa ukadu, X — wektor niewiadomych, B — kolumna wyrazów wolnych. Wszystkie niezbdne metody umie w klasie programu.

Zadanie 28.26. Napisz program rozwizujcy ukad n-równa liniowych z n niewiadomymi. Ukad równa rozwi, stosujc metod eliminacji. Wszystkie niezbdne metody umie w klasie programu.

Zadanie 28.27. Utwórz klas Matrix, która na podstawie tablic dwuwymiarowych, podanych wymiarów macierzy lub innych obiektów klasy Matrix (konstruktor kopiujcy) bdzie umoliwia tworzenie obiektów reprezentujcych macierze. Utwórz metody uatwiajce dostp do elementów macierzy (pól obiektu), wprowadzanie i wywietlanie danych oraz wypenianie macierzy wartociami losowymi. Napisz program demonstrujcy dziaanie metod klasy Matrix.

Zadanie 28.28. Docz do klasy Matrix metody umoliwiajce wykonywanie podstawowych dziaa na macierzach: dodawanie, odejmowanie i mnoenie macierzy oraz mnoenie macierzy przez skalar. Napisz program demonstrujcy dziaania na macierzach.

Zadanie 28.29. Docz do klasy Matrix metody umoliwiajce przeksztacanie macierzy kwadratowych na posta trójktn lub diagonaln. Napisz program demonstrujcy dziaanie tych metod.

Zadanie 28.30. Docz do klasy Matrix metod umoliwiajc obliczanie wyznacznika macierzy. Napisz program demonstrujcy dziaanie tej metody.

Zadanie 28.31. Docz do klasy Matrix metod umoliwiajc obliczanie macierzy odwrotnej. Napisz program demonstrujcy obliczanie macierzy odwrotnej. Sprawd uzyskany wynik, wykonujc odpowiednie mnoenie.

Zadanie 28.32. Wykorzystujc moliwoci klasy Matrix i obliczenia na macierzach, rozwi ukad n-równa liniowych z n niewiadomymi.

92

Programowanie w jzyku Java

Zadanie 28.33. Wykorzystujc moliwoci klasy Matrix i metod wyznaczników, rozwi ukad n-równa liniowych z n niewiadomymi. Utwórz metod pomocnicz replaceCol(), która w macierzy wywoujcej t metod zastpi wskazan kolumn kolumn przekazan jako parametr (bdzie to kolumna wyrazów wolnych).

29. Obliczanie wartoci funkcji, rekurencja i inne zadania Zadanie 29.1. Napisz aplikacj testujc dziaanie podanej metody dla rónych argumentów. Okrel, co oblicza ta metoda. Nadaj jej odpowiedni nazw. static double f(double x) { return (x > 0)?x:-x; }

Zadanie 29.2. ­ x, gdy x d y ­ x, gdy x t y Okrelono dwie funkcje: min( x, y ) ® oraz max( x, y ) ® . ¯ y, gdy x ! y ¯ y, gdy x y Utwórz klas MinMax z metodami min() i max() obliczajcymi i zwracajcymi wartoci tych funkcji. Napisz aplikacj pokazujc dziaanie tych metod.

Zadanie 29.3. ­ 1, gdy x 0 ° Okrelono funkcj f ( x) ®0, gdy x 0 . Co oblicza ta funkcja? Utwórz metod ob°1, gdy x ! 0 ¯ liczajc warto tej funkcji. Napisz aplikacj pokazujc dziaanie zbudowanej metody.

Zadanie 29.4. ­0, gdy x 0 ° Okrelono funkcj f ( x) ® x . Co oblicza ta funkcja? Utwórz metod ob° , gdy x z 0 ¯x liczajc warto tej funkcji. Napisz aplikacj pokazujc dziaanie zbudowanej metody.

Rozdzia 4. i Czwarty krok — pliki, tablice i macierze

93

Zadanie 29.5. Napisz aplikacj testujc wartoci funkcji okrelonych wzorami: a) f x, y

x y x y

b) g x, y

x y x y

c) h( x)

2

2

f ( x,  x)

Co obliczaj te funkcje? Utworzonym metodom nadaj odpowiednie nazwy.

Zadanie 29.6. Napisz definicje metod square() i cube() obliczajcych kwadrat i szecian liczby x. Zastosuj utworzone metody do obliczenia kwadratów i szecianów liczb: a) cakowitych od 1 do 15, b) rzeczywistych od 1 do 3 z krokiem 0,25.

Zadanie 29.7. Potg o wykadniku cakowitym dodatnim okrelamy wzorem a n

a ˜ a

˜ ... ˜ a . Utwórz n

metod adoen() obliczajc an. Napisz aplikacj pokazujc dziaanie tej metody.

Zadanie 29.8. Potg o wykadniku cakowitym nieujemnym moemy okreli wzorem rekurencyj­1, dla n 0 nym: a n ® . Napisz definicj metody rekurencyjnej adoen() oblin 1 ¯a ˜ a , dla n ! 0 czajcej an oraz aplikacj pokazujc dziaanie tej metody.

Zadanie 29.9. Szybkie potgowanie — inn wersj metody rekurencyjnej obliczajcej an (szybsz ze wzgldu na mniejsz liczb wywoa rekurencyjnych i zredukowanie liczby mnoe) moemy zrealizowa na podstawie wzoru:

an

­ ° °1 dla n 0 ° § n 1 · 2 ° 2 ®a ˜ ¨ a ¸ dla n nieparzystego (n ! 0) . ¹ © ° ° n 2 °§¨ a 2 ·¸ dla n parzystego (n ! 0) ¯°© ¹

94

Programowanie w jzyku Java

Utwórz metod adoen() obliczajc an. Napisz aplikacj pokazujc dziaanie tej metody.

Zadanie 29.10. Potg o podstawie a rónej od 0 i wykadniku cakowitym n moemy zdefiniowa ­a ˜ a ˜ ... ˜ a, dla n ! 0 °

n ° n w nastpujcy sposób: a ®1, dla n 0 . °1 ° n , dla n 0 ¯a Napisz definicj metody power() (prototyp: double power(double a, int n)) obliczajcej an dla dowolnej liczby cakowitej oraz aplikacj pokazujc dziaanie tej funkcji. Funkcj adoen (zob. zadanie 29.7, 29.8 lub 29.9) obliczajc an dla n > 1 wykorzystamy w funkcji power (do obliczania a n lub a n

1 dla n 1, 2, 3, ... ). an

Zadanie 29.11. Pierwiastek drugiego stopnia z liczby dodatniej a moemy obliczy metod iteracyjn na podstawie wzoru x

1§ a· ¨ x  ¸ , przyjmujc jako pierwsze przyblienie x 2© x¹

1 . Ob-

liczenia kontynuujemy do chwili, gdy rónica pomidzy dwoma kolejnymi przyblieniami pierwiastka bdzie dostatecznie maa. Napisz metod sqrt() (ang. square root) obliczajc pierwiastek kwadratowy z podanej liczby dodatniej. Zbuduj aplikacj pokazujc dziaanie metody sqrt() i porównujc otrzymane wyniki z wynikami metody bibliotecznej Math.sqrt().

Zadanie 29.12. Pierwiastek trzeciego stopnia z liczby dodatniej a moemy obliczy metod iteracyjn na podstawie wzoru x 1 §¨ 2 x  a ·¸ , przyjmujc jako pierwsze przyblienie x 1 . Ob3© x2 ¹ liczenia kontynuujemy do chwili, gdy rónica pomidzy dwoma kolejnymi przyblieniami pierwiastka bdzie dostatecznie maa. Napisz metod cbrt() (ang. cube root) obliczajc pierwiastek trzeciego stopnia z podanej liczby dodatniej. Zbuduj aplikacj pokazujc dziaanie metody cbrt() i porównujc otrzymane wyniki z wynikami metody bibliotecznej Math.cbrt(). Podany wzór wynika z metody Newtona-Raphsona — iteracyjnego algorytmu wyznaczania przyblionej wartoci pierwiastka funkcji. Dotyczy to równie wzoru z zadania 29.11.

Rozdzia 4. i Czwarty krok — pliki, tablice i macierze

95

Zadanie 29.13. Pierwiastek n-tego stopnia z liczby dodatniej a moemy obliczy metod iteracyjn na podstawie wzoru x 1 §¨ n  1 x  a ·¸ , przyjmujc jako pierwsze przyblienie n© x n 1 ¹ x 1 . Obliczenia kontynuujemy do chwili, gdy rónica pomidzy dwoma kolejnymi przyblieniami pierwiastka bdzie dostatecznie maa. Na podstawie podanego wzoru napisz metod nRoot() obliczajc pierwiastek n-tego stopnia z podanej liczby dodatniej. Zbuduj aplikacj pokazujc dziaanie metody nRoot() i porównujc otrzymane wyniki z wynikami uzyskanymi przy zastosowaniu funkcji bibliotecznej. 1

Poniewa n a a n , to warto pierwiastka moemy obliczy przy zastosowaniu funkcji Math.pow(a, 1.0/n).

Skorzystaj z opracowanej w zadaniu 29.7 metody power() do obliczania wartoci x n 1 .

Zadanie 29.14. W klasie Math zdefiniowano metody obliczajce funkcje hiperboliczne — sinus hiperboliczny (Math.sinh()) i cosinus hiperboliczny (Math.cosh()). Napisz program wywietlajcy na ekranie tablice wszystkich funkcji hiperbolicznych w przedziale  5, 5 z krokiem 0,1. Wyniki oblicze zapisz w pliku tekstowym FunkcjeHiperboliczne.txt. Wyniki pracy programu mona zapisa w pliku tekstowym, stosujc w konsoli polecenie: java Z29_14 > FunkcjeHiperboliczne.txt

(przyjmujemy, e rozwizanie zadania zapisano w pliku ródowym Z29_14.java).

Zadanie 29.15. W klasie Math zdefiniowano metod Math.exp() obliczajc warto funkcji wykadniczej e x . Rozwi zadanie 29.14, nie korzystajc z metod Math.sinh() i Math.cosh().

Wartoci funkcji mona wyliczy na podstawie wzorów: sinh x

cosh x

e x  e  x itp. 2

e x  e x , 2

96

Programowanie w jzyku Java

Zadanie 29.16. Zbuduj klas FH (funkcje hiperboliczne) zawierajc metody statyczne obliczajce wartoci wszystkich funkcji hiperbolicznych i funkcji do nich odwrotnych. Napisz aplikacj pokazujc dziaanie tych metod.

Zadanie 29.17. Zbuduj klas FTD, która bdzie zawiera metody statyczne obliczajce warto szeciu funkcji trygonometrycznych i szeciu funkcji do nich odwrotnych. Argumenty funkcji trygonometrycznych i wartoci funkcji odwrotnych powinny by wyraane w stopniach. Udostpnij równie metody konwersji stopni na radiany i radianów na stopnie. Napisz aplikacj pokazujc moliwoci metod statycznych zawartych w tej klasie.

Zadanie 29.18. Zbuduj klas FTR, która bdzie zawiera metody statyczne obliczajce warto szeciu funkcji trygonometrycznych i szeciu funkcji do nich odwrotnych. Argumenty funkcji trygonometrycznych i wartoci funkcji odwrotnych powinny by wyraane w radianach. Udostpnij równie metody konwersji stopni na radiany i radianów na stopnie. Napisz aplikacj pokazujc moliwoci metod statycznych zawartych w tej klasie.

Rozdzia 5.

Rozwizania zada 1. Historia Javy i pierwsze zadania Zadanie 1.1. Podane rozwizanie ma charakter pogldowy i byo w caoci aktualne, gdy powstawa ten tekst. Zmiany na stronach producenta Javy spowodoway, e Czytelnik nie moe dokadnie wykorzysta tego rozwizania i musi, wzorujc si na nim, samodzielnie pobra i zainstalowa rodowisko JDK.

Zakadamy, e dysponujesz komputerem klasy PC z systemem operacyjnym Windows XP lub nowszym i dostpem do internetu. Wykonaj nastpujce czynnoci: 1. Otwórz stron internetow firmy Oracle http://www.oracle.com/pl/index.html. 2. Przejd do dziau Do pobrania. 3. Odszukaj link Java SE i przejd do tej podstrony. 4. Wybierz wersj Java 6 Update 27 i klikajc przycisk Download, pobierz JDK

(Java Development Kit) — http://www.oracle.com/technetwork/java/javase/ downloads/jdk-6u27-download-440405.html. 5. Zapoznaj si z licencj i zaakceptuj j. 6. Wybierz plik instalacyjny waciwy dla posiadanego systemu operacyjnego

i zapisz go na swoim dysku lokalnym: jdk-6u27-windows-i586.exe (76,81 MB) — dla systemu 32-bitowego, jdk-6u27-windows-x64.exe (67,40 MB) — dla systemu 64-bitowego. 7. Otwórz zapisany plik instalacyjny i przeprowad proces instalacji.

98

Programowanie w jzyku Java

Podczas typowej instalacji rodowisko JDK zostanie zainstalowane w folderze C:\Program Files\Java\jdk1.6.0_27\bin1. Pliki binarne (wykonywalne) znajduj si w podfolderze \bin. Naley doda do systemowej cieki przeszukiwa ciek C:\Program Files\Java\jdk1.6.0_27\bin (lub inn, wynikajc z przebiegu instalacji). W Panelu sterowania otwórz aplet System i przejd do zakadki Zaawansowane. Kliknij przycisk Zmienne rodowiskowe, na licie Zmienne uytkownika odszukaj i edytuj zmienn Path (dopisz potrzebn ciek).

Zadanie 1.2. Otwórz konsol (w Windows: Start/Uruchom… — w polu edycyjnym w pisz polecenie cmd i kliknij przycisk OK), wpisz w konsoli polecenie java i nacinij Enter. Jeli w konsoli zostanie wywietlona informacja o sposobie uruchomiania programu (help), to znaczy, e masz zainstalowane rodowisko uruchomieniowe Javy (JRE). Po wpisaniu polecenia java –version uzyskasz informacj o wersji posiadanej maszyny wirtualnej Javy. Wpisz w konsoli polecenie javac. Jeli w konsoli pojawi si informacja o sposobie i opcjach uruchomienia kompilatora, to masz poprawnie zainstalowane rodowisko JDK. Moesz sprawdzi wersj kompilatora (javac –version). Niepowodzenie testu, w postaci komunikatu: Nazwa 'javac' nie jest rozpoznawana jako polecenie wewntrzne lub zewntrzne, program wykonywalny lub plik wsadowy , nie wiadczy o braku JDK. By moe nie zostaa poprawnie ustawiona cieka dostpu (path) do folderu bin zawierajcego kompilator javac.exe. Sprawd to.

Zadanie 1.3. Uruchom aplikacj w linii komend i przekieruj wywietlane dane do pliku, np. java –? > java.txt lub java –help > java.txt (wystarczy równie polecenie java > java.txt). Nastpnie w dowolnym edytorze tekstowym sformatuj ten tekst wedug swoich potrzeb i wydrukuj. Moesz przetumaczy opisy (ale nie sowa bdce opcjami!) na jzyk polski, np.: -? -help -? -help

print this help message wywietl komunikat pomocy

Wydrukuj „cigawk”, czsto z niej zapewne skorzystasz. Usage: java [-options] class [args...] (to execute a class) or java [-options] -jar jarfile [args...] (to execute a jar file) where options include: -client to select the "client" VM -server to select the "server" VM -hotspot is a synonym for the "client" VM [deprecated]. The default VM is client. -cp -classpath A ; separated list of directories, JAR archives, and ZIP archives to search for class files.

1

Wersja 32-bitowa JDK w 64-bitowym systemie operacyjnym Windows 7 zainstaluje si w folderze C:\Program Files (x86)\Java\jdk1.6.0_27\bin.

Rozdzia 5. i Rozwizania zada

99

-D= set a system property -verbose[:class|gc|jni] enable verbose output -version print product version and exit -version: require the specified version to run -showversion print product version and continue -jre-restrict-search | -jre-no-restrict-search include/exclude user private JREs in the version search -? -help print this help message -X print help on non-standard options -ea[:...|:] -enableassertions[:...|:] enable assertions -da[:...|:] -disableassertions[:...|:] disable assertions -esa | -enablesystemassertions enable system assertions -dsa | -disablesystemassertions disable system assertions -agentlib:[=] load native agent library , e.g. -agentlib:hprof, see also, -agentlib:jdwp=help and -agentlib:hprof=help -agentpath:[=] load native agent library by full pathname -javaagent:[=] load Java programming language agent, see java.lang.instrument -splash: show splash screen with specified image

Zadanie 1.4. Uruchomienie aplikacji javac.exe bez podania parametrów powoduje wywietlenie nastpujcej instrukcji: Usage: javac where possible options include: -g Generate all debugging info -g:none Generate no debugging info -g:{lines,vars,source} Generate only some debugging info -nowarn Generate no warnings -verbose Output messages about what the compiler is doing -deprecation Output source locations where deprecated APIs are used -classpath Specify where to find user class files and annotation processors -cp Specify where to find user class files and annotation processors -sourcepath Specify where to find input source files -bootclasspath Override location of bootstrap class files -extdirs Override location of installed extensions -endorseddirs Override location of endorsed standards path -proc:{none,only} Control whether annotation processing and/or compilation is done. -processor [,,...] Names of the annotation processors to run; bypasses default discovery process -processorpath Specify where to find annotation processors -d Specify where to place generated class files -s Specify where to place generated source files -implicit:{none,class} Specify whether or not to generate class files for implicitly referenced files -encoding Specify character encoding used by source files -source Provide source compatibility with specified release -target Generate class files for specific VM version -version Version information -help Print a synopsis of standard options

100

Programowanie w jzyku Java -Akey[=value] -X -J

Options to pass to annotation processors Print a synopsis of nonstandard options Pass directly to the runtime system

Przechwycenie tego tekstu poleceniem javac > opis.txt do pliku opis.txt si nie powiedzie. Moemy natomiast tekst w konsoli zaznaczy (menu wywoane prawym przyciskiem myszy) i skopiowa zaznaczony fragment lub cay tekst do schowka (naciskajc klawisz Enter).

Zadanie 1.5. 1. Plik console.bat — otwieranie konsoli w biecym folderze. cmd

Moesz ten plik wsadowy rozbudowa tak, aby automatycznie wywoywa kolejne dwa pliki wsadowe. call setpath call setdrive cls cmd

Do pliku console.bat utwórz skrót na pulpicie lub w innym dogodnym miejscu. 2. Plik setpath.bat — ustawianie cieki dostpu do folderu bin na komputerach,

na których nie mamy uprawnie do zmian konfiguracyjnych w systemie lub nie chcemy tych zmian dokonywa2. path C:\Program Files\Java\jdk1.6.0_27\bin; %PATH%

3. Plik setdrive.bat — ustawienie folderu z plikami ródowymi jako dysku X:3. subst X: H:\!JAVA_ZZ\Pliki X:

4. Plik kompiluj.bat — kompilacja pliku ródowego o nazwie podanej jako

parametr dla pliku wsadowego (nazw podamy bez rozszerzenia .java i to jest nasze mae uproszczenie pracy). javac %1.java

Moemy ten plik rozbudowa, dodajc ciek do kompilatora. C:\Program Files\Java\jdk1.6.0_27\bin\javac %1.java

5. Plik uruchom.bat — uruchomienie wirtualnej maszyny Javy (JVM)

i przekazanie do wykonania kodu skompilowanej klasy. Nazw klasy podajemy jako parametr pliku wsadowego (tu adnego uproszczenia pracy nie wida). java %1 2

3

Na komputerze Czytelnika cieka moe by inna, zalena od tego, gdzie zainstalowano JDK. Autor uywa cieki dla standardowego przebiegu procesu instalacji rodowiska Javy. Autor w czasie opracowywania niniejszego zbioru zada korzysta z pendrive’a, który instalowa si w systemie jako dysk H:. Na materiay zwizane z tworzonym zbiorem autor utworzy folder !JAVA_ZZ, a pliki ródowe zapisywa w folderze !JAVA_ZZ\Pliki. Na komputerze Czytelnika cieka z plikami moe by inna.

Rozdzia 5. i Rozwizania zada

101

Program cmd.exe umoliwia uycie dziesiciu zmiennych do oznaczania parametrów pliku wsadowego (od %0 do %9). Zmienna %0 przekazuje nazw pliku wsadowego, a zmienne od %1 do %9 zawieraj kolejne argumenty wpisane przez uytkownika w wierszu polecenia. Moemy zatem do pliku wsadowego przekaza nazw klasy (%1) i maksymalnie 8 parametrów (od %2 do %9). java %1 %2 %3 %4 %5 %6 %7 %8 %9

6. Plik edytuj.bat — uruchomienie systemowego Notatnika (notepad.exe)

i przekazanie do edycji kodu ródowego klasy. Nazw klasy podajemy jako parametr pliku wsadowego (nazwa pliku powstanie z nazwy klasy i rozszerzenia .java). start notepad.exe %1.java

Przypomnijmy na koniec, e dysk X: moemy usun poleceniem subst X: /D. Nie powoduje to oczywicie utraty danych, które s bezpiecznie przechowywane w folderze dotychczas skojarzonym z napdem X:. Konsol natomiast zamkniemy poleceniem exit. Na listingu 1.1 przedstawiono wersj pliku console.bat uywan przez autora. Listing 1.1. console.bat path C:\Program Files\Java\jdk1.6.0_27\bin; %PATH% subst X: H:\!JAVA_ZZ\Pliki X: cls call cmd c: subst X: /D

Dwa kocowe wiersze s wykonywane dopiero po zamkniciu konsoli poleceniem exit (nie naley zamyka okna konsoli w inny sposób). Na rysunku 1.1 widoczne jest rozwizanie zastosowane w konfiguracji skrótu na pulpicie.

2. JDK, Notatnik i klasyczny przykad „Hello World” Zadanie 2.1. Hello.java, Z02_1.java Kolejno postpowania bdzie nastpujca: 1. Przygotuj do pracy dysk X: (otwórz skrót z pulpitu). Dalej pracuj w konsoli

na dysku X:. 2. Poleceniem edytuj Hello utwórz plik tekstowy Hello.java (w Notatniku)

i przepisz podany kod. Zapisz tekst (Ctrl+S) i zamknij Notatnik (Alt+F4).

102

Programowanie w jzyku Java

Rysunek 1.1. Propozycja konfiguracji skrótu na pulpicie

public class Hello { public static void main(String args[]) { System.out.println("Hello World"); } }

3. Skompiluj kod ródowy poleceniem kompiluj Hello (stosujc plik wsadowy kompiluj.bat) lub javac Hello.java. Jeli kompilacja si nie powioda

(s komunikaty o bdach), wró do punktu 2. 4. Uruchom aplikacj poleceniem uruchom Hello (plik wsadowy uruchom.bat) lub java Hello. Pamitaj o wielkoci liter (Java rozrónia wielko liter — sowa: hello, Hello i HELLO s trzema rónymi identyfikatorami).

Jako parametr uruchomienia podajemy nazw klasy, a nie nazw pliku. Pierwsza aplikacja zostaa uruchomiona. Przedstawion tu procedur stosuj do dalszych zada. Zapamitaj równie kilka wanych informacji. Prosta aplikacja w jzyku Java skada si z jednej publicznej klasy. Nazw klasy rozpoczynamy zwykle od wielkiej litery. Jeli nazwa klasy skada si z kilku sów, to czymy je w jedno sowo, stosujc tzw. notacj wielbdzi (CamelCase), np.: MojaPierwszaKlasa. Klasa ta musi zawiera publiczn i statyczn metod main, od której rozpoczyna si wykonanie aplikacji. Nazwa pliku ródowego musi by zgodna (równie pod wzgldem wielkoci liter) z nazw klasy. Wymagane jest rozszerzenie .java, np. MojaPierwszaKlasa.java. Kompilujemy kod ródowy klasy, np. javac MojaPierwszaKlasa.java. Efektem kompilacji jest kod bajtowy (B-kod, betakod, ang. bytecode) zapisany w pliku MojaPierwszaKlasa.class. Aplikacj uruchamiamy, otwierajc wirtualn maszyn Javy (JVM) i przekazujc do interpretacji (jako parametr) nazw skompilowanej klasy, np. java MojaPierwszaKlasa.

Rozdzia 5. i Rozwizania zada

103

Umiesz ju przepisa kod, skompilowa plik ródowy i uruchomi aplikacj. Przeanalizujmy ten prosty przykad. Zacznijmy od budowy klasy. Kod klasy skada si ze sowa kluczowego class, identyfikatora (nazwy klasy) i ciaa klasy ujtej w nawiasy klamrowe {}, np. class Pusta { }. W naszym przypadku wystpuje jeszcze sowo kluczowe public, okrelajce dostp (publiczny) do klasy. W ciele klasy wystpuje publiczna i statyczna metoda main: public static void main(String args[]) { }

Sowo kluczowe public oznacza, e metoda main() jest widoczna dla wszystkich elementów programu. Metoda statyczna (sowo kluczowe static) jest dostpna bez koniecznoci tworzenia obiektu klasy. Przed nazw metody main wystpuje sowo kluczowe void, informujce, e metoda nie zwraca adnej wartoci (pusty typ wyniku). W nagówku metody main() konieczne jest zadeklarowanie tablicy argumentów String args[] lub String[] args (obie postacie deklaracji oznaczaj to samo). String jest nazw klasy (typu obiektowego) sucej do wykonywania operacji na acuchach znaków (tekstach), args jest identyfikatorem deklarowanego obiektu4, a symbol [] oznacza tablic zoon z kilku obiektów. Podczas uruchomienia aplikacji ta tablica jest wypeniana przez system parametrami wywoania. Szczegóy wkrótce. W tym przykadzie nie korzystamy z tablicy argumentów, ale taka deklaracja musi by w nagówku metody main(). W ciele metody wystpuje jeden wiersz, odpowiedzialny za wywietlenie tekstu Hello World w konsoli: System.out.println("Hello World");

W klasie System zdefiniowana jest statycznie zmienna obiektowa out. Metody tej zmiennej dziaaj na standardowym strumieniu wyjciowym. Uyta w przykadzie metoda println() wysya na standardowe wyjcie (konsol) dane przekazane jako parametr podczas wywoania metody i kod koca wiersza5. W tym przykadzie argumentem jest staa warto tekstowa, czyli litera acuchowy "Hello World".

Zadanie 2.2. Witam.java, Z02_2.java To kolejny przykad wykorzystania metody System.out.println opisanej w rozwizaniu zadania 2.1. Problem prawidowego wywietlania liter z polskimi znakami diakrytycznymi w konsoli omówiono, podajc wskazówk do zadania.

4

5

Ten identyfikator mona zmieni, ale nie ma potrzeby tego robi. Sowo args jest po prostu skrótem od sowa argumenty (ang. arguments). Parametr moe by wielkoci sta (literaem), zmienn dowolnego typu lub wyraeniem. Metoda println() wywoana bez parametru powoduje tylko przeniesienie kursora na pocztek nowej linii. Istnieje te podobnie dziaajca metoda print(), która wypisuje informacj na standardowym wyjciu, ale nie przenosi kursora do nowego wiersza.

104

Programowanie w jzyku Java public class Witam { public static void main(String args[]) { System.out.println("Witaj, wiecie."); System.out.println("Ucz si programowa w jzyku Java."); } }

Zadanie 2.3. Adres.java, Z02_3.java W acuchu znaków umieszczono specjalny znak \n, powodujcy przejcie tekstu umieszczonego za znakiem do nowego wiersza. public class Adres { public static void main(String args[]) { /* Dane osoby i adres s zupenie fikcyjne */ System.out.println("Ewa Nowak\nul. Krótka 1\n11-111 Fikcja Dolna"); } }

W ten sposób w acuchu moemy umieci inne znaki specjalne: \b — backspace, \t — tabulacja, \r — powrót karetki, \" — cudzysów, \' — apostrof, \\ — lewy ukonik.

Zadanie 2.4. Etykieta.java, Z02_4.java public class Etykieta { public static void main(String args[]) { System.out.println("******* Programowanie *******"); System.out.println("* obiektowe w jzyku Java *"); System.out.println("* Jan Nowak *"); System.out.println("*****************************"); } }

3. Znaki, tablice znaków i klasa String Zadanie 3.1. Witaj.java, Z03_1.java Deklarujemy tablic znaków (char[]) o nazwie witaj. Rozmiar tablicy nie zosta ustalony. Poniewa czymy deklaracj z inicjowaniem elementów tablicy, to kompilator na tej podstawie obliczy rozmiar tablicy i wypeni j odpowiednimi wartociami. Zwrómy uwag na sposób zapisu znaków z uyciem apostrofów i zapamitajmy zasadnicz rónic: 'A' — znak, litera A; "A" — acuch znaków (jednoelementowy), zawierajcy jeden znak A. Jeli potrzebujemy wywietli wszystkie znaki zapisane w tablicy (w kolejnoci ich wystpowania), to moemy uy metody print lub println, przekazujc nazw tablicy jako parametr wywoania metody. public class Witaj { public static void main(String args[]) {

Rozdzia 5. i Rozwizania zada

105

char[] witaj = {'D', 'z', 'i', 'e', ' ', ' ', 'd', 'o', 'b', 'r', 'y'}; System.out.println(witaj); } }

Zadanie 3.2. Informatyka.java, Z03_2.java W dziaaniach zwizanych z przetwarzaniem tablic czsto wykorzystujemy instrukcje iteracyjne (ptle). Zawarto tablicy moemy wywietli, uywajc ptli typu for each (wprowadzonej do jzyka Java SE 5.0): for(typ_zmiennej zmienna : kolekcja) instrukcja;

W powyszym zapisie for jest sowem kluczowym definiujcym ptl, identyfikator zmienna oznacza zmienn typu typ_zmiennej zawartego w kolekcji, dwukropek (:) oddziela zmienn od identyfikatora kolekcji (wymaga tego skadnia ptli for each), kolekcja w tym przypadku oznacza nazw tablicy6. Identyfikator zmiennej i nazwa kolekcji ujte s w nawiasy ( ), natomiast za nawiasem znajduje si instrukcja do powtarzania. Instrukcja powtarzana jest tyle razy, ile elementów zawiera kolekcja; w kadym powtórzeniu cyklu warto zmiennej jest równa wartoci kolejnego elementu kolekcji. Naley doda, e ptla typu for each suy do odczytywania kolekcji i za porednictwem zmiennej nie moemy modyfikowa wartoci elementów kolekcji. Ptla for(char x : a) System.out.print(x); wywietli w konsoli po kolei wszystkie znaki zapisane w tablicy a. Oczywicie moemy z wartoci zmiennej x wykona inne, bardziej skomplikowane operacje ni tylko wywietlanie w konsoli. a) W ptli for(char znak : dane) ... pobieramy do zmiennej znak kolejne elementy z tablicy dane. Kady pobrany z tablicy znak wywietlamy w odrbnym wierszu konsoli System.out.println(znak). b) Pisanie tekstem rozstrzelonym (spacjowanie) polega na pisaniu tekstu znak

po znaku, oddzielajc kolejne znaki odstpami (spacjami). W ptli pobieramy z tablicy kolejne znaki i wywietlamy w konsoli System.out.print(znak); System.out.print(" ");. c) W klasie Character zdefiniowano statyczn metod toUpperCase()

zmieniajc ma liter na odpowiadajc jej wielk liter. Wykorzystujemy t metod do zamiany znaków odczytywanych z tablicy System.out.print(Character.toUpperCase(znak));. d) Pobrane z tablicy dane znaki (mae lub wielkie litery), zamieniamy na mae litery (Character.toLowerCase(znak)) i wywietlamy w konsoli. public class Informatyka { public static void main(String args[]) { char dane[] = {'I', 'n', 'f', 'o', 'r', 'm', 'a', 't', 'y', 'k', 'a'}; /* Zadanie 3.2a */ System.out.println("Pionowo: ");

6

Dalej bd przedstawione inne kolekcje.

106

Programowanie w jzyku Java for(char znak : dane) System.out.println(znak); System.out.println(); /* Zadanie 3.2b */ System.out.print("Tekst rozstrzelony: "); for(char znak : dane) { System.out.print(znak); System.out.print(" "); } System.out.println(); /* Zadanie 3.2c */ System.out.print("Wielkie litery: "); for(char znak : dane) System.out.print(Character.toUpperCase(znak)); System.out.println(); /* Zadanie 3.2d */ System.out.print("Mae litery: "); for(char znak : dane) System.out.print(Character.toLowerCase(znak)); System.out.println(); } }

Metody toLowerCase() i toUpperCase() zmieniaj wycznie wielko liter, nie powoduj adnych zmian w pozostaych znakach.

Zadanie 3.3. Programowanie.java, Z03_3.java Stosujc podstawienie dane[0] = Character.toUpperCase(dane[0]);, zmienimy pierwszy znak zapisany w tablicy dane. Podobnie mona postpi z pozostaymi znakami. Indeksy znaków zapisanych w tablicy zmieniaj si w zakresie od 0 do wartoci o 1 mniejszej od rozmiaru tablicy. Dostp do wszystkich znaków w tablicy dane uzyskamy, stosujc ptl typu for: for(int i=0; i < dane.length; ++i) { // Tu wykonaj przeksztacenie zwizane z elementem dane[i]. }

Ptla for bdzie dalej omówiona dokadniej; na razie zapamitaj, e zmienna i typu cakowitego int bdzie w tym przypadku zmieniaa si od 0 (na pocztku inicjujemy zmienn int i=0;) do wartoci dane.length–1. Instrukcja zawarta w ciele ptli wykonuje si, gdy speniony jest warunek i < dane.length. Po kadym wykonaniu ptli warto zmiennej i jest zwikszana o 1 (operator inkrementacji ++i7). Ptla wykona si dokadnie tyle razy, ile elementów ma tablica dane, a zmienna i przyjmie kolejno wartoci indeksów wszystkich elementów tablicy. Sowo kluczowe int jest nazw typu do przechowywania liczb cakowitych w zakresie od –231 do 231–1. Konstrukcja int a; jest deklaracj zmiennej a typu int, natomiast int a = warto; deklaruje zmienn i inicjuje jej warto pocztkow (warto moe by literaem lub wyraeniem). 7

Zapis ++i jest równowany podstawieniu i = i+1.

Rozdzia 5. i Rozwizania zada

107

public class Programowanie { public static void main(String args[]) { char dane[] = {'p', 'r', 'o', 'g', 'r', 'a', 'm', 'o', 'w', 'a', 'n', 'i', 'e'}; System.out.print("Tablica znaków: "); System.out.println(dane); /* Zmiana pierwszej litery na wielk */ dane[0] = Character.toUpperCase(dane[0]); System.out.print("Pierwsza litera wielka: "); System.out.println(dane); /* Zmiana wszystkich liter na wielkie */ for(int i=0; i < dane.length; ++i) dane[i] = Character.toUpperCase(dane[i]); System.out.print("Wszystkie litery wielkie: "); System.out.println(dane); } }

Zadanie 3.4. Wspak1.java, Z03_4.java Do przegldania tablicy zastosujemy ptl for, w której nastpuje odliczanie w dó (od wartoci wikszych do mniejszych: for(int i=dane.length–1; i >= 0; ––i) { // Tu wykonamy przeksztacenie zwizane z elementem dane[i]. }

Na pocztku zmienn i inicjujemy wartoci równ indeksowi ostatniego elementu (rozmiar tablicy zmniejszony o 1 — int i=dane.length–1). Instrukcje s wykonywane, gdy i >= 0 (i jest wiksze lub równe 0). Po kadym wykonaniu instrukcji warto zmiennej i jest zmniejszana o 1 (dekrementacja ––i8). public class Wspak1 { public static void main(String args[]) { char dane[] = {'p', 'r', 'o', 'g', 'r', 'a', 'm', 'o', 'w', 'a', 'n', 'i', 'e'}; System.out.print("Normalna kolejno znaków: "); System.out.println(dane); System.out.print("Odwrotna kolejno znaków: "); for(int i = dane.length-1; i >= 0; --i) System.out.print(dane[i]); System.out.println(); } }

Zadanie 3.5. Wspak2.java, Z03_5.java Do zamiany wartoci dwóch elementów uyjemy zmiennej pomocniczej wedug schematu: p = a; a = b; b = p; — spowoduje to wymian wartoci pomidzy zmiennymi a i b. Odwracanie tablicy znaków zrealizujemy, zamieniajc pierwszy znak z ostatnim, drugi z przedostatnim — i tak do chwili, gdy dojdziemy do rodka tablicy. W tym celu wykorzystamy nastpujce zmienne: i — indeks pierwszego znaku (indeks ten zwiksza 8

Zapis ––i jest równowany podstawieniu i = i–1.

108

Programowanie w jzyku Java

si, przechodzc od pocztku (int i = 0) do rodka tablicy), j — indeks ostatniego znaku (indeks ten zmniejsza si, przechodzc od koca (int j = dane.length-1) do rodka tablicy), tmp — zmienna pomocnicza do zamiany wartoci dwóch elementów tablicy. Czynnoci zamiany elementów s powtarzane, gdy i < j. Na koniec kadego cyklu zwikszamy indeks i (++i) i zmniejszamy indeks j (--j), zbliajc si do rodka tablicy. public class Wspak2 { public static void main(String args[]) { char dane[] = {'p', 'r', 'o', 'g', 'r', 'a', 'm', 'o', 'w', 'a', 'n', 'i', 'e'}; System.out.print("Normalna kolejno znaków: "); System.out.println(dane); for(int i = 0, j = dane.length-1; i < j ; ++i, --j) { char tmp = dane[i]; dane[i] = dane[j]; dane[j] = tmp; } System.out.print("Odwrotna kolejno znaków: "); System.out.println(dane); } }

Zadanie 3.6. DemoCharacter.java, Z03_6.java Pierwszy wiersz kodu import static java.lang.System.*; powoduje zaimportowanie do naszej klasy wszystkich elementów statycznych z klasy java.lang.System (w tym obiektu out). W dalszej czci kodu moemy posugiwa si tym obiektem bez podawania nazwy klasy, z której pochodzi. Zamiast odwoania System.out.println(...); wystarczy out.println(...);. Na pocztku umieszczono kilka informacji o metodzie digit (ang. digit — cyfra):  out.println("Klasa: java.lang.Character"); — klasa Character znajduje si w pakiecie java.lang.  out.println("Metoda statyczna: digit\n"); — omawiana metoda jest metod statyczn, nie potrzebujemy tworzy obiektu klasy Character,

aby skorzysta z tej metody.  out.println("static int digit(int ch, int radix)"); — nagówek metody digit zawiera: sowo kluczowe static (metoda jest statyczna), typ zwracanej wartoci int i list parametrów wywoania metody (int ch, int radix).  out.println("Returns the numeric value of the character ch in the specified radix."); — pierwsze zdanie z dokumentacji metody, informujce o dziaaniu metody. Metoda digit zwraca liczb bdc wartoci cyfry reprezentowanej przez znak ch w ukadzie pozycyjnym o okrelonej podstawie (radix).

Nastpnie zadeklarowano przykadow tablic znaków zawierajc znaki napisu Euro 2012 — char znak[] = {'E', 'u', 'r', 'o', ' ', '2', '0', '1', '2'};.

Rozdzia 5. i Rozwizania zada

109

Dziaanie metody pokazano w dwóch przypadkach, obliczajc wartoci znaków w tablicy jako cyfr ukadów dziesitkowego (radix = 10) oraz szesnastkowego (radix = 16). W ptli for pobieramy kolejne znaki z tablicy, wywietlamy w konsoli ich posta znakow i warto jako cyfry w okrelonym ukadzie liczbowym. Sprawdzamy cyfry ukadu dziesitkowego: for(char z : znak) out.println("Znak: "+z+"

Cyfra: "+Character.digit(z, 10));

Wynik -1 oznacza, e znak nie jest cyfr w tym ukadzie liczbowym. Warto znaku jako cyfry w ukadzie dziesitkowym (radix = 10) Znak: E Cyfra: -1 Znak: u Cyfra: -1 Znak: r Cyfra: -1 Znak: o Cyfra: -1 Znak: Cyfra: -1 Znak: 2 Cyfra: 2 Znak: 0 Cyfra: 0 Znak: 1 Cyfra: 1 Znak: 2 Cyfra: 2

Podobnie sprawdzimy cyfry w ukadzie szesnastkowym: for(char z : znak) out.println("Znak: "+z+"

Cyfra: "+Character.digit(z, 16));

Po wykonaniu kodu zauwaymy, e litera E jest cyfr w ukadzie szesnastkowym (warto dziesitna 14). Warto znaku jako cyfry w ukadzie szesnastkowym (radix = 16) Znak: E Cyfra: 14 Znak: u Cyfra: -1 Znak: r Cyfra: -1 Znak: o Cyfra: -1 Znak: Cyfra: -1 Znak: 2 Cyfra: 2 Znak: 0 Cyfra: 0 Znak: 1 Cyfra: 1 Znak: 2 Cyfra: 2

Zadanie 3.7. Cyfry.java, Z03_7.java Zgodnie z podan wskazówk odrzucamy najprostsze rozwizanie: char[] cyfry = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};. Wykorzystamy fakt, e kody cyfr dziesitnych (0123456789) s liczbami z zakresu od 48 do 57. Aby zamieni kod znaku (liczb cakowit) na odpowiadajcy mu znak, posuymy si rzutowaniem typów, np.: (char) 48 — liczb cakowit 48 rzutujemy na typ char i otrzymujemy znak '0'. public class Cyfry { public static void main(String args[]) { char[] cyfry = new char[10];

110

Programowanie w jzyku Java for(int i = 0; i < 10; ++i) cyfry[i] = (char)(i+48); System.out.print("Cyfry ukadu dziesitkowego: "); System.out.println(cyfry); } }

Ptl wypeniajc tablic moemy równie zapisa w postaci: for(int i = 48; i < 58; ++i) cyfry[i] = (char)i;

Zadanie 3.8. Cyfry16.java, Z03_8.java Zadanie to moemy rozwiza podobnie jak zadanie 3.7. Do zapisania liczby w ukadzie szesnastkowym potrzebujemy szesnastu cyfr — dziesi z nich to cyfry znane z ukadu dziesitkowego (0123456789 — znaki o kodach od 48 do 57), jako sze pozostaych cyfr wykorzystamy litery ABCDEF (znaki o kodach od 65 do 70). public class Cyfry16 { public static void main(String args[]) { char[] cyfry = new char[16]; for(int i = 0; i < 10; ++i) cyfry[i] = (char)(i+48); for(int i = 10; i < 16; ++i) cyfry[i] = (char)(i+55); System.out.print("Cyfry ukadu szesnastkowego: "); System.out.println(cyfry); } }

Do rozwizania zadania moemy wykorzysta statyczn metod forDigit (z dwoma parametrami int digit i int radix) z klasy Character, zamieniajc warto liczbow (parametr digit) na odpowiadajc jej cyfr (znak) w ukadzie liczbowym o podstawie radix. public class Cyfry16 { public static void main(String args[]) { char[] cyfry = new char[16]; for(int i = 0; i < 16; ++i) cyfry[i] = Character.forDigit(i, 16); System.out.print("Cyfry ukadu szesnastkowego: "); System.out.println(cyfry); } }

Metoda forDigit zwróci cyfry o wartoci wikszej od 9 jako mae litery (abcdef). Moemy przyj takie rozwizanie lub dodatkowo zamieni te znaki na wielkie litery (stosujc metod poznan w rozwizaniu zadania 3.2): for(int i = 0; i < 16; ++i) cyfry[i] = Character.toUpperCase(Character.forDigit(i, 16));

Rozdzia 5. i Rozwizania zada

111

4. Klasa String — operacje na tekstach Zadanie 4.1. TestString.java, Z04_1.java "Zadania z programowania." — acuch znaków stanowicy punkt wyjcia do dalszych

przeksztace. "Zadania z programowania.".charAt(0) — wyodrbnienie znaku o indeksie 0 (pierw-

szy znak acucha). "Zadania z programowania.".length() — dugo acucha (liczba znaków, w tym przypadku 24). "Zadania z programowania.".charAt(23) — wyodrbnienie znaku o indeksie 23 (ostat-

ni znak acucha). "Zadania z programowania.".toUpperCase() — zamiana liter w acuchu na wielkie litery (oczywicie zwracana jest kopia acucha, na której dokonano zmian, orygina pozostaje nienaruszony). "Zadania z programowania.".toLowerCase() — zamiana liter w acuchu na mae li-

tery (jw.). "Zadania z programowania.".indexOf('z') — indeks pozycji pierwszego wystpienia znaku z. Jeli podany znak nie wystpuje w acuchu, to zwracana jest warto –1. "Zadania z programowania.".indexOf("prog") — indeks pozycji pierwszego wystpienia cigu "prog". Jeli podany cig nie wystpuje w acuchu, to zwracana jest warto –1. "Zadania z programowania.".replace('.', '?') — zwraca nowy cig, w którym wszystkie znaki kropki (.) zostan zastpione znakiem pytajnika (?). "Zadania z programowania.".replace("adania", "dania") — zastpienie wszystkich wystpie cigu "adania" cigiem "dania". "Zadania z programowania.".replaceAll("ania", "anka") — zastpienie wszystkich wystpie cigu "ania" cigiem "anka". "Zadania z programowania.".replaceFirst("ania", "anka") — zastpienie pierwszego wystpienia cigu "ania" cigiem "anka". "Zadania z programowania.".substring(10) — wyodrbnienie cigu od znaku o in-

deksie 10 do koca acucha wyjciowego. "Zadania z programowania.".substring(10, 17) — wyodrbnienie cigu od znaku o indeksie 10 do znaku stojcego przed znakiem o indeksie 17. Dugo wyodrbnio-

nego acucha: 17–10 = 7 znaków.

112

Programowanie w jzyku Java "Zadania z programowania.".concat("\b z podpowiedziami.") — doczenie na kocu acucha "Zadania z programowania." cigu znaków "\b z podpowiedziami.". Pierwszy znak w doczanym cigu jest znakiem specjalnym \b (backspace) i spowo-

duje skasowanie ostatniego znaku (kropki) w acuchu wyjciowym. "Zadania z programowania."+"\b"+" z odpowiedziami." — zczenie trzech acuchów znaków w jeden acuch (operator +).

Zadanie 4.2. DemoString.java, Z04_2.java Tworzymy zmienn obiektow napis klasy String i inicjujemy j wartoci "Zadania z programowania.". String napis = "Zadania z programowania.";

W tej sytuacji przykad z listingu 4.1 wyglda tak: public class DemoString { public static void main(String args[]) { String napis = "Zadania z programowania."; System.out.println(napis); System.out.println(napis.charAt(0)); System.out.println(napis.length()); System.out.println(napis.charAt(napis.length()-1)); System.out.println(napis.toUpperCase()); System.out.println(napis.toLowerCase()); System.out.println(napis.indexOf('z')); System.out.println(napis.indexOf("prog")); char kropka = '.', pytajnik = '?'; System.out.println(napis.replace(kropka, pytajnik)); System.out.println(napis.replace("adania", "dania")); String str1 = "ania", str2 = "anka"; System.out.println(napis.replaceAll(str1, str2)); System.out.println(napis.replaceFirst(str1, str2)); System.out.println(napis.substring(10)); System.out.println(napis.substring(10, 17)); str1 = "\b z podpowiedziami."; System.out.println(napis.concat(str1)); System.out.println(napis+str1.substring(0, 4)+str1.substring(5)); } }

Dziaanie zastosowanych metod omówiono w rozwizaniu zadania 4.1.

Zadanie 4.3. WitajStr.java, Z04_3.java Tworzymy obiekt witaj klasy String zainicjowany wartoci "Dzie dobry". Metoda length zwraca rozmiar (dugo) acucha znaków. Znaki acucha s indeksowane (podobnie jak tablice) indeksami o wartociach od 0 do wartoci o 1 mniejszej od dugoci acucha. Znaki acucha o podanym indeksie udostpnia nam metoda charAt. W ptli for(int i = 0; i < witaj.length(); ++i)... uzyskamy dostp (po kolei) do wszystkich znaków acucha witaj.charAt(i). Znaki moemy w ten sposób wycznie odczytywa. Tak wanie rozwiemy czci a) i b) naszego zadania.

Rozdzia 5. i Rozwizania zada

113

public class WitajStr { public static void main(String args[]) { String witaj = "Dzie dobry"; /* Zadanie 4.3a */ System.out.println("Pionowo: "); for(int i = 0; i < witaj.length(); ++i) System.out.println(witaj.charAt(i)); System.out.println(); /* Zadanie 4.3b */ System.out.print("Tekst rozstrzelony: "); for(int i = 0; i < witaj.length(); ++i) System.out.print(witaj.charAt(i)+" "); System.out.println(); /* Zadanie 4.3c */ System.out.print("Wielkie litery: "+witaj.toUpperCase()); System.out.println(); /* Zadanie 4.3d */ System.out.print("Mae litery: "+witaj.toLowerCase()); System.out.println(); } }

W przypadku acucha znaków nie musimy zamienia odrbnie kadego znaku (mae litery na wielkie lub odwrotnie, wielkie na mae). Do rozwizania czci zadania zawartych w podpunktach c) i d) moemy wykorzysta metody toUpperCase lub toLowerCase zwracajce acuch (obiekt) zapisany odpowiednio wielkimi lub maymi literami. Jeli zamienimy acuch na tablic znaków, to moemy skorzysta z ptli typu for each (podajemy fragment kodu) i rozwiza zadanie w sposób znany z rozwizania zadania 3.2: /* Zadanie 4.3a */ System.out.println("Pionowo: "); for(char z : witaj.toCharArray()) System.out.println(z); System.out.println(); /* Zadanie 4.3b */ System.out.print("Tekst rozstrzelony: "); for(char z : witaj.toCharArray()) System.out.print(z+" "); System.out.println();

Zadanie 4.4. ProgramowanieStr.java, Z04_4.java, Z04_4a.java Obiekt klasy String nie jest modyfikowalny, czyli nie jest moliwe zmienianie w nim znaków, dodawanie do niego nowych znaków lub usuwanie z niego znaków istniejcych. Moemy natomiast zbudowa na jego podstawie nowy acuch speniajcy warunki zadania i przypisa go do tej samej referencji (zmiennej nazwa). Zbdny acuch zostanie usunity z pamici przez mechanizm garbage collection (ang. — czyszczenie pamici, usuwanie niepotrzebnych obiektów). Tworzymy acuch znaków String napis = "programowanie"; zawierajcy sowo programowanie zapisane maymi literami.

114

Programowanie w jzyku Java a) Z acucha napis pobieramy pierwszy znak napis.charAt(0), czyli znak p, i zamieniamy go na wielk liter Character.toUpperCase(napis.charAt(0)), otrzymujc znak P. Do tego znaku dodajemy podacuch acucha napis, od znaku o indeksie 1 do koca acucha napis.substring(1), czyli sowo rogramowanie. Operator konkatenacji (+) zamieni znak 'P' na acuch jednoelementowy "P" i poczy z acuchem "rogramowanie" w acuch "Programowanie": napis = Character.toUpperCase(napis.charAt(0))+napis.substring(1);

Mona to samo uzyska nieco inaczej: napis = (""+napis.charAt(0)).toUpperCase()+napis.substring(1);

W wyniku dodawania ""+napis.charAt(0) (pusty acuch "" czymy z pojedynczym znakiem 'p') otrzymujemy jednoelementowy acuch "p", który metoda toUpperCase zamienia na acuch "P". Nastpnie mamy znan ju operacj "P"+"rogramowanie", oczywicie zapisan w inny sposób. I jeszcze raz to samo, ale w innym zapisie (komentarz naley do Czytelnika): napis = napis.substring(0, 1).toUpperCase()+napis.substring(1);

b) Zamieniajc wszystkie litery na wielkie, wystarczy uy metody toUpperCase dla obiektu napis — napis = napis.toUpperCase();. public class ProgramowanieStr { public static void main(String args[]) { String napis = "programowanie"; System.out.print("a cuch znaków: "); System.out.println(napis); /* Zmiana pierwszej litery na wielk */ napis = Character.toUpperCase(napis.charAt(0))+ napis.substring(1); System.out.print("Pierwsza litera wielka: "); System.out.println(napis); /* Zmiana wszystkich liter na wielkie */ napis = napis.toUpperCase(); System.out.print("Wszystkie litery wielkie: "); System.out.println(napis); } }

Powracajc do podpunktu a) zadania, moemy zaproponowa takie rozwizanie: String napis = "programowanie"; char[] znaki = napis.toCharArray(); znaki[0] = Character.toUpperCase(znaki[0]); napis = String.valueOf(znaki);

Analiz kodu zostawiamy Czytelnikowi.

Zadanie 4.5. WspakStr1.java, Z04_5.java Podobnie jak w rozwizaniu zadania 3.4, wykorzystamy ptl for ze zmniejszaniem wartoci zmiennej sterujcej.

Rozdzia 5. i Rozwizania zada

115

public class WspakStr1 { public static void main(String args[]) { String napis = "programowanie"; System.out.print("Normalna kolejno znaków: "); System.out.println(napis); System.out.print("Odwrotna kolejno znaków: "); for(int i = napis.length()-1; i >= 0 ; --i) System.out.print(napis.charAt(i)); System.out.println(); } }

Porównajmy fragment powyszego kodu z fragmentem rozwizania zadania 3.4: for(int i = dane.length-1; i >= 0; --i) System.out.print(dane[i]);

Obiekt napis klasy String ma metod length() zwracajc liczb znaków w acuchu, natomiast obiekt dane typu tablicowego (char[]) ma pole length zawierajce liczb elementów tablicy (w tym przypadku liczb znaków). Ponadto inny jest sposób odczytywania znaków o podanym indeksie.

Zadanie 4.6. WspakStr2.java, Z04_6.java Zadanie to moemy rozwiza w trzech krokach: zamieni acuch znaków na tablic znaków, odwróci kolejno znaków w tablicy (zob. zadanie 3.5), zbudowa acuch znaków na podstawie odwróconej tablicy. public class WspakStr2 { public static void main(String args[]) { String napis = "programowanie"; System.out.print("Normalna kolejno znaków: "); System.out.println(napis); /* Zamiana acucha na tablic znaków */ char[] dane = napis.toCharArray(); /* Odwracanie tablicy znaków. */ for(int i = 0, j = dane.length-1; i < j ; i++, j--) { char tmp = dane[i]; dane[i] = dane[j]; dane[j] = tmp; } /* Zamiana tablicy znaków na acuch */ napis = new String(dane); System.out.print("Odwrotna kolejno znaków: "); System.out.println(napis); } }

Do utworzenia acucha znaków na podstawie odwróconej tablicy wykorzystalimy konstruktor (napis = new String(dane)). Moemy zastosowa metod statyczn valueOf z klasy String (napis = String.valueOf(dane)).

116

Programowanie w jzyku Java

Zadanie 4.7. CyfryStr.java, Z04_7.java Odrzucilimy proste rozwizanie String cyfry = "0123456789";. Moemy zbudowa tablic znaków zawierajc cyfry (zob. rozwizanie zadania 3.7) i nastpnie zbudowa na tej podstawie acuch znaków: String cyfry = new String(tablica). Poniewa zadanie ma bardziej charakter poznawczy ni praktyczny, proponujemy modyfikacj rozwizania zadania 3.7 w nastpujcy sposób: public class CyfryStr { public static void main(String args[]) { String cyfry = ""; for(int i = 0; i < 10; ++i) cyfry += (char)(i+48); System.out.print("Cyfry ukadu dziesitkowego: "); System.out.println(cyfry); } }

Zwrómy uwag na operator += (podstawianie z dodawaniem — w tym przypadku dotyczce dodawania acuchów znaków), który skraca zapis wyraenia. Zamiast cyfry = cyfry+(char)(i+48) piszemy krócej: cyfry += (char)(i+48). Naley doda, e w tym przykadzie do acucha znaków dodajemy jeden znak (konwersja znaku na acuch nastpuje automatycznie w czasie wykonywania tej operacji). Zastosowane tutaj dodawanie acuchów jest przemienne, wic poprawny bdzie zapis wyraenia w postaci cyfry = (char)(i+48)+cyfry (nie mamy moliwoci skrócenia wyraenia za pomoc operatora +=). Jaki bdzie efekt, Czytelnik moe sprawdzi sam. Takiego zastosowania klasy String nie naley poleca . Kade dodawanie pojedynczego znaku (lub innego acucha) powoduje tworzenie nowego acucha z wynikiem (na szczcie nie musimy si troszczy o ich usuwanie). Póniej poznasz klasy StringBuffer i StringBuilder lepiej nadajce si do rozwizywania podobnych zada.

Zadanie 4.8. CyfryStr16.java, Z04_8.java Do zbudowania acucha cyfr szesnastkowych wykorzystamy statyczn metod forDigit z klasy Character. public class CyfryStr16 { public static void main(String args[]) { String cyfry = ""; for(int i = 0; i < 16; ++i) cyfry += Character.forDigit(i, 16); System.out.print("Cyfry ukadu szesnastkowego: "); cyfry = cyfry.toUpperCase(); System.out.println(cyfry); } }

Uwaga zamieszczona w rozwizaniu zadania 4.7 pozostaje aktualna. Zamian maych liter na wielkie moemy wykona równie podczas tworzenia acucha cyfry (w ptli): cyfry += Character.toUpperCase(Character.forDigit(i, 16));

Rozdzia 5. i Rozwizania zada

117

Moemy równie skopiowa kod rozwizania zadania 3.8 i uzupeni go o jedn linijk kodu String cyfryHex = String.valueOf(cyfry); lub String cyfryHex = new String(cyfry);.

5. Tablica argumentów aplikacji Zadanie 5.1. Argumenty.java, Z05_1.java Po uruchomieniu aplikacji poleceniem java Argumenty parametr1 parametr2 ... parametrN system operacyjny przekazuje podane argumenty do aplikacji w postaci tablicy. Deklaracj tej tablicy obowizkowo umieszczamy w nagówku metody main. Do przegldania tablicy argumentów moemy zastosowa ptl typu for each. public class Argumenty { public static void main(String args[]) { System.out.println("Liczba argumentów "+args.length); /* Lista argumentów - ptla typu for each */ for(String argument: args) System.out.println(argument); } }

W Javie kada tablica jest obiektem, którego waciwo length zawiera liczb elementów tablicy. Zatem pole args.length zawiera liczb przekazanych argumentów. Argumenty w programie s dostpne przy uyciu indeksów od 0 do args.length–1: args[0], args[1],…, args[N–1], gdzie N oznacza liczb argumentów. Do przegldania listy argumentów moemy zastosowa ptl typu for. /* Lista argumentów - ptla typu for */ for(int i = 0; i < args.length; ++i) System.out.println(args[i]);

Zadanie 5.2. Osoba.java, Z05_2.java Uruchamiamy w konsoli program poleceniem java Osoba Maria Kowalska. System operacyjny przekae do tablicy argumentów dwa parametry (imi i nazwisko). W tablicy argumentów mamy zatem args[0] = "Maria" i args[1] = "Kowalska". Zakadajc (zgodnie z treci zadania), e uytkownik moe niedokadnie wprowadzi wielko liter, musimy dokona odpowiednich korekt danych przed ich wywietlaniem. Nazwisko: Kowalska — rozdzielamy args[1] na dwie czci: pierwszy znak i reszta

acucha; pierwszy znak zamienimy na wielk liter, a reszt acucha wywietlimy maymi literami: System.out.println(args[1].substring(0, 1).toUpperCase() +args[1].substring(1).toLowerCase());

Imi: Maria — rozdzielamy args[0] na dwie czci: pierwszy znak i reszta acucha; pierwszy znak zamienimy na wielk liter, a reszt acucha wywietlimy maymi literami:

118

Programowanie w jzyku Java System.out.println(Character.toUpperCase(args[0].charAt(0)) +args[0].substring(1).toLowerCase());

Nazwisko i imi: KOWALSKA Maria — nazwisko wywietlamy wielkimi literami (args[1]. toUpperCase()), imi tak jak w poprzednim punkcie. Inicjay: MK — wywietlamy pierwsze litery imienia i nazwiska: System.out.print(Character.toUpperCase(args[0].charAt(0))); System.out.println(Character.toUpperCase(args[1].charAt(0)));

Login: KOmar — login budujemy z dwóch pocztkowych liter nazwiska, zapisanych wielkimi literami (args[1].substring(0, 2).toUpperCase()) i trzech pocztkowych liter imienia zapisanych maymi literami (args[0].substring(0, 3).toLowerCase()). import static java.lang.System.out; public class Osoba { public static void main(String args[]) { out.print("Nazwisko: "); out.println(args[1].substring(0, 1).toUpperCase()+ args[1].substring(1).toLowerCase()); out.print("Imi: "); out.println(Character.toUpperCase(args[0].charAt(0))+ args[0].substring(1).toLowerCase()); out.print("Nazwisko i imi: "+args[1].toUpperCase()+" "); out.println(Character.toUpperCase(args[0].charAt(0))+ args[0].substring(1).toLowerCase()); out.print("Inicjay: "); out.print(Character.toUpperCase(args[0].charAt(0))); out.println(Character.toUpperCase(args[1].charAt(0))); out.print("Login: "); out.print(args[1].substring(0, 2).toUpperCase()); out.println(args[0].substring(0, 3).toLowerCase()); } }

Zwrómy uwag na skrócenie wierszy programu poprzez import statycznego obiektu out z klasy System i pomijanie nazwy klasy w operacjach wyjcia. W przykadzie pokazano równie dwa sposoby zamienienia pierwszego znaku acucha na wielk liter: str.toUpperCase().charAt(0) — utworzono acuch zapisany wielkimi literami i pobrano pierwszy znak, Character.toUpperCase(str.charAt(0)) — pobrano pierwszy znak acucha str i zamieniono na wielk liter. W podanym rozwizaniu nie zastosowano adnych dodatkowych zmiennych acuchowych. Uycie pomocniczych zmiennych mogoby zmniejszy liczb wykonywanych operacji na acuchach znaków. Pozostawimy to wiczenie do wykonania Czytelnikowi.

Zadanie 5.3. ArgsWspak.java, Z05_3.java Wywietlanie tablicy argumentów w odwrotnej kolejnoci moemy zrealizowa w ptli for z odliczaniem w dó, od ostatniego do pierwszego elementu.

Rozdzia 5. i Rozwizania zada

119

public class ArgsWspak { public static void main(String args[]) { for(int i = args.length-1; i >= 0; --i) System.out.print(args[i]+" "); System.out.println("\b"); } }

Do kadego argumentu dodawany jest znak odstpu. Za ostatnim argumentem ten znak jest niepotrzebny (zreszt jest te niewidoczny, ale czasem mógby przeszkadza), wic kasujemy ten odstp przy uyciu specjalnego znaku '\b' (ang. backspace).

Zadanie 5.4. ArgWspak.java, Z05_4.java W ptli zewntrznej przegldamy zawarto tablicy argumentów, a w ptli wewntrznej wywietlamy argument w odwrotnej kolejnoci (wspak). public class ArgWspak { public static void main(String args[]) { /* Przegldanie tablicy argumentów - ptla zewntrzna. */ for(String argument : args) { /* Wywietlanie argumentu wspak */ for(int i = argument.length()-1; i >= 0; --i) System.out.print(argument.charAt(i)); /* Przejcie do nowego wiersza */ System.out.println(); } } }

Zadanie 5.5. EtykietaArg.java, Z05_5.java Podczas wywoania programu podajemy imi i nazwisko jako argumenty. Do trzeciego wiersza etykiety (String wiersz = "* *";) musimy wstawi imi i nazwisko (String tekst = args[0]+" "+args[1];). Najpierw obliczamy rónic dugoci tych napisów int znaki = wiersz.length()-tekst.length();. Z acucha wiersz bierzemy pocztek, poow wyliczonej liczby znaków (wiersz. substring(0, znaki/2)). Do tego dodajemy imi i nazwisko (tekst) i na koniec dopisujemy reszt znaków, z koca acucha wiersz (wiersz.substring(wiersz.length() -znaki+znaki/2)). public class EtykietaArg { public static void main(String args[]) { /* Wypiszemy pierwszy i drugi wiersz etykiety. */ System.out.println("******* Programowanie *******"); System.out.println("* obiektowe w jzyku Java *"); /* Budujemy trzeci wiersz etykiety. Do tego wiersza musimy wstawi imi i nazwisko. */ String wiersz = "* *"; String tekst = args[0]+" "+args[1]; /* Obliczymy, ile znaków z oryginalnego wiersza naley pozostawi . */ int znaki = wiersz.length()-tekst.length();

120

Programowanie w jzyku Java /* Poow pozostawionych znaków (pocztek wiersza) wstawimy przed tekstem. */ String tmp = wiersz.substring(0, znaki/2)+tekst; /* Reszt znaków (koniec wiersza) dopiszemy po tekcie. */ tmp += wiersz.substring(wiersz.length()-znaki+znaki/2); /* Wypisujemy trzeci wiersz. */ System.out.println(tmp); /* Pozosta do wypisania ostatni wiersz etykiety. */ System.out.println("*****************************"); } }

Wystpujce w obliczeniach dzielenie jest dzieleniem cakowitym, co oznacza, e nie zawsze wyraenie znaki–znaki/2 ma tak sam warto jak wyraenie znaki/2. Nieparzysta liczba znaków nie moe by rozdzielona równomiernie przed tekstem i za tekstem. W takim przypadku na koniec zostawiamy o jeden znak wicej.

6. Prawda czy fasz — logiczny typ danych Zadanie 6.1. OperatoryLogiczne.java, Z06_1.java Tworzymy tablic bool zawierajc dwa elementy false i true typu boolean. W ptli for(boolean p: bool) {...} zmienna logiczna p bdzie przyjmowaa kolejno wartoci false i true. Dziki temu bdziemy mogli utworzy tabelk negacji i testowa prawa logiczne z jednym zdaniem p. Zagniedajc ptle for(boolean p: bool) for(boolean q: bool) {...}, otrzymamy par zmiennych logicznych p i q, przyjmujcych kolejno wartoci: (false, false), (false, true), (true, false) i (true, true). Pozwoli nam to na utworzenie tabelek koniunkcji, alternatywy i innych funktorów logicznych dwuargumentowych oraz testowanie praw logicznych z dwoma zdaniami logicznymi p i q. Powysze uwagi zostan wykorzystane w rozwizaniach zada 6.1, 6.2, 6.3, 6.4, 6.5 i 6.6 oraz innych podobnych. Do sformatowania (w kolumnach) wyników operacji logicznych uyjemy znaku tabulatora '\t' wewntrz acuchów tworzcych nagówki tabelek (aby uproci kod, nie rysujemy linii, pozostawiajc to Czytelnikowi) i acucha "\t" zawierajcego znak tabulatora, czonego z wartociami wywietlanych zmiennych, np. p+"\t"+!p. W zadaniu wykorzystujemy operator negacji (!), alternatywy (|) i koniunkcji (&). public class OperatoryLogiczne { public static void main(String args[]) { boolean[] bool = {false, true}; System.out.println("Operator negacji (NOT) - !");

Rozdzia 5. i Rozwizania zada

121

System.out.println(" p\t !p"); for(boolean p: bool) System.out.println(p+"\t"+!p); System.out.println(); System.out.println("Operator koniunkcji (AND) - & lub &&"); System.out.println(" p\t q\tp & q"); for(boolean p: bool) for(boolean q: bool) System.out.println(p+"\t"+q+"\t"+(p & q)); System.out.println(); System.out.println("Operator alternatywy (OR) - | lub ||"); System.out.println(" p\t q\tp | q"); for(boolean p: bool) for(boolean q: bool) System.out.println(p+"\t"+q+"\t"+(p | q)); System.out.println(); } }

Operatory & i | s wykorzystywane równie do przeprowadzania operacji bitowych na binarnej reprezentacji danych. Poniewa true odpowiada liczbie 1, a false liczbie 0 (w reprezentacji wewntrznej), to obliczenia wykonane na wartociach logicznych daj waciwy wynik. Operatory && i || su wycznie do dziaa na wartociach logicznych. S nazywane szybkimi. Od operatorów & i | róni si sposobem wyliczania wartoci. Aby alternatywa dwóch wyrae bya prawdziwa, wystarczy, e jeden z operandów alternatywy jest prawdziwy. Jeli pierwszy operand alternatywy ma warto true, to wiadomo, e alternatywa jest prawdziwa (wartoci drugiego operandu nie musimy oblicza ). W przypadku koniunkcji — jeli pierwszy operand ma warto false, to cae wyraenie ma warto false.

Zadanie 6.2. PrawaLogiczne.java, Z06_2.java Badane prawa s zdaniami logicznymi zbudowanymi ze zdania p i poznanych w zadaniu 6.1 operatorów logicznych. Wartoci zdania p pobieramy z tablicy bool i budujemy odpowiednie wyraenia logiczne: p || !p — prawo wyczonego rodka, !(p && !p) — prawo niesprzecznoci, !(!p) == p) — prawo podwójnego przeczenia. W ostatnim przypadku jako operator równowanoci wykorzystano operator porównania ==, który zwraca warto true dla pary zda równowanych (false == false, true == true) i warto false dla zda nierównowanych (false == true, true == false). public class PrawaLogiczne { public static void main(String args[]) { boolean[] bool = {false, true}; System.out.println("Prawo wyczonego rodka - p || !p"); System.out.println(" p\t !p\tp || !p"); for(boolean p: bool) System.out.println(p+"\t"+!p+"\t"+(p || !p)); System.out.println();

122

Programowanie w jzyku Java System.out.println("Prawo niesprzecznoci - !(p && !p)"); System.out.println(" p\t !p\tp && !p\t!(p && !p)"); for(boolean p: bool) System.out.println(p+"\t"+!p+"\t"+(p && !p)+"\t"+!(p && !p)); System.out.println(); System.out.println("Prawo podwójnego przeczenia - !(!p) == p)"); System.out.println(" p\t !p\t!(!p)\t!(!p) == p)"); for(boolean p: bool) System.out.println(p+"\t"+!p+"\t"+!(!p)+"\t"+(!(!p) == p)); System.out.println(); } }

Zadanie 6.3. PrawaDeMorgana.java, Z06_3.java Stosujc tablic bool i zagniedone ptle (zob. komentarz w rozwizaniu zadania 6.1), moemy zbada prawa De Morgana. W dwóch pocztkowych kolumnach umieszczamy wszystkie moliwe wartoci dla dwóch zda logicznych ( p i q). W kolejnych umieszczamy wartoci porednich wyników, a w ostatniej kolumnie warto caego zdania (kompletne wyraenie). Uzyskane w ostatniej kolumnie wartoci true wiadcz, e to wyraenie jest prawem logicznym. public class PrawaDeMorgana { public static void main(String args[]) { boolean[] bool = {false, true}; System.out.println("Zaprzeczenie koniunkcji jest równowane alternatywie zaprzecze "); System.out.println("p\tq\tp&&q\t!(p&&q)\t!p\t!q\t!p||!q\t!(p&&q) (!p||!q)"); for(boolean p: bool) for(boolean q: bool) { System.out.print(p+"\t"+q+"\t"+(p&&q)+"\t"+!(p&&q)); System.out.print("\t"+!p+"\t"+!q+"\t"+(!p||!q)); System.out.println("\t"+(!(p&&q)==(!p||!q))); } System.out.println("\n"); System.out.println("Zaprzeczenie alternatywy jest równowane koniunkcji zaprzecze "); System.out.println("p\tq\tp||q\t!(p||q)\t!p\t!q\t!p&&!q\t!(p||q) (!p&&!q)"); for(boolean p: bool) for(boolean q: bool) { System.out.print(p+"\t"+q+"\t"+(p||q)+"\t"+!(p||q)); System.out.print("\t"+!p+"\t"+!q+"\t"+(!p&&!q)); System.out.println("\t"+(!(p||q)==(!p&&!q))); } System.out.println("\n"); } }

Zadanie 6.4. Implikacja.java, Z06_4.java, Z06_4a.java Wykorzystujc rozwizanie zadania 6.2, uwagi z rozwizania zadania 6.1 oraz podan wskazówk, utworzymy nastpujc aplikacj:

Rozdzia 5. i Rozwizania zada

123

public class Implikacja { public static void main(String args[]) { boolean[] bool = {false, true}; System.out.println("Implikacja - jeeli p, to q"); System.out.println("p\tq\tp=>q"); for(boolean p: bool) for(boolean q: bool) System.out.println(p+"\t"+q+"\t"+ (Boolean.valueOf(p).compareTo(q) < 1)); System.out.println(); } }

Moemy zdefiniowa wasn metod statyczn realizujc zadania operatora implikacji (proponujemy nazw impl). Wicej szczegóów o definiowaniu metod poznasz dalej. static boolean impl(boolean p, boolean q) { return (Boolean.valueOf(p).compareTo(q) < 1)); }

Po takiej zmianie otrzymamy nastpujcy kod: public class Implikacja { static boolean impl(boolean p, boolean q) { return (Boolean.valueOf(p).compareTo(q) < 1); } public static void main(String args[]) { boolean[] bool = {false, true}; System.out.println("Implikacja - jeeli p, to q"); System.out.println("p\tq\tp=>q"); for(boolean p: bool) for(boolean q: bool) System.out.println(p+"\t"+q+"\t"+ impl(p, q)); System.out.println(); } }

Zadanie 6.5. Xor.java, Z06_5.java Alternatywa wykluczajca (p albo q) realizowana jest przez operator XOR (^) — alternatywa wykluczajca (ang. exclusive or). Moemy równie skorzysta z operatora nie jest równe (!=), poniewa alternatywa wykluczajca jest prawdziwa, gdy jedno ze zda jest prawdziwe, a drugie faszywe, czyli gdy ich wartoci logiczne nie s równe. W rozwizaniu zadania pokaemy i porównamy dziaanie operatora XOR (^) oraz operatora nie jest równe (!=) dla wartoci logicznych. public class Xor { public static void main(String args[]) { boolean[] bool = {false, true}; System.out.println("Operator alternatywy wykluczajcej (XOR) - ^"); System.out.println(" p\t q\tp ^ q"); for(boolean p: bool)

124

Programowanie w jzyku Java for(boolean q: bool) System.out.println(p+"\t"+q+"\t"+(p ^ q)); System.out.println(); System.out.println("Operator nie jest równe - !="); System.out.println(" p\t q\tp != q"); for(boolean p: bool) for(boolean q: bool) System.out.println(p+"\t"+q+"\t"+(p != q)); System.out.println(); } }

Zadanie 6.6. Z06_6a.java, Z06_6b.java, Z06_6b.java, Z06_6d.java, Z06_6e.java W prawach dowodzonych w podpunktach a), b) i c) mamy prawa logiczne z trzema zdaniami logicznymi p, q i r. Uyjemy trzech zagniedonych ptli for i tablicy bool do wygenerowania wszystkich moliwych trójek wartoci logicznych dla zda logicznych p, q i r. Prawa dowodzone w podpunktach d) i e) zawieraj tylko dwa zdania logiczne p i q. W zadaniach a), d) i e) wystpuje implikacja. Skorzystamy z metody impl wprowadzonej w rozwizaniu zadania 6.4. W tabelach wprowadzono dodatkowe oznaczenia A, B, C i D, skracajce opis nagówka tabeli. a) Prawo przechodnioci implikacji

> p Ÿ q š q Ÿ r @ Ÿ p Ÿ r .

public class PrawoLogiczneA { static boolean impl(boolean p, boolean q) { return (Boolean.valueOf(p).compareTo(q) < 1); } public static void main(String args[]) { boolean[] bool = {false, true}; System.out.println("Prawo przechodnioci implikacji"); System.out.println("p\tq\tr\tp=>q\tq=>r\tA & B\tp=>r\tC=>D"); System.out.println("\t\t\t(A)\t(B)\t(C)\t(D)"); for(boolean p: bool) for(boolean q: bool) for(boolean r: bool) { System.out.print(p+"\t"+q+"\t"+r); System.out.print("\t"+impl(p, q)+"\t"+impl(q,r)); System.out.print("\t"+(impl(p, q)&impl(q, r))); System.out.print("\t"+impl(p,r)+"\t"); System.out.println(impl(impl(p, q)&impl(q, r), impl(p,r))); } System.out.println(); } }

b) Prawo rozdzielnoci alternatywy wzgldem koniunkcji > p › q š r @ œ > p › q š p › r @ . W celu uproszczenia zapisu wprowadzono dodatkowe zmienne a, b, c, d i e typu boolean. public class PrawoLogiczneB { public static void main(String args[]) {

Rozdzia 5. i Rozwizania zada boolean[] bool = {false, true}; System.out.println("Prawo rozdzielnoci alternatywy wzgldem koniunkcji\n"); System.out.println("p\tq\tr\tq&r\tp|A\tp|q\tp|r\tC&D\tBE "); System.out.println("\t\t\t(A)\t(B)\t(C)\t(D)\t(E)"); for(boolean p: bool) for(boolean q: bool) for(boolean r: bool) { System.out.print(p+"\t"+q+"\t"+r); boolean a = q&r; boolean b = p|a; boolean c = p|q; boolean d = p|r; boolean e = c&d; System.out.print("\t"+a+"\t"+b+"\t"+c+"\t"+d+"\t"+e+"\t"); System.out.println(b == e); } System.out.println(); } }

c) Prawo rozdzielnoci koniunkcji wzgldem alternatywy > p š q › r @ œ > p š q › p š r @ . Podobnie jak w podpunkcie b),

w celu uproszczenia zapisu wprowadzono dodatkowe zmienne a, b, c, d i e typu boolean. public class PrawoLogiczneC { public static void main(String args[]) { boolean[] bool = {false, true}; System.out.println("Prawo rozdzielnoci koniunkcji wzgldem alternatywy\n"); System.out.println("p\tq\tr\tq|r\tp&A\tp&q\tp&r\tC|D\tBE"); System.out.println("\t\t\t(A)\t(B)\t(C)\t(D)\t(E)"); for(boolean p: bool) for(boolean q: bool) for(boolean r: bool) { System.out.print(p+"\t"+q+"\t"+r); boolean a = q|r; boolean b = p&a; boolean c = p&q; boolean d = p&r; boolean e = c|d; System.out.print("\t"+a+"\t"+b+"\t"+c+"\t"+d+"\t"+e+"\t"); System.out.println(b == e); } System.out.println(); } }

d) Prawo odrywania

> p Ÿ q š q@ Ÿ q .

Zbudujemy dodatkow klas Impl zawierajc definicj metody impl zbudowanej w rozwizaniu zadania 6.4. W pliku Impl.java wpisujemy kod: public class Impl { static boolean impl(boolean p, boolean q) { return (Boolean.valueOf(p).compareTo(q) < 1); } }

125

126

Programowanie w jzyku Java

Po skompilowaniu otrzymamy plik Impl.class. Jeli ten plik umiecimy w biecym folderze, to metoda statyczna impl bdzie dostpna dla wszystkich klas znajdujcych si w tym samym folderze, czyli w tzw. pakiecie domylnym. Jest to w tym zbiorze zada pierwszy przykad klasy niezawierajcej metody main(), czyli niebdcej aplikacj. Metod bdziemy wywoywa z innych klas, np. Impl.impl(p, q). public class PrawoLogiczneD { public static void main(String args[]) { boolean[] bool = {false, true}; System.out.println("Prawo odrywania [(p => q) & q] => q\n"); System.out.println("p\tq\tp=>q\tA & q\tB=>q"); System.out.println("\t\t(A)\t(B)"); for(boolean p: bool) for(boolean q: bool) { boolean a = Impl.impl(p, q); boolean b = a & q; System.out.print(p+"\t"+q+"\t"+a+"\t"+b+"\t"); System.out.println(Impl.impl(b, q)); } System.out.println(); } }

e) Prawo eliminacji implikacji p Ÿ q œ ™p › q . Podobnie jak w punkcie d), skorzystamy z metody impl (zastpujcej operator implementacji) zdefiniowanej w klasie Impl. public class PrawoLogiczneE { public static void main(String args[]) { boolean[] bool = {false, true}; System.out.print("Prawo eliminacji implikacji "); System.out.println("(p => q) (!p|q)\n"); System.out.println("p\tq\tp=>q\t!p\t!p|q\tAB"); System.out.println("\t\t(A)\t\t(B)"); for(boolean p: bool) for(boolean q: bool) { boolean a = Impl.impl(p, q); boolean b = !p | q; System.out.print(p+"\t"+q+"\t"+a+"\t"+(!p)+"\t"+b+"\t"); System.out.println(a == b); } System.out.println(); } }

Zadanie 6.7. StringIsEmpty.java, Z06_7.java Metoda isEmpty zwraca warto true, gdy acuch nie zawiera ani jednego znaku (jest pusty), i warto false, gdy acuch zawiera co najmniej jeden znak. public class StringIsEmpty { public static void main(String[] args) { String str1 = ""; System.out.println("String: "+str1); System.out.println("Dugo a cucha: "+str1.length()); System.out.println("Czy string jest pusty? "+str1.isEmpty()); str1 = "Krótki tekst...";

Rozdzia 5. i Rozwizania zada

127

System.out.println("String: "+str1); System.out.println("Dugo a cucha: "+str1.length()); System.out.println("Czy string jest pusty? "+str1.isEmpty()); } }

Zadanie 6.8. TestChar.java, Z06_8.java a) Cig skada si z 7 znaków, s to: wielka litera A, tzw. spacja nierozdzielajca (kod dziesitny 160, ósemkowy \240), maa litera b, cyfra 3, znak &, cyfra 4

i odstp (spacja — kod dziesitny 32, biay znak). Program testujcy wywietla znaki wystpujce w acuchu, a nastpnie tworzy tabel z wynikami testów z uyciem metod isDigit(), isLetter(), isLetterOrDigit(), isLowerCase(), isSpaceChar(), isUpperCase() i isWhiteSpace(). W kadej kolumnie znajduj si znak, kod znaku i wyniki testu dla tego znaku. public class TestChar { public static void main(String[] args) { String str = "A\240b3&4\040"; // podpunkt a) System.out.println("Znaki: "+str); char[] znaki = str.toCharArray(); System.out.print("Znak "); for(char z : znaki) System.out.print("\t"+z); System.out.println(); System.out.print("Kod znaku "); for(char z : znaki) System.out.print("\t"+(int)z); System.out.println(); System.out.print("isDigit() "); for(char z : znaki) System.out.print("\t"+Character.isDigit(z)); System.out.println(); System.out.print("isLetter() "); for(char z : znaki) System.out.print("\t"+Character.isLetter(z)); System.out.println(); System.out.print("isLetterOrDigit()"); for(char z : znaki) System.out.print("\t"+Character.isLetterOrDigit(z)); System.out.println(); System.out.print("isLowerCase() "); for(char z : znaki) System.out.print("\t"+Character.isLowerCase(z)); System.out.println(); System.out.print("isSpaceChar() "); for(char z : znaki) System.out.print("\t"+Character.isSpaceChar(z)); System.out.println(); System.out.print("isUpperCase() "); for(char z : znaki) System.out.print("\t"+Character.isUpperCase(z)); System.out.println(); System.out.print("isWhitespace() ");

128

Programowanie w jzyku Java for(char z : znaki) System.out.print("\t"+Character.isWhitespace(z)); System.out.println(); } }

Po uruchomieniu programu uzyskamy wynik: Znaki: A b3&4 Znak Kod znaku isDigit() isLetter() isLetterOrDigit() isLowerCase() isSpaceChar() isUpperCase() isWhitespace()

A 65 false true true false false true false

160 false false false false true false false

b 98 false true true true false false false

3 51 true false true false false false false

& 38 false false false false false false false

4 52 true false true false false false false

32 false false false false true false true

b) Cig skada si z 7 znaków, s to: wielka litera , maa litera o, maa litera , znak podkrelenia _, cyfra 0, znak + i znak tabulatora (\t — kod dziesitny 9). W kodzie programu TestChar zmieniamy jeden wiersz: String str = "o_4 -\t";. Dla tego acucha otrzymamy: Znaki: o_0+ Znak Kod znaku isDigit() isLetter() isLetterOrDigit() isLowerCase() isSpaceChar() isUpperCase() isWhitespace()

 321 false true true false false true false

o 111 false true true true false false false

 347 false true true true false false false

_ 95 false false false false false false false

0 48 true false true false false false false

+ 43 false false false false false false false

Prezentowane znaki s znakami Unicode, co wyra nie wida w przypadku polskich znaków i  (kody wiksze od 255, dwubajtowe). c) Cig skada si z 7 znaków, s to: znak #, znak cudzysowu " (znak specjalny \"), wielka litera Ä (kod ósemkowy \304), znak \ (znak specjalny \\), maa litera ä (kod ósemkowy \344), znak backspace (znak specjalny \b, kod dziesitny 8) i znak newline (znak specjalny \n, kod dziesitny 10).

W kodzie programu podstawimy wiersz String str = "#\"\304\\\344\b\n"; i uzyskamy wynik: Znaki: #"Ä\ä Znak

#

"

Ä

\

ä

Kod znaku isDigit() isLetter() isLetterOrDigit() isLowerCase() isSpaceChar() isUpperCase() isWhitespace()

35 false false false false false false false

34 false false false false false false false

196 false true true false false true false

92 false false false false false false false

228 false true true true false false false

8 false false false false false false false

10 false false false false false false true

Rozdzia 5. i Rozwizania zada

129

7. Liczby cakowite typu int i klasa Integer Zadanie 7.1. StaticInteger.java, Z07_1.java Objanienia staych i wybranych metod statycznych klasy Integer opakowujcej typ prosty int zawarto w tekcie programu. public class StaticInteger { public static void main(String args[]) { System.out.println("Wybrane stae i metody statyczne klasy Integer\n"); System.out.println("Warto minimalna typu int: "+ Integer.MIN_VALUE); System.out.println("Warto maksymalna typu int: "+ Integer.MAX_VALUE); System.out.println("Rozmiar (w bitach) typu int: "+Integer.SIZE); int a = 179; System.out.println("Liczba cakowita a = "+a+ " - zapis (cig cyfr):"); System.out.println("w systemie binarnym: "+ Integer.toBinaryString(a)); System.out.println("w systemie ósemkowym: "+ Integer.toOctalString(a)); System.out.println("w systemie szesnastkowym: "+ Integer.toHexString(a)); System.out.println("w systemie dziesitkowym: "+ Integer.toString(a)); System.out.println("w systemie czwórkowym: "+ Integer.toString(a, 4)); int b = Integer.parseInt("-177"); System.out.println("b = "+b); int c = Integer.parseInt("-177", 8); System.out.println("c = "+c); System.out.println("Metoda signum():"); System.out.println("Znak liczby a: "+Integer.signum(a)); System.out.println("Znak liczby b: "+Integer.signum(b)); System.out.println("Znak liczby 0: "+Integer.signum(0)); } }

Zwrómy uwag na moliwo parsowania tego samego cigu znaków (np. "-177") w ukadach pozycyjnych o rónej podstawie. Skompilujmy i uruchommy ten program dla rónych wartoci zmiennej a. Porównajmy sposób zapisu liczby dodatniej i ujemnej (np. 179 i –179) w rónych systemach liczbowych.

Zadanie 7.2. ObjectInteger.java, Z07_2.java Objanienia metod zawarto w kodzie lub komentarzach do kodu. public class ObjectInteger { public static void main(String args[]) { System.out.println("Wybrane metody obiektów klasy Integer\n");

130

Programowanie w jzyku Java /* Konstruktor tworzcy nowy obiekt typu Integer reprezentujcy podan liczb, w tym przypadku 1024. */ Integer a = new Integer(1024); /* Konstruktor tworzcy nowy obiekt klasy Integer na podstawie podanego acucha znaków (cigu cyfr). Zero nieznaczce zostanie pominite. */ Integer b = new Integer("02000"); /* Statyczna metoda decode() zwraca obiekt reprezentujcy liczb zakodowan w acuchu znaków - 0 na pocztku oznacza liczb zapisan w systemie ósemkowym. */ Integer c = Integer.decode("02000"); /* Jw. - pocztek cigu w postaci 0x oznacza liczb zakodowan w systemie szesnastkowym. */ Integer d = Integer.decode("0x2000"); System.out.println("a = "+a); System.out.println("b = "+b); System.out.println("c = "+c); System.out.println("d = "+d); /* Metoda equals() sprawdza, czy obiekt wywoujcy t metod jest równy obiektowi podanemu jako parametr. Wynik porównania jest wartoci logiczn (true albo false). */ System.out.println("Czy obiekt a jest równy obiektowi b? "+ a.equals(b)); System.out.println("Czy obiekt a jest równy obiektowi c? "+ a.equals(c)); /* Metoda compareTo() porównuje obiekt wywoujcy t metod z obiektem stanowicym parametr. Wynik jest jedn z liczb: -1, 0 i 1. 0 oznacza równo obiektów, -1 oznacza, e pierwszy obiekt (wywoujcy metod) jest mniejszy od drugiego obiektu (parametru), a 1 oznacza, e pierwszy obiekt jest wikszy od drugiego). */ System.out.println("Porównanie obiektu a z obiektem c? "+ a.compareTo(c)); System.out.println("Porównanie obiektu c z obiektem d? "+ c.compareTo(d)); System.out.println("Porównanie obiektu d z obiektem c? "+ d.compareTo(c)); /* Metoda statyczna valueOf() zwraca obiekt klasy Integer reprezentujcy warto okrelon jako parametr - liczba cakowita lub acuch znaków (cyfr dziesitnych). */ a = Integer.valueOf(1000); b = Integer.valueOf("1000"); /* Drugi parametr metody statycznej valueOf okrela podstaw systemu liczbowego, w którym naley zinterpretowa cig cyfr podany jako pierwszy parametr metody. */ c = Integer.valueOf("1000", 2); // 1000 w ukadzie binarnym d = Integer.valueOf("1000", 16); // 1000 w ukadzie szesnastkowym System.out.println("a = "+a); System.out.println("b = "+b); System.out.println("c = "+c); System.out.println("d = "+d); /* Tu wstaw ponownie kod do porównywania obiektów. */ } }

Rozdzia 5. i Rozwizania zada

131

Metoda obj1.equals(obj2) zwraca warto false, gdy obiekty maj róne wartoci, i true w przypadku równych wartoci wszystkich pól obiektów obj1 i obj2 (o ile w implementacji metody equals() nie zdecydujemy inaczej). Uycie operatora porównania obj1 == obj2 zwróci nam wynik porównania referencji obiektów, a nie ich wartoci. Metoda obj1.compareTo(obj2) zwraca 0, gdy obiekty s równe; –1, gdy warto obj1 jest mniejsza od wartoci obj2, albo 1, gdy warto obj1 jest wiksza od wartoci obj2.

Zadanie 7.3. Dodawanie.java, Z03_3.java Na listingu przedstawiono trzy warianty rozwizania zadania (w jednym pliku), rónice si sposobem obliczenia i wywietlenia wyniku. W pierwszym przypadku najpierw jest wywietlany tekst "a + b = " przy uyciu metody print(), a potem obliczana jest warto wyraenia a+b. Wynik przekazany jest jako parametr wywoania metody println(). W drugim przypadku nastpuje poczenie (dodawanie) tekstu z wynikiem dodawania wartoci zmiennych. Poniewa dziaania dodawania wykonywane s od strony lewej do prawej, to do tekstu dodana jest warto zmiennej a (skonwertowanej na tekst), a nastpnie do wyniku (bdcego acuchem znaków) dodawana jest druga liczba b (zamieniona na tekst). W efekcie zamiast sumy dwóch liczb otrzymujemy sum acuchów cyfr reprezentujcych te liczby. Aby uzyska prawidowy rezultat, naley zmieni kolejno wykonywania dziaa (uy nawiasów). Najpierw bdzie obliczona suma wartoci zmiennych (a+b), a nastpnie wynik zostanie zamieniony na acuch znaków i doczony z prawej strony tekstu "a + b =". W trzecim przypadku uywamy dodatkowej zmiennej c do przechowania sumy a+b. Wywietlenie wyniku nie sprawia nam adnych niespodzianek. public class Dodawanie { public static void main(String args[]) { int a = 2451, b = 375; System.out.println("a = "+a+", b = "+b); /* wariant 1. */ System.out.print("a + b = "); System.out.println(a+b); /* wariant 2. */ System.out.println("a + b = "+a+b); // bd System.out.println("a + b = "+(a+b)); /* wariant 3. */ int c = a+b; System.out.println("a + b = "+c); } }

132

Programowanie w jzyku Java

Zadanie 7.4. Z07_4a.java, Z07_4b.java, Z07_4c.java, Z07_4d.java a) Odejmowanie.java — wzorujc si na rozwizaniu zadania 7.3, zbudujemy

program: public class Odejmowanie { public static void main(String args[]) { int a = 2451, b = 375; System.out.println("a = "+a+", b = "+b); /* Wariant 1. - osobne wywietlanie tekstu i liczby. */ System.out.print("a - b = "); System.out.println(a-b); /* Wariant 2. - bdny wynik. */ // System.out.println("a - b = "+a-b); // le System.out.println("a - b = "+(a-b)); // dobrze /* Wariant 3. - wprowadzamy dodatkow zmienn c. */ int c = a-b; System.out.println("a - b = "+c); } }

Zauwamy, e w rozwizaniu zadania 7.3 instrukcja System.out.println("a + b = "+a+b); dawaa bdny wynik (w stosunku do treci zadania), natomiast w przypadku odejmowania instrukcja o postaci System.out.println("a — b = "+a–b); si nie skompiluje. Nie ma odejmowania acuchów znaków! Poniewa operatory + i – maj ten sam priorytet, naley uy nawiasów w celu zmiany kolejnoci wykonywania dziaa System.out.println("a — b = "+(a-b));. b) Mnoenie.java — program ten budujemy w podobny sposób jak program

7.3 i 7.4a. public class Mnoenie { public static void main(String args[]) { int a = 2451, b = 375; System.out.println("a = "+a+", b = "+b); System.out.println("a * b = "+a*b); } }

Na powyszym listingu przedstawiono tylko jeden z moliwych wariantów rozwizania zadania (zob. rozwizania zada 7.3 i 7.4a). Uwaga przedstawiona w rozwizaniu zadania 7.4a nie jest ju aktualna — operator mnoenia * ma wyszy priorytet ni operator +, wic uycie nawiasu nie jest konieczne. Kod w tej postaci skompiluje si i obliczenia zostan wykonane poprawnie. c) Dzielenie.java — kod jest zupenie podobny do tego z rozwizania zadania 7.4b (operator * zastpiono operatorem /). public class Dzielenie { public static void main(String args[]) { int a = 2451, b = 375; System.out.println("a = "+a+", b = "+b); System.out.println("a / b = "+a/b); } }

Rozdzia 5. i Rozwizania zada

133

Operator dzielenia ma wyszy priorytet od operatora dodawania, wic uycie nawiasów nie jest konieczne (zob. uwagi do rozwiza zada 7.3, 7.4a i 7.4b). d) Reszta.java — wyraenie a%b oblicza reszt z dzielenia liczby cakowitej a przez liczb cakowit b. Operator % ma wyszy priorytet od operatora (+). public class Reszta { public static void main(String args[]) { int a = 2451, b = 375; System.out.println("a = "+a+", b = "+b); System.out.println("a % b = "+a%b); System.out.println("b % a = "+b%a); } }

Zadanie 7.5. Dzielenie2.java, Z07_5.java Dzielenie z reszt wykonujemy dla wybranej pary liczb. Zmieniamy znaki tych liczb tak, aby uzyska wszystkie moliwe pary znaków dzielnej i dzielnika. public class Dzielenie2 { public static void main(String args[]) { int a = 153, b = 15; System.out.println("a = "+a+", b = "+b); System.out.println("a : b = "+a/b+" r. "+a%b+"\n"); b = -15; System.out.println("a = "+a+", b = "+b); System.out.println("a : b = "+a/b+" r. "+a%b+"\n"); a = -153; System.out.println("a = "+a+", b = "+b); System.out.println("a : b = "+a/b+" r. "+a%b+"\n"); b = 15; System.out.println("a = "+a+", b = "+b); System.out.println("a : b = "+a/b+" r. "+a%b+"\n"); } }

Zauwamy, e reszta z dzielenia przyjmuje znak dzielnej, natomiast znak ilorazu zaley od znaków dzielnej i dzielnika (iloraz jest dodatni, gdy dzielna i dzielnik maj ten sam znak — ujemny, gdy operandy maj róne znaki).

Zadanie 7.6. Suma.java, Z07_6.java Z tablicy argumentów odczytujemy dwa argumenty: args[0] i args[1]. Zamieniamy acuchy znaków na liczby cakowite (stosujemy statyczn metod parseInt z klasy Integer) i obliczamy ich sum. public class Suma { public static void main(String args[]) { int suma = Integer.parseInt(args[0])+Integer.parseInt(args[1]); System.out.println("Suma S = "+suma); } }

134

Programowanie w jzyku Java

Aplikacj uruchamiamy z dwoma parametrami, np. java Suma 231 -347. Jeli podczas uruchomienia nie podamy dwóch argumentów lub argumenty nie bd poprawnie zapisanymi liczbami, to aplikacja przerwie prac i pojawi si odpowiedni komunikat.

Zadanie 7.7. Sumuj.java Aplikacj uruchamiamy z kilkoma parametrami, np. java Sumuj 127 -242 391. Deklarujemy i inicjujemy zmienn cakowit int suma = 0;. Odczytujemy kolejne argumenty z tablicy args w ptli for, zamieniamy je na liczby cakowite i dodajemy do zmiennej suma. public class Sumuj { public static void main(String args[]) { int suma = 0; for(String argument: args) suma += Integer.parseInt(argument); System.out.println("Suma S = "+suma); } }

W obliczeniach moemy równie posuy si metodami z klasy Integer: suma += Integer.valueOf(argument).intValue();

Najpierw tworzymy obiekt Integer.valueOf(argument), a nastpnie przy wykorzystaniu metody intValue() zwracamy warto jedynego pola obiektu (typ int). Taki sam efekt uzyskamy z uyciem metody decode(): suma += Integer.decode(argument).intValue();

W tym przypadku argumenty mona podawa równie w postaci szesnastkowej (np. 0xAF, 0XAF lub #1AF0) albo ósemkowej (0742). Moemy w wyraeniu sumujcym uy polecenia new i konstruktora: suma += new Integer(argument).intValue();

Gdy pominiemy metod intValue() w powyszych wariantach rozwizania, nie spowoduje to bdu (w Javie od wersji 5. wprowadzono autoboxing). Podczas kompilacji wyraenia obiekt klasy Integer jest automatycznie zamieniany na warto typu int. Jeli uruchomimy aplikacj bez argumentów, to otrzymamy sum 0. Jeli natomiast który z parametrów nie bdzie liczb cakowit, to dziaanie programu zostanie przerwane.

Zadanie 7.8. Zamiana.java, Z07_8.java Aplikacj uruchamiamy z dwoma parametrami — pierwszy parametr interpretujemy jako podstaw systemu (int radix = Integer.parseInt(args[0])), a drugi bdzie zamienian liczb (int n = Integer.parseInt(args[1])). Stosujc metod toString z klasy Integer, zamieniamy liczb cakowit n na acuch znaków str reprezentujcy t liczb w systemie pozycyjnym o podstawie radix. Podstawa radix powinna by liczb z zakresu od 2 do 36; wyjcie poza ten zakres nie spowoduje bdów — zostanie przyjta domylna warto podstawy (radix = 10).

Rozdzia 5. i Rozwizania zada

135

public class Zamiana { public static void main(String args[]) { int radix = Integer.parseInt(args[0]); int n = Integer.parseInt(args[1]); String str = Integer.toString(n, radix); System.out.println(args[1]+"[10] = "+str+"["+radix+"]"); } }

Uruchamiajc aplikacj, np. java Zamiana 2 255, otrzymamy wynik 255[10] = 1111 1111[2].

Zadanie 7.9. Zamiana2.java, Z07_9.java Pierwszy parametr interpretujemy jako podstaw systemu (int radix = Integer.parse Int(args[0])), a drugi bdzie cigiem cyfr w systemie pozycyjnym o podstawie radix. Stosujc metod parseInt z klasy Integer, zamieniamy acuch znaków args[1] reprezentujcy liczb w systemie o podstawie radix na liczb w systemie dziesitkowym (int n = Integer.parseInt(args[1], radix)). public class Zamiana2 { public static void main(String args[]) { int radix = Integer.parseInt(args[0]); int n = Integer.parseInt(args[1], radix); System.out.println(args[1]+"["+radix+"] = "+n+"[10]"); } }

Wywoujc aplikacj, np. java Zamiana2 2 11111111, otrzymamy wynik 11111111[2] = 255[10]. Podanie podstawy wykraczajcej poza dopuszczalny zakres lub cigów znaków niebdcych liczbami w wybranym systemie spowoduje przerwanie programu.

8. Inne typy liczb cakowitych w Javie Zadanie 8.1. LongNumber.java, Z08_1.java, Z08_1a.java Po skompilowaniu i uruchomieniu aplikacji (z listingu 8.1) otrzymamy w konsoli taki wynik: n = 9223372036854775807 BIN: 111111111111111111111111111111111111111111111111111111111111111 HEX: 7fffffffffffffff m = -9223372036854775808 BIN: 1000000000000000000000000000000000000000000000000000000000000000 HEX: 8000000000000000 Zamiana na typ int, m = -1 BIN: 11111111111111111111111111111111 HEX: ffffffff Zamiana na typ int, m = 0 BIN: 0 HEX: 0

136

Programowanie w jzyku Java

Przeanalizujmy fragmenty kodu ródowego: long n = Long.MAX_VALUE; System.out.println("n = "+n); System.out.println("BIN: "+Long.toBinaryString(n)); System.out.println("HEX: "+Long.toHexString(n));

Najwiksz liczb cakowit dodatni 64-bitow ze znakiem (typu long) jest 263–1 (n = 9223372036854775807). W klasie opakowujcej Long reprezentuje t liczb staa MAX_VALUE. Stosujc statyczn metod toBinaryString dla tej liczby, zobaczymy jej posta binarn — cig 63 cyfr 1; szedziesity czwarty (najstarszy) bit ma warto 0 i nie jest wywietlany (pominicie tzw. zer nieznaczcych). W postaci szesnastkowej, uzyskanej metod statyczn toHexString, otrzymujemy szesnacie cyfr — cyfr 7 (binarnie 0111) i pitnacie cyfr f (binarnie 1111, dziesitnie 15). long m = n+1; System.out.println("m = "+m); System.out.println("BIN: "+Long.toBinaryString(m)); System.out.println("HEX: "+Long.toHexString(m));

Po dodaniu liczby 1 otrzymamy (zgodnie z reguami dziaa na liczbach binarnych) cig bitów zoony z jedynki i 63 zer. Odpowiada to liczbie dziesitnej –263 (–9223 372036854775808). Najstarszy bit (1) jest w tym przypadku bitem znaku i oznacza liczb ujemn (w kodzie uzupenie do dwóch). W postaci szesnastkowej mamy cyfr 8 (binarnie 1000) i pitnacie cyfr 0 (binarnie 0000). Long max = new Long(n); System.out.println("Zamiana na typ int, m = "+max.intValue()); System.out.println("BIN: "+Integer.toBinaryString(max.intValue())); System.out.println("HEX: "+Integer.toHexString(max.intValue()));

Tworzymy obiekt max (reprezentujcy liczb n) klasy opakowujcej Long. Stosujc metod intValue, otrzymamy liczb typu int równ –1 (w postaci binarnej 11111111111 111111111111111111111 — 32 bity 1). Z liczby omiobajtowej (long) obcito cztery starsze bajty i zostawiono reszt (cztery modsze bajty) — liczb 32-bitow typu int. Podobny efekt mona uzyska, wykonujc rzutowanie liczby typu long na typ int. System.out.println("Zamiana na typ int, m = "+(int)m); System.out.println("BIN: "+Integer.toBinaryString((int)m)); System.out.println("HEX: "+Integer.toHexString((int)m));

Przy wywietlaniu liczb zostay pominite zera nieznaczce. Zmieniajc warto zmiennej n na minimaln oraz biorc liczb m o jeden mniejsz (Long n = new Long(Long.MIN_VALUE); Long),

otrzymamy taki rezultat: n = -9223372036854775808 BIN: 1000000000000000000000000000000000000000000000000000000000000000 HEX: 8000000000000000 m = 9223372036854775807 BIN: 111111111111111111111111111111111111111111111111111111111111111

Rozdzia 5. i Rozwizania zada

137

HEX: 7fffffffffffffff Zamiana na typ int, m = 0 BIN: 0 HEX: 0 Zamiana na typ int, m = -1 BIN: 11111111111111111111111111111111 HEX: ffffffff

Analiz wyniku pozostawiamy Czytelnikowi.

Zadanie 8.2. MinMax.java, Z08_2.java Liczba cakowita n-bitowa ze znakiem ma najmniejsz warto –2n–1 (bit 1 i n–1 bitów 0) i najwiksz warto 2n–1–1 (n bitów 1). W Javie typy proste byte, short, int i long s typami liczb cakowitych ze znakiem, o dugoci (odpowiednio do kolejnoci podanych nazw) 8, 16, 32 i 64 bitów. Nie musimy oblicza wartoci granicznych wedug podanej wyej zasady, gdy klasy opakowujce Byte, Short, Integer i Long zawieraj odpowiednie stae MIN_VALUE i MAX_VALUE. public class MinMax { public static void main(String args[]) { System.out.println("byte "); System.out.println("short "); System.out.println("int "); System.out.println("long "); } }

Po wykonaniu programu otrzymamy wynik: byte short int long



Zadanie 8.3. MaxPositive.java, Z08_3.java W rozwizaniu zadania wykorzystamy stae z klas opakowujcych proste typy liczbowe: Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE i Long.MAX_VALUE, a take metody toBinaryString i toHexString — z klasy Integer dla typów byte, short i int oraz z klasy Long dla typu long (lub wszystkich wymienionych typów). public class MaxPositive { public static void main(String args[]) { System.out.print("byte "+ Integer.toBinaryString(Byte.MAX_VALUE)); System.out.println("\t"+Integer.toHexString(Byte.MAX_VALUE)); System.out.print("short "+ Integer.toBinaryString(Short.MAX_VALUE)); System.out.println("\t"+Integer.toHexString(Short.MAX_VALUE)); System.out.print("int "+ Integer.toBinaryString(Integer.MAX_VALUE));

138

Programowanie w jzyku Java System.out.println("\t"+Integer.toHexString(Integer.MAX_VALUE)); System.out.print("long "+Long.toBinaryString(Long.MAX_VALUE)); System.out.println("\t"+Long.toHexString(Long.MAX_VALUE)); } }

Zadanie 8.4. Kodowanie.java, Z08_4.java, Z08_4a.java Po uruchomieniu aplikacji: public class Kodowanie { public static void main(String[] args) { String napis = "kodowanie"; System.out.println("Tekst: "+napis); System.out.print("Cig bajtów:"); byte[] kod = napis.getBytes(); for(byte n : kod) System.out.print(" "+n+","); System.out.println("\b."); } }

uzyskamy nastpujcy wynik: Tekst: kodowanie Cig bajtów: 107, 111, 100, 111, 119, 97, 110, 105, 101.

Zwrómy uwag na sposób wywietlania poszczególnych elementów tablicy (w ptli): odstp, liczba i przecinek. Przecinek po ostatniej liczbie kasujemy, wpisujc znak \b (ang. backspace), a nastpnie stawiamy kropk. Jeli skorzystamy z klasy Arrays (potrzebny bdzie import klasy java.util.Arrays) opakowujcej typy tablicowe, to moemy tablic bajtów kod zamieni na acuch znaków w postaci [107, 111, 100, 111, 119, 97, 110, 105, 101] i wywietli go w konsoli. Uyjemy do tego celu statycznej metody Arrays.toString(), np.: System.out.print("Cig bajtów: "); System.out.println(Arrays.toString(napis.getBytes()));

Zadanie 8.5. Dekodowanie.java, Z08_5.java Na podstawie cigu bajtów tworzymy tablic bajtów byte[] kod = {115, 122, 121, 102, 114}, wywietlamy zawarto tablicy w konsoli (zob. drugi wariant rozwizania zadania 8.4). Na podstawie tablicy bajtów (kod) tworzymy acuch znaków — klasa String posiada odpowiedni konstruktor (String wynik = new String(kod)). import java.util.Arrays; public class Dekodowanie { public static void main(String[] args) { byte[] kod = {115, 122, 121, 102, 114}; System.out.println("Cig bajtów: "+Arrays.toString(kod)); String wynik = new String(kod); System.out.println("Tekst: "+wynik); } }

Rozdzia 5. i Rozwizania zada

139

Zadanie 8.6. DodajCyfry.java, Z08_6a.java, Z08_6b.java a) Liczba podana w postaci acucha znaków (cyfr) nie ma waciwie

ograniczenia liczby cyfr powodowanego zakresem cakowitych typów liczbowych w Javie. Cig cyfr zamieniamy na cig (tablic) odpowiadajcych im bajtów. Podczas sumowania od kolejnych bajtów odejmujemy 48 (kod 0) i uzyskujemy warto liczbow odpowiedniej cyfry. public class DodajCyfry { public static void main(String[] args) { String liczba = "3784596320"; byte[] kod = liczba.getBytes(); int suma = 0; for(byte c: kod) suma += c-48; System.out.println("Liczba naturalna: "+liczba); System.out.println("Suma cyfr: "+suma); } }

b) Jeli liczba zapisana jest w pamici w postaci numerycznej (proponujemy uy typu o najwikszym zakresie, czyli long), to zamieniamy j na acuch

znaków: long n = 3784596320L; String liczba = Long.toString(n);

i kontynuujemy obliczenia wedug podpunktu a). Naley zwróci uwag na sposób zainicjowania zmiennej n — liczby cakowite wiksze od Integer. MAX_VALUE (2147483647) s liczbami typu long i reprezentujce je literay musz by zakoczone liter L (mona równie uy maej litery l, ale ten znak moemy pomyli z cyfr 1). Najwiksz liczb, dla której moemy to zadanie wykona, jest Long.MAX_VALUE, czyli 9223372036854775807.

Zadanie 8.7. Txt2Hex.java, Z08_7.java Podobnie jak w rozwizaniu zadania 8.4, zamienimy acuch znaków (String napis = "szyfr") na cig bajtów zapisany w tablicy kod (byte[] kod = napis.getBytes()). Wywietlajc zawarto tablicy, zamienimy liczby (n typu byte) na ich reprezentacj szesnastkow (Integer.toHexString(n).toUpperCase()). public class Txt2Hex { public static void main(String[] args) { String napis = "szyfr"; System.out.print(napis+" -> "); byte[] kod = napis.getBytes(); for(byte n : kod) System.out.print(Integer.toHexString(n).toUpperCase()); } }

Zadanie 8.8. Hex2Txt.java, Z08_8.java

acuch hex zawiera zakodowany cig znaków (String hex = "737A796672"). Kade dwie cyfry szesnastkowe (bajt) odpowiadaj jednemu znakowi. Tworzymy tablic

140

Programowanie w jzyku Java

bajtów o rozmiarze dwa razy mniejszym od rozmiaru acucha hex (byte[] tmp = new byte[hex.length()/2]). W ptli for z acucha hex pobieramy po dwie cyfry szesnastkowe (hex.substring(2*i,2*i+2)), zamieniamy je na liczby i przechowujemy w tablicy tmp. Na koniec zamieniamy tablic bajtów na acuch znaków (new String(tmp)). public class Hex2Txt { public static void main(String[] args) { String hex = "737A796672"; System.out.print(hex+" -> "); byte[] tmp = new byte[hex.length()/2]; for(int i = 0; i < tmp.length; ++i) tmp[i] = Byte.parseByte(hex.substring(2*i,2*i+2), 16); System.out.println(new String(tmp)); } }

9. Typy liczb zmiennoprzecinkowych Zadanie 9.1. DemoDouble.java, Z09_1.java Zobaczmy wyniki pracy programu: Minimalna warto dodatnia: 4.9E-324 BIN: 1 HEX: 0x0.0000000000001p-1022 Liczba przeciwna: -4.9E-324 BIN: 1000000000000000000000000000000000000000000000000000000000000001 HEX: -0x0.0000000000001p-1022

Staa Double.MIN_VALUE ma warto najmniejszej liczby dodatniej moliwej do przedstawienia w postaci liczby zmiennoprzecinkowej podwójnej precyzji (typu double), czyli warto 4.9E-324 (4,9·10–324). Jej reprezentacja binarna ma posta (64 bity, w konsoli zera nieznaczce zostay pominite): 0000000000000000000000000000000000000000000000000000000000000001

W skad tej reprezentacji wchodz: 0 (0 oznacza liczb dodatni), 11 bitów cechy 000 00000000 i 52 bity mantysy 0000000000000000000000000000000000000000000000000001. Poniewa wszystkie bity cechy s zerami, wic mantysa jest zdenormalizowana (bez bitu cakowitego 1) i ma posta binarn 0,00000000000000000000000000000000000000 00000000000001 (cyfra 1 na pidziesitej drugiej pozycji po przecinku), a to odpowiada liczbie dziesitnej 2–52. Mnoc mantys przez liczb 21–1023, uzyskamy warto 2-52·21–1023 = 2–1074 = 4,9·10–324. Zapis binarny liczby przeciwnej róni si jedynie bitem znaku: 1 oznacza liczb ujemn. W programie zastosowano nastpujce elementy statyczne z klas Double i Long:  Double.MIN_VALUE — staa o wartoci najmniejszej liczby dodatniej typu double,

Rozdzia 5. i Rozwizania zada

141

 long Double.doubleToLongBits(double) — metoda zamieniajca liczb zmiennoprzecinkow typu double na liczb cakowit typu long o identycznej

reprezentacji binarnej,  String Long.toBinaryString(long) — metoda zamieniajca liczb cakowit typu long na acuch zawierajcy reprezentacj binarn tej liczby

(z pominiciem zer nieznaczcych),  String Double.toHexString(double) — metoda zamieniajca liczb zmiennoprzecinkow typu double na acuch znaków heksadecymalnych reprezentujcych t liczb; np. w cigu znaków 0x0.0000000000001p-1022

kolejne elementy oznaczaj: 0x — liczba jest zapisana w kodzie szesnastkowym; 0.0000000000001 — zdenormalizowana mantysa — cyfra jednoci 0,

13 cyfr szesnastkowych po przecinku (13·4 = 52 bity mantysy); p–1022 — wykadnik (–1022) zapisany w kodzie dziesitkowym

(podstaw potgi jest 2). Zapis ten reprezentuje liczb zmiennoprzecinkow o wartoci mantysa·21022.

Zadanie 9.2. DoubleBin.java, Z09_2.java

acuch zero zawierajcy 63 znaki 0 przyda si do uzupeniania zer nieznaczcych do 64 bitów w liczbach dodatnich, dla których metoda toBinaryString zera nieznaczce pomija. Liczby lub symbole, których posta binarn chcemy pozna, umieszczamy w tablicy double[] a = {...}. W ptli pobieramy elementy (for(double x : a)...) tej tablicy, wywietlamy ich posta zmiennoprzecinkow w konsoli (System.out.println ("x = "+x)), zamieniamy liczb x typu double na liczb typu long, majc identyczn reprezentacj binarn (Double.doubleToLongBits(x)), a t liczb typu long przedstawiamy w postaci binarnej (String tmp = Long.toBinaryString(...)) — acuch tmp. Z acucha tmp tworzymy acuch bin o dugoci 64 znaków (sowo 64-bitowe), dodajc zera (nieznaczce) na pocztku acucha. Z acucha bin wybieramy bit znaku (bin.charAt(0)), cech (bin.substring(1, 12)) i mantys (bin.substring(12)), przedstawiajc w ten sposób binarn posta liczby lub symbolu zmiennoprzecinkowego. public class DoubleBin { static String zero = "0000000000000000000000000000000000000000000000000000000000000000"; public static void main(String[] args) { double[] a = {0.25, 0.5, 1.0, 2.0, 512.0}; /* podpunkt a) */ for(double x : a) { System.out.println("x = "+x); String tmp = Long.toBinaryString(Double.doubleToLongBits(x)); String bin = zero.substring(0, 64-tmp.length())+tmp; System.out.println("BIN: "+bin); System.out.println("Bit znaku: "+bin.charAt(0)); System.out.println("Cecha: "+bin.substring(1, 12)); System.out.println("Mantysa: "+bin.substring(12));

142

Programowanie w jzyku Java System.out.println(); } } }

a) Wybrane potgi liczby: 0,25; 0,5; 1,0; 2,0; 512,0. x = 0.25 BIN: 0011111111010000000000000000000000000000000000000000000000000000 Bit znaku: 0 Cecha: 01111111101 Mantysa: 0000000000000000000000000000000000000000000000000000 x = 0.5 BIN: 0011111111100000000000000000000000000000000000000000000000000000 Bit znaku: 0 Cecha: 01111111110 Mantysa: 0000000000000000000000000000000000000000000000000000 x = 1.0 BIN: 0011111111110000000000000000000000000000000000000000000000000000 Bit znaku: 0 Cecha: 01111111111 Mantysa: 0000000000000000000000000000000000000000000000000000 x = 2.0 BIN: 0100000000000000000000000000000000000000000000000000000000000000 Bit znaku: 0 Cecha: 10000000000 Mantysa: 0000000000000000000000000000000000000000000000000000 x = 512.0 BIN: 0100000010000000000000000000000000000000000000000000000000000000 Bit znaku: 0 Cecha: 10000001000 Mantysa: 0000000000000000000000000000000000000000000000000000

Wszystkie liczby s dodatnie (bit znaku 0). Ich cechy s róne od zera, wic mantysy s znormalizowane i równe (binarnie 1,0000…) 1. Cechy kolejnych liczb s równe binarnie 01111111101, 01111111110, 01111111111, 10000000000 i 10000001000, co odpowiada liczbom dziesitnym 1021, 1022, 1023, 1024 i 1032. Po uwzgldnieniu przesunicia –1023 otrzymamy wykadniki –2, –1, 0, 1 i 9. Poniewa mantysa jest równa 1 dla wszystkich liczb z podanego zestawu, to wartoci tych liczb s równe 2–2 = 0,25; 2–1 = 0,5; 20 = 1; 21 = 2 i 29 = 512. b) Podane liczby s potgami liczby 10. double[] a = {0.01, 0.1, 1.0, 10.0, 100.0};

W postaci binarnej nie dostrzeemy adnego zwizku pomidzy tymi liczbami. c) Podane liczby s liczbami dziesitnymi zapisanymi przy uyciu tych

samych cyfr i róni si pooeniem przecinka dziesitnego. double[] a = {1.367, 1367, 1.367e-12, 1.367e12, 13.67, -13.67};

Rozdzia 5. i Rozwizania zada

143

W postaci binarnej nie dostrzeemy adnych podobiestw, z wyjtkiem ostatnich dwu liczb, które s liczbami przeciwnymi (róni si bitem znaku). d) Symbole specjalne (NaN i rf ). double[] a = {Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY};

Wszystkie symbole specjalne maj cech zoon z samych bitów 1. Mantysa znaku NaN (ang. Not a Number) skada si z bitu 1 i 51 bitów 0. x = NaN BIN: 0111111111111000000000000000000000000000000000000000000000000000 Bit znaku: 0 Cecha: 11111111111 Mantysa: 1000000000000000000000000000000000000000000000000000

Symbole nieskoczonoci maj mantysy zoone z bitów 0, a bit znaku decyduje o znaku wartoci. x = -Infinity BIN: 1111111111110000000000000000000000000000000000000000000000000000 Bit znaku: 1 Cecha: 11111111111 Mantysa: 0000000000000000000000000000000000000000000000000000 x = Infinity BIN: 0111111111110000000000000000000000000000000000000000000000000000 Bit znaku: 0 Cecha: 11111111111 Mantysa: 0000000000000000000000000000000000000000000000000000

e) Dwie reprezentacje zera (dodatnia i ujemna) oraz dodatnie wartoci

ekstremalne. double[] a = {0.0, -0.0, Double.MIN_VALUE, Double.MAX_VALUE, 2.2250738585072014e-308};

Cecha i mantysa skadaj si z samych bitów 0. To reprezentacja liczby 0.0. Jedynie bit znaku moe przyjmowa warto 0 lub 1. Mamy zatem dwie reprezentacje binarne zera w liczbach zmiennoprzecinkowych — w informatyce uywamy czasem wyrae „zero dodatnie” i „zero ujemne”. x = 0.0 BIN: 0000000000000000000000000000000000000000000000000000000000000000 Bit znaku: 0 Cecha: 00000000000 Mantysa: 0000000000000000000000000000000000000000000000000000 x = -0.0 BIN: 1000000000000000000000000000000000000000000000000000000000000000 Bit znaku: 1 Cecha: 00000000000 Mantysa: 0000000000000000000000000000000000000000000000000000

T warto (najmniejsz moliw do zapisania liczb dodatni — sta Double.MIN_VALUE) omówiono dokadnie w rozwizaniu zadania 9.1 (mantysa tej liczby nie jest znormalizowana).

144

Programowanie w jzyku Java x = 4.9E-324 BIN: 0000000000000000000000000000000000000000000000000000000000000001 Bit znaku: 0 Cecha: 00000000000 Mantysa: 0000000000000000000000000000000000000000000000000001

Najwiksza moliwa do zapisania liczba zmiennoprzecinkowa (staa Double. MAX_VALUE) ma cech 11111111110 (najwiksz, jak mona zapisa na 11 bitach, bo cecha 11111111111 jest zarezerwowana dla symboli specjalnych) i mantys (znormalizowan) zoon z samych bitów 1. x = 1.7976931348623157E308 BIN: 0111111111101111111111111111111111111111111111111111111111111111 Bit znaku: 0 Cecha: 11111111110 Mantysa: 1111111111111111111111111111111111111111111111111111

Binarna mantysa 1,1111111111111111111111111111111111111111111111111111 po przeliczeniu na ukad dziesitkowy ma warto 2–2–52, cecha 11111111110 ma warto 2046, wic warto dziesitna tej liczby wynosi (2–2–52)·22046–1023 = (2–2–52)·21023 = 1,7976931348623157·10308. Kolejna liczba jest najmniejsz liczb dodatni o znormalizowanej mantysie 1,0·21–1023 = 2–1022 = 2,2250738585072014·10-308. x = 2.2250738585072014E-308 BIN: 0000000000010000000000000000000000000000000000000000000000000000 Bit znaku: 0 Cecha: 00000000001 Mantysa: 0000000000000000000000000000000000000000000000000000

Zadanie 9.3. Bin2Float.java, Z09_3.java Cig bitów o dugoci nieprzekraczajcej 32 znaków zapisujemy w acuchu bin. Obliczmy warto cakowit n odpowiadajc podanemu acuchowi cyfr binarnych (int n = Integer.parseInt(bin, 2)). Liczb cakowit typu int zamieniamy na liczb zmiennoprzecinkow typu float o identycznej reprezentacji binarnej (float x = Float.intBitsToFloat(n)). public class Bin2Float { public static void main(String[] args) { String bin ="111110000011110000111000110010"; int n = Integer.parseInt(bin, 2); float x = Float.intBitsToFloat(n); System.out.println("bin: "+bin); System.out.println("int: "+n); System.out.println("float: "+x); } }

Cig bitów 111110000011110000111000110010 reprezentuje liczb zmiennoprzecinkow (float) 0,13970259.

Rozdzia 5. i Rozwizania zada

145

Zadanie 9.4. Bin2Double.java, Z09_4.java Cig bitów o dugoci nieprzekraczajcej 64 znaków zapisujemy w acuchu bin. Obliczmy warto cakowit n (64-bitow, typu long) odpowiadajc podanemu acuchowi cyfr binarnych (long n = Integer.parseLong(bin, 2)). Liczb cakowit typu long zamieniamy na liczb zmiennoprzecinkow typu double o identycznej reprezentacji binarnej (double x = Double.longBitsToDouble(n)). public class Bin2Double { public static void main(String[] args) { String bin ="111110000011110000111000110010"; long n = Long.parseLong(bin, 2); double x = Double.longBitsToDouble(n); System.out.println("bin: "+bin); System.out.println("long: "+n); System.out.println("double: "+x); } }

Cig bitów 111110000011110000111000110010 reprezentuje liczb zmiennoprzecinkow (double) 5,144083374E-315 (porównaj ten wynik z wynikiem uzyskanym w zadaniu 9.3).

Zadanie 9.5. Bin2Double.java, Z09_5.java W symbolach specjalnych cecha ma wszystkie bity równe 1 (w cigach bitów symbole te zostay wyrónione przez pogrubienie). Oto reprezentacje binarne trzech symboli specjalnych):  nieskoczono ujemna ( f ) 11111111100000000000000000000000,  nieskoczono dodatnia ( f ) 01111111100000000000000000000000,  nie liczba (NaN) 01111111111111111111111111111111 (co najmniej najstarszy bit mantysy musi by równy 1). public class TestBinFloat { public static void main(String[] args) { float x = Float.intBitsToFloat(Integer.parseInt(args[0], 2)); System.out.println(args[0]+" -> "+x); } }

Kod wyglda na poprawny, ale niestety kopoty sprawia metoda Integer.parseInt (String, int), która nie akceptuje (zgodnie z dokumentacj) cigów cyfr binarnych 32-bitowych, majcych najstarszy bit 1 (liczby cakowite ujemne w kodzie uzupenie do 2), natomiast dopuszcza zastosowanie znaku – (minus) przed cigiem cyfr binarnych, nie duszym ni 31 bitów. Aby wyznaczy liczb typu float majc reprezentacj binarn 111111111000000000 00000000000000, powinnimy zanegowa w tym cigu wszystkie bity 0000000001111 1111111111111111111, a nastpnie doda 1 (dodawanie zgodnie z reguami dodawania liczb w systemie binarnym). Otrzymamy w ten sposób cig cyfr 000000001000000000 00000000000000, przed którym stawiamy znak minus (–00000000100000000000000000

146

Programowanie w jzyku Java 000000). Zera nieznaczce mona pomin — ich obecno jednak nie wpywa na wynik (w tym przypadku –Infinity, czyli nieskoczono ujemna).

Rozwaana sytuacja nie obejmuje najmniejszej liczby typu int (binarnie 1000000000 0000000000000000000000), której w typie float odpowiada warto –0.0 (zero ujemne!). Moemy o tym si przekona, wykorzystujc nastpujcy wiersz kodu: System.out.println(Float.intBitsToFloat(Integer.MIN_VALUE));

Rozdzia 6.

Rozwizania zada 10. Wywietlanie sformatowanych wyników w konsoli. Stae i metody z klasy Math Zadanie 10.1. Z10_1.java Najprostszym rozwizaniem jest uycie metody printf() wprowadzonej w J2SE ver. 5.0 (1.5). Umieszczony w acuchu formatujcym "4/7 = %.5f\n" cig znaków %.5f jest specyfikatorem okrelajcym, e parametr x podstawiony w miejsce specyfikatora ma by zinterpretowany jako liczba zmiennoprzecinkowa (f) i wywietlona z precyzj 5 miejsc po przecinku (.5). Symbol % sygnalizuje, e wystpujce po nim znaki tworz specyfikator. public class Z10_1 { public static void main(String[] args) { double x = (double)4/7; System.out.printf("4/7 = %.5f\n", x); } }

Poznane wczeniej metody print() i println() równie pozwalaj wywietli liczby z okrelon precyzj, pod warunkiem e odpowiednio zaokrglimy wynik. Pomnómy warto zmiennej x przez 100000 (przesunicie przecinka o 5 miejsc w prawo), dodajmy 0.5 i obetnijmy cz uamkow liczby (konwersja liczby zmiennoprzecinkowej na liczb cakowit przez rzutowanie), a nastpnie podzielmy wynik przez 100000.0 (dzielimy liczb cakowit przez liczb zmiennoprzecinkow, aby uzyska wynik zmiennoprzecinkowy). Otrzymany rezultat jest poprawnym zaokrgleniem wartoci x do 5 miejsc po przecinku. double y = (int)(100000*x+0.5)/100000.0; System.out.println("4/7 = "+y);

148

Programowanie w jzyku Java

Moemy zastosowa zaokrglenie przy uyciu metody round(). y = Math.round(100000*x+0.5)/100000.0;

Podobne obliczenia moemy zrealizowa z zastosowaniem obiektu klasy Double. y = new Double(100000*x+0.5).intValue()/100000.0;

Inn moliwo stwarza metoda format() klasy String: System.out.println(String.format("4/7 = %.5f", x));

Zauwamy podobiestwo pomidzy pierwszym i ostatnim przypadkiem (sposób tworzenia acucha znaków). Uzyskany wynik jest zgodny z ustawieniami lokalnymi komputera: 0,57143 (przecinek dziesitny). W pozostaych przypadkach metoda println() wywietla liczby dziesitne z kropk.

Zadanie 10.2. Z10_2.java W pakiecie java.lang zdefiniowano klas Math zawierajc wartoci przyblione staych e i S oraz róne funkcje matematyczne. Dostp do staych lub funkcji otrzymujemy, podajc nazw klasy, kropk i nazw staej lub funkcji, np. Math.E, Math.PI (nazwy staych piszemy zwyczajowo wielkimi literami1) lub Math.sqrt(x) — x jest argumentem funkcji sqrt (ang. square root — pierwiastek kwadratowy). public class Z10_2 { public static void main(String[] System.out.printf("Liczba e System.out.printf("Liczba pi System.out.printf("Liczba fi } }

args) { = %15.10f\n", Math.E); = %15.10f\n", Math.PI); = %15.10f\n", (1+Math.sqrt(5))/2);

Moemy statycznie importowa klas Math i w zapisie wzorów pomin nazw klasy. import static java.lang.Math.*; public class Z10_2a { public static void main(String[] System.out.printf("Liczba e System.out.printf("Liczba pi System.out.printf("Liczba fi } }

args) { = %15.10f\n", E); = %15.10f\n", PI); = %15.10f\n", (1+sqrt(5))/2);

Zadanie 10.3. Z10_3.java W klasie Math oprócz funkcji sqrt() obliczajcej pierwiastek kwadratowy zdefiniowano funkcj cbrt() obliczajc pierwiastek trzeciego stopnia (ang. cube root — pierwiastek szecienny). W ptli typu for each zmienna n przyjmuje kolejno wartoci zapisane w tablicy dane. Dla kadej wartoci zmiennej n metoda printf() wywietla w konsoli zgodnie z acuchem formatujcym: 1

Standard kodowania zaleca pisanie nazw staych wielkimi literami; ostateczna decyzja w tej sprawie naley do programujcego.

Rozdzia 6. i Rozwizania zada

149

 %3d — na polu o szerokoci 3 znaków liczb cakowit n;  %15.8f — na polu o szerokoci 15 znaków liczb zmiennoprzecinkow (warto wyraenia sqrt(n)) z dokadnoci do 8 miejsc po przecinku;  %15.8f — na polu o szerokoci 15 znaków liczb zmiennoprzecinkow (warto wyraenia cbrt(n)) z dokadnoci do 8 miejsc po przecinku;  \n — znak koca linii; kursor przechodzi na pocztek nowego wiersza. import static java.lang.Math.*; public class Z10_3 { public static void main(String[] args) { int[] dane = {2, 3, 5, 7, 9, 11, 13, 17}; for(int n : dane) System.out.printf("%3d%15.8f%15.8f\n", n, sqrt(n), cbrt(n)); } }

Zadanie 10.4. Z10_4.java Funkcja pow (ang. power — potga) z klasy Math posiada dwa parametry. Pierwszy jest 1

podstaw, a drugi wykadnikiem obliczanej potgi. Wzór x sa w postaci x = Math.pow(5, 1.0/n).

n

5

5 n moemy zapi-

public class Z10_4 { public static void main(String[] args) { int[] dane = {2, 3, 4, 5, 6, 7, 8, 9, 10}; for(int n : dane) { double x = Math.pow(5, 1.0/n); System.out.printf("Pierwiastek %2d stopnia z 5: %f\n", n, x); } } }

Precyzja 6 miejsc po przecinku jest domylnie ustawiana dla metody printf(), wic w tym zadaniu uyto specyfikatora %f zamiast %.6f. Zwrómy równie uwag na sposób obliczania wykadnika — wyraenie 1.0/n daje nam zmiennoprzecinkow warto uamka (1/n — dzielenie cakowite daoby wykadnik równy 0).

Zadanie 10.5. Z10_5.java Najpierw wywietlamy wiersz nagówka, rezerwujc na pierwsz kolumn 4 znaki (rozmiar sowa Znak) i na pozostae po 10 znaków (specyfikator %10s — pole o szerokoci 10 znaków dla acucha znaków, s — string).

acuch znaków "ABCDEFGHIJKLMNOPQRSTUVWXYZ" zamieniamy, stosujc metod toChar Array(), na tablic znaków znaki. W ptli for each przegldamy zawarto tablicy znaków i wywietlamy w konsoli znak z oraz kod tego znaku (int)z (rzutowanie wartoci typu char na typ int). W specyfikatorach wystpuj symbole %1$ i %2$. W miejsce %1$ wstawiana jest warto pierwszego parametru (znak z), a w miejsce %2$ — warto drugiego parametru (kod znaku (int)z).

150

Programowanie w jzyku Java public class Z10_5 { public static void main(String[] args) { System.out.printf("Znak%10s%10s%10s\n", "OCT", "DEC", "HEX"); char[] znaki = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); for(char z : znaki) { System.out.printf("%1$3c %2$10o%2$10d%2$10X\n", z, (int)z); } } }

Przeanalizujmy specyfikatory w acuchu formatujcym:  %1$3c — zmienna typu char (pierwszy parametr) jest wywietlana na polu

szerokoci 3 znaków;  %2$10o — liczba cakowita (drugi parametr) wywietlana jest w systemie

ósemkowym (oktalnym) na polu o szerokoci 10 znaków;  %2$10d — liczba cakowita (drugi parametr) wywietlana jest w systemie

dziesitnym (decymalnym) na polu o szerokoci 10 znaków;  %2$10X — liczba cakowita (drugi parametr) wywietlana jest w systemie

szesnastkowym (heksadecymalnym) na polu o szerokoci 10 znaków. Cyfry szesnastkowe (ABCDEF) wywietlane s wielkimi literami.

Zadanie 10.6. Z10_6.java Metoda (funkcja) toDegrees() z klasy Math zamienia miar kta podan w radianach na miar wyraon w stopniach. Symbol stopnia w tekcie uzyskujemy, wpisujc znak '\u00B0'. public class Z10_6 { public static void main(String[] args) { double alfa = Math.toDegrees(1); // 1 radian w stopniach System.out.println("1 rad = "+alfa+"\u00B0"); int st, min, sek; st = (int)alfa; min = (int)((alfa-st)*60+0.5); System.out.printf("1 rad = %d\u00B0%02d\'\n", st, min); min = (int)((alfa-st)*60); sek = (int)((alfa-st-min/60.0)*3600+0.5); System.out.printf("1 rad = %d\u00B0%02d\'%02d\"\n", st, min, sek); } }

Aby zrozumie algorytm zamiany miary stopniowej kta wyraonej uamkiem dziesitnym na stopnie (wyraone liczb cakowit), minuty i sekundy ktowe, przeled my rachunek dla kta o mierze 1 radiana:  1 rad = 57.29577951308232° — wynik dziaania metody Math.toDegrees(1);.  1 rad = 57°18' — liczba stopni jest czci cakowit liczby 57.29577951308232 (st = (int)alfa;), a liczba minut jest czci cakowit

iloczynu 0,29577951308232·60 = 17,7467707849392, po zaokrgleniu (min = (int)((alfa-st)*60+0.5);).

Rozdzia 6. i Rozwizania zada

151

 1 rad = 57°17'45" — tym razem nie zaokrglamy liczby minut, ale bierzemy tylko cz cakowit (min = (int)((alfa-st)*60);). Liczba sekund jest

równa iloczynowi 0,7467707849392·60 = 44,806247096352 zaokrglonemu do czci cakowitej (sek = (int)((alfa-st-min/60.0)*3600+0.5);).

Zadanie 10.7. Z10_7.java Metoda (funkcja) toRadians() z klasy Math zamienia miar kta podan w stopniach 1 1 na miar w radianach. Obliczenia wykonamy dla liczb 1 (1°), (1') i (1"). 60 3600 public class Z10_7 { public static void main(String[] args) { double rad = Math.toRadians(1.0); System.out.printf("1\u00B0 = %.15f rad\n", rad); rad = Math.toRadians(1.0/60); System.out.printf("1\' = %.15f rad\n", rad); rad = Math.toRadians(1.0/3600); System.out.printf("1\" = %.15f rad\n", rad); } }

Zadanie 10.8. Z10_8.java a 3 jest jednoczenie sic 5 nusem jednego kta ostrego i cosinusem drugiego kta. Stosujc funkcje odwrotne (dostpne w klasie Math), moemy wyznaczy miary któw ostrych wyraone w radianach: alfa = Math.asin(a/c) i beta = Math.acos(a/c). Wedug algorytmu opisanego w rozwizaniu zadania 10.7 moemy zamieni miary w radianach na miar w stopniach, stopniach i minutach oraz stopniach, minutach i sekundach i sformuowa odpowiedzi.

W trójkcie egipskim o bokach a = 3, b = 4 i c = 5 iloraz

public class Z10_8 { public static void main(String[] args) { double a = 3.0, b = 4.0, c = 5.0; double alfa, beta; int st, min; // do podpunktu c) i d) int sek; // do podpunktu c) alfa = Math.asin(a/c); beta = Math.acos(a/c); /* odpowied a) */ System.out.printf("alfa = %.4f rad\nbeta = %.4f rad", alfa, beta); /* odpowied b) */ System.out.println(); alfa = Math.toDegrees(alfa); beta = Math.toDegrees(beta); System.out.printf("alfa = %.1f\u00B0\nbeta = %.1f\u00B0", alfa, beta); /* odpowied c) */ System.out.println(); st = (int)alfa; min = (int)((alfa-st)*60+0.5); System.out.printf("alfa = %d\u00B0%02d\'\n", st, min);

152

Programowanie w jzyku Java st = (int)beta; min = (int)((beta-st)*60+0.5); System.out.printf("beta = %d\u00B0%02d\'\n", st, min); /* odpowied d) */ System.out.println(); st = (int)alfa; min = (int)((alfa-st)*60); sek = (int)((alfa-st-min/60.0)*3600+0.5); System.out.printf("alfa = %d\u00B0%02d\'%02d\"\n", st, min, sek); st = (int)beta; min = (int)((beta-st)*60); sek = (int)((beta-st-min/60.0)*3600+0.5); System.out.printf("beta = %d\u00B0%02d\'%02d\"\n", st, min, sek); } }

11. Wczytywanie danych — klasa Scanner Zadanie 11.1. Z11_1.java Zaczynamy od utworzenia obiektu input klasy Scanner odczytujcego dane ze standardowego wejcia System.in. Zgodnie z treci zadania dane wejciowe mog by uamkami dziesitnymi, wic uyjemy zmiennej typu float (liczby zmiennoprzecinkowej pojedynczej precyzji) lub double (liczby zmiennoprzecinkowej podwójnej precyzji). Dla kadego typu danych mamy odrbn metod wczytujc dane ze strumienia: float t = input.nextFloat();

lub: double t = input.nextDouble();

Dane wprowadzamy w postaci liczby cakowitej lub uamka dziesitnego (z przecinkiem). Dopuszczalny jest równie format naukowy, np. 2,35e2 (2,35·102). import java.util.Scanner; public class Z11_1 { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Podaj temperatur w \u00B0C, t = "); double t = input.nextDouble(); System.out.printf("%.1f\u00B0C = %.1f\u00B0F\n", t, t*1.8+32); input.close(); } }

Dane wejciowe i wynik s wywietlane z dokadnoci do jednego miejsca po przecinku (specyfikator w acuchu formatujcym %.1f). Symbol ° (stopnia) wprowadzany jest jako znak \u00B0 (Unicode). Na koniec nie zapomnijmy o zamkniciu skanera input.close().

Rozdzia 6. i Rozwizania zada

153

Ze strumienia danych moemy pobra kolejny token (acuch znaków do najbliszego znaku biaego — odstpu, tabulatora lub koca wiersza): String s = input.next();

i zamieni go na liczb zmiennoprzecinkow, stosujc odpowiedni metod statyczn klasy Float lub Double: float t = Float.parseFloat(s);

lub: float t = Float.valueOf(s);

lub: double t = Double.parseDouble(s);

lub: double t = Double.valueOf(s);

Nie jest to rozwizanie korzystne — dane liczbowe bdziemy musieli wprowadza z kropk dziesitn (konwencja angielska), a wyniki bd wywietlane z przecinkiem. Lepiej uywa zlokalizowanych metod nextFloat() lub nextDouble().

Nie jest konieczne tworzenie obiektu s klasy String, moemy po prostu zapisa w jednym wierszu float t = Float.parseFloat(input.next()).

Zadanie 11.2. Z11_2.java Wzór °F = °C·1,8+32 przeksztacamy na posta °C = (°F-32)/1,8. Temperatura wejciowa wyraona jest liczb cakowit (zgodnie z treci zadania), wic warto pobieramy ze strumienia, stosujc metod input.nextInt(). import java.util.Scanner; public class Z11_2 { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Podaj temperatur w \u00B0F, t = "); int t = input.nextInt(); System.out.printf("%d\u00B0F = %.1f\u00B0C\n", t, (t-32)/1.8); input.close(); } }

Ze strumienia danych moemy pobra kolejny token: String s = input.next();

i zamieni go na liczb cakowit, stosujc wybran metod statyczn klasy Integer: int t = Integer.parseInt(s);

lub: int t = Integer.decode(s);

154

Programowanie w jzyku Java

lub: int t = Integer.valueOf(s);

Moemy ten zapis skróci, eliminujc obiekt s, np.: int t = Integer.valueOf(input.next());

Zadanie 11.3a. Z11_3a.java Dugo przeciwprostoktnej w trójkcie prostoktnym obliczymy ze wzoru c a 2  b2 wynikajcego z twierdzenia Pitagorasa. Do dyspozycji w klasie Math mamy metod sqrt() (pierwiastek kwadratowy) i metod pow() (potgowanie): double c = Math.sqrt(Math.pow(a, 2)+Math.pow(b, 2));

Dwukrotne wywoanie metody pow() w tej sytuacji jest nieekonomiczne. Obliczanie kwadratu liczby wykonamy szybciej, stosujc mnoenie: double c = Math.sqrt(a*a+b*b);

Wprowadzanie danych z klawiatury i wywietlanie wyniku nie sprawi problemu — naley jednak zauway, e program nie kontroluje poprawnoci danych. import java.util.Scanner; public class Z11_3a { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Podaj dugo przyprostoktnej, a = "); double a = input.nextDouble(); System.out.print("Podaj dugo przyprostoktnej, b = "); double b = input.nextDouble(); double c = Math.sqrt(a*a+b*b); System.out.printf("Dugo przeciwprostoktnej c = %.3f\n", c); input.close(); } }

Zadanie 11.3b. Z11_3b.java Zadanie to jest typowym przykadem zastosowania funkcji trygonometrycznych (kta ostrego) do obliczania elementów trójkta prostoktnego (tzw. rozwizywania trójktów). a a . , c ˜ sin D a, c c sin D Naley pamita, e funkcje trygonometryczne dostpne w klasie Math (sin, cos i tan

Przyjmujc standardowe oznaczenia, obliczymy: sin D

— tangens) wymagaj podania argumentu (miary kta) w radianach. Do konwersji miary kta moemy uy metody toRadians() z klasy Math. import java.util.Scanner; public class Z11_3b { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Podaj dugo przyprostoktnej, a = "); double a = input.nextDouble(); System.out.print("Podaj miar kta ostrego (°), alfa = ");

Rozdzia 6. i Rozwizania zada

155

double alfa = input.nextDouble(); double c = a/Math.sin(Math.toRadians(alfa)); System.out.printf("Dugo przeciwprostoktnej c = %.3f\n", c); input.close(); } }

Zadanie 11.4. Z11_4.java Liczba bitów zostaa ograniczona do 31 ze wzgldu na zastosowanie typu zmiennych int i klasy Integer. Mona liczb bitów zwikszy do 63, stosujc zmienne typu long i klas opakowujc Long. Wykorzystujc metod next(), odczytujemy ze skanera kolejny token i nastpnie zamieniamy go na liczb cakowit. Metoda parseInt() z klasy Integer umoliwia okrelenie podstawy systemu liczbowego (drugi parametr). Po odkodowaniu (z systemu binarnego) dwóch liczb a i b moemy obliczy ich sum a+b, któr nastpnie zamieniamy na cig znaków reprezentujcy jej posta binarn Integer. toBinaryString(a+b). import java.util.Scanner; public class Z11_4 { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.println("Podaj dwie liczby w systemie binarnym (do 31 bitów)"); System.out.print("a = "); String str = input.next(); int a = Integer.parseInt(str, 2); System.out.print("b = "); str = input.next(); int b = Integer.parseInt(str, 2); str = Integer.toBinaryString(a+b); System.out.println("a+b = "+str); input.close(); } }

Moemy zmieni podstaw systemu liczbowego w skanerze, uywajc metody useRadix(), a nastpnie odczytywa liczby cakowite zapisane w systemie liczbowym o tej podstawie. input.useRadix(2); System.out.print("a = "); int a = input.nextInt(); System.out.print("b = "); int b = input.nextInt();

Zadanie 11.5. Z11_5.java Uamek zwyky wprowadzamy z klawiatury jako acuch znaków (np. 23/45), w którym licznik i mianownik (liczby cakowite) oddzielone s symbolem / (bez odstpów). Zakadamy, e uytkownik poprawnie wprowadzi dane. Wczytujemy token ze skanera input i zamieniamy na liczby cakowite a i b czci acucha przed znakiem / i po nim. Aby obliczy warto dziesitn uamka, podzielimy licznik przez mianownik a/b. Takie dzielenie daoby jednak wynik cakowity, wic naleaoby co najmniej jedn z tych liczb skonwertowa (rzutowa) na typ zmiennoprzecinkowy double (lub

156

Programowanie w jzyku Java float) i uzyska wynik zmiennoprzecinkowy, np. (double)a/b lub a/(double)b. Po-

niewa dodatkowo potrzebujemy zamieni ten uamek na procent, to mnoymy wynik przez 100. Stosujc sta w postaci zmiennoprzecinkowej 100.0 (double) lub 100.0f (float) i odpowiedni kolejno dziaa, uzyskamy waciwy rezultat (bez potrzeby jawnego rzutowania a lub b na typ zmiennoprzecinkowy): 100.0*a/b lub 100.0f*a/b. Mnoenie i dzielenie maj ten sam priorytet, ale dziaania w tym przypadku wykonywane s od strony lewej do prawej — mnoenie da wynik zmiennoprzecinkowy, wic wynik pó niejszego dzielenia równie bdzie liczb zmiennoprzecinkow. import java.util.Scanner; public class Z11_5 { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Podaj uamek zwyky (np. 23/45): "); String u = input.next(); int a = Integer.parseInt(u.substring(0, u.indexOf("/"))); int b = Integer.parseInt(u.substring(u.indexOf("/")+1)); System.out.printf("%d/%d = %.1f%%%n", a, b, 100.0*a/b); input.close(); } }

Zadanie 11.6. Z11_6.java

acuch s zawiera dane tekstowe — cztery tokeny oddzielone odstpami (dwa sowa, liczb cakowit i liczb dziesitn). String s = "Jan Nowak 150 25,3"; Scanner input = new Scanner(s);

Podajc acuch s jako parametr konstruktora, otrzymamy obiekt input umoliwiajcy odczytanie danych z acucha znaków. Stosujc metod next(), odczytamy sowa (Jan i Nowak), potem odczytamy liczb cakowit 150 (metod nextInt()) i liczb dziesitn (zmiennoprzecinkow) 25,3 (metod nextDouble()). Majc dane, wykonamy obliczenia i sformuujemy odpowied . Na koniec zamykamy skaner (input.close()). import java.util.Scanner; public class Z11_6 { public static void main(String[] args) { String s = "Jan Nowak 150 25,3"; Scanner input = new Scanner(s); String s1 = input.next(); String s2 = input.next(); int a = input.nextInt(); double b = input.nextDouble(); System.out.printf("%s %s %.2f\n", s2, s1, a*b); input.close(); } }

Zadanie 11.7. Z11_7.java Rozwizanie tego zadania jest podobne do rozwizania zadania 11.6. Istotn rónic jest ródo danych — tym razem dane odczytamy z pliku. Dodatkowo importujemy dwie klasy z pakietu java.io, klas IOException (wyjtki operacji wejcia-wyjcia,

Rozdzia 6. i Rozwizania zada

157

które poznasz dokadniej w dalszych rozdziaach) i klas File. W nagówku metody main dopisujemy informacj o licie wyjtków (throws IOException), które mog zosta wygenerowane podczas operacji z plikami. Obsug tych wyjtków zajmie si wirtualna maszyna Javy, wywoujca metod main. Sytuacja ta zostanie omówiona dokadniej na dalszych stronach. Teraz skoncentrujmy uwag na wykorzystaniu klasy Scanner do odczytywania danych z pliku. Tworzymy obiekt f klasy File skojarzony z plikiem dane.txt (File f = new File("dane.txt")) i obiekt input klasy Scanner do odczytywania danych z pliku (Scanner input = new Scanner(f)). Reszta kodu pozostaje bez zmian. import java.io.File; import java.io.IOException; import java.util.Scanner; public class Z11_7 { public static void main(String[] args) throws IOException { File f = new File("dane.txt"); Scanner input = new Scanner(f); String s1 = input.next(); String s2 = input.next(); int a = input.nextInt(); double b = input.nextDouble(); System.out.printf("%s %s %.2f\n", s2, s1, a*b); input.close(); } }

12. Operacje na tekstach — klasy StringBuffer i StringBuilder Zadanie 12.1. Z12_1.java To zadanie i dwa zadania nastpne (12.2 i 12.3) traktujemy jako pretekst do przedstawienia wybranych metod klasy StringBuilder (lub StringBuffer). Wykresem równania y

ax 2  bx  c, a z 0 jest parabola o wierzchoku §¨  b ,  ' ·¸ , © 2a 4 a ¹

gdzie ' b  4ac . Pobieramy dane (wspóczynniki trójmianu) z konsoli, zakadajc, e uytkownik poda poprawne liczby (a róne od zera), i obliczamy wyrónik trójmianu (delta). Pozostae obliczenia wykonamy podczas budowania odpowiedzi. 2

Tworzymy obiekt point klasy StringBuilder zawierajcy acuch znaków "Wierzchoek paraboli (", czyli pocztek odpowiedzi. StringBuilder point = new StringBuilder("Wierzchoek paraboli (");

Stosujc metod append(), dodamy na kocu acucha znaków (obiektu point) kolejno: warto pierwszej wspórzdnej wierzchoka paraboli (–b/(2*a)), przecinek i odstp (", "), warto drugiej wspórzdnej wierzchoka paraboli (–delta/(4*a)) i nawias

158

Programowanie w jzyku Java

zamykajcy par wspórzdnych punktu (")"). Zwrómy uwag na uycie nawiasów w mianownikach wyrae, wyznaczajcych waciw kolejno wykonywania dziaa (mnoenia i dzielenia). import java.util.Scanner; public class Z12_1 { public static void main(String args[]) { System.out.println("Obliczanie wspórzdnych wierzchoka paraboli"); System.out.print("Podaj wspóczynniki trójmianu kwadratowego oddzielone odstpami: "); double a, b, c; /* Wczytywanie danych z konsoli */ Scanner input = new Scanner(System.in); a = input.nextDouble(); b = input.nextDouble(); c = input.nextDouble(); input.close(); /* Obliczenia i budowanie odpowiedzi */ double delta = b*b-4*a*c; StringBuilder point = new StringBuilder("Wierzchoek paraboli ("); point.append(-b/(2*a)).append(", "). append(-delta/(4*a)).append(")"); System.out.println(point); } }

Do sformuowania odpowiedzi moemy uy operatora konkatenacji (czenia tekstów +). Kompilator w tym przypadku równie wykorzysta metody klasy StringBuilder. String s = "Wierzchoek paraboli ("+(-b/(2*a))+", "+(-delta/(4*a))+")"; System.out.println(s);

1. Zadanie moemy rozwiza w taki sam sposób, zastpujc klas StringBuilder klas StringBuffer. Klasy maj identyczne metody, jednak klasa String Builder jest nowsza. Po klas StringBuffer signiemy wtedy, gdy niezbdne bdzie buforowanie operacji na acuchu znaków. 2. Odpowied moemy sformuowa i sformatowa , stosujc metod printf() lub format() do wywietlania wyniku: System.out.printf("Wierzchoek paraboli(%.2f, %.2f)", -b/(2*a), -delta/(4*a));

lub metod format() do budowania acucha: String s = String.format(("Wierzchoek paraboli(%.2f, %.2f)", -b/(2*a), -delta/(4*a));

Zadanie 12.2. Z12_2.java Ponownie rozwizujemy zadanie 12.1, stosujc inny sposób budowania odpowiedzi. Zaczynamy od acucha (obiekt point klasy StringBuilder) zoonego z pary nawiasów okrgych, przecinka i odstpu "(, )" — cznie cztery znaki o indeksach 0, 1, 2 i 3.

Rozdzia 6. i Rozwizania zada

159

Przed znakiem o indeksie 3 (midzy odstpem i nawiasem zamykajcym) wstawiamy warto drugiej wspórzdnej wierzchoka paraboli point.insert(3, (-delta/(4*a))). Konwersja zmiennoprzecinkowego typu wartoci wyraenia na acuch znaków wykonywana jest przez metod insert. Nastpnie przed znakiem o indeksie 1 (midzy nawiasem otwierajcym i przecinkiem) wstawiamy warto pierwszej wspórzdnej wierzchoka paraboli point.insert(1, -b/(2*a)). Obie te czynnoci moemy zapisa cznie, w jednym wierszu: point.insert(3, (-delta/(4*a))).insert(1, -b/(2*a));

Bardzo wana jest kolejno wstawiania tych liczb do acucha pocztkowego "(, )". /* Obliczenia i budowanie odpowiedzi */ double delta = b*b-4*a*c; StringBuilder point = new StringBuilder("(, )"); point.insert(3, (-delta/(4*a))).insert(1, -b/(2*a)); System.out.println("Wierzchoek paraboli: "+point);

Pozostaa cz kodu jest podobna jak w zadaniu 12.1.

Zadanie 12.3. Z12_3.java Jeszcze raz rozwizujemy zadanie 12.1, stosujc tym razem metod replace() (zastp) z klasy StringBuilder. Na pocztek budujemy acuch (obiekt point klasy String Builder) o postaci "(#1, #2)". Wystpujce w acuchu symbole #1 i #2 wskazuj miejsca, w których umiecimy wyniki oblicze. Metoda replace() ma trzy parametry, dwa indeksy okrelajce zakres zastpowanych znaków i podstawiany w to miejsce acuch znaków (dugo tego acucha nie jest ograniczona przez zakres zastpowanych znaków). Liczby przed wstawieniem musimy zamieni na acuchy znaków. Najpierw znajdujemy pooenie (indeks pierwszego znaku) symbolu "#1" w obiekcie point (start = point.indexOf("#1")), a nastpnie zamieniamy dwa znaki (od indeksu start do indeksu start+1) acuchem znaków utworzonym z wartoci pierwszej wspórzdnej wierzchoka paraboli (String.valueOf(-b/(2*a))). Podobnie zamieniamy symbol "#2" na odpowiedni warto. /* Obliczenia i budowanie odpowiedzi */ double delta = b*b-4*a*c; StringBuilder point = new StringBuilder("(#1, #2)"); int start = point.indexOf("#1"); point.replace(start, start+1, String.valueOf(-b/(2*a))); start = point.indexOf("#2"); point.replace(start, start+1, String.valueOf(-delta/(4*a))); System.out.println("Wierzchoek paraboli: "+point);

W drugim wariancie rozwizania proponujemy inny sposób zamiany liczby zmiennoprzecinkowej na acuch znaków (new Double(-b/(2*a)).toString()). /* Obliczenia i budowanie odpowiedzi */ double delta = b*b-4*a*c; StringBuilder point = new StringBuilder("(#1, #2)"); int start = point.indexOf("#1"); point.replace(start, start+1, new Double(-b/(2*a)).toString()); start = point.indexOf("#2");

160

Programowanie w jzyku Java point.replace(start, start+1, new Double(-delta/(4*a)).toString()); System.out.println("Wierzchoek paraboli: "+point);

Kolejny wariant moe wykorzysta waciwoci operatora konkatenacji (+): point.replace(start, start+1, ""+(-b/(2*a)));

Zadanie 12.4. Z12_4.java Z konsoli odczytujemy liczb cakowit dodatni n (nie sprawdzamy poprawnoci danych wprowadzonych przez uytkownika) i tworzymy obiekt liczba klasy String Builder, reprezentujcy pusty acuch znaków. Po wywoaniu metod liczba.append(n).reverse() obiekt liczba zawiera cyfry liczby n, zapisane w odwrotnej kolejnoci. W odpowiednim momencie zamienimy zawarto obiektu na liczb cakowit Integer.parseInt(liczba.toString()). Drugi obiekt wynik klasy StringBuilder i metod append() wykorzystamy do skonstruowania odpowiedzi. import java.util.Scanner; public class Z12_4 { public static void main(String args[]) { System.out.print("Podaj liczb cakowit dodatni: "); Scanner input = new Scanner(System.in); int n = input.nextInt(); input.close(); StringBuilder liczba = new StringBuilder(); liczba.append(n).reverse(); StringBuilder wynik = new StringBuilder(); wynik.append(n).append("-").append(liczba).append(" = "); wynik.append(n - Integer.parseInt(liczba.toString())); System.out.println(wynik); } }

Zadanie 12.5. Z12_5.java Wspórzdne wektora wprowadzamy w postaci pary liczb oddzielonych przecinkiem i zawartych w nawiasie prostoktnym, np. [2.5, –3]. Z konsoli wczytujemy wiersz tekstu i usuwamy (metoda trim()) zbdne biae znaki z pocztku i koca acucha String wekt = input.nextLine().trim(). Zakadamy, e otrzymany acuch zawiera poprawn posta wspórzdnych wektora, i tworzymy nowy obiekt, na którym wykonamy dalsze przeksztacenia (StringBuilder tmp = new StringBuilder(wekt)). Z acucha usuwamy nawiasy prostoktne, czyli pierwszy (tmp.deleteCharAt(0)) i ostatni znak (tmp.deleteCharAt(tmp.length()-1)). Nastpnie odszukujemy pooenie przecinka oddzielajcego wspórzdne wektora (int poz = tmp.indexOf(",")) i rozdzielamy acuch na dwa podacuchy, które konwertujemy na zmiennoprzecinkowe wartoci wspórzdnych wektora (liczby zapisane s z kropk dziesitn lub w postaci cakowitej):

Rozdzia 6. i Rozwizania zada

161

double a = Double.parseDouble(tmp.substring(0, poz)); double b = Double.parseDouble(tmp.substring(poz+1));

Na koniec pozostaje obliczenie dugoci wektora ze wzoru u

a 2  b 2 (Math.sqrt

(a*a+b*b)) i sformuowanie odpowiedzi. import java.util.Scanner; public class Z12_5 { public static void main(String args[]) { System.out.print("Podaj wspórzdne wektora (w postaci [a, b]): "); Scanner input = new Scanner(System.in); String wekt = input.nextLine().trim(); input.close(); StringBuilder tmp = new StringBuilder(wekt); /* Usuwamy pierwszy i ostatni znak, czyli nawiasy prostoktne. */ tmp.deleteCharAt(0).deleteCharAt(tmp.length()-1); /* Znajdujemy pozycj przecinka midzy liczbami. */ int poz = tmp.indexOf(","); /* Odczytujemy wartoci liczb. */ double a = Double.parseDouble(tmp.substring(0, poz)); double b = Double.parseDouble(tmp.substring(poz+1)); /* Obliczamy i wywietlamy dugo wektora. */ System.out.println("Dugo wektora "+wekt+" jest równa "+ Math.sqrt(a*a+b*b)); } }

Do pobrania wspórzdnych wektora z acucha znaków moemy wykorzysta metod split() z klasy String. W tym celu tworzymy tablic acuchów temp[], konwertujemy obiekt tmp na acuch znaków i wywoujemy metod split(), podajc przecinek jako separator — ",": String temp[] = tmp.toString().split(",");

Nastpnie odczytujemy (z tablicy) wartoci wspórzdnych wektora: double a = Double.parseDouble(temp[0]); double b = Double.parseDouble(temp[1]);

Pozostaa cz kodu pozostaje bez zmian. Stosujc metody substring() i split(), moemy zrezygnowa z uycia obiektu tmp klasy StringBuilder: String temp[] = wekt.substring(1, wekt.length()-1).split(",");

Oczywicie dane musz by wprowadzane zgodnie z przyjt umow.

Zadanie 12.6. Z12_6.java Zadanie to rozwizujemy podobnie jak zadanie 12.5. Istotna rónica polega na tym, e mamy trzy wspórzdne oddzielone dwoma przecinkami. Pooenie tych przecinków (pierwszego i ostatniego) ustalimy, uywajc metod indexOf() i lastIndexOf().

162

Programowanie w jzyku Java import java.util.Scanner; public class Z12_6 { public static void main(String args[]) { System.out.print("Podaj wspórzdne wektora (w postaci [a, b, c]): "); Scanner input = new Scanner(System.in); String wekt = input.nextLine().trim(); input.close(); StringBuilder tmp = new StringBuilder(wekt); /* Usuwamy pierwszy i ostatni znak, czyli nawiasy prostoktne. */ tmp.deleteCharAt(0).deleteCharAt(tmp.length()-1); /* Znajdujemy pozycje przecinków midzy liczbami. */ int poz1 = tmp.indexOf(","); int poz2 = tmp.lastIndexOf(","); /* Odczytujemy wartoci liczb. */ double a = Double.parseDouble(tmp.substring(0, poz1)); double b = Double.parseDouble(tmp.substring(poz1+1, poz2)); double c = Double.parseDouble(tmp.substring(poz2+1)); /* Obliczamy i wywietlamy dugo wektora. */ System.out.println("Dugo wektora "+wekt+" jest równa "+ Math.sqrt(a*a+b*b+c*c)); } }

Podobnie jak w rozwizaniu zadania 12.5, do wyznaczenia wspórzdnych wektora moemy zastosowa metod split() z klasy String: /* Pomijamy pierwszy i ostatni znak, czyli nawiasy prostoktne, i dzielimy acuch znaków na czci rozdzielone przecinkiem. */ String temp[] = wekt.substring(1, wekt.length()-1).split(","); /* Odczytujemy wartoci liczb - wspórzdnych wektora. */ double a = Double.parseDouble(temp[0]); double b = Double.parseDouble(temp[1]); double c = Double.parseDouble(temp[2]);

13. Instrukcje warunkowe i instrukcja selekcji Zadanie 13.1. Z13_1.java Wprowadzone imi jest przechowywane w obiekcie str klasy String. Odpowied skonstruujemy jako obiekt name klasy StringBuilder — StringBuilder name = new StringBuilder(str);. W zmiennej z przechowujemy ostatni znak imienia — char z = name.charAt(name.length()-1);. Do imienia (name) dodajemy sowo " jest " wraz z odstpami przed sowem i za sowem — name.append(" jest ");. Na koniec uzupeniamy odpowied sowem okrelajcym pe osoby, w zalenoci od tego, jak warto ma wyraenie logiczne z == 'a'. Jeli wyraenie ma warto true (ostatni liter imienia jest a), to do odpowiedzi dodajemy tekst "kobiet.", w przeciwnym razie dodajemy tekst "mczyzn.".

Rozdzia 6. i Rozwizania zada

163

import java.util.Scanner; public class Z13_1 { public static void main(String args[]) { System.out.print("Podaj imi: "); Scanner input = new Scanner(System.in); String str = input.next(); input.close(); StringBuilder name = new StringBuilder(str); char z = name.charAt(name.length()-1); name.append(" jest "); if (z == 'a') name.append("kobiet."); else name.append("mczyzn."); System.out.println(name); } }

Zadanie 13.2. Z13_2.java Jeeli wczytana warto zmiennej a (dugo boku kwadratu) jest dodatnia, to wykonujemy obliczenia i wywietlamy wynik. W kolejnej instrukcji warunkowej badamy, czy podana dugo boku jest mniejsza lub równa 0 — jeli tak jest, to wywietlamy komunikat o bdnych danych. import java.util.Scanner; public class Z13_2 { public static void main(String args[]) { System.out.println("Obliczanie pola powierzchni i obwodu kwadratu"); Scanner input = new Scanner(System.in); System.out.print("Podaj dugo boku, a = "); double a = input.nextDouble(); input.close(); if (a > 0) { double pole = a*a; double obwod = 4*a; System.out.println("Pole powierzchni P = "+pole); System.out.println("Obwód kwadratu L = "+obwod); } if (a 0 i a 0) { double pole = a*a; double obwod = 4*a; System.out.println("Pole powierzchni P = "+pole); System.out.println("Obwód kwadratu L = "+obwod); } else System.out.println("Bd! Dugo boku ma by liczb dodatni.");

164

Programowanie w jzyku Java

Zadanie 13.3. Z13_3.java Po wprowadzeniu danych tworzymy obiekt wynik klasy StringBuilder. Stanowicy odpowied acuch znaków skada si z nawiasów < i > dla przedziau domknitego lub { i } w przypadku zbioru jednoelementowego (przypadek a jest równe b). Wartoci zmiennych a i b w przypadku przedziau powinny by wprowadzone do wyniku w porzdku rosncym. Mamy zatem trzy przypadki: Przypadek

Budowanie odpowiedzi

a < b

wynik.append("");

b < a

wynik.append("");.

a == b

wynik.append("{").append(a).append("}");

Przedstawiona sytuacja wymaga zbudowania trzech instrukcji warunkowych lub zastosowania tzw. zagniedenia instrukcji warunkowej. import java.util.Scanner; public class Z13_3 { public static void main(String args[]) { System.out.println("Podaj dwie liczby a i b:"); Scanner input = new Scanner(System.in); System.out.print("a = "); double a = input.nextDouble(); System.out.print("b = "); double b = input.nextDouble(); input.close(); StringBuilder wynik = new StringBuilder(); if (a < b) wynik.append(""); else if (b < a) wynik.append(""); else wynik.append("{").append(a).append("}"); wynik.insert(0, "Zbiór wszystkich liczb zawartych pomidzy a i b, X = "); System.out.println(wynik); } }

Zadanie 13.4. Z13_4.java Po wprowadzeniu wartoci wspóczynnika a trójmianu ax 2  bx  c sprawdzamy podan warto. Jeli a jest zerem, to wywietlamy komunikat skierowany do standardowego strumienia bdów System.err.println(...) i zamykamy aplikacj System. exit(0). Gdy a jest róne od zera, wczytujemy pozostae wspóczynniki trójmianu ' 4a



 b 2  4ac 4a znaku wspóczynnika a i wartoci q:

(b i c) i obliczamy q



4ac  b 2 . Zbiór wartoci funkcji zaley od 4a

Rozdzia 6. i Rozwizania zada

Znak a a > 0 a < 0

Zbiór wartoci

q,  f ) (f, q

165

Budowanie odpowiedzi wynik.append("").insert(6, q);

import java.util.Scanner; public class Z13_4 { public static void main(String args[]) { System.out.println("Podaj wspóczynniki funkcji kwadratowej:"); Scanner input = new Scanner(System.in); System.out.print("a = "); double a = input.nextDouble(); if (a == 0) { System.err.println("a = 0, to nie jest funkcja kwadratowa."); System.exit(0); } System.out.print("b = "); double b = input.nextDouble(); System.out.print("c = "); double c = input.nextDouble(); input.close(); double q = (4*a*c-b*b)/(4*a); StringBuilder wynik = new StringBuilder(); if (a > 0) wynik.append("").insert(6, q); System.out.println("Zbiór wartoci: "+wynik); } }

Zadanie 13.5. Z13_5.java Wczytywanie danych (wspóczynników trójmianu) zorganizujemy tak, jak w rozwizaniu zadania 13.4. Nastpnie obliczymy wspórzdne p i q wierzchoka paraboli bdcej wykresem tej funkcji kwadratowej. double p = -b/(2*a); double q = (4*a*c-b*b)/(4*a);

W budowanej odpowiedzi umiecimy symbole #1 i #2. W miejsce tych symboli podstawimy pó niej odpowiednie sowa "rosnca" i "malejca", w zalenoci od znaku wspóczynnika a. StringBuilder wynik = new StringBuilder(); wynik.append("Funkcja jest #1 w przedziale (-oo, ").append(p); wynik.append("> i #2 w przedziale 360) throw new IllegalArgumentException("Liczba stopni poza zakresem."); x = deg/180.0*Math.PI; } /** Tworzy nowy obiekt Angle reprezentujcy kt o podanej * liczbie stopni i minut. * @param deg liczba stopni, liczba cakowita typu int * z przedziau , * @param min liczba minut, liczba cakowita typu int

Rozdzia 7. i Rozwizania zada

273

* z przedziau . * @throws IllegalArgumentException, gdy liczba stopni nie mieci si * w przedziale , * @throws IllegalArgumentException, gdy liczba minut nie mieci si * w przedziale . */ public Angle(int deg, int min) { if (deg < 0 || deg > 360) throw new IllegalArgumentException("Liczba stopni poza zakresem."); if (min < 0 || min > 60) throw new IllegalArgumentException("Liczba minut poza zakresem."); x = (deg+min/60.0)/180.0*Math.PI; } /** Tworzy nowy obiekt Angle reprezentujcy kt o podanej * liczbie stopni, minut i sekund. * @param deg liczba stopni, liczba cakowita typu int * z przedziau , * @param min liczba minut, liczba cakowita typu int * z przedziau , * @param sek liczba sekund, liczba cakowita typu int * z przedziau . * @throws IllegalArgumentException, gdy liczba stopni nie mieci si * w przedziale , * @throws IllegalArgumentException, gdy liczba minut nie mieci si * w przedziale , * @throws IllegalArgumentException, gdy liczba sekund nie mieci si * w przedziale . */ public Angle(int deg, int min, int sek) { if (deg < 0 || deg > 360) throw new IllegalArgumentException("Liczba stopni poza zakresem."); if (min < 0 || min > 60) throw new IllegalArgumentException("Liczba minut poza zakresem."); if (sek < 0 || sek > 60) throw new IllegalArgumentException("Liczba sekund poza zakresem."); x = (deg+min/60.0+sek/3600.0)/180.0*Math.PI; }

Obliczenia przykadowe podamy dla kilku któw, np. 15°, 22°30' i 10°30" (zero minut pominlimy w tym zapisie, ale musimy przekaza do metody warto 0 jako drugi parametr). /** Zadanie Z21.4 */ public class Z21_4 { public static void main(String args[]) { Angle alfa = new Angle(15); System.out.print("alfa = "+alfa); System.out.println(" = "+alfa.radian()+" rad"); alfa = new Angle(22, 30); System.out.print("alfa = "+alfa); System.out.println(" = "+alfa.radian()+" rad"); alfa = new Angle(10, 0, 30);

274

Programowanie w jzyku Java System.out.print("alfa = "+alfa); System.out.println(" = "+alfa.radian()+" rad"); } }

Zadanie 21.5. Z21_5.java, Angle.java Wyznaczamy pooenie znaków stopnia (int p = st.indexOf("\u00B0")), minuty (int q = st.indexOf("\'")) i sekundy ktowej (int r = st.indexOf("\"")) w cigu wejciowym. Otrzymamy indeksy wskazujce pooenie tych znaków w acuchu st lub warto -1, gdy znak nie wystpuje w acuchu. Na tej podstawie moemy wstpnie oceni poprawno cigu znaków. Pominiemy t analiz i spróbujemy wyznaczy liczb stopni, minut i sekund, konwertujc odpowiedni podcig na liczb cakowit. Czynnoci te ujmujemy w bloku try {...} i przechwytujemy ewentualne wyjtki. Przyczyn zgoszenia wyjtku moe by brak jednego z symboli (°, ' lub "), co spowoduje podanie parametru -1 do metody substring() i wygenerowanie wyjtku java. lang.StringIndexOutOfBoundsException. Drugim powodem zgoszenia wyjtku moe by bd w zapisie liczb, np. 2O°30'15" (litera O zamiast cyfry 0) — metoda parseInt() zgosi wyjtek java.lang.NumberFormatException. Przechwycimy te wyjtki i zastpimy je wyjtkiem throw new IllegalArgumentException(st). Jeli dane wejciowe s poprawne, to moemy zamieni odczytane wartoci deg, min i sek na miar kta w radianach i podstawi uzyskan warto do pola x obiektu: this.x = (deg+min/60.0+sek/3600.0)/180.0*Math.PI;. public Angle(String st) { int deg, min, sek; int p = st.indexOf("\u00B0"); // stopie int q = st.indexOf("\'"); // minuta ktowa int r = st.indexOf("\""); // sekunda ktowa try { deg = Integer.parseInt(st.substring(0, p)); min = Integer.parseInt(st.substring(p+1, q)); sek = Integer.parseInt(st.substring(q+1, r)); } catch (Exception e) { throw new IllegalArgumentException(st); } this.x = (deg+min/60.0+sek/3600.0)/180.0*Math.PI; }

Ta wersja konstruktora ma co najmniej trzy wady: 1. Nie dopuszcza skróconych postaci danych, np. 25°15' lub 33° (naley

napisa 25°15'0" lub 33°'0'0"). 2. Pozwala na dziwne postacie danych, np. 13°–13'17" (ujemna liczba minut)

lub 1°360'99" (zbyt dua liczba minut i sekund) — dane te zostan zinterpretowane jako 12°47'17" (od 13° odjto 13' i wyszo 12°47') lub 7°1'39" (360' = 6°, 99" = 1'39" — ogólny bilans si zgadza). 3. le interpretuje ujemn miar kta, np. 22°30'0" = 0.39269908169872414

rad, ale –22°30'0" zostanie zinterpretowane jako –21°30'0" = –0.3752457891787809 rad.

Rozdzia 7. i Rozwizania zada

275

Spróbujemy te wady wyeliminowa. Zainicjowanie zmiennej sek = 0 i dodanie instrukcji warunkowej: if (r > 0) sek = Integer.parseInt(st.substring(q+1, r));

pozwoli pomija w cigu danych liczb sekund i symbol sekundy ("). Dopuszczalna jest posta danych bez sekund, np. 22°30'. Zainicjujmy dodatkowo min = 0 i dodajmy instrukcje warunkowe: if (q > 0) { min = Integer.parseInt(st.substring(p+1, q)); if (r > 0) sek = Integer.parseInt(st.substring(q+1, r)); }

Teraz moemy wprowadza dane w postaci 22°15'37", 22°15' lub 22°. Nie mona pomin minut, gdy wystpuj sekundy — kt 15°30" musimy zapisa jako 15°0'30" — oraz nie mona pomin stopni — musimy pisa 0°45' zamiast 45'. To ju nie jest zbyt dua niedogodno. Liczba minut i liczba sekund powinny przyjmowa wartoci wycznie dodatnie z zakresu od 0 do 59. Fakt ten sprawdzimy przed przeliczaniem podanej miary kta na radiany: if ((min < 0) || (min > 59) || (sek < 0) || (sek > 59)) throw new IllegalArgumentException(st);

i zgosimy wyjtek, gdy dane nie bd poprawne. Problem ujemnej miary kta moemy rozwiza tak: boolean znak =false; if (deg < 0) { znak = true; deg = -deg; } this.x = (deg+min/60.0+sek/3600.0)/180.0*Math.PI; if (znak) this.x = -this.x;

Po tych zmianach kod konstruktora bdzie wyglda nastpujco: public Angle(String st) { int deg, min = 0, sek = 0; int p = st.indexOf("\u00B0"); // stopie int q = st.indexOf("\'"); // minuta ktowa int r = st.indexOf("\""); // sekunda ktowa try { deg = Integer.parseInt(st.substring(0, p)); if (q > 0) { min = Integer.parseInt(st.substring(p+1, q)); if (r > 0) sek = Integer.parseInt(st.substring(q+1, r)); } } catch (Exception e) { throw new IllegalArgumentException(st); }

276

Programowanie w jzyku Java if ((min < 0) || (min > 59) || (sek < 0) || (sek > 59)) throw new IllegalArgumentException(st); boolean znak =false; if (deg < 0) { znak = true; deg = -deg; } this.x = (deg+min/60.0+sek/3600.0)/180.0*Math.PI; if (znak) this.x = -this.x; }

Dziaanie konstruktora moemy sprawdzi dla kilku przykadowych acuchów znaków (poprawnych lub bdnych). /** Zadanie Z21.5 */ public class Z21_5 { public static void main(String args[]) { String[] angles = { "15°30'27\"", "43°52'", "22°", "-22°30'", "22°30'", "35'30\"", "1°65'", "abc", "36", "15°-30'" }; Angle alfa = null; for(String a: angles) { try { alfa = new Angle(a); System.out.print("alfa = "+alfa); System.out.println(" = "+alfa.radian()+" rad"); } catch (IllegalArgumentException e){ System.out.println("Bdne dane: "+a); } } } }

Zadanie 21.6. Z21_6.java, Angle.java Funkcje trygonometryczne s funkcjami okresowymi w swojej dziedzinie (zbiorze liczb rzeczywistych). Funkcje odwrotne moemy okreli w sposób jednoznaczny wycznie w wybranych przedziaach. Zwykle przyjmujemy takie dziedziny funkcji odwrotnych: 

S S

, 2 2

dla funkcji arcus

S S sinus i arcus cosecans, 0, S dla arcus cosinus i arcus secans, §¨  , ·¸ dla funkcji

arcus tangens i 0, S dla arcus cotangens.

©

2 2¹

W obliczeniach wykorzystamy metody z klasy Math: asin() (arcus sinus), acos() (arcus cosinus) i atan() (arcus tangens) oraz znane waciwoci funkcji trygonometrycznych i funkcji do nich odwrotnych. Funkcje sinus i cosinus przyjmuj wartoci z przedziau  1, 1 , wic argumentem funkcji odwrotnej mog by wycznie liczby z tego przedziau. Funkcjom arcus sinus i arcus cosinus odpowiadaj metody:

Rozdzia 7. i Rozwizania zada

277

public void setOfSin(double x) { if (x >= -1 && x = -1 && x -1 && x < 1) throw new IllegalArgumentException(); else this.x = Math.acos(1/x); } public void setOfCsc(double x) { if (x > -1 && x < 1) throw new IllegalArgumentException(); else this.x = Math.asin(1/x); }

Tworzc program demonstrujcy dziaanie tych metod wybieramy takie wartoci argumentu x, dla których wywietlone wyniki bd atwe do zweryfikowania. /** Zadanie Z21.6 */ public class Z21_6 { public static void main(String args[]) { Angle alfa = new Angle(0);; double x = Math.sqrt(2)/2; alfa.setOfSin(x); System.out.printf("sin x = %.6f, ", x); System.out.println("alfa = "+alfa); alfa.setOfCos(-x);

278

Programowanie w jzyku Java System.out.printf("cos x System.out.println("alfa x = -1; alfa.setOfTan(x); System.out.printf("tan x System.out.println("alfa alfa.setOfCot(x); System.out.printf("cot x System.out.println("alfa x = 2/Math.sqrt(3); alfa.setOfSec(x); System.out.printf("sec x System.out.println("alfa alfa.setOfCsc(x); System.out.printf("csc x System.out.println("alfa

= %.6f, ", -x); = "+alfa);

= %.6f, ", x); = "+alfa); = %.6f, ", x); = "+alfa);

= %.6f, ", x); = "+alfa); = %.6f, ", x); = "+alfa);

} }

We my znan warto sin 60q sin csc 60q

csc

S

2

3

3

sec

S 6

S 3

3 2

cos

S 6

cos 30q . Std moemy obliczy

sec 30q . Wykonujc powyszy program, uzyskamy tak

odpowied (dla metod setOfSec() i setOfCsc()), zgodn z oczekiwaniem: sec x = 1,154701, alfa = 30° csc x = 1,154701, alfa = 60°

Zadanie 21.7. Z21_7.java, Angle.java W klasie Math mamy metod atan2() z dwoma parametrami x i y, które s wspórzdnymi punktu P w prostoktnym ukadzie wspórzdnych. Wspórzdne tego punktu moemy zapisa w ukadzie biegunowym w postaci r , T , gdzie x r ˜ cosT i y r ˜ sin T . Do obliczenia miary kta T suy wanie metoda atan2(). Zwracany kt naley do przedziau od S do S (miara kta ma znak parametru y). W metodzie korygujemy ten wynik dla ujemnych wartoci parametru y, dodajc 2S (podwójny okres funkcji tangens). Ostateczny wynik naley do przedziau od 0 do 2S (od 0° do 360°). public void setOfPoint(double x, double y) { if (x == 0 && y == 0) throw new IllegalArgumentException(); if (y >= 0) this.x = Math.atan2(y, x); else this.x = 2*Math.PI+Math.atan2(y, x); }

Przykad dziaania metody setOfPoint(): /** Zadanie Z21.7 */ public class Z21_7 { public static void main(String args[]) { Angle a = new Angle(0); double x = 5.0, y = 5.0;

Rozdzia 7. i Rozwizania zada

279

a.setOfPoint(x, y); System.out.printf("P(%.2f, %.2f), ", x, y); System.out.println("kt "+a.degree()+"\u00B0"); x = 0.0; y = -5.0; System.out.printf("P(%.2f, %.2f), ", x, y); a.setOfPoint(x, y); System.out.println("kt "+a.degree()+"\u00B0"); } }

Zadanie 21.8. Z21_8.java, Angle.java Kod konstruktora bdzie podobny do kodu metody setOfPoint() przedstawionej w rozwizaniu zadania 21.7. public Angle(double x, double y) { if (x == 0 && y == 0) throw new IllegalArgumentException(); if (y >= 0) this.x = Math.atan2(y, x); else this.x = 2*Math.PI+Math.atan2(y, x); }

Dziaanie konstruktora pokaemy na przykadzie dwóch punktów A(3, 4) i B(-5, 0). Pomimo cakowitych wartoci wspórzdnych punktów musimy pamita o koniecznoci ich przedstawienia w postaci liczb zmiennoprzecinkowych (kompilator na podstawie typów parametrów wywoania konstruktora dobierze waciwy kod konstruktora). /** Zadanie Z21.8 */ public class Z21_8 { public static void main(String args[]) { // punkt A(4.0, 3.0) Angle a = new Angle(4.0, 3.0); System.out.println("A(4.0, 3.0), kt "+a); // punkt B(-5.0, 0.0) Angle b = new Angle(-5.0, 0.0); System.out.println("B(-5.0, 0.0), kt "+b); } }

W aktualnej postaci klasy Angle dla punktu A(4, 3) poprawne bd konstrukcje Angle a = new Angle(4.0, 3.0), Angle a = new Angle(4.0, 3) i Angle a = new Angle(4, 3.0), którym odpowiada kt 36°52'12". Natomiast konstrukcja Angle a = new Angle(4, 3) zbuduje kt 4°3', korzystajc z konstruktora Angle(int, int) pochodzcego z rozwizania zadania 21.4.

Zadanie 21.9. Z21_9.java, Angle.java We wszystkich utworzonych metodach statycznych valueOf() na podstawie parametrów wywoania utworzymy obiekt klasy Angle i zwrócimy referencj do tego obiektu. W zalenoci od typu i liczby parametrów wejciowych wykorzystamy odpowiedni konstruktor.

280

Programowanie w jzyku Java

Metoda zwraca obiekt Angle reprezentujcy kt x radianów. public static Angle valueOf(double x) { return new Angle(x); }

Metoda zwraca obiekt reprezentujcy kt o podanej cakowitej liczbie stopni. Moemy zamieni podan liczb stopni deg na radiany i wywoa podstawowy konstruktor Angle(double), znany z zadania 20.1 (nie ma kontroli zakresu dla zmiennej deg): public static Angle valueOf(int deg) { return new Angle(deg/180.0*Math.PI); }

lub wykorzysta konstruktor z zadania 21.4 (uyty konstruktor sprawdzi, czy zmienna deg mieci si w zakresie od 0° do 360°): public static Angle valueOf(int deg) { return new Angle(deg); }

Kolejne metody statyczne zbudujemy wedug tego samego schematu: public static Angle valueOf(int deg, int min) { return new Angle((deg+min/60.0)/180.0*Math.PI); } public static Angle valueOf(int deg, int min, int sek) { return new Angle((deg+min/60.0+sek/3600.0)/180.0*Math.PI); }

lub: public static Angle valueOf(int deg, int min) { return new Angle(deg, min); } public static Angle valueOf(int deg, int min, int sek) { return new Angle(deg, min, sek); }

Zamian cigu znaków (postaci xxx°yy'zz") na obiekt klasy Angle moemy zrealizowa, uywajc metody statycznej wykorzystujcej odpowiedni konstruktor: public static Angle valueOf(String st) { return new Angle(st); }

Poniewa ten konstruktor ma pewne ograniczenia (omówione w rozwizaniu zadania 21.5), moemy spróbowa rozwiza ten problem inaczej. Szczegóow analiz kodu pozostawiamy Czytelnikowi. public static Angle valueOf(String st) { int deg = 0, min = 0, sek = 0; int pst = st.indexOf("\u00B0"); if (pst == -1) { int pmin = st.indexOf("\'"); if (pmin == -1) { int psek = st.indexOf("\"");

// stopie // nie ma symbolu stopnia // minuta ktowa // nie ma symbolu minuty // sekunda ktowa

Rozdzia 7. i Rozwizania zada

281

if (psek == -1) { // nie ma symbolu sekundy throw new IllegalArgumentException(); } else // tylko sekundy sek = Integer.parseInt(st.substring(pmin+1, psek)); } else { min = Integer.parseInt(st.substring(0, pmin)); int psek = st.indexOf("\""); // sekunda ktowa if (psek != -1) sek = Integer.parseInt(st.substring(pmin+1, psek)); } } else { // jest symbol stopnia deg = Integer.parseInt(st.substring(0, pst)); int pmin = st.indexOf("\'"); // minuta ktowa if (pmin == -1) { int psek = st.indexOf("\""); // sekunda ktowa if (psek != -1) sek = Integer.parseInt(st.substring(pst+1, psek)); } else { min = Integer.parseInt(st.substring(pst+1, pmin)); int psek = st.indexOf("\""); // sekunda ktowa if (psek != -1) sek = Integer.parseInt(st.substring(pmin+1, psek)); } } return new Angle(deg, min, sek); }

W tej postaci metoda akceptuje nastpujce cigi znaków: 15°, 15°33', 15°33'25", 15°25", 33', 33'25", 25". Za bdne uznaje cigi cyfr bez jakichkolwiek symboli (tylko liczba bez znaku stopnia, minuty lub sekundy), niebdce liczbami (zawierajce litery lub inne znaki niedozwolone w zapisie liczb), oraz poprawnie zbudowane cigi znaków ze znakiem minus na pocztku, np. –22°30'. Ten ostatni przypadek wynika z ogranicze narzuconych przez uyty konstruktor (liczba stopni od 0 do 360) — kostrutor ten jednak sprawdza poprawno liczby minut i sekund, wic nie bdziemy z niego rezygnowa. Wprowadzimy poprawki rozszerzajce zakres liczby któw na wartoci ujemne od –360 do 0. Instrukcj return new Angle(deg, min, sek) zastpimy nastpujcym cigiem instrukcji: boolean minus = false; if (deg < 0) { deg = -deg; minus = true; } Angle tmp = new Angle(deg, min, sek); if (minus) tmp.x = -tmp.x; return tmp;

W przypadku bdnych danych metoda rzuca wyjtek IllegalArgumentException, gdy wejciowy acuch znaków nie odpowiada poprawnej mierze kta, lub NumberFormat Exception, gdy w wejciowym acuchu (pomidzy symbolami jednostek) znajduje si niepoprawna posta liczby cakowitej.

282

Programowanie w jzyku Java

Pozostaje jeszcze metoda zwracajca obiekt — kt wyznaczony przez punkt P(x, y), rodek ukadu wspórzdnych i o OX: public static Angle valueOf(double x, double y) { return new Angle(x, y); }

Dziaanie zdefiniowanych metod sprawdzimy, piszc program: /** Zadanie Z21.9 */ public class Z21_9 { public static void main(String args[]) { Angle a; a = Angle.valueOf(Math.PI/4); System.out.println("a = "+a); a = Angle.valueOf(25); System.out.println("a = "+a); a = Angle.valueOf(25, 30); System.out.println("a = "+a); a = Angle.valueOf(25, 30, 17); System.out.println("a = "+a); String[] angles = { "33°", "33°52'", "33°52'17\"", "33°30\"", "52'17\"", "17\"", "1°65'", "2o°13'", "36", "15°-30'" }; Angle alfa = null; for(String x: angles) { try { alfa = Angle.valueOf(x); System.out.print("alfa = "+alfa); System.out.println(" = "+alfa.radian()+" rad"); } catch (Exception e){ System.out.println("Bdne dane: "+x+" "+e); } } a = Angle.valueOf(0.5, Math.sqrt(3)/2); System.out.println("a = "+a); } }

Zadanie 21.10. Z21_10.java, Angle.java Dodawanie lub odejmowanie obiektów sprowadza si do wykonania odpowiedniego dziaania na polu x tych obiektów i zwrócenia wyniku. public Angle add(Angle x) { return new Angle(this.x+x.x); } public Angle sub(Angle x) { return new Angle(this.x-x.x); }

Przykad ilustrujcy dziaanie metod: /** Zadanie Z21.10 */ public class Z21_10 { private static void writeln(String s, Angle x) { StringBuilder w = new StringBuilder(s);

Rozdzia 7. i Rozwizania zada

283

w.append(" = ").append(x.radian()).append(" rad"); w.append(" = ").append(x.degree()).append("\u00B0"); System.out.println(w); } public static void main(String args[]) { Angle a = new Angle(Math.PI/3); Angle b = new Angle(Math.PI/6); writeln("a", a); writeln("b", b); writeln("a+b", a.add(b)); writeln("a-b", a.sub(b)); } }

Zbudowan tu metod writeln() wykorzystamy w kilku kolejnych zadaniach (kopiujc kod metody do kodu rozwizania zadania).

Zadanie 21.11. Z21_11.java, Angle.java W metodach statycznych sum() i diff() sucych do dodawania i odejmowania obiektów Angle (miar któw) wykorzystamy jeden z tych obiektów, metody add() i sub() (pokazane w rozwizaniu zadania 21.10) i drugi obiekt podany jako parametr. public static Angle sum(Angle x, Angle y) { return x.add(y); } public static Angle diff(Angle x, Angle y) { return x.sub(y); }

Przykad ilustrujcy dziaanie metod statycznych: /** Zadanie Z21.11 */ public class Z21_11 { /* Tu wstaw kod metody: writeln */ public static void main(String args[]) { Angle a = new Angle(Math.PI/2); Angle b = new Angle(Math.PI/6); writeln("a", a); writeln("b", b); writeln("a+b", Angle.sum(a, b)); writeln("a-b", Angle.diff(a, b)); } }

Kod metody writeln pokazano w rozwizaniu zadania 21.11.

Zadanie 21.12. Z21_12.java, Angle.java Mnoenie miary kta (obiektu) przez liczb zmiennoprzecinkow lub cakowit (wielokrotno kta): public Angle mult(double a) { return new Angle(a*this.x); }

284

Programowanie w jzyku Java public Angle mult(int n) { return new Angle(n*this.x); }

Dzielenie miary kta (obiektu) przez liczb: public Angle div(double a) { if (a == 0.0) throw new ArithmeticException("Dzielenie przez 0!"); return new Angle(a*this.x/a); } public Angle div(int n) { if (n == 0) throw new ArithmeticException("Dzielenie przez 0!"); return new Angle(this.x/n); }

Przykad dziaania metod mult() i div(): /** Zadanie Z21.12 */ public class Z21_12 { /* Tu wstaw kod metody: writeln */ public static void main(String args[]) { Angle a = new Angle("22°30'"); writeln("a", a); writeln("2a", a.mult(2)); writeln("4a", a.mult(4)); writeln("1.5a", a.mult(1.5)); writeln("a/2", a.div(2)); } }

Wyniki bd wywietlanie w postaci 1.5a = 0.5890486225480862 rad = 33.75°. Jeli chcemy, aby miara stopniowa bya podawana z minutami i sekundami, to naley w kodzie metody writeln() zamieni wiersz: w.append(" = ").append(x.degree()).append("\u00B0");

na nastpujcy: w.append(" = ").append(x.toString());

Zadanie 21.13. Z21_13.java, Angle.java W metodach statycznych prod() i quot() sucych do dzielenia obiektów Angle (miar któw) przez liczb wywoamy metody mult() i div() (pokazane w rozwizaniu zadania 21.12) dla obiektu podanego jako pierwszy parametr. Drugi parametr (liczb) przekaemy jako parametr do metod mult() i div(). public static Angle prod(Angle x, double y) { return x.mult(y); } public static Angle prod(Angle x, int n) { return x.mult(n); } public static Angle quot(Angle x, double y) { return x.div(y);

Rozdzia 7. i Rozwizania zada

285

} public static Angle quot(Angle x, int n) { return x.div(n); }

Przykad dziaania metod statycznych prod() i quot(): /** Zadanie Z21.13 */ public class Z21_13 { /* Tu wstaw kod metody: writeln */ public static void main(String args[]) { Angle a = new Angle("11°15'"); writeln("a", a); writeln("2a", Angle.prod(a, 2)); writeln("4a", Angle.prod(a, 4)); writeln("1.5a", Angle.prod(a, 1.5)); writeln("a/3", Angle.quot(a, 2)); } }

Zadanie 21.14. Z21_14.java, Angle.java Definiujemy publiczne i statyczne stae typu obiektowego i nadajemy im odpowiednie wartoci. Ze wzgldu na uycie sowa final nie bdziemy mogli tym staym przypisa referencji do innych obiektów, np. Angle RADIAN = new Angle(2.0). Niestety, moliwo zmiany pola obiektu przy uyciu metod setOfXxx (zob. zadania 21.6 i 21.7) jest nadal aktualna. public public public public public public public

static static static static static static static

final final final final final final final

Angle Angle Angle Angle Angle Angle Angle

RIGHT_ANGLE = new Angle(Math.PI/2); STRAIGHT_ANGLE = new Angle(Math.PI); FULL_ANGLE = new Angle(2*Math.PI); RADIAN = new Angle(1.0); DEGREE = new Angle(1); ARCMINUTE = new Angle(0, 1); ARCSECOND = new Angle(0, 0, 1);

W przykadzie wywietlimy wartoci miar któw reprezentowanych przez zdefiniowane stae. /** Zadanie Z21.14 */ public class Z21_14 { public static void main(String args[]) { System.out.println("Kt prosty: "+Angle.RIGHT_ANGLE); System.out.println("Kt pópeny: "+Angle.STRAIGHT_ANGLE); System.out.println("Kt peny: "+Angle.FULL_ANGLE); System.out.println("1 radian: "+Angle.RADIAN); System.out.println("PI radian: "+Angle.RADIAN.mult(Math.PI)); System.out.println("1 stopie : "+Angle.DEGREE); System.out.println("1 minuta ktowa: "+Angle.ARCMINUTE); System.out.println("1 sekunda ktowa: "+Angle.ARCSECOND); } }

Zwrómy uwag na moliwo wykonywania oblicze (przy uyciu metod) zwizanych z tymi staymi, np. Angle.RADIAN.mult(Math.PI).

286

Programowanie w jzyku Java

Zadanie 21.15. Z21_15.java, Angle.java Kty dopeniajce maj wspólne jedno rami i ich suma jest ktem prostym (co moemy wyrazi wzorem D  E 90q , czyli E 90q  D ). public static Angle compl(Angle x) { if (x.x < 0.0 && x.x > RIGHT_ANGLE.x) throw new IllegalArgumentException(); return RIGHT_ANGLE.sub(x); }

Kty przylege maj wspólne jedno rami i ich suma jest ktem pópenym ( D  E czyli E 180q  D ).

180q ,

public static Angle suppl(Angle x) { if (x.x < 0.0 && x.x > STRAIGHT_ANGLE.x) throw new IllegalArgumentException(); return STRAIGHT_ANGLE.sub(x); }

Przykad oblicze z zastosowaniem metod compl() i suppl(): /** Zadanie Z21.15 */ public class Z21_15 { public static void main(String args[]) { Angle alfa = new Angle(27, 32, 15); System.out.println("alfa = "+alfa); System.out.println("Kt dopeniajcy do alfa: "+ Angle.compl(alfa)); System.out.println("Kt przylegy do alfa: "+Angle.suppl(alfa)); } }

Zadanie 21.16. Z21_16.java Do wczytywania danych wykorzystamy obiekt input klasy Scanner. Najpierw sprawdzimy, czy w strumieniu danych jest liczba cakowita. Jeli tak, to potraktujemy j jako miar kta wyraon w stopniach. W przeciwnym razie sprawdzamy, czy nie jest to liczba zmiennoprzecinkowa. Jeli wprowadzono liczb zmiennoprzecinkow, to zamieniamy t liczb (traktowan jako miar kta w stopniach) na radiany i wywoujemy odpowiedni metod. Natomiast gdy w strumieniu nie ma liczby, to spodziewamy si tekstu o postaci 23°35'25". Bdny cig znaków wygeneruje wyjtek zgoszony przez konstruktor Angle(String). private static Angle inputAngle(String s) { System.out.print("Podaj "+s); Scanner input = new Scanner(System.in); if (input.hasNextInt()) return new Angle(input.nextInt()); else if (input.hasNextDouble()) return new Angle(Math.toRadians(input.nextDouble())); else { String str = input.next(); return new Angle(str); } }

Rozdzia 7. i Rozwizania zada

287

W trójkcie równoramiennym kty przy podstawie ( E ) maj równe miary. Suma któw wewntrznych trójkta jest ktem pópenym: D  2E 180q , czyli 2E 180q  D 180q D (do oblicze wykorzystamy metod suppl()). Std E , co moemy wyrazi 2

formu Angle beta = Angle.suppl(alfa).div(2). Sprawdzenie oblicze wykonamy, dodajc miary wszystkich któw trójkta: beta.mult(2).add(alfa). import java.util.Scanner; /** Zadanie Z21.16 */ public class Z21_16 { /* Tu wstaw kod metody inputAngle. */ public static void main(String args[]) { System.out.println("Obliczanie miar któw w trójkcie równoramiennym."); Angle alfa = inputAngle("Kt przy wierzchoku trójkta równoramiennego,\nalfa = "); Angle beta = Angle.suppl(alfa).div(2); System.out.println("Kt przy wierzchoku trójkta równoramiennego, alfa = "+alfa); System.out.println("Kt przy podstawie trójkta równoramiennego, beta = "+beta); System.out.println("Sprawdzenie - suma któw w trójkcie:"+ beta.mult(2).add(alfa)); } }

Zadanie 21.17. Z21_17.java Do wprowadzania danych wykorzystamy metod inputAngle() omówion w rozwizaniu zadania 21.16. Kt lecy naprzeciw podstawy w trójkcie równoramiennym obliczymy ze wzoru D 180q  2E , gdzie E jest miar kta przylegego do podstawy. Obliczenie to zrealizujemy w nastpujcy sposób: Angle alfa = Angle.suppl(beta. mult(2)). import java.util.Scanner; /** Zadanie Z21.17 */ public class Z21_17 { /* Tu wstaw kod metody inputAngle. */ public static void main(String args[]) { System.out.println("Obliczanie miar któw w trójkcie równoramiennym."); Angle beta = inputAngle("Kt przy podstawie trójkta równoramiennego,\nalfa = "); Angle alfa = Angle.suppl(beta.mult(2)); System.out.println("Kt przy podstawie trójkta równoramiennego, beta = "+beta); System.out.println("Kt przy wierzchoku trójkta równoramiennego, alfa = "+alfa); System.out.println("Sprawdzenie - suma któw w trójkcie: "+beta.mult(2).add(alfa)); } }

Obliczenia sprawdzimy, dodajc miary któw trójkta: beta.mult(2).add(alfa).

288

Programowanie w jzyku Java

Zadanie 21.18. Z21_18.java Do wprowadzania danych (dugoci odcinków) wykorzystamy metod inputSide() (ang. side — bok wielokta). private static Double inputSide(String s) { System.out.print("Podaj "+s); Scanner input = new Scanner(System.in); return input.nextDouble(); }

Do wyznaczenia miary kta moemy zastosowa twierdzenie cosinusów (bdce uogólnieniem twierdzenia Pitagorasa), wyraone wzorem c 2 a 2  b 2  2ab cos J (kt J a2  b2  c2 . Przestawiajc cyklicznie 2ab

ley naprzeciw boku c). Std obliczymy cos J

dugoci boków, otrzymamy kolejne wzory: cos D (po uporzdkowaniu cos E

b2  b2  a 2 2bb

c2  a2  b2 2ca

a2  c2  b2 ). 2ac

Podstawiajc b = c we wzorze cos D cosD

b2  c2  a2 i cos E 2bc

2b 2  a 2 2b 2

1

b2  c2  a2 , otrzymamy 2bc a2 2b 2

Na podstawie tego wzoru obliczymy: alfa.setOfCos(1-a*a/(2*b*b));

Kt E moemy obliczy w sposób poznany w rozwizaniu zadania 21.16: Angle beta = Angle.suppl(alfa).div(2)

lub ponownie stosujc wzór wynikajcy z twierdzenia cosinusów: cos E

c2  a2  b2 2ca

b2  a 2  b2 2ba

a2 2ab

a 2b

beta.setOfCos(a/2/b);

Kod programu przedstawia si nastpujco: import java.util.Scanner; /** Zadanie Z21.18 */ public class Z21_18 { /* Tu wstaw kod metody inputSide. */ public static void main(String args[]) { System.out.println("Obliczanie miar któw w trójkcie równoramiennym."); double a = inputSide("Dugo podstawy trójkta równoramiennego,\na = "); double b = inputSide("Dugo ramienia trójkta równoramiennego,\nb = ");

Rozdzia 7. i Rozwizania zada

289

Angle alfa = new Angle(0); alfa.setOfCos(1-a*a/(2*b*b)); Angle beta = new Angle(0); beta.setOfCos(a/2/b); System.out.println("Kt przy wierzchoku trójkta równoramiennego, alfa = "+alfa); System.out.println("Kt przy podstawie trójkta równoramiennego, beta = "+beta); System.out.println("Sprawdzenie - suma któw w trójkcie: "+ beta.mult(2).add(alfa)); } }

Zadanie 21.19. Z21_19.java Do wprowadzania danych (dugoci odcinków) wykorzystamy metod inputSide() przedstawion w rozwizaniu zadania 21.18. Wysoko opuszczona na podstaw dzieli trójkt równoramienny na dwa przystajce trójkty prostoktne o przyprostoktnych o dugoci a i h (kty ostre lece naprze2

ciw tych boków maj miary D i E ). Poniewa tan D miar kta D :

2

2

a 2 h

a , to moemy obliczy 2h

alfa.setOfTan(a/2/h); // poowa kta alfa alfa = alfa.mult(2); // kt alfa

Podobnie obliczymy tan E

h a 2

2h , wic: a

beta.setOfTan(2*h/a); // kt beta

Oto kompletny kod programu: import java.util.Scanner; /** Zadanie Z21.19 */ public class Z21_19 { /* Tu wstaw kod metody inputSide. */ public static void main(String args[]) { System.out.println("Obliczanie miar któw w trójkcie równoramiennym."); double a = inputSide("Dugo podstawy trójkta równoramiennego,\na = "); double h = inputSide("Wysoko trójkta równoramiennego,\nh = "); Angle beta = new Angle(0); beta.setOfTan(2*h/a); Angle alfa = new Angle(0); alfa.setOfTan(a/2/h); alfa = alfa.mult(2); System.out.println("Kt przy wierzchoku trójkta równoramiennego, alfa = "+alfa); System.out.println("Kt przy podstawie trójkta równoramiennego, beta = "+beta);

290

Programowanie w jzyku Java System.out.println("Sprawdzenie - suma któw w trójkcie: "+ beta.mult(2).add(alfa)); } }

Zadanie 21.20. Z21_20.java Do wprowadzania danych (dugoci boków trójkta) zastosujemy metod inputSide() przedstawion w rozwizaniu zadania 21.18. Miary któw obliczymy na podstawie twierdzenia cosinusów — wzory omówiono w rozwizaniu zadania 21.18. import java.util.Scanner; /** Zadanie Z21.20 */ public class Z21_20 { /* Tu wstaw kod metody inputSide. */ public static void main(String args[]) { System.out.println("Obliczanie miar któw w trójkcie o bokach a, b i c."); double a = inputSide("Dugo boku trójkta,\na = "); double b = inputSide("Dugo boku trójkta,\nb = "); double c = inputSide("Dugo boku trójkta,\nc = "); Angle alfa = new Angle(0); alfa.setOfCos((b*b+c*c-a*a)/(2*b*c)); Angle beta = new Angle(0); beta.setOfCos((a*a+c*c-b*b)/(2*a*c)); Angle gamma = new Angle(0); gamma.setOfCos((a*a+b*b-c*c)/(2*a*b)); System.out.println("alfa = "+alfa); System.out.println("beta = "+beta); System.out.println("gamma = "+gamma); System.out.println("Sprawdzenie - suma któw w trójkcie: "+ alfa.add(beta).add(gamma)); } }

Po obliczeniu miar dwóch któw ( D i E ) miar trzeciego kta moemy wyznaczy ze wzoru J

180q  D  E :

Angle gamma = Angle.diff(Angle.STRAIGHT_ANGLE, Angle.sum(alfa, beta));

lub: Angle gamma = Angle.STRAIGHT_ANGLE.sub(alfa.add(beta));

22. Liczby rzymskie i klasa Roman Zadanie 22.1. Z22_1.java Analizujc zapis liczb rzymskich (z zakresu od 1 do 3999), moemy zauway, e symbole M (1000), C (100), X (10) i I (1) mog powtarza si do trzech razy obok siebie, a symbole D (500), L (50) i V (5) wystpuj maksymalnie jeden raz. Ponadto wane s kombinacje dwóch znaków: CM (900), CD (400), XC (90), XL (40), IX (9) i IV (4).

Rozdzia 7. i Rozwizania zada

291

Kod zamieniajcy liczb n na cig znaków w systemie rzymskim jest obszerny, ale niezbyt trudny do zrozumienia. Liczb n zmniejszamy kolejno, jeli jest to moliwe, o wartoci 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1. W zamian za to do wyniku dodajemy odpowiednio znaki M, CM, D, CD, C, XC, L, XL, X, IX, V, IV, I. Znaki M, C, X i I mog wystpi co najwyej trzykrotnie (std uycie ptli while), pozostae tylko raz. Naley zauway, e wystpienie CM wyklucza pojawienie si D, CD i C w dalszej czci cigu znaków, podobnie D wyklucza CD i C oraz CD wyklucza C (stosujemy zagniedone instrukcje warunkowe). Podobne reguy obowizuj dla zestawu znaków XC, L, XL i X oraz IX, V, IV i I. StringBuilder tmp = new StringBuilder(""); /* Znaki rzymskie M, CM, D i CD - liczby 1000, 900, 500, 400 */ while (n >= 1000) { n -= 1000; tmp.append("M"); } if (n >= 900) { n -= 900; tmp.append("CM"); } else if (n >= 500) { n -= 500; tmp.append("D"); } else if (n >= 400) { n -= 400; tmp.append("CD"); } /* Znaki rzymskie C, XC, L, XL - liczby 100, 90, 50, 40 */ while (n >= 100) { n -= 100; tmp.append("C"); } if (n >= 90) { n -= 90; tmp.append("XC"); } else if (n >= 50) { n -= 50; tmp.append("L"); } else if (n >= 40) { n -= 40; tmp.append("XL"); } /* Znaki rzymskie X, IX, V, IV - liczby 10, 9, 5, 4 */ while (n >= 10) { n -= 10; tmp.append("X"); } if (n >= 9) { n -= 9; tmp.append("IX"); } else if (n >= 5) { n -= 5; tmp.append("V"); } else if (n >= 4) { n -= 4;

292

Programowanie w jzyku Java tmp.append("IV"); } /* Znak I - liczba 1 */ while (n >= 1) { n -= 1; tmp.append("I"); }

Obiekt tmp zawiera pocztkow warto liczby n w zapisie rzymskim (aktualna warto n jest zerem). Pobieran z klawiatury warto liczby bdziemy przechowywali w zmiennej liczba (typu int). W programie utworzymy ptl ze sprawdzaniem warunku na kocu — dziaanie ptli przerwiemy, gdy zmienna liczba bdzie miaa warto 0. W ptli wczytujemy liczb cakowit i sprawdzamy, czy jej warto mieci si w zakresie od 1 do 3999. Jeli liczba jest poza tym zakresem, wywietlamy stosowny komunikat ("Liczba poza zakresem.") i przechodzimy (instrukcj continue) do sprawdzania warunku powtarzania ptli, pomijajc kod zamiany n na liczb w systemie rzymskim. import java.util.Scanner; /** Zadanie Z22.1 */ public class Z22_1 { public static void main(String args[]) { Scanner input = new Scanner(System.in); System.out.println("Rzymski sposób zapisu liczb od 1 do 3999"); int liczba; do { System.out.print("Podaj liczb (0 - koniec oblicze ), n = "); liczba = input.nextInt(); if (liczba < 1 || liczba > 3999) { System.out.println("Liczba poza zakresem."); continue; } int n = liczba; /* Tu wstaw kod zamiany n na liczb w systemie rzymskim */ System.out.println(liczba+" = "+tmp.toString()); } while (liczba !=0); } }

Stosujc dwie tablice z wartociami wybranych liczb rzymskich i odpowiadajcych im wartoci dziesitnych: private static final String[] rz = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; private static final int[] ar = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};

moemy uproci kodowanie liczb w systemie rzymskim. StringBuilder tmp = new StringBuilder(""); for(int i = 0; i= ar[i]) {

Rozdzia 7. i Rozwizania zada

293

n -= ar[i]; tmp.append(rz[i]); } }

Na pocztku warto zmiennej n jest równa konwertowanej liczbie i mieci si w zakresie od 1 do 3999. Elementy w obu tablicach s uporzdkowane od wartoci najwikszej (1000) do najmniejszej (1). Bierzemy kolejne wartoci i dopóki liczba jest wiksza od tej wartoci, dopóty do cigu znaków rzymskich dodajemy odpowiedni symbol, a liczb zmniejszamy o t warto. Po dojciu do koca tablicy mamy poprawnie zakodowan liczb w systemie rzymskim.

Zadanie 22.2. Z22_2.java Oprócz tablic (wprowadzonych w rozwizaniu zadania 22.1): private static final String[] rz = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; private static final int[] ar = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};

dodamy tablic lp zawierajc maksymaln liczb powtórze symboli z tablicy rz: private static final int[] lp = {3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3};

oraz tablic err z niedozwolonymi kombinacjami symboli: private static final String[] err = {"CMD", "CMC", "XCL", "XCX", "IXV", "IXI", "DCD", "CDC", "LXL", "XLX", "VIV", "IVI"};

Cig symboli CMD oznaczaby liczb 900+500 = 1400, któr poprawnie zapisujemy w postaci MCD (1000+400). Kolejny cig CMC mona interpretowa jako 900+100 = 1000, ale to nie ma sensu, bo 1000 zapisujemy jednym znakiem M. Podobnie jest z pozostaymi cigami uznanymi za bdne i zapisanymi w tablicy err. Najpierw sprawdzimy, czy podany cig znaków (roman) nie zawiera niedozwolonych cigów zapisanych w tablicy err. Przegldajc tablic bdnych sekwencji znaków, sprawdzamy, czy wystpuj w acuchu roman. Jeli tak si zdarzy, to metoda indexOf() zwróci warto -1 i zostanie zgoszony wyjtek. for (String x: err) if (roman.indexOf(x) != -1) throw new ArithmeticException("Niewaciwy cig znaków: "+x+ " w "+roman);

Jeli cig wejciowy nie zawiera niedozwolonych sekwencji, moemy ustali pocztkow warto wyniku (tmp) i zainicjowa indeks analizowanego znaku rzymskiego (pobieranego z tablicy rz). int tmp = 0; int index = 0;

// indeks analizowanego znaku rzymskiego

Przegldamy w ptli (for (int i = 0; i < 13; i++)) tablic rz.

294

Programowanie w jzyku Java

Zerujemy (int powt = 0) licznik powtórze symbolu rz[i]. W ptli (while) sprawdzamy, ile razy symbol rzymski (rz[i]) pojawia si w cigu znaków roman. Kada pozytywna odpowied powoduje zwikszenie zmiennej tmp (tmp += ar[i]) o warto (ar[i]) odpowiadajc sprawdzanemu symbolowi (rz[i]), zwikszenie indeksu o rozmiar symbolu (index += rz[i].length()) i zwikszenie licznika powtórze (++powt). Badany na pocztku ptli while warunek roman.startsWith(rz[i], index) sprawdza, czy w acuchu roman na pozycji o indeksie index rozpoczyna si cig znaków rz[i] — wynik jest wartoci logiczn (true lub false). Po wyjciu z ptli while sprawdzamy, czy symbol rz[i] nie wystpi zbyt wiele razy (if (powt > lp[i])...). Jeli liczba powtórze przekracza dozwolon liczb (zapisan w tabeli lp), to zgaszany jest wyjtek. Po wyjciu z ptli for dokonujemy jeszcze jednego sprawdzenia: if (index != roman.length()) throw new ArithmeticException("Niewaciwa liczba rzymska: "+roman);

Rozbieno pomidzy wartoci zmiennej index i dugoci acucha roman wiadczy o niepoprawnej budowie liczby rzymskiej. Poniszy kod zamienia acuch znaków roman na liczb tmp lub zgasza wyjtek: for (String x: err) if (roman.indexOf(x) != -1) throw new ArithmeticException("Niewaciwy cig znaków: "+ x+" w "+roman); int tmp = 0; // warto pocztkowa wyniku int index = 0; // indeks analizowanego znaku for (int i = 0; i < 13; i++) { int powt = 0; while (roman.startsWith(rz[i], index)) { tmp += ar[i]; index += rz[i].length(); ++powt; } if (powt > lp[i]) throw new ArithmeticException("Za duo znaków: "+rz[i]+" w "+roman); } if (index != roman.length()) throw new ArithmeticException("Niewaciwa liczba rzymska: "+roman);

W gównej ptli programu (do {...} while(true);) wczytujemy liczb rzymsk, dokonujemy jej zamiany na liczb dziesitn i wywietlamy wynik. Ptla zostanie przerwana (wiadomie przez uytkownika) po wprowadzeniu pustego acucha znaków lub w wyniku bdnej postaci liczby (wystpi wyjtek). Ewentualne przechwycenie i obsuenie wyjtku pozostawimy Czytelnikowi. import java.util.Scanner; /** Zadanie Z22.2 */ public class Z22_2 { /* Tu wstaw cztery tablice: rz, ar, lp i err. */ public static void main(String args[]) { Scanner input = new Scanner(System.in);

Rozdzia 7. i Rozwizania zada

295

System.out.println("Odczytywanie liczb rzymskich"); String roman; do { System.out.print("Podaj liczb rzymsk: "); roman = input.next(); if (roman.equals("")) break; /* Tu wstaw kod zamiany liczb rzymskich na dziesitne. */ System.out.println(roman+" = "+tmp); } while (true); } }

Zadanie 22.3. Z22_3.java Na podstawie rozwizania zadania 22.1 moemy zbudowa nastpujc metod: private static String decToRoman(int n) { if (n < 1 || n > 3999) throw new ArithmeticException("Liczba poza zakresem: "+n); String[] rz = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; int[] ar = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; StringBuilder tmp = new StringBuilder(""); for(int i = 0; i= ar[i]) { n -= ar[i]; tmp.append(rz[i]); } } return tmp.toString(); }

Tablice niezbdne do konwersji liczb dziesitnych na rzymskie zostay umieszczone w kodzie metody. Zatem kod metody jest kompletny i moe w tej postaci by przenoszony do dowolnej aplikacji. Dziaanie metody pokaemy dla kilkunastu liczb wybranych w sposób losowy. /** Zadanie Z22.3 */ public class Z22_3 { /* Tu wstaw kod metody decToRoman() */ public static void main(String args[]) { System.out.println("Zapis liczb w systemie rzymskim"); for(int i = 0; i < 15; ++i) { int n = (int)(1+3999*Math.random()); System.out.println(n+" = "+decToRoman(n)); } } }

Definicje tablic rz i ar moemy umieci w kodzie klasy (tak jak w zadaniu 21.1 lub 21.2) i usun z kodu metody decToRoman().

296

Programowanie w jzyku Java

Zadanie 22.4. Z22_4.java Utworzymy klas RN z dwoma polami: r typu String (do przechowywania symboli rzymskich) oraz d typu int (do przechowywania wartoci dziesitnej symbolu). Klas definiujemy z modyfikatorem final — po tej klasie nie bdzie mona dziedziczy. Pola klasy definiujemy z modyfikatorami protected i final (do pól bdzie dostp, ale po utworzeniu obiektu nie bdzie mona zmieni wartoci pól). Konstruktor deklarujemy jako metod prywatn. Poza klas RN konstruktor nie bdzie dostpny. Wykorzystamy go tylko do utworzenia trzynastoelementowej tablicy rn (statycznej i finalnej), czyli jedynego elementu udostpnionego przez zdefiniowan klas. final class RN { protected final String r; protected final int d; private RN(String r, int d) { this.r = r; this.d = d; }; static final RN[] rn = {new RN("M", 1000), new RN("CM", 900), new RN("D", 500), new RN("CD", 400), new RN("C", 100), new RN("XC", 90), new RN("L", 50), new RN("XL", 40), new RN("X", 10), new RN("IX", 9), new RN("V", 5), new RN("IV", 4), new RN("I", 1)}; }

Z tej tablicy moe korzysta metoda decToRoman(): private static String decToRoman(int n) { StringBuilder tmp = new StringBuilder(""); for(int i = 0; i= RN.rn[i].d) { n -= RN.rn[i].d; tmp.append(RN.rn[i].r); } } return tmp.toString(); }

Pokazujc dziaanie metody, wywietlimy potgi liczby 2 zapisane w systemie rzymskim. /** Zadanie Z22.4 */ /* Tu wstaw kod klasy RN.*/ public class Z22_4 { /* Tu wstaw kod metody decToRoman(). */ public static void main(String args[]) { System.out.println("Potgi liczby 2 w systemie rzymskim"); int i = 0, n = 1; while (i < 13) { System.out.println("2^"+i+" = "+decToRoman(n)); ++i; n *= 2; } } }

Rozdzia 7. i Rozwizania zada

297

Kody obu klas (RN i Z22_4) znajdoway si w jednym pliku: Z22_4.java. Po kompilacji otrzymujemy dwa pliki: RN.class i Z22_4.class — kada skompilowana klasa znajduje si w odrbnym pliku.

Zadanie 22.5. Z22_5.java Wykorzystajmy klas RN i metod decToRoman() z rozwizania zadania 22.4. Na podstawie rozwizania zadania 22.2 moemy zbudowa metod: private int int for

static int romanToDec(String s) { tmp = 0; index = 0; // indeks analizowanego znaku (int i = 0; i < 13; i++) while (s.startsWith(RS.rn[i].r, index)) { tmp += RS.rn[i].d; index += RS.rn[i].r.length(); } if (!s.equals(decToRoman(tmp)) || tmp > 3999) throw new ArithmeticException("Niewaciwa liczba rzymska: "+s); return tmp;

}

Dziaanie metody sprawdzimy dla kilku liczb rzymskich zapisanych w tablicy. /** Zadanie Z22.5 */ /* Tu wstaw kod klasy RN lub w biecym folderze umie skompilowany plik klasy (RN.class). */ public class Z22_5 { /* Tu wstaw kod metody decToRoman(). */ /* Tu wstaw kod metody romanToDec(). */ public static void main(String args[]) { System.out.println("Odczytywanie liczb w systemie rzymskim"); String[] test = {"XXVII", "CCXLV", "III", "MMMCMXCIX", "MXXIV"}; for(String r: test) System.out.println(r+" = "+romanToDec(r)); } }

Zadanie 22.6. Z22_6.java, Roman.java Na pocztek tworzymy klas z jednym prywatnym polem (int n;) i publicznym konstruktorem z jednym parametrem — liczb cakowit. Jeli podana liczba nie mieci si w zakresie od 1 do 3999, to wygenerowany zostanie wyjtek. public class Roman { private int n; public Roman(int n) { if(n < 1 || n > 3999) throw new ArithmeticException("Liczba poza zakresem");

298

Programowanie w jzyku Java else this.n = n; } }

Klas moemy rozszerzy o kolejne metody — metod zwracajc warto dziesitn liczby naturalnej przechowywanej w obiekcie: public int intValue() { return n; }

oraz metod statyczn zwracajc obiekt klasy Roman odpowiadajcy podanej liczbie cakowitej: public static Roman valueOf(int n) { return new Roman(n); }

Z klasy w tej postaci jest jeszcze niewielki poytek. Do jej kodu dodamy wewntrzn klas RN (z rozwizania zadania 22.4), dopisujc w nagówku modyfikator static: private static final class RN { final String r; final int d; private RN(String r, int d) { this.r = r; this.d = d; }; static final RN[] rn = {new RN("M", 1000), new RN("CM", 900), new RN("D", 500), new RN("CD", 400), new RN("C", 100), new RN("XC", 90), new RN("L", 50), new RN("XL", 40), new RN("X", 10), new RN("IX", 9), new RN("V", 5), new RN("IV", 4), new RN("I", 1)}; }

oraz metody statyczne korzystajce z tablicy rn zdefiniowanej w tej klasie (tym razem zadeklarowane jako publiczne): decToRoman() (zadanie 22.4) i romanToDec() (zadanie 22.5). public static String decToRoman(int n) { StringBuilder tmp = new StringBuilder(""); for(int i = 0; i= RN.rn[i].d) { n -= RN.rn[i].d; tmp.append(RN.rn[i].r); } } return tmp.toString(); } public static int romanToDec(String s) { int tmp = 0; int index = 0; // indeks analizowanego znaku for (int i = 0; i < 13; i++) while (s.startsWith(RN.rn[i].r, index)) { tmp += RN.rn[i].d;

Rozdzia 7. i Rozwizania zada

299

index += RN.rn[i].r.length(); } if (!s.equals(decToRoman(tmp)) || tmp > 3999) throw new ArithmeticException("Niewaciwa liczba rzymska: " +s); return tmp; }

Korzystajc z metody decToRoman(), moemy przesoni metod toString() dziedziczon z klasy Object: @Override public String toString() { return decToRoman(this.n); }

Natomiast metod romanToDec() moemy zastosowa do zbudowania konstruktora tworzcego nowy obiekt na podstawie liczby zapisanej w systemie rzymskim lub statycznej metody nadajcej obiektowi now warto utworzon na podstawie acucha znaków. public Roman(String s) { this.n = romanToDec(s);; } public static Roman valueOf(String s) { return new Roman(s); }

Teraz moemy uzna klas Roman za kompletn. Klasa RN jest klas wewntrzn klasy Roman i jej kod ródowy znajduje si w pliku Roman.java. Po kompilacji otrzymujemy dwa pliki: Roman.class i Roman$RN.class — kada skompilowana klasa znajduje si w odrbnym pliku. Klasa RN jest dostpna jednak wycznie wewntrz klasy Roman.

Przykad wykorzystania obiektów i metod klasy Roman: /** Zadanie Z22.6 */ public class Z22_6 { public static void main(String args[]) { Roman a = new Roman(2012); System.out.println(a.intValue()+" = "+a); Roman b = Roman.valueOf("XLIV"); System.out.println(b.intValue()+" = "+b); a = Roman.valueOf(137); System.out.println(a.intValue()+" = "+a); Roman c = new Roman("MMMCMXCIX"); System.out.println(c.intValue()+" = "+c); System.out.println("175 = "+Roman.decToRoman(175)); System.out.println("XXXIV = "+Roman.romanToDec("XXXIV")); System.out.println("MMMM = "+Roman.romanToDec("MMMM")); } }

300

Programowanie w jzyku Java

Zadanie 22.7. Z22_7.java Ustalimy liczb pyta (int pytania = 10) i maksymaln warto wylosowanej liczby (int zakres = 50). Na podstawie tych parametrów utworzymy tablic a, wypenion wylosowanymi i niepowtarzajcymi si wartociami. W tym celu wykorzystamy metod rndUniqueArray() z klasy MyRandomArray. Wystarczy, e do biecego folderu skopiujemy skompilowany kod klasy (MyRandomArray.class) lub kod ródowy klasy (MyRandomArray.java). Nastpnie wartoci elementów tablicy zwikszymy o 1; w ten sposób otrzymamy liczby z zakresu od 1 do 50 (zmienna zakres). Ustalimy liczb punktów (int pkt = 0). W ptli zamieniamy liczb z tablicy na obiekt klasy Roman. Wypisujemy liczb rzymsk w konsoli. Uytkownik podaje warto dziesitn tej liczby. Jeli podana warto jest równa liczbie rzymskiej ( n == roman.int Value()), powikszamy liczb punktów (++pkt). Po zakoczeniu ptli wywietlimy wynik — sum zdobytych punktów. import java.util.Scanner; /** Zadanie Z22.7 */ public class Z22_7 { public static void main(String args[]) { Scanner input = new Scanner(System.in); int pytania = 10; // 10 pyta int zakres = 50; // najwiksza liczba 50 int[] a = MyRandomArray.rndUniqueArray(pytania, zakres); MyRandomArray.addToArray(a, 1); int pkt = 0; Roman roman; for(int i = 0; i < pytania; ++i) { roman = Roman.valueOf(a[i]); System.out.print(roman+" = "); int n = input.nextInt(); if (n == roman.intValue()) ++pkt; } System.out.println("Wynik: "+pkt+" z "+pytania+"."); } }

Zadanie 22.8. Z22_8.java Rozwizanie jest podobne do rozwizania zadania 22.7. Rónica polega na odwróceniu czynnoci w gównej ptli programu. Wywietlamy warto dziesitn liczby, a uytkownik wprowadza rzymsk posta tej liczby. Do porównania acuchów znaków — wprowadzonego przez uytkownika (s) i przedstawiajcego liczb rzymsk (roman.toString()) — uyjemy metody equals() z klasy String. int pkt = 0; Roman roman; for(int i = 0; i < pytania; ++i) { roman = Roman.valueOf(a[i]); System.out.print(a[i]+" = "); String s = input.next(); if (s.equals(roman.toString())) ++pkt; } System.out.println("Wynik: "+pkt+" z 10.");

Rozdzia 7. i Rozwizania zada

301

23. Trójmian kwadratowy i klasa QuadratPoly Zadanie 23.1. Z23_1.java, QuadratPoly.java W klasie definiujemy trzy prywatne pola a, b i c typu int, odpowiadajce tradycyjnemu zapisowi postaci trójmianu kwadratowego. Konstruktor z trzema parametrami (a, b i c) pozwala na tworzenie obiektów klasy QuadratPoly. Podanie wartoci 0 jako pierwszego parametru spowoduje zgoszenie wyjtku. Metody value() obliczajce warto trójmianu dla podanego argumentu definiujemy w dwóch wariantach — dla argumentu cakowitego n lub dla zmiennoprzecinkowego argumentu x. Warto trójmianu liczymy wedug wzoru: ax 2  bx  c

a ( x  b) x  c

(tzw. schemat Hornera umoliwiajcy szybkie obliczanie wartoci wielomianu dowolnego stopnia). public class QuadratPoly { private int a, b, c; public QuadratPoly() {} public QuadratPoly(int a, int b, int c) { if (a == 0) throw new ArithmeticException("Niedozwolony parametr a = 0!"); this.a = a; this.b = b; this.c = c; } public int value(int n) { return (a*n+b)*n+c; } public double value(double x) { return (a*x+b)*x+c; } }

W przykadzie demonstrujemy obliczanie wartoci trójmianu kwadratowego 2 x 2  3x  1 dla cakowitych argumentów z przedziau  5, 5 oraz prób skonstruowania obiektu QuadratPoly z niedozwolon wartoci parametru (a = 0). /** Zadanie Z23.1 */ public class Z23_1 { public static void main(String args[]) { QuadratPoly w = new QuadratPoly(2, -3, 1); for(int i = -5; i < 6; ++i) System.out.printf("w(%d) = %d\n", i, w.value(i)); QuadratPoly v = new QuadratPoly(0, 3, -1); } }

302

Programowanie w jzyku Java

Zadanie 23.2. Z23_2.java, QuadratPoly.java Wanym pojciem charakteryzujcym trójmian kwadratowy jest wyrónik ' Aby tej wielkoci nie oblicza wielokrotnie, dodamy do klasy pole:

b 2  4ac .

private int delta;

W konstruktorze obliczymy warto wyrónika i przechowamy j w polu delta. this.delta = b*b-4*a*c;

Tworzymy publiczn metod zwracajc warto wyrónika (getDelta()). public int getDelta() { return delta; }

W przykadzie utworzymy dwa obiekty QuadratPoly (trójmiany kwadratowe) i obliczymy ich wyróniki. /** Zadanie Z23.2 */ public class Z23_2 { public static void main(String args[]) { QuadratPoly w1 = new QuadratPoly(2, -3, 1); System.out.println("Delta: "+w1.getDelta()); QuadratPoly w2 = new QuadratPoly(1, 2, 1); System.out.println("Delta: "+w2.getDelta()); } }

Zadanie 23.3. Z23_3.java, QuadratPoly.java Metoda toString() zdefiniowana w klasie QuadratPoly przesoni metod dziedziczon z klasy Object. Zwrócony acuch znaków bdzie znanym z matematyki zapisem trójmianu. Wspóczynnik a jest róny od zera, dla a = –1 na pocztku acucha umiecimy tylko znak liczby (–), dla a = 1 wspóczynnik pominiemy, w pozostaych przypadkach wypisujemy warto wspóczynnika. Symbol x 2 w trybie tekstowym zapiszemy w sposób umowny: x^2. Drugi czon trójmianu wypisujemy tylko wtedy, gdy wspóczynnik b nie jest zerem. Dla wartoci dodatnich wypisujemy znak +, warto wspóczynnika b i symbol x; dla wartoci ujemnych wypisujemy tylko warto wspóczynnika b i symbol x. Podobnie postpujemy w przypadku wspóczynnika c. @Override public String toString() { StringBuilder wz = new StringBuilder(); if (a == -1) wz.append("-"); else if (a != 1) wz.append(a); wz.append("x^2");

Rozdzia 7. i Rozwizania zada

303

if (b == -1) wz.append("-x"); else if (b == 1) wz.append("+x"); else if (b > 1) wz.append("+").append(b).append("x"); else if (b < -1) wz.append(b).append("x"); if (c > 0) wz.append("+").append(c); else if (c < 0) wz.append(c); return wz.toString(); }

Dziaanie metody sprawdzimy dla dwóch przykadowych trójmianów. Zauwamy, e w wyraeniu "w(x) = "+w lub v+" = 0" metoda jest wywoywana przez operator konkatenacji (+). Nie musimy w tej sytuacji jawnie wywoywa metody (np. "w(x) = "+w.toString()). /** Zadanie Z23.3 */ public class Z23_3 { public static void main(String args[]) { QuadratPoly w = new QuadratPoly(2, -3, 1); System.out.println("w(x) = "+w); QuadratPoly v = new QuadratPoly(1, 0, -4); System.out.println(v+" = 0"); } }

Zadanie 23.4. Z23_4.java, QuadratPoly.java Przydatn informacj jest znak wyrónika trójmianu kwadratowego. Do klasy dodamy metod zwracajc znak wyrónika; zrobimy to wedug nastpujcego schematu: –1 — delta ujemna, 0 — delta równa zero, 1 — delta dodatnia. public int sgnDelta() { return (delta > 0)?1:(delta < 0)?-1:0; }

Wspóczynniki wielomianu wprowadzimy z klawiatury, korzystajc z obiektu input klasy Scanner. Zwrómy uwag na sposób wczytywania wspóczynnika a. Wczytywanie powtarzamy do skutku, a podana warto bdzie róna od zera. Nie jest to potrzebne w przypadku wczytywania wspóczynników b i c. Jeli wyrónik (delta) jest ujemny, to równanie nie ma pierwiastków rzeczywistych (0 pierwiastków). Gdy wyrónik jest równy zero, mamy jeden pierwiastek rzeczywisty (podwójny). Dla wyrónika dodatniego s dwa róne pierwiastki rzeczywiste. Moemy zauway zwizek pomidzy liczb pierwiastków i znakiem wyrónika wyraonym w postaci liczby (liczba pierwiastków jest równa 1+w.sgnDelta()).

304

Programowanie w jzyku Java import java.util.Scanner; /** Zadanie Z23.4 */ public class Z23_4 { public static void main(String args[]) { Scanner input = new Scanner(System.in); System.out.println("Podaj wspóczynniki trójmianu kwadratowego ax^2+bx+c"); int a, b, c; do { System.out.print("a = "); a = input.nextInt(); } while (a == 0); System.out.print("b = "); b = input.nextInt(); System.out.print("c = "); c = input.nextInt(); QuadratPoly w = new QuadratPoly(a, b, c); System.out.println("Trójmian kwadratowy: "+w); System.out.println("Liczba rzeczywistych pierwiastków: "+ (1+w.sgnDelta())); } }

Odpowied moemy sformuowa, uywajc instrukcji warunkowej: System.out.print("Trójmian kwadratowy: "+w+" "); int sgn = w.sgnDelta(); if (sgn == 1) System.out.println("ma dwa róne pierwiastki rzeczywiste."); else if (sgn == 0) System.out.println("ma jeden pierwiastek rzeczywisty dwukrotny."); else System.out.println("nie ma pierwiastków rzeczywistych.");

lub wyraenia warunkowego: int znak = w.sgnDelta(); System.out.println("Liczba rzeczywistych pierwiastków: "+ (znak == -1)?0:(znak == 0)?:1:2);

Kolejn moliwo utworzenia odpowiedzi stwarza nam instrukcja wyboru. String s = ""; switch (w.sgnDelta()) { case 1: s = "ma dwa róne pierwiastki rzeczywiste."; break; case 0: s = "ma jeden pierwiastek rzeczywisty dwukrotny."; break; case -1: s = "nie ma pierwiastków rzeczywistych."; break; } System.out.print("Trójmian kwadratowy: "+w+" "+s);

Rozdzia 7. i Rozwizania zada

305

Zadanie 23.5. Z23_5.java, QuadratPoly.java Na podstawie wzorów x1

b ' i x2 2a

b ' budujemy dwie metody (getX1() 2a

i getX2()) zwracajce wartoci rzeczywistych pierwiastków trójmianu kwadratowego, o ile takie wartoci istniej ( ' t 0 ). Jeli wyrónik trójmianu jest ujemny ( ' 0 ), to metoda Math.sqrt(delta) zwraca warto NaN. Tak sam warto zwracaj metody getX1() i getX2(). public double getX1() { return (-b-Math.sqrt(delta))/(2*a); } public double getX2() { return (-b+Math.sqrt(delta))/(2*a); }

Wspóczynniki równania wprowadzimy, stosujc obiekt input klasy Scanner. Wprowadzanie danych mona dodatkowo zabezpieczy przed bdami, przechwytujc i obsugujc wyjtki pochodzce od metody nextInt(). Pozostawimy to do decyzji Czytelnika. W rozwizaniu zadania wykorzystano metod sgnDelta() i instrukcj wyboru switch (zob. objanienia z rozwizania zadania 23.4). import java.util.Scanner; /** Zadanie Z23.5 */ public class Z23_5 { public static void main(String args[]) { Scanner input = new Scanner(System.in); System.out.println("Podaj wspóczynniki równania ax^2+bx+c = 0"); int a, b, c; do { System.out.print("a = "); a = input.nextInt(); } while (a == 0); System.out.print("b = "); b = input.nextInt(); System.out.print("c = "); c = input.nextInt(); QuadratPoly w = new QuadratPoly(a, b, c); System.out.print("Równanie "+w+" = 0 "); switch (w.sgnDelta()) { case 1: System.out.println("ma dwa pierwiastki rzeczywiste:"); System.out.println("x = "+w.getX1()); System.out.println("x = "+w.getX2()); break; case 0: System.out.println("ma pierwiastek rzeczywisty dwukrotny:"); System.out.println("x = "+w.getX1()); break; case -1: System.out.println("nie ma pierwiastków rzeczywistych."); break; } } }

306

Programowanie w jzyku Java

Zadanie 23.6. Z23_6.java, QuadratPoly.java Wykresem trójmianu kwadratowego ax 2  bx  c, a z 0 jest parabola o wierzchoku '· § b , ¨ ¸ . Metoda getP() zwraca pierwsz wspórzdn (x) wierzchoka tej para4a ¹ © 2a boli, a metoda getQ() — drug wspórzdn (y). public double getP() { return -(double)b/(2*a); } public double getQ() { return -(double)delta/(4*a); }

Pierwsze z powyszych zda, opisujcych to rozwizanie, formuujemy w programie przykadowym dla konkretnego trójmianu, wykorzystujc informacje zwrócone przez metody toString(), getP() i getQ(). /** Zadanie Z23.6 */ public class Z23_6 { public static void main(String args[]) { QuadratPoly w = new QuadratPoly(2, -3, 1); StringBuilder s = new StringBuilder("Wykresem trójmianu "); s.append(w).append(" jest parabola o wierzchoku ("); s.append(w.getP()).append(", ").append(w.getQ()).append(")."); System.out.println(s); } }

Zadanie 23.7. Z23_7.java, QuadratPoly.java Uytkownik nie ma dostpu do prywatnych pól klasy. W wielu sytuacjach potrzebuje wiedzie, jaki znak ma wspóczynnik a trójmianu. Metoda isAPositive() zwraca warto true, gdy wspóczynnik a jest dodatni, i warto false w przeciwnym wypadku (warto wyraenia logicznego a > 0). public boolean isAPositive() { return a > 0; }

Jeli a jest dodatnie, to zbiorem wartoci trójmianu ax 2  bx  c jest przedzia q,  f , a dla ujemnego wspóczynnika a — przedzia  f, q , gdzie q  /** Zadanie Z23.7 */ public class Z23_7 { public static void main(String args[]) { QuadratPoly w = new QuadratPoly(-2, -3, 1); StringBuilder s = new StringBuilder(); if (w.isAPositive()) s.append(""); System.out.println("Zbiór wartoci trójmianu "+w+": "+s); } }

Zadanie 23.8. Z23_8.java Wprowadzenie danych zorganizujemy tak jak w rozwizaniu zadania 23.4. Jeli a b warto minimaln 2a ' ' , a dla ujemnego wspóczynnika a — warto maksymaln ymax  . ymin  4a 4a b ) Budujc odpowied , uyjemy wartoci zwracanych przez metody getP() (  2a ' ) oraz wyraenia warunkowego zwracajcego odpowiednie sowo (zai getQ() (  4a lene od znaku parametru a): (w.isAPositive())?"minimaln":"maksymaln". Odpowied budujemy z wykorzystaniem obiektu s i metod klasy StringBuilder.

jest dodatnie, to trójmian ax 2  bx  c osiga w punkcie x 

QuadratPoly w = new QuadratPoly(a, b, c); StringBuilder s = new StringBuilder("Trójmian kwadratowy "); s.append(w).append(" osiga dla x = ").append(w.getP()); s.append(" warto ").append((w.isAPositive())?"minimaln":"maksymaln"); s.append(" y = ").append(w.getQ()).append("."); System.out.println(s);

Zadanie 23.9. Z23_9.java, QuadratPoly.java Metoda getVertex() zwraca wspórzdne wierzchoka paraboli w postaci acucha znaków, np. (–2, 1.5). public String getVertex() { return "("+getP()+", "+getQ()+")"; }

Wynik zwracany przez metod moe by wykorzystany podczas konstruowania opisów waciwoci trójmianu. /** Zadanie Z23.9 */ public class Z23_9 { public static void main(String args[]) { QuadratPoly w = new QuadratPoly(2, -5, 1); System.out.println("Wierzchoek paraboli y = "+w+ " ma wspórzdne "+w.getVertex()+"."); } }

Zadanie 23.10. Z23_10.java, QuadratPoly.java W rozwizaniu zadania 23.7 mona byo zobaczy sposób przedstawiania zbioru wartoci trójmianu kwadratowego. Na tej podstawie budujemy metod zwracajc w postaci acucha znaków przedzia liczbowy bdcy zbiorem wartoci funkcji (przeciwdziedzin).

308

Programowanie w jzyku Java public String getCodomain() { StringBuilder s = new StringBuilder(); if (isAPositive()) s.append(""); return s.toString(); }

Wynik zwracany przez metod moe by wykorzystany podczas opisywania waciwoci trójmianu kwadratowego. /** Zadanie Z23.10 */ public class Z23_10 { public static void main(String args[]) { QuadratPoly w = new QuadratPoly(-2, -3, 1); System.out.println("Zbiór wartoci trójmianu "+w+ ": "+w.getCodomain()); w = new QuadratPoly(2, 3, -5); System.out.println("Zbiór wartoci trójmianu "+w+ ": "+w.getCodomain()); } }

Zadanie 23.11. Z23_11.java Korzystajc z metod klasy QuadratPoly i rozwiza poprzednich zada, moemy sporzdzi kompletny opis funkcji kwadratowej. /** Zadanie Z23.11 */ public class Z23_11 { private static void opisFunkcji(QuadratPoly w) { System.out.println("Funkcja kwadratowa f(x) = "+w); System.out.println("1. Dziedzina: R (zbiór liczb rzeczywistych)"); System.out.println("2. Zbiór wartoci: "+w.getCodomain()); System.out.println("3. Przedziay monotonicznoci:"); StringBuilder s = new StringBuilder(); s.append(" - funkcja jest "); s.append((w.isAPositive())?"malejca":"rosnca"); s.append(" w przedziale (-oo, "); s.append(w.getP()).append(">\n - funkcja jest "); s.append((w.isAPositive())?"rosnca":"malejca"); s.append(" w przedziale 0"); /* Deklaracja i wczytanie wspóczynników a, b i c */ QuadratPoly w = new QuadratPoly(a, b, c); System.out.println("Nierówno "+w+" > 0 "); StringBuilder s = new StringBuilder(); switch (w.sgnDelta()) { case 1: if (w.isAPositive()) { s.append("(-oo, ").append(w.getX1()); s.append(") lub ("); s.append(w.getX2()).append(", +oo)"); } else { s.append("(").append(w.getX2()).append(", "); s.append(w.getX1()).append(")"); } break; case 0: if (w.isAPositive()) s.append("R\\{").append(w.getX1()).append("}"); else s.append("{} (zbiór pusty)"); break; case -1: if (w.isAPositive()) s.append("R (zbiór liczb rzeczywistych)"); else s.append("{} (zbiór pusty)"); break; } System.out.println("Zbiór rozwiza Z = "+s); } }

Zadanie 23.13. Z23_13.java Podobnie jak w rozwizaniu zadania 23.12, mamy sze przypadków wyznaczonych przez znaki wspóczynnika a i wyrónika '. W porównaniu z zadaniem 23.12 do zbioru rozwiza doczamy dodatkowo miejsca zerowe trójmianu — w nierównoci operator jest wiksze od 0 (>) zosta zastpiony operatorem jest wiksze lub równe ( t ). '>0 a>0

'=0

 f, x

1

a 0), zbiorem jednoelementowym (' = 0) lub zbiorem pustym (' < 0). Do klasy QuadratPoly doczamy metod: public String solutionQE() { StringBuilder s = new StringBuilder("{"); switch (sgnDelta()) {

312

Programowanie w jzyku Java case 1: s.append(getX1()).append(", ").append(getX2()).append("}"); break; case 0: s.append(getX1()).append("}"); break; case -1: s.append("}"); break; } return s.toString(); }

Dziaanie metody pokaemy, rozwizujc trzy róne równania kwadratowe: /** Zadanie Z23.15 */ public class Z23_15 { public static void main(String args[]) { QuadratPoly w = new QuadratPoly(2, -3, -1); System.out.println("Równanie kwadratowe "+w+ " = 0\nZbiór rozwiza Z ="+w.solutionQE()+"\n"); w = new QuadratPoly(1, -4, 4); System.out.println("Równanie kwadratowe "+w+ " = 0\nZbiór rozwiza Z ="+w.solutionQE()+"\n"); w = new QuadratPoly(4, 1, 3); System.out.println("Równanie kwadratowe "+w+ " = 0\nZbiór rozwiza Z ="+w.solutionQE()+"\n"); } }

Zadanie 23.16. Z23_16.java, QuadratPoly.java Na podstawie rozwizania 23.12 budujemy w klasie QuadratPoly prywatn metod solutionQIe1() zwracajc w postaci acucha znaków rozwizanie nierównoci kwadratowej ax 2  bx  c ! 0, a z 0 . private String solutionQIe1() { StringBuilder s = new StringBuilder(); switch (sgnDelta()) { case 1: if (isAPositive()) { s.append("(-oo, ").append(getX1()); s.append(") lub ("); s.append(getX2()).append(", +oo)"); } else { s.append("(").append(getX2()).append(", "); s.append(getX1()).append(")"); } break; case 0: if (isAPositive()) s.append("R\\{").append(getX1()).append("}"); else s.append("{}"); break; case -1:

Rozdzia 7. i Rozwizania zada

313

if (isAPositive()) s.append("R"); else s.append("{}"); break; } return s.toString(); }

Korzystajc z rozwizania zadania 23.13, budujemy w klasie QuadratPoly prywatn metod solutionQIe2() zwracajc w postaci acucha znaków rozwizanie nierównoci kwadratowej ax 2  bx  c t 0, a z 0 . private String solutionQIe2() { StringBuilder s = new StringBuilder(); switch (sgnDelta()) { case 1: if (isAPositive()) { s.append("(-oo, ").append(getX1()).append("> lub ", "=" i "")) return this.solutionQIe1(); else if (typ.equals(">=")) return this.solutionQIe2(); else if (typ.equals("=", "= 0"); System.out.println("Rozwizanie Z = "+r2.solutionQIe(">=")); } }

24. Rozwizania zada — liczby zespolone Zadanie 24.1. Z24_1.java, Complex.java Klasa Complex zawiera dwa prywatne pola re (cz rzeczywista liczby, ang. real) i im (cz urojona liczby, ang. imaginary) typu double. public class Complex { private double re, im; }

Do klasy doczymy trzy podstawowe konstruktory. Pierwszy, bezparametrowy konstruktor zastpuje konstruktor domylny i buduje obiekt Complex odpowiadajcy liczbie 0+0i (re = 0; im = 0;). public Complex() {}

Drugi konstruktor, z jednym parametrem x typu double, buduje obiekt (liczb zespolon) odpowiadajcy liczbie rzeczywistej x (x+0i — z zerow czci urojon). public Complex(double x) { this.re = x; this.im = 0; }

Konstruktor z dwoma parametrami, x i y typu double, buduje obiekt odpowiadajcy liczbie zespolonej x+yi. public Complex(double x, double y) { this.re = x; this.im = y; }

Metody setRe() i setIm() wywoane przez obiekt ustawiaj cz rzeczywist lub urojon (stosownie do nazwy metody) liczby zespolonej reprezentowanej przez ten obiekt na warto podan jako parametr (x typu double). public void setRe(double x) { this.re = x; } public void setIm(double x) { this.im = x; }

Rozdzia 7. i Rozwizania zada

319

Metoda toString()utworzona w klasie Complex przesoni metod toString() dziedziczon z klasy Object i zwróci liczb zespolon (reprezentowan przez obiekt Complex) w postaci acucha znaków, np. –2.4+3i, 0–3i, 4.5 itp. @Override public String toString() { StringBuffer tmp = new StringBuffer(); tmp.append(re); if (im > 0) { tmp.append("+"); tmp.append(im); tmp.append("i"); } else if (im < 0) { tmp.append(im); tmp.append("i"); } return tmp.toString(); }

W przykadzie pokazujcym dziaanie podstawowych konstruktorów i metod klasy Complex niezbdne objanienia zawarto w komentarzach. /** Zadanie Z24.1 */ public class Z24_1 { public static void main(String[] args) { /* Konstruktor domylny */ Complex a = new Complex(); System.out.println("a = "+a); /* Zmiana czci rzeczywistej liczby zespolonej */ a.setRe(-7.2); System.out.println("a = "+a); /* Zmiana czci urojonej liczby zespolonej */ a.setIm(4.5); System.out.println("a = "+a); /* Liczba rzeczywista */ Complex b = new Complex(5.3); System.out.println("b = "+b); /* Liczba zespolona */ Complex c = new Complex(2, -3); System.out.println("c = "+c); /* Liczba urojona */ Complex d = new Complex(0, 4); System.out.println("d = "+d); } }

Zadanie 24.2. Z24_2.java Jeli ' 0 , to równanie ma pierwiastki rzeczywiste, które moemy zapisa w postaci zespolonej x+0i. Gdy '  0 , równanie kwadratowe az 2  bz  c 0, a z 0 , ma dwa pierwiastki zespolone: z

b '  i lub z 2a 2a

public class Z24_2 { public static void main(String[] args) { double a = 2.0, b = -1.0, c = 0.5; double delta = b*b-4*a*c;

b ' i.  2a 2a

320

Programowanie w jzyku Java if (delta < 0) { double re = -b/(2*a); double im = Math.sqrt(-delta)/(2*a); Complex z1 = new Complex(re, -im); System.out.println("z1 = "+z1); Complex z2 = new Complex(re, im); System.out.println("z2 = "+z2); } else if (delta > 0) { Complex z1 = new Complex((-b-Math.sqrt(delta))/(2*a)); System.out.println("z1 = "+z1); Complex z2 = new Complex((-b+Math.sqrt(delta))/(2*a)); System.out.println("z2 = "+z2); } else { Complex z = new Complex(-b/(2*a)); System.out.println("Pierwiastek dwukrotny z = "+z); } } }

Zadanie 24.3. Z24_3.java, Complex.java Sum dwóch liczb zespolonych obliczamy ze wzoru a  bi  c  di

a  c  b  d i .

public Complex add(Complex x) { return new Complex(this.re+x.re, this.im+x.im); }

Podobnie obliczymy rónic liczb zespolonych: a  bi  c  di

a  c  b  d i .

public Complex sub(Complex x) { return new Complex(this.re-x.re, this.im-x.im); }

Kod metod add() i sub() doczamy do klasy Complex i sprawdzamy ich dziaanie, wykonujc kilka przykadowych oblicze. public class Z24_3 { public static void main(String[] args) { Complex a = new Complex(4.5, 7); System.out.println("a = "+a); Complex b = new Complex(-2, 3.3); System.out.println("b = "+b); System.out.println("a+b = "+a.add(b)); System.out.println("b+a = "+b.add(a)); System.out.println("a-b = "+a.sub(b)); System.out.println("a-1 = "+a.sub(new Complex(1))); } }

Zadanie 24.4. Z24_4.java, Complex.java Niech z oznacza liczb zespolon a  bi . Liczb przeciwn (ang. opposite lub additive inverse) do liczby z jest liczba  z  a  bi . Jeli nie ma konfliktów pomidzy nazwami zmiennych i pól klasy, to moemy stosowa zapis skrócony: re zamiast this.re oraz im zamiast this.im.

Rozdzia 7. i Rozwizania zada

321

public Complex opp() { return new Complex(-re, -im); }

Liczb sprzon (ang. conjugate) do liczby zespolonej z nazywamy liczb z

a  bi .

public Complex conj() { return new Complex(re, -im); }

Liczb odwrotn (ang. reciprocal lub multiplicative inverse) moemy wyznaczy ze 1 z a  bi a  bi a b  2 wzoru z 1 i. 2 2 2 2 z z ˜ z a  bi a  bi a  b a b a  b2 public Complex rec() { double sc = re*re+im*im; return new Complex(re/sc, -im/sc); }

Kilka prostych przykadów ilustruje dziaanie zdefiniowanych metod. public class Z24_4 { public static void main(String[] args) { Complex a = new Complex(2, -3.5); System.out.println("a = "+a); System.out.println("Liczba przeciwna: "+a.opp()); System.out.println("a+(-a) = "+a.add(a.opp())); System.out.println("Liczba sprzona: "+a.conj()); System.out.println("Liczba odwrotna: "+a.rec()); } }

Zadanie 24.5. Z24_5.java, Complex.java Mnoenie liczb zespolonych wykonamy na podstawie wzoru:

a  bi c  di

ac  adi  bci  bdi 2

ac  bd  ad  bc i .

public Complex mult(Complex x) { return new Complex(re*x.re-im*x.im, re*x.im+im*x.re); }

Dzielenie przez liczb zespolon zastpimy mnoeniem przez jej odwrotno (skorzystamy z metody rec() podanej w rozwizaniu zadania 24.4). public Complex div(Complex x) { return this.mult(x.rec()); }

Dziaanie metod zademonstrujemy, obliczajc kwadrat liczby zespolonej ( a.mult(a)) oraz iloraz dwóch liczb zespolonych. public class Z24_5 { public static void main(String[] args) { Complex a = new Complex(0, 1); System.out.println("a = "+a);

322

Programowanie w jzyku Java System.out.println("a*a = "+a.mult(a)); Complex b = new Complex(3, 4); System.out.println("b = "+b); System.out.println("b/a = "+b.div(a)); } }

Zadanie 24.6. Z24_6.java, Complex.java Do klasy Complex dodajemy trzy stae odpowiadajce liczbom 0, 1 i jednostce urojonej i. public static final Complex ZERO = new Complex(0); public static final Complex ONE = new Complex(1); public static final Complex I = new Complex(0, 1);

Wykonujc seri oblicze, pokaemy waciwoci zdefiniowanych staych w arytmetyce liczb zespolonych. public class Z24_6 { public static void main(String[] args) { System.out.println("Wasnoci staych 0, 1 oraz i"); System.out.println("a = "+Complex.ZERO); System.out.println("0+1 = "+Complex.ZERO.add(Complex.ONE)); System.out.println("0+i = "+Complex.ZERO.add(Complex.I)); Complex b = new Complex(2, -3); System.out.println("b = "+b); System.out.println("b*0 = "+b.mult(Complex.ZERO)); System.out.println("b*1 = "+b.mult(Complex.ONE)); System.out.println("b*i = "+b.mult(Complex.I)); System.out.println("Potgi jednostki urojonej i"); System.out.println("i^1 = "+Complex.I); System.out.println("i^2 = "+Complex.I.mult(Complex.I)); System.out.println("i^3 = "+Complex.I.mult(Complex.I). mult(Complex.I)); System.out.println("i^4 = "+Complex.I.mult(Complex.I). mult(Complex.I).mult(Complex.I)); } }

Zadanie 24.7. Z24_7.java, Complex.java Modu (bezwzgldn warto) liczby zespolonej z ru z

a  bi moemy obliczy ze wzo-

a2  b2 .

public double abs() { return Math.sqrt(re*re+im*im); }

Liczb zespolon z = a+bi (w postaci kanonicznej) interpretujemy geometrycznie jako punkt P o wspórzdnych (a, b) w prostoktnym (kartezjaskim) ukadzie wspórzdnych. Argument liczby zespolonej (rónej od 0+0i) jest ktem (najczciej podawanym w radianach) pomidzy promieniem PO (O — rodek ukadu wspórzdnych) i osi OX. Zaleno pomidzy wspórzdnymi (a, b) i argumentem liczby zespolonej z = a+bi przedstawia si nastpujco:

Rozdzia 7. i Rozwizania zada

Arg z

323

­ §b· °arctan¨ a ¸, gdy a ! 0 © ¹ ° ° §b· °arctan¨ ¸  S , gdy a 0 i b t 0 ©a¹ ° ° °arctan§¨ b ·¸  S , gdy a 0 i b 0 ® ©a¹ ° ° S , gdy a 0 i b ! 0 °2 ° ° S , gdy a 0 i b ! 0 ° 2 °0, gdy a 0 i b 0 ¯

Korzystajc z metody Math.atan(), staej Math.PI oraz instrukcji warunkowych, moemy odpowiedni metod zbudowa. W klasie Math mamy zdefiniowan metod atan2(), która nam to zadanie uatwia. public double arg() { return Math.atan2(im, re); }

Naley doda, e pojcie argumentu nie jest jednoznaczne. Nasza metoda arg() wyznacza tzw. argument gówny liczby zespolonej. Pozostae argumenty tej liczby róni si od gównego o wielokrotno 2S . W przykadzie obliczymy modu i argument dla dwóch wybranych liczb zespolonych 4–3i i 4+4i. Argument drugiej z tych liczb podajemy w stopniach. public class Z24_7 { public static void main(String[] args) { Complex a = new Complex(4, -3); System.out.println("a = "+a); System.out.println("|a| = "+a.abs()); System.out.println("Arg(a) = "+a.arg()); a.setIm(4); System.out.println("a = "+a); System.out.println("|a| = "+a.abs()); System.out.println("Arg(a) = "+Math.toDegrees(a.arg())+"°"); } }

Zadanie 24.8. Z24_8.java, Complex.java Metody getRe() i getIm() zwracaj warto pól obiektu, czyli cz rzeczywist (re) i cz urojon (im) liczby zespolonej reprezentowanej przez obiekt. public double getRe() { return re; } public double getIm() { return im; }

324

Programowanie w jzyku Java

Dziaanie metod pokaemy na przykadzie wybranej liczby zespolonej. public class Z24_8 { public static void main(String[] args) { Complex a = new Complex(4, -3); System.out.println("a = "+a); System.out.println("Cz rzeczywista liczby a: "+a.getRe()); System.out.println("Cz urojona liczby a: "+a.getIm()); } }

Zadanie 24.9. Z24_9.java, Complex.java Wywoanie metody print() spowoduje wywietlenie na standardowym wyjciu wartoci obiektu w postaci acucha znaków. public void print() { System.out.print(this.toString()); }

Wiersz kodu System.out.print(this.toString()) moemy zapisa krócej: System. out.print(this) lub System.out.print(toString()). Gdy w konsoli zostanie wypisana liczba zespolona, kursor pozostanie w biecym wierszu. Jeli bdziemy potrzebowali, aby kursor przeszed na pocztek nowego wiersza, to wystarczy uy drugiej metody: public void println() { System.out.println(this.toString()); }

Poniewa niejednokrotnie chcemy poprzedzi wywietlan warto dodatkowym tekstem, to zbudujemy wersje tych metod z parametrem typu String (wypisywanym przed liczb). public void print(String str) { System.out.print(str+this); } public void println(String str) { System.out.println(str+this); }

Dysponujc tymi metodami, moemy w programach korzystajcych z obiektów klasy Complex zamiast instrukcji System.out.println("a = "+a) pisa a.println("a = ") — efekt bdzie taki sam. Dokadniej ilustruje to przykad: public class Z24_9 { public static void main(String[] args) { Complex a = new Complex(4, -3); System.out.println("a = "+a); System.out.print("a = "); a.println(); a.println("a = "); a.add(a).println("a+a = "); } }

Rozdzia 7. i Rozwizania zada

325

Zadanie 24.10. Z24_10.java, Complex.java Konstruktor kopiujcy odczytuje pola obiektu podanego jako parametr i tworzy nowy obiekt z takimi samymi wartociami pól. public Complex(Complex z) { this.re = z.re; this.im = z.im; }

Dwie liczby zespolone s równe wtedy i tylko wtedy, gdy równe s ich czci rzeczywiste i urojone. Porównanie wartoci obiektów moemy ograniczy wycznie do obiektów klasy Complex: public boolean equals(Complex z) { return re == z.re && im == z.im; }

lub wzorujc si na rozwizaniu zadania 20.18, zbudowa metod przesaniajc metod Object.equals(). @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || !(o instanceof Complex)) return false; Complex c = (Complex) o; if (this.re == c.re && this.im == c.im) return true; else return false; }

Przesaniajc metod equals(), powinnimy przedefiniowa metod hashCode()2: @Override public int hashCode() { int result = 17; long tmp = Double.doubleToLongBits(re); result = 31*result+(int)(tmp^(tmp>>>32)); tmp = Double.doubleToLongBits(im); result = 31*result+(int)(tmp^(tmp>>>32)); return result; }

Przykad przedstawia dziaanie konstruktora kopiujcego i metody equals(). Proponujemy Czytelnikowi uruchomienie przykadowego kodu i jego dokadn analiz. public class Z24_10 { public static void main(String[] args) { System.out.println("Dwa nowe obiekty a i b"); Complex a = new Complex(2, -3); a.println("a = "); Complex b = new Complex(a); b.println("b = ");

2

Opracowane na podstawie: J. Bloch, Java. Efektywne programowanie. Wydanie II, Helion 2009.

326

Programowanie w jzyku Java System.out.print("Porównanie referencji a == b: "); System.out.println(a == b); System.out.print("Porównanie obiektów a.equals(b): "); System.out.println(a.equals(b)); System.out.println("Nowy obiekt c i podstawienie c = a"); Complex c; c = a; c.println("c = "); System.out.print("Porównanie referencji a == c: "); System.out.println(a == c); System.out.print("Porównanie obiektów a.equals(c): "); System.out.println(a.equals(c)); System.out.println("Zmiana wartoci c zmienia warto a"); c.setRe(0); c.println("c = "); a.println("a = "); System.out.println("Zmiana wartoci b nie zmienia wartoci a"); b.setRe(5); b.println("b = "); a.println("a = "); System.out.println("Nowy obiekt d, kopia obiektu c"); Complex d = new Complex(c); // konstruktor kopiujcy c.println("c = "); d.println("d = "); System.out.print("Porównanie referencji c == d: "); System.out.println(c == d); System.out.print("Porównanie obiektów c.equals(d): "); System.out.println(c.equals(d)); } }

Zadanie 24.11. Z24_11.java, Complex.java Zaczniemy od sprawdzenia, czy w cigu znaków wystpuje symbol jednostki urojonej (i). Jeli nie ma jednostki urojonej, to wprowadzony acuch znaków (s) moe by liczb rzeczywist (re = Double.parseDouble(s); im = 0;), np. "–2.4". Bd podczas parsowania tekstu sygnalizuje, e wprowadzona liczba nie jest poprawna (np. "2o3"). Gdy jednostka urojona i wystpuje w acuchu, powinna w nim by ostatnim znakiem. Jeli tak nie jest, to acuch nie jest poprawn liczb zespolon (np. "2+i5" lub "3.4–5ix"). Pozosta nam jeszcze do rozwaenia acuch typu „ r a r bi ”, gdzie znaki a i b oznaczaj cigi cyfr — liczby cakowite lub dziesitne. Usuwamy ostatni znak i do analizy pozostaje nam cig znaków o postaci „ r a r b ”. Moliwe s róne sytuacje opisane w komentarzach do kodu. public Complex(String s) { int n = s.indexOf("i"); if (n == -1) { // Nie ma jednostki urojonej - liczba rzeczywista. re = Double.parseDouble(s); im = 0; } else {

Rozdzia 7. i Rozwizania zada

327

// Jest jednostka urojona if (n == s.length()-1) { // i jest ostatnim znakiem. s = s.substring(0, s.length()-1); if (s.isEmpty() || s.equals("+")) {// liczba "i" lub "+i" re = 0; im = 1; return; } if (s.equals("-")) { // liczba "-i" re =0; im = -1; return; } int znakPlus = s.lastIndexOf("+"); if (znakPlus == s.length()-1) { // liczba "a+i" lub bd re = Double.parseDouble(s.substring(0, znakPlus)); im = 1; return; } int znakMinus = s.lastIndexOf("-"); if (znakMinus == s.length()-1) { // liczba "a-i" lub bd re = Double.parseDouble(s.substring(0, znakMinus)); im = -1; return; } if (znakPlus == -1 && znakMinus == -1) {// "bi" lub bd re = 0; im = Double.parseDouble(s); return; } else if (znakMinus > 0 || znakPlus > 0) { if (znakMinus > 0) { // liczba o postaci "-2-3i", "+2-3i", "2-3i" lub bd re = Double.parseDouble(s.substring(0, znakMinus)); im = Double.parseDouble(s.substring(znakMinus)); return; } if (znakPlus > 0) { // liczba o postaci "-2+3i", "+2+3i", "2+3i" lub bd re = Double.parseDouble(s.substring(0, znakPlus)); im = Double.parseDouble(s.substring(znakPlus)); return; } } } else // i nie jest ostatnim znakiem - bdne dane. throw new ArithmeticException("Bdna liczba: "+s); } }

Dziaanie metody sprawdzimy dla kilku przykadowych cigów znaków, przedstawiajcych róne moliwe przypadki. public class Z24_11 { public static void main(String[] args) { String[] test = {"1", "+2.5", "-3.5", "i", "+i", "-i", "2+3i", "-2+3i", "2-3i", "-2+3i", "+2-3i", "+2+3i", "1+i", "2-i", "-4e-02-2i", "2+4ix"}; for(String x: test) {

328

Programowanie w jzyku Java Complex z = new Complex(x); System.out.println("\""+x+"\"\t --> "+z); } } }

Zadanie 24.12. Z24_12.java, Complex.java Do zbudowania metody statycznej parseComplex() zamieniajcej acuch znaków na obiekt klasy Complex moemy wykorzysta (skopiowa) kod z rozwizania zadania 24.11 lub uy konstruktora. static public Complex parseComplex(String s) { return new Complex(s); }

Dziaanie metody sprawdzimy dla kilku przykadowych cigów znaków (zapisanych w tablicy test), podobnie jak w rozwizaniu zadania 24.11. for(String x: test) System.out.println("\""+x+"\"\t --> "+Complex.parseComplex(x));

Zadanie 24.13. Z24_13.java Przyjmujemy warto pocztkow p = 1+0i. Dla wykadnika n > 0 w ptli powtarzamy obliczenie p = p.mult(a), co odpowiada wyraeniu a n 1 a n ˜ a . Dla n < 0 n 1 § 1 · . Mnoenie przez 1 zastpujemy dzieleniem przez stosujemy wzór a n ¨ ¸ n a a ©a¹ a, czyli w ptli powtarzamy dziaanie p = p.div(a). Pozostaje przypadek wykadnika równego 0 i wtedy zwracamy jako wynik pocztkow warto p = 1+0i. public class Z24_13 { public static Complex power(Complex a, int n) { Complex p = Complex.ONE; if (n > 0) for(int i = 0; i < n; ++i) p = p.mult(a); else if (n < 0) for(int i = 0; i < -n; ++i) p = p.div(a); return p; } public static void main(String[] args) { Complex x = new Complex(1, -1); for(int i = -5; i < 10; ++i) { System.out.print("("+x.toString()+")^"+i+" = "); power(x, i).println(); } } }

Demonstrujc dziaanie metody, obliczylimy kilka potg liczby 1–i.

Rozdzia 7. i Rozwizania zada

329

Zadanie 24.14. Z24_14.java, Complex.java Metod statyczn kopiujemy bezporednio z rozwizania zadania 24.13 do klasy Complex: public static Complex power(Complex a, int n) { Complex p = Complex.ONE; if (n > 0) for(int i = 0; i < n; ++i) p = p.mult(a); else if (n < 0) for(int i = 0; i < -n; ++i) p = p.div(a); return p; }

Kopiujemy kod metody po raz drugi, usuwany sowo kluczowe static i parametr a z nagówka funkcji. W ciele metody zmienn a zastpujemy sowem kluczowym this. public Complex power(int n) { Complex p = Complex.ONE; if (n > 0) for(int i = 0; i < n; ++i) p = p.mult(this); else if (n < 0) for(int i = 0; i < -n; ++i) p = p.div(this); return p; }

Obliczymy potgi jednostki urojonej i o wykadnikach od –4 do 9. Do oblicze wykorzystamy obie metody. public class Z24_14 { public static void main(String[] args) { Complex x = new Complex(0, 1); for(int i = -4; i < 5; ++i) System.out.println("("+x+")^"+i+" = "+Complex.power(x, i)); for(int i = 5; i < 10; ++i) System.out.println("("+x+")^"+i+" = "+x.power(i)); } }

Zadanie 24.15. Complex.java, DemoComplex_15.java Zgodnie z definicj a 2 a ˜ a kwadrat liczby zespolonej reprezentowanej przez obiekt a wyznaczymy, wykonujc mnoenie a.mult(a). public Complex sqr() { return this.mult(this); }

Podobnie moemy zbudowa metod statyczn:

330

Programowanie w jzyku Java public static Complex sqr(Complex z) { return z.mult(z); }

lub: public static Complex sqr(Complex z) { return z.sqr(); }

Aby obliczy pierwiastek drugiego stopnia towe x  yi 2

a  bi , rozwiemy równanie kwadra-

­° x 2  y 2 a  bi . Po przeksztaceniu otrzymamy ukad równa: ® °¯2 xy b

Z ukadu równa otrzymamy x

a2  b2  a i y 2

H

a

.

a 2  b2  a , gdzie H ozna2

cza znak czci urojonej liczby podpierwiastkowej (znak b: –1 lub 1). Std mamy dwa pierwiastki r x  yi . Przypadek b = 0 naley rozpatrywa osobno. Dla a t 0 otrzymamy w wyniku liczb rzeczywist r a , a dla a

0 liczb urojon r i  a .

public Complex sqrt() { if (im == 0) if (re >= 0) return new Complex(Math.sqrt(re)); else return new Complex(0.0, Math.sqrt(-re)); else return new Complex(Math.sqrt((abs()+re)/2), Math.signum(im)*Math.sqrt((abs()-re)/2)); }

Drugi (nastpny) pierwiastek jest liczb przeciwn (do poprzedniego): public Complex nextSqrt() { return this.sqrt().opp(); }

Po niewielkich poprawkach otrzymamy metody statyczne obliczajce pierwiastek drugiego stopnia z liczby zespolonej: public static Complex sqrt(Complex z) { if (z.im == 0) if (z.re >= 0) return new Complex(Math.sqrt(z.re)); else return new Complex(0.0, Math.sqrt(-z.re)); else return new Complex(Math.sqrt((z.abs()+z.re)/2), Math.signum(z.im)*Math.sqrt((z.abs()-z.re)/2)); } public static Complex nextSqrt(Complex z) { return sqrt(z).opp(); }

Rozdzia 7. i Rozwizania zada

331

W przykadzie sprawdzamy na wybranych wartociach liczb zespolonych zdefiniowane metody sqr() i sqrt(), skadajc te funkcje

a 2 lub

a . 2

public class Z24_15 { public static void main(String[] args) { /* Podnoszenie pierwiastka kwadratowego do kwadratu */ new Complex( 1, -2).sqrt().sqr().println(); new Complex( 1, 2).sqrt().sqr().println(); new Complex(-1, -2).sqrt().sqr().println(); new Complex(-1, 2).sqrt().sqr().println(); /* Pierwiastkowanie kwadratu liczby zespolonej */ new Complex( 1, -2).sqr().sqrt().println(); new Complex( 1, 2).sqr().sqrt().println(); new Complex(-1, -2).sqr().sqrt().println(); // liczba przeciwna new Complex(-1, -2).sqr().nextSqrt().println(); new Complex(-1, 2).sqr().sqrt().println(); // liczba przeciwna new Complex(-1, 2).sqr().nextSqrt().println(); /* Metody statyczne sqr i sqrt */ Complex x = new Complex(2.5, -4); System.out.println("x = "+x); Complex y = Complex.sqr(x); System.out.println("y = x^2 = "+y); System.out.println("z = sqrt(y) = "+Complex.sqrt(y)); System.out.println("z = sqrt(y) = "+Complex.nextSqrt(y)); } }

Zadanie 24.16. Z24_16.java, Complex.java Aby wywietli cz rzeczywist i urojon liczby zespolonej w konsoli, uyjemy metody System.out.printf(). Zwrómy uwag na specyfikator "%f%+fi". Wystpujcy w acuchu znak plus (+) powoduje, e przed drug liczb (czci urojon) bdzie wywietlany znak liczby — plus równie. public void printf() { System.out.printf("%f%+fi", this.re, this.im); } public void printf(String str) { System.out.printf(str+"%f%+fi", this.re, this.im); } public void printlnf() { System.out.printf("%f%+fi\n", this.re, this.im); } public void printlnf(String str) { System.out.printf(str+"%f%+fi\n", this.re, this.im); }

Czytelnik moe zmodyfikowa te metody, dodajc parametr okrelajcy precyzj (liczb miejsc po przecinku) lub przekazujc specyfikator. W przykadzie porównajmy sposób dziaania metody println() (z zadania 24.9) i zdefiniowanej metody printf(). public class Z24_16 { public static void main(String[] args) {

332

Programowanie w jzyku Java Complex a = new Complex(-5); a.println("Metoda println: \ta = "); a.printlnf("Metoda printlnf:\ta = "); a.sqrt().println("Metoda println: \tsqrt(a) = "); a.sqrt().printlnf("Metoda printlnf:\tsqrt(a) = "); } }

Zadanie 24.17. Z24_17.java Rozwizywanie równania kwadratowego o wspóczynnikach zespolonych w zbiorze liczb zespolonych sprowadza si do obliczenia wyrónika ( ' b 2  4ac ) i wyznaczenia pierwiastków równania na podstawie wzoru z r

b ' . 2a

public class Z24_17 { public static void main(String[] args) { /* Wspóczynniki zespolone równania az^2+bz+c = 0 */ Complex a = new Complex(1, -2); a.printlnf("a = "); Complex b = new Complex(0, 1); b.printlnf("b = "); Complex c = new Complex(-1); c.printlnf("c = "); System.out.println("Równanie ("+a+")z^2+("+b+")z+"+a+" = 0"); /* Obliczenie pierwiastków kwadratowych */ Complex delta = b.sqr().sub(new Complex(4).mult(a).mult(c)); delta.printlnf("delta = "); Complex z1 = b.opp().sub(delta.sqrt()).div(new Complex(2). mult(a)); z1.printlnf("z1 = "); Complex z2 = b.opp().add(delta.sqrt()).div(new Complex(2). mult(a)); z2.printlnf("z2 = "); System.out.println("Sprawdzenie:"); a.mult(z1.sqr()).add(b.mult(z1)).add(c).printlnf("w(z1) = "); a.mult(z2.sqr()).add(b.mult(z2)).add(c).printlnf("w(z2) = "); } }

Zadanie 24.18. Oznaczmy x Suma: x  y

a  bi oraz y

c  di .

a  bi  c  di a  c  b  d i .

public static Complex sum(Complex x, Complex y) { return new Complex(x.re+y.re, x.im+y.im); }

Rónica: x  y

a  bi  c  di a  c  b  d i .

public static Complex diff(Complex x, Complex y) { return new Complex(x.re-y.re, x.im-y.im); }

Rozdzia 7. i Rozwizania zada

Iloczyn: x ˜ y

333

a  bi ˜ c  di ac  bd  ad  bc i .

public static Complex prod(Complex x, Complex y) { return new Complex(x.re*y.re-x.im*y.im, x.re*y.im+x.im*y.re); }

Iloraz:

x y

a  bi c  di

a  bi ˜ c  di ac  bd  bc  ad i c  di ˜ c  di c d 2

2

ac  bd bc  ad  i. c2  d 2 c2  d 2

public static Complex quot(Complex x, Complex y) { double s = x.re*x.re+y.re*y.re; return new Complex((x.re*y.re+x.im*y.im)/s, (x.im*y.re-x.re*y.im)/s); }

Jak wykorzysta w programie zdefiniowane metody, pokazuje przykad: public class Z24_18 { public static void main(String[] args) { Complex a = new Complex(1, -2); a.printlnf("a = "); Complex b = new Complex(0, 1); b.printlnf("b = "); Complex c = Complex.sum(a, b); c.printlnf("a+b = "); c = Complex.diff(a, b); c.printlnf("a-b = "); c = Complex.prod(a, b); c.printlnf("a·b = "); c = Complex.quot(a, b); c.printlnf("a/b = "); } }

Zadanie 24.19. Z24_19.java, PolarComplex.java Klasa PolarComplex zawiera dwa prywatne pola r (promie, modu liczby zespolonej, r t 0 ) i fi (kt, argument liczby zespolonej) oraz domylny konstruktor (nadajcy obiektowi warto 0). public class PolarComplex { private double r, fi; public PolarComplex() {} }

Do klasy doczmy konstruktor z parametrami r i fi: public PolarComplex(double r, double fi) { if (r < 0) throw new ArithmeticException("Niewaciwy parametr: "+r); this.r = r; this.fi = fi; }

oraz konstruktor z jednym parametrem r, przyjmujcy domylne M 0 (this.fi = 0.0) dla liczby rzeczywistej nieujemnej r, M S (this.fi = -Math.PI) dla liczby ujemnej r.

334

Programowanie w jzyku Java public PolarComplex(double r) { this.r = Math.abs(r); if (r >= 0.0) this.fi = 0.0; else this.fi = -Math.PI; }

Zamian wspórzdnych biegunowych na kartezjaskie zrealizujemy za pomoc wzo­ x r cos M ru ® : ¯ y r sin M public Complex toComplex() { return new Complex(r*Math.cos(fi), r*Math.sin(fi)); }

Wartoci pól obiektu (r i fi) typu double zamienimy na acuchy znaków reprezentujce liczby z szecioma miejscami po przecinku, z których nastpnie budujemy wynik (acuch wyjciowy). Do formatowania liczby uywamy obiektu formatter klasy DecimalFormat (dziedziczcej z klasy java.text.NumberFormat — niezbdne jest importowanie odpowiednich klas w klasie PolarComplex): import java.text.DecimalFormat; import java.text.NumberFormat;

Przesaniamy metod toString() z klasy Object: @Override public String toString() { NumberFormat formatter = new DecimalFormat("#0.000000"); String s1 = formatter.format(this.r); String s2 = formatter.format(this.fi); return "[r="+s1+"; fi="+s2+"]"; }

Dziaanie konstruktorów i metody toComplex() pokaemy dla kilku wybranych wartoci. /** Zadanie Z24.19 */ public class Z24_19 { public static void main(String[] args) { PolarComplex a = new PolarComplex(); System.out.println("a = "+a.toComplex()+" = "+a); PolarComplex b = new PolarComplex(5.4); System.out.println("b = "+b.toComplex()+" = "+b); PolarComplex c = new PolarComplex(-1); System.out.println("c = "+c.toComplex()+" = "+c); c.toComplex().printlnf("c = "); PolarComplex d = new PolarComplex(Math.sqrt(2), Math.PI/4); System.out.println("d = "+d.toComplex()+" = "+d); d.toComplex().printlnf("d = "); } }

Rozdzia 7. i Rozwizania zada

335

Zadanie 24.20. Z24_20.java, PolarComplex.java Do klasy PolarComplex dodajemy konstruktor kopiujcy, który tworzy nowy obiekt PolarComplex, reprezentujcy t sam warto zespolon co obiekt przekazany jako parametr (efektem porównania tych obiektów metod equals() powinna by warto true, natomiast porównanie referencji (==) da wynik false). public PolarComplex(PolarComplex z) { r = z.r; fi = z.fi; }

Drugi konstruktor tworzy nowy obiekt PolarComplex, reprezentujcy liczb zespolon podan jako parametr typu Complex ( r z i M arg z ). public PolarComplex(Complex z) { r = z.abs(); fi = z.arg(); }

W przykadowym programie tworzymy obiekt a klasy PolarComplex, reprezentujcy liczb zespolon i (jednostk urojon) — w postaci kanonicznej 0+i, w postaci bieguS nowej §¨1, ·¸ . Obiekt b jest utworzony przez konstruktor kopiujcy z obiektu a. Za© 2¹ mieniajc te obiekty na obiekty klasy Complex (metoda toComplex()), zauwaymy rozbienoci na dalszych miejscach po przecinku (rzdu 10–16). Podobn precyzj uzyskamy podczas konwersji liczby 3–4i i innych liczb zespolonych. /** Zadanie Z24.20 */ public class Z24_20 { public static void main(String[] args) { PolarComplex a = new PolarComplex(1, Math.PI/2); System.out.println("a = "+a.toComplex()); PolarComplex b = new PolarComplex(a); System.out.println("b = "+b.toComplex()); PolarComplex c = new PolarComplex(new Complex(3, -4)); System.out.println("c = "+c.toComplex()); } }

Zadanie 24.21. Z24_21.java, Complex.java W klasie Complex dodajemy konstruktor budujcy nowy obiekt Complex, odpowiadajcy liczbie zespolonej przekazanej jako parametr typu PolarComplex. Do zmiany typu wykorzystamy metod toComplex() z klasy PolarComplex (Complex tmp = z.toComplex()). Nastpnie wartoci pól obiektu tmp skopiujemy do pól nowego obiektu. public Complex(PolarComplex z) { Complex tmp = z.toComplex(); this.re = tmp.re; this.im = tmp.im; }

336

Programowanie w jzyku Java

Do konwersji obiektu Complex na obiekt PolarComplex zbudujemy metod toPolar Complex() ( r z i M arg z ). public PolarComplex toPolarComplex() { return new PolarComplex(this.abs(), this.arg()); }

Podobnie jak w rozwizaniu zadania 24.20, pokazujemy konwersj pomidzy obiektami klasy PolarComplex i Complex. /** Zadanie Z24.21 */ public class Z24_21 { public static void main(String[] args) { PolarComplex a = new PolarComplex(1, Math.PI/2); System.out.println("a = "+a.toComplex()); Complex b = new Complex(a); System.out.println("b = "+b); Complex c = new Complex(3, -4); c.toPolarComplex().toComplex().println("c = "); } }

Zadanie 24.22. Z24_22.java, PolarComplex.java Iloczyn dwóch liczb zespolonych zapisanych w postaci trygonometrycznej:

x

x sin M  i cos M



i y

y sin\  i cos\

wyraa si wzorem:

xy

x y sin M  \  i sin M  \

Na tej podstawie moemy zbudowa metod obliczajc iloczyn liczb zespolonych — obiektów klasy PolarComplex. public PolarComplex mult(PolarComplex z) { return new PolarComplex(this.r*z.r, this.fi+z.fi); }

W przykadzie obliczymy iloczyn dwóch liczb zespolonych podanych w postaci biegunowej (obiektów klasy PolarComplex) i wywietlimy wyniki w postaci kanonicznej (po zamianie wyniku na obiekt Complex) z dokadnoci do 6 miejsc po przecinku (metoda printlnf() z zadania 24.16) oraz w postaci biegunowej (stosujc metod toString() dla obiektu klasy PolarComplex — wywoywan podczas czenia tekstów w parametrze metody, np. System.out.println("a = "+a)). /** Zadanie Z24.22 */ public class Z24_22 { public static void main(String[] args) { PolarComplex a = new PolarComplex(1, Math.PI/4); a.toComplex().printlnf("a = "); PolarComplex b = new PolarComplex(-2, Math.PI/2); b.toComplex().printlnf("b = "); a.mult(b).toComplex().printlnf("a·b = "); b.mult(a).toComplex().printlnf("b·a = "); System.out.println("a = "+a);

Rozdzia 7. i Rozwizania zada

337

System.out.println("b = "+b); System.out.println("a·b = "+a.mult(b)); } }

Zadanie 24.23. Z24_23.java, PolarComplex.java Zapiszmy liczby zespolone w postaci trygonometrycznej:

x

x sin M  i cos M



i y

y sin\  i cos\

Iloraz tych liczb wyraa si wzorem: xy

x y

sin M  \  i sin M  \

który wykorzystamy do zbudowania metody obliczajcej iloraz liczb zespolonych. public PolarComplex div(PolarComplex z) { return new PolarComplex(this.r/z.r, this.fi-z.fi); }

Obliczymy iloraz dwóch liczb i podobnie jak w rozwizaniu zadania 24.22, wywietlimy wyniki w postaci kanonicznej oraz w postaci biegunowej. /** Zadanie Z24.23 */ public class Z24_23 { public static void main(String[] args) { PolarComplex a = new PolarComplex(1, Math.PI/4); a.toComplex().printlnf("a = "); PolarComplex b = new PolarComplex(-2, Math.PI/2); b.toComplex().printlnf("b = "); Complex x = a.div(b).toComplex(); x.printlnf("x = a/b = "); Complex y = b.div(a).toComplex(); y.printlnf("y = b/a = "); x.mult(y).printlnf("x·y = "); System.out.println("a = "+a); System.out.println("b = "+b); System.out.println("a/b = "+a.div(b)); System.out.println("b/a = "+b.div(a)); } }

Zadanie 24.24. Z24_24.java, PolarComplex.java Stosujc wzór na iloczyn liczb zespolonych, podany w rozwizaniu zadania 24.22, obliczymy kwadrat i szecian liczby zespolonej (podanej w postaci biegunowej). public PolarComplex sqr() { return new PolarComplex(r*r, 2*fi); } public PolarComplex cube() { return new PolarComplex(r*r*r, 3*fi); }

338

Programowanie w jzyku Java

Skadajc w przykadowym programie odpowiednio metody sqr(), cube() oraz mult(a), obliczymy potgi (o wykadnikach od 1 do 6) liczby zespolonej reprezentowanej przez 1 i 3 obiekt a. Obliczenia wykonamy dla liczby (w postaci biegunowej r 1 , 2 S M rad 60q ). 3 /** Zadanie Z24.24 */ public class Z24_24 { public static void main(String[] args) { PolarComplex a = new PolarComplex(1, Math.PI/3); a.toComplex().printf("a^1 = "); System.out.println(" = "+a); a.sqr().toComplex().printf("a^2 = "); System.out.println(" = "+a.sqr()); a.cube().toComplex().printf("a^3 = "); System.out.println(" = "+a.cube()); a.sqr().sqr().toComplex().printf("a^4 = "); System.out.println(" = "+a.sqr().sqr()); a.sqr().sqr().mult(a).toComplex().printf("a^5 = "); System.out.println(" = "+a.sqr().sqr().mult(a)); a.sqr().cube().toComplex().printf("a^6 = "); System.out.println(" = "+a.sqr().cube()); } }

Zadanie 24.25. Z24_25.java, PolarComplex.java Potgowanie liczb zapisanych w postaci trygonometrycznej z gunowej) jest atwe przy wykorzystaniu wzoru de Moivre’a: z n

z cos M  i sin M (biez

n

cos nM  i sin nM .

public PolarComplex power(int n) { return new PolarComplex(Math.pow(r, n), n*fi); }

Aby zilustrowa zastosowanie metody power(), obliczymy potgi (o wykadnikach od 0 do 12) liczby zespolonej reprezentowanej przez obiekt a. Obliczenia wykonamy dla 3 i S liczby (w postaci biegunowej r 1 , M rad 30q . 2 6 /** Zadanie Z24.25 */ public class Z24_25 { public static void main(String[] args) { PolarComplex a = new PolarComplex(1, Math.PI/6); for(int i = 0; i < 13; ++i) { a.power(i).toComplex().printf("a^"+i+" = "); System.out.println(" = "+a.power(i)); } } }

Rozdzia 7. i Rozwizania zada

339

Zadanie 24.26. Z24_26.java, PolarComplex.java Niezerowa liczba zespolona z ma n rónych zespolonych pierwiastków n-tego stopnia, które mona obliczy, korzystajc ze wzoru de Moivre’a: zk

n

M  2kS M  2kS · § z ¨ cos  i sin ¸ dla k = 0, 1, …, n–1. n n © ¹

Dla n = 2 otrzymujemy: zk

M  2kS M  2kS · §  i sin z ¨ cos ¸ 2 2 © ¹

§ §M · §M ·· z ¨¨ cos¨  kS ¸  i sin ¨  kS ¸ ¸¸ dla k = 0, 1. 2 2 ¹ © ¹¹ © ©

public PolarComplex sqrt(int k) { k %= 2; return new PolarComplex(Math.sqrt(r), fi/2+k*Math.PI); }

Jako przykad dziaania metody obliczymy pierwiastki stopnia drugiego z liczby urojonej 2i. /** Zadanie Z24.26 */ public class Z24_26 { public static void main(String[] args) { PolarComplex a = new PolarComplex(2, Math.PI/2); System.out.print("a = "+a+" = "); a.toComplex().printlnf(); System.out.println("Pierwiastki drugiego stopnia"); PolarComplex x1 = a.sqrt(0); System.out.print("x1 = "+x1+" = "); x1.toComplex().printlnf(); PolarComplex x2 = a.sqrt(1); System.out.print("x2 = "+x2+" = "); x2.toComplex().printlnf(); } }

Zadanie 24.27. Z24_27.java, PolarComplex.java Na podstawie wzoru de Moivre’a (zob. rozwizanie zadania 24.26) dla n = 3 otrzymuM  2kS M  2kS · § jemy z k 3 z ¨ cos  i sin ¸ dla k = 0, 1, 2. 3 3 © ¹ public PolarComplex cbrt(int k) { k %= 3; return new PolarComplex(Math.cbrt(r), (fi+2*k*Math.PI)/3); }

Podajc przykad dziaania metody, obliczymy pierwiastki stopnia trzeciego z liczby –8 (w tym jeden pierwiastek rzeczywisty –2). /** Zadanie Z24.27 */ public class Z24_27 { public static void main(String[] args) { PolarComplex a = new PolarComplex(8, -Math.PI); System.out.print("a = "+a+" = "); a.toComplex().printlnf();

340

Programowanie w jzyku Java System.out.println("Pierwiastki PolarComplex x1 = a.cbrt(0); System.out.print("x1 = "+x1+" = x1.toComplex().printlnf(); PolarComplex x2 = a.cbrt(1); System.out.print("x2 = "+x2+" = x2.toComplex().printlnf(); PolarComplex x3 = a.cbrt(2); System.out.print("x3 = "+x3+" = x3.toComplex().printlnf();

trzeciego stopnia"); ");

");

");

} }

Zadanie 24.28. Z24_28.java, PolarComplex.java Na podstawie rozwizania zadania 24.26 budujemy bezparametrow metod sqrt() zwracajc tablic obiektów Complex z dwoma pierwiastkami drugiego stopnia z liczby zespolonej reprezentowanej przez obiekt PolarComplex wywoujcy metod. public Complex[] sqrt() { Complex[] tmp = new Complex[2]; tmp[0] = new PolarComplex(Math.sqrt(r), fi/2).toComplex(); tmp[1] = new PolarComplex(Math.sqrt(r), fi/2+Math.PI).toComplex(); return tmp; }

Podobnie (zob. rozwizanie zadania 24.27) budujemy bezparametrow metod cbrt() zwracajc tablic obiektów Complex z trzema pierwiastkami trzeciego stopnia z liczby zespolonej. public Complex[] cbrt() { Complex[] tmp = new Complex[3]; tmp[0] = new PolarComplex(Math.sqrt(r), fi/3).toComplex(); tmp[1] = new PolarComplex(Math.sqrt(r), (fi+2*Math.PI)/3). toComplex(); tmp[2] = new PolarComplex(Math.sqrt(r), (fi+4*Math.PI)/3). toComplex(); return tmp; }

W przykadowym programie obliczymy pierwiastki drugiego stopnia z –4 i pierwiastki trzeciego stopnia z 8i. /** Zadanie Z24.28 */ public class Z24_28 { public static void main(String[] args) { PolarComplex a = new PolarComplex(new Complex(4)); System.out.println("Pierwiastki kwadratowe z liczby 4:"); for(Complex x: a.sqrt()) { x.printf("x = "); System.out.println(" = "+x.toPolarComplex()); } a = new PolarComplex(new Complex(-4)); System.out.println("Pierwiastki kwadratowe z liczby -4:"); for(Complex x: a.sqrt()) { x.printf("x = "); System.out.println(" = "+x.toPolarComplex());

Rozdzia 7. i Rozwizania zada

341

} a = new PolarComplex(new Complex(0, 8)); System.out.println("Pierwiastki szecienne z liczby 8i:"); for(Complex x: a.cbrt()) { x.printf("x = "); System.out.println(" = "+x.toPolarComplex()); } } }

Poniewa bezparametrowe metody sqrt() i cbrt() zwracaj pierwiastki zebrane w tablicy, to do wywietlania wartoci moemy uy statycznej metody toString() z klasy Arrays. import java.util.Arrays; /** Zadanie Z24.28 */ public class Z24_28a { public static void main(String[] args) { PolarComplex a = new PolarComplex(new Complex(4)); System.out.println("Pierwiastki kwadratowe z liczby 4:"); System.out.println(Arrays.toString(a.sqrt())); a = new PolarComplex(new Complex(-4)); System.out.println("Pierwiastki kwadratowe z liczby 4:"); System.out.println(Arrays.toString(a.sqrt())); a = new PolarComplex(new Complex(0, 8)); System.out.println("Pierwiastki szecienne z liczby 8i:"); System.out.println(Arrays.toString(a.cbrt())); } }

Zadanie 24.29. Z24_29a.java, Z24_29b.java a) Jeli a z 0 , równanie az 2  c

0 jest równowane równaniu z 2

Równanie to ma dwa pierwiastki zespolone z





c . a

c (rzeczywiste a

c c , gdy  ! 0 ) lub pierwiastek dwukrotny z 0 dla c 0 . a a Do wyznaczenia pierwiastków najwygodniej bdzie uy metody sqrt() z jednym parametrem (zob. rozwizanie zadania 24.26). z

r 

import java.util.Scanner; /** Zadanie Z24.29a */ public class Z24_29a { public static void main(String[] args) { System.out.println("Równanie az^2+c = 0 o wspóczynnikach rzeczywistych"); Scanner input = new Scanner(System.in); System.out.print("a = "); double a = input.nextDouble(); System.out.print("c = "); double c = input.nextDouble(); if (a != 0) { PolarComplex x = new Complex(-c/a).toPolarComplex(); x.sqrt(0).toComplex().printlnf("z1 = ");

342

Programowanie w jzyku Java x.sqrt(1).toComplex().printlnf("z2 = "); } else System.out.println("Równanie sprzeczne lub nieoznaczone."); } }

b) Równanie z  a 3

0 jest równowane równaniu z 3

a . Równanie to ma

 a (w tym jeden jest zawsze rzeczywisty) trzy pierwiastki zespolone z lub pierwiastek trzykrotny z 0 dla a 0 . Pierwiastki obliczymy, stosujc metod cbrt() z jednym parametrem (zob. rozwizanie zadania 24.27). 3

import java.util.Scanner; /** Zadanie Z24.29b */ public class Z24_29b { public static void main(String[] args) { System.out.println("Równanie z^3+a = 0 o wspóczynnikach rzeczywistych"); Scanner input = new Scanner(System.in); System.out.print("a = "); double a = input.nextDouble(); PolarComplex x = new Complex(-a).toPolarComplex(); x.cbrt(0).toComplex().printlnf("z1 = "); x.cbrt(1).toComplex().printlnf("z2 = "); x.cbrt(2).toComplex().printlnf("z3 = "); } }

Zadanie 24.30. Z24_30a.java, Z2430b.java a) Rozwizujc równanie az 2  c

0 o wspóczynnikach zespolonych, postpujemy podobnie jak w rozwizaniu zadania 24_29a. Rónica polega na innym sposobie wprowadzania danych, wykonywaniu porówna i dziaa (w sposób specyficzny dla liczb zespolonych). Oto podstawowe rónice:

Wspóczynniki rzeczywiste

Wspóczynniki zespolone

Wczytywanie danych

Wczytywanie danych

System.out.print("a = "); double a = input.nextDouble();

Porównywanie a z zerem

System.out.print("a.re = "); double re = input.nextDouble(); System.out.print("a.im = "); double im = input.nextDouble(); Complex a = new Complex(re, im);

Porównywanie a z zerem

if(a != 0)...

Obliczenie prawej strony równania (–c/a) (i zamiana na liczb zespolon)

if(!a.equals(Complex.ZERO))...

Obliczenie prawej strony równania (–c/a)

PolarComplex x = new Complex (-c/a).toPolarComplex();

Obliczenie i wywietlenie pierwiastków zespolonych x.sqrt(0).toComplex().printlnf("z1 = "); x.sqrt(1).toComplex().printlnf("z2 = ");

PolarComplex x = c.opp().div(a).toPolarComplex();

Rozdzia 7. i Rozwizania zada

343

import java.util.Scanner; /** Zadanie Z24.30a */ public class Z24_30a { public static void main(String[] args) { System.out.println("Równanie az^2+c = 0 o wspóczynnikach zespolonych"); Scanner input = new Scanner(System.in); System.out.print("a.re = "); double re = input.nextDouble(); System.out.print("a.im = "); double im = input.nextDouble(); Complex a = new Complex(re, im); a.printlnf("a = "); System.out.print("c.re = "); re = input.nextDouble(); System.out.print("c.im = "); im = input.nextDouble(); Complex c = new Complex(re, im); c.printlnf("c = "); if (!a.equals(Complex.ZERO)) { PolarComplex x = c.opp().div(a).toPolarComplex(); x.sqrt(0).toComplex().printlnf("z1 = "); x.sqrt(1).toComplex().printlnf("z2 = "); } else System.out.println("Równanie sprzeczne lub nieoznaczone."); } }

b) Równanie z  a 3

a (a.opp()), a to

0 jest równowane równaniu z 3

 a lub pierwiastek równanie ma trzy (róne) pierwiastki zespolone z trzykrotny z 0  0i dla a 0  0i (porównaj z rozwizaniem zadania 24.29b). 3

import java.util.Scanner; /** Zadanie Z24.30b */ public class Z24_30b { public static void main(String[] args) { System.out.println("Równanie z^3+a = 0 o wspóczynnikach zespolonych"); Scanner input = new Scanner(System.in); System.out.print("a.re = "); double re = input.nextDouble(); System.out.print("a.im = "); double im = input.nextDouble(); Complex a = new Complex(re, im); a.printlnf("a = "); PolarComplex x = a.opp().toPolarComplex(); x.cbrt(0).toComplex().printlnf("z1 = "); x.cbrt(1).toComplex().printlnf("z2 = "); x.cbrt(2).toComplex().printlnf("z3 = "); } }

344

Programowanie w jzyku Java

Zadanie 24.31. Z24_31.java, PolarComplex.java Metoda root() jest realizacj wzoru de Moivre’a: n

z

n

§ § M  2kS · § M  2kS r ¨¨ cos¨ ¸  i sin ¨ n n © ¹ © ©

·· ¸ ¸¸ , k = 0, 1, 2… n-1. ¹¹

public PolarComplex root(int n, int k) { k %= n; return new PolarComplex(Math.pow(r, 1.0/n), (fi+2*k*Math.PI)/n); }

Testujc dziaanie metody, wyznaczymy pierwiastki zespolone pitego stopnia z 32, wród nich jest jedna warto rzeczywista (liczba 2). import java.util.Scanner; /** Zadanie Z24.31 */ public class Z24_31 { public static void main(String[] args) { System.out.println("Pierwiastki zespolone 5 stopnia z 32"); PolarComplex a = new Complex(32).toPolarComplex(); a.toComplex().printlnf("a = "); for(int i = 0; i < 5; ++i) { PolarComplex x = a.root(5, i); System.out.print("x"+i+" = "); x.toComplex().printf(); System.out.println(" = "+x); } } }

Zadanie 24.32. Z24_32.java, PolarComplex.java Na podstawie rozwizania zadania 24.31 budujemy tablic obiektów Complex zawierajc n pierwiastków n-tego stopnia z liczby zespolonej reprezentowanej przez obiekt PolarComplex wywoujcy metod. public Complex[] root(int n) { Complex[] tmp = new Complex[n]; for(int k = 0; k < n; ++k) { tmp[k] = new PolarComplex(Math.pow(r, 1.0/n), (fi+2*k*Math.PI)/n). toComplex(); } return tmp; }

Testujc dziaanie metody, wyznaczymy pierwiastki ósmego stopnia z 1, w tym dwie liczby rzeczywiste 1 i –1. /** Zadanie Z24.32 */ public class Z24_32 { public static void main(String[] args) { System.out.println("Pierwiastki zespolone 8 stopnia z 1"); PolarComplex a = new Complex(1).toPolarComplex(); a.toComplex().printlnf("a = ");

Rozdzia 7. i Rozwizania zada

345

for(Complex x: a.root(8)) { System.out.print("x = "); x.printf(); System.out.println(" = "+x.toPolarComplex()); } } }

Zadanie 24.33. Z24_33.java a) Rozwizanie równania z  1 n

0 w zbiorze liczb zespolonych, równowanego równaniu z 1 , sprowadza si do obliczenia pierwiastków zespolonych n-tego stopnia z liczby –1. Liczb rzeczywist –1 zamieniamy na liczb zespolon –1+0i, a nastpnie na jej posta biegunow PolarComplex a = new Complex(-1).toPolarComplex();. Wywoanie metody a.root(n) zwraca nam n-elementow tablic obiektów klasy Complex, pierwiastków zespolonych obiektu a (odpowiadajcego liczbie –1) — rozwizanie naszego równania. n

import java.util.Scanner; /** Zadanie Z24.33 */ public class Z24_33a { public static void main(String[] args) { System.out.println("Pierwiastki równania z^n+1 = 0"); Scanner input = new Scanner(System.in); System.out.print("n = "); int n = input.nextInt(); PolarComplex a = new Complex(-1).toPolarComplex(); a.toComplex().printlnf("a = "); int i = 1; for(Complex x: a.root(n)) { System.out.print("z"+i+" = "); ++i; x.printf(); System.out.println(" = "+x.toPolarComplex()); } } }

Przedstawione rozwizanie moemy uogólni dla wszystkich równa o postaci z n  a 0 . b) W rozwizaniu zadania 24.33a zmieniamy dwa wiersze programu

na nastpujce: System.out.println("Pierwiastki równania z^n+i = 0");

oraz PolarComplex a = new Complex(0, -1).toPolarComplex();

c) Rozwizujemy w zbiorze liczb zespolonych równanie kwadratowe

x 2  ix  1 0 (zob. rozwizanie zadania 24.17) i otrzymujemy dwa pierwiastki zespolone x1 i x2 .

346

Programowanie w jzyku Java /* Równanie kwadratowe ax^2+bx+c = 0, a = 1, b = i, c = 1 */ Complex a = new Complex(1); Complex b = new Complex(0, 1); Complex c = new Complex(1); Complex delta = b.sqr().sub(new Complex(4).mult(a).mult(c)); Complex x1 = b.opp().sub(delta.sqrt()).div(new Complex(2).mult(a)); Complex x2 = b.opp().add(delta.sqrt()).div(new Complex(2).mult(a));

Nastpnie rozwizujemy dwa równania: z n x1 i z n x2 , wzorujc si na rozwizaniu zadania 24.33a (24.33b). Najpierw obliczymy seri n pierwiastków pierwszego równania ( z n x1 ). int i = 1; /* Równanie z^n = x1 */ PolarComplex z = x1.toPolarComplex(); for(Complex x: z.root(n)) { System.out.print("z"+i+" = "); ++i; x.printf(); System.out.println(" = "+x.toPolarComplex()); }

Kolejne pierwiastki wyznaczymy w ten sam sposób, na podstawie drugiego równania ( z n x2 ).

Rozdzia 8.

Rozwizania zada 25. Operacje na plikach tekstowych Zadanie 25.1. Z25_1.java Z pakietu java.io importujemy dwie klasy IOException i FileWriter. W nagówku metody main() umieszczamy sowo kluczowe throws i nazw klasy IOException — uyte metody mog zgosi wyjtki tej klasy, a metoda main() nie bdzie ich przechwytywa i obsugiwa. Jeli wyjtek zostanie zgoszony, to dziaanie programu zostanie przerwane i maszyna wirtualna Javy wywietli stosowny komunikat (np. mówicy o próbie uycia nazwy pliku ?.txt): Exception in thread "main" java.io.FileNotFoundException: ?.txt (Nazwa pliku, nazwa katalogu lub skadnia etykiety woluminu jest niepoprawna) at java.io.FileOutputStream.open(Native Method) at java.io.FileOutputStream.(FileOutputStream.java:194) at java.io.FileOutputStream.(FileOutputStream.java:84) at java.io.FileWriter.(FileWriter.java:46) at Z25_1.main(Z25_1.java:6)

Tworzymy obiekt fout klasy FileWriter skojarzony z plikiem tekst.txt w biecym folderze. Jeli plik wczeniej nie istnia, to zostanie utworzony, natomiast w przypadku pliku istniejcego jego dotychczasowa zawarto zostanie usunita. Metoda write() wpisuje do pliku acuch znaków. Na koniec musimy pamita o zamkniciu pliku (metoda close()). import java.io.IOException; import java.io.FileWriter; /** Zadanie Z25.1 */ public class Z25_1 { public static void main(String[] args) throws IOException { FileWriter fout = new FileWriter("tekst.txt"); fout.write("Programowanie obiektowe"); fout.close(); } }

348

Programowanie w jzyku Java

Wszelkie sytuacje bdne, zwizane z otwarciem pliku lub zapisem do pliku, wygeneruj wyjtek, który przerwie prac programu. Wyjtki moemy przechwyci i obsuy. public static void main(String[] args) { try { FileWriter fout = new FileWriter("tekst.txt"); fout.write("Programowanie obiektowe"); fout.close(); } catch (IOException e) { System.err.println("Bd "+e); } }

Zadanie 25.2. Z25_2.java Uwagi przekazane w rozwizaniu zadania 25.1 pozostaj aktualne; istotn rónic jest sposób tworzenia obiektu FileWriter fout = new FileWriter("tekst.txt", true); — warto true drugiego parametru w konstruktorze oznacza otwarcie pliku w trybie dopisywania na kocu pliku (podanie wartoci false spowoduje, e dotychczasowa zawarto pliku zostanie usunita — jest to warto przyjmowana domylnie, gdy pominiemy drugi parametr). Koniec wiersza uzyskamy, wpisujc do strumienia acuch zawierajcy znaki CR+LF fout.write("\r\n") lub kady znak osobno: fout.write('\r') (CR, kod ASCII 13), fout.write('\n') (LF, kod ASCII 10). /** Zadanie Z25.2 */ import java.io.IOException; import java.io.FileWriter; public class Z25_2 { public static void main(String[] args) { try { FileWriter fout = new FileWriter("tekst.txt", true); fout.write(" w jzyku Java\r\n"); fout.write("jest bardzo interesujce."); fout.close(); } catch (IOException e) { System.err.println("Bd "+e); } } }

Po jednokrotnym wykonaniu programu z zadania 25.1 i 25.2 plik tekstowy tekst.txt powinien zawiera nastpujcy tekst: Programowanie obiektowe w jzyku Java jest bardzo interesujce.

Do tego pliku odwoamy si w dalszych zadaniach.

Zadanie 25.3. Z25_3.java Podobnie jak w rozwizaniu zadania 25.1, otwieramy plik tekstowy silnia.txt do zapisywania. W ptli obliczamy wartoci silni i zapisujemy wyniki do pliku. Argumentem

Rozdzia 8. i Rozwizania zada

349

metody write() moe by pojedynczy znak (liczba typu int traktowana jako kod znaku), tablica znaków lub acuch znaków (String). Z dwóch liczb i tekstu, wykorzystujc waciwoci operatora konkatenacji tekstów, budujemy wiersz odpowiedzi i zapisujemy go do pliku fout.write(i+"! = "+silnia). Koniec linii wpisujemy warunkowo we wszystkich wierszach odpowiedzi z wyjtkiem ostatniego (dwunastego wiersza) if (i < 12) fout.write("\r\n"). Na koniec zamykamy plik (fout.close()). /** Zadanie Z25.3 */ import java.io.IOException; import java.io.FileWriter; public class Z25_3 { public static void main(String[] args) { try { FileWriter fout = new FileWriter("silnia.txt"); int silnia = 1; for(int i = 1; i < 13; ++i) { silnia *= i; fout.write(i+"! = "+silnia); if (i < 12) fout.write("\r\n"); } fout.close(); } catch (IOException e) { System.err.println("Bd "+e); } } }

Zadanie 25.4. Z25_4.java Zadanie to rozwizujemy podobnie jak zadanie 25.3. Liczby zamieniamy na sformatowane acuchy znaków przy uyciu metody format() z klasy String:  String.format("%2d\t", n) — liczba cakowita n zostanie umieszczona w dwóch pierwszych znakach acucha, trzecim znakiem bdzie znak tabulatora '\t'.  String.format("%.12f\t", Math.sqrt(n)) — liczba zmiennoprzecinkowa, pierwiastek kwadratowy z n, zostanie umieszczona na pocztku acucha

z dwunastoma miejscami po przecinku; za liczb bdzie dodany znak tabulatora '\t'.  String.format("%.12f\t", Math.cbrt(n)) — liczba zmiennoprzecinkowa, pierwiastek szecienny z n, zostanie umieszczona w acuchu z dwunastoma

miejscami po przecinku. Znak koca linii (fout.write("\r\n")) wpisywany jest warunkowo we wszystkich wierszach z wyjtkiem wiersza ostatniego. /** Zadanie Z25.4 */ import java.io.IOException; import java.io.FileWriter; public class Z25_4 { public static void main(String[] args) { try { FileWriter fout = new FileWriter("pierwiastki.txt"); for(int n = 2; n b.length) while (i < a.length) { s[i] = a[i]; ++i; } else if (a.length < b.length) while (i < b.length) { s[i] = b[i]; ++i; } else if(s[s.length-1] == 0) { int n = s.length;

362

Programowanie w jzyku Java while (s[n-1] == 0 && n > 1) --n; s = Arrays.copyOf(s, n); } System.out.println("Suma wielomianów: "); System.out.println("a+b = "+Arrays.toString(s)); } }

Moemy zbudowa metod korekta(), która usunie z koca tablicy wszystkie elementy o wartoci 0 (elementy zerowe wewntrz tablicy musz bezwzgldnie pozosta). private static double[] korekta(double[] w) { int n = w.length; while (w[n-1] == 0 && n > 1) --n; return Arrays.copyOf(w, n); }

W szczególnym przypadku zwracana tablica moe zawiera tylko jeden element odpowiadajcy wielomianowi zerowego stopnia. Metod t moemy wykorzysta do skorygowania ostatecznego wyniku (if(s[s.length-1] == 0) s = korekta(s);) lub danych wejciowych (np. a = korekta(a)) wprowadzonych przez uytkownika programu.

Zadanie 26.4. Z26_4.java Zadanie to rozwiemy podobnie jak zadanie 26.3. Naley zwróci uwag na przypadek, gdy odejmowany wielomian ma wyszy stopie ni wielomian, od którego odejmujemy. for(i = 0; i < Math.min(a.length, b.length); ++i) s[i] = a[i]-b[i]; // obliczanie rónicy if (a.length > b.length) while (i < a.length) { s[i] = a[i]; ++i; } else if (a.length < b.length) while (i < b.length) { s[i] = -b[i]; // zmiana znaku wspóczynników ++i; } else if(s[s.length-1] == 0) s = korekta(s);

Zmiany zaznaczono dodatkowymi komentarzami.

Zadanie 26.5. Z26_5.java Mnoenie wielomianu przez liczb rón od zera (liczby przez wielomian — dziaanie jest przemienne) polega na pomnoeniu wszystkich wspóczynników wielomianu przez t liczb, np. 2 ˜ 3 x 2  2 x  4 6 x 2  4 x  8 . Stopie wielomianu nie ulega przy tym zmianie. Jeli liczba równa jest 0, to w wyniku mnoenia otrzymamy wielomian zerowy. /** Zadanie Z26.5 */ import java.util.Arrays;

Rozdzia 8. i Rozwizania zada

363

public class Z26_5 { public static void main(String[] args) { double[] a = {-1, 4, 2, 1}; System.out.println("a = "+Arrays.toString(a)); double b = -2; System.out.println("b = "+b); /* Iloczyn wielomianu przez liczb (rón od zera) */ double[] w = new double[a.length]; for(int i = 0; i < a.length; ++i) w[i] = a[i]*b; System.out.println("Iloczyn wielomianu a przez liczb b: "); System.out.println("a*b = "+Arrays.toString(w)); } }

Zadanie 26.6. Z26_6.java Mnoc dwa niezerowe wielomiany stopnia m i n, otrzymujemy niezerowy wielomian stopnia m+n. Mnoymy kady wyraz jednego wielomianu przez kady wyraz drugiego wielomianu i otrzymane jednomiany dodajemy (po uporzdkowaniu jednomianów wzgldem ich stopnia — postpujemy tak, wykonujc obliczenia na kartce). W programie wygodnie bdzie dodawa jednomiany na bieco, zaraz po ich obliczeniu (w[i+j] += a[i]*b[j]). /** Zadanie Z26.6 */ import java.util.Arrays; public class Z26_6 { public static void main(String[] args) { double[] a = {-1, 4, 2, 1}; System.out.println("a = "+Arrays.toString(a)); double[] b = {3, -4, 2, 1, 2}; System.out.println("b = "+Arrays.toString(b)); /* Iloczyn wielomianów */ double[] w = new double[a.length+b.length-1]; for(int i = 0; i < a.length; ++i) for(int j = 0; j < b.length; ++j) w[i+j] += a[i]*b[j]; System.out.println("Iloczyn wielomianów: "); System.out.println("a*b = "+Arrays.toString(w)); } }

Stopie wielomianu a jest równy a.length-1, stopie wielomianu b jest równy b.length-1, wic stopie iloczynu wielomianów wynosi a.length+b.length-2. Std wynika deklaracja double[] w = new double[a.length+b.length-1] — rozmiar tablicy jest o 1 wikszy od stopnia wielomianu.

Zadanie 26.7. Z26_7.java Pochodna wielomianu jest wielomianem (stopnia o 1 niszego)

a x n

n

c  an1 x n 1  ...  a1 x  a0

nan x n1  (n  1)an 1 x n  ...  a1 .

364

Programowanie w jzyku Java /** Zadanie Z26.7 */ import java.util.Arrays; public class Z26_7 { public static void main(String[] args) { double[] a = {-1, 4, 2, 1}; System.out.println("a = "+Arrays.toString(a)); /* Pochodna wielomianu */ double[] w = new double[a.length-1]; for(int i = 0; i < w.length; ++i) w[i] = a[i+1]*(i+1); System.out.println("Pochodna wielomianu: "); System.out.println("a\' = "+Arrays.toString(w)); } }

Zadanie 26.8. Z26_8.java Caka nieoznaczona (funkcja pierwotna) wielomianu jest wielomianem (stopnia o 1 an n1 an1 n wyszego) an x n  an1 x n 1  ...  a1 x  a0 dx x  x  ...  a0  c , gdzie n 1 n c jest dowoln sta. W programie przyjmiemy c = 0.

³

/** Zadanie Z26.8 */ import java.util.Arrays; public class Z26_8 { public static void main(String[] args) { double[] a = {-1, 4, 2, 1}; System.out.println("a = "+Arrays.toString(a)); /* Caka wielomianu (funkcja pierwotna) */ double[] w = new double[a.length+1]; for(int i = 0; i < a.length; ++i) w[i+1] = a[i]/(i+1); w[0] = 0; // moe by dowolna staa c System.out.println("Caka (funkcja pierwotna) wielomianu: "); System.out.println("A = "+Arrays.toString(w)); } }

Zadanie 26.9. Polynomial.java, Z26_9.java Na pocztek w klasie Polynomial umiecimy konstruktor z jednym parametrem, tablic liczb typu double. Poniewa uytkownik moe wskaza jako parametr tablic zawierajc warto 0 bdc ostatnim elementem (lub nawet kilka kocowych elementów bdzie miao warto 0), wic w konstruktorze wykorzystamy metod korekta(), zdefiniowan w rozwizaniu zadania 26.4 (metod t wczamy do klasy). W klasie Polynomial przesaniamy dziedziczon z klasy java.lang.Object metod toString(); zwracany acuch znaków jest zgodny ze wskazówk z zadania 26.3. import java.util.Arrays; public class Polynomial { private double[] w; private static double[] korekta(double[] a) { int n = a.length; while (a[n-1] == 0 && n > 1) --n;

Rozdzia 8. i Rozwizania zada

365

return Arrays.copyOf(a, n); } public Polynomial(double[] a) { a = korekta(a); w = new double[a.length]; for(int i = 0; i < a.length; ++i) this.w[i] = a[i]; } @Override public String toString() { return Arrays.toString(this.w); } }

Do klasy doczymy kilka metod. Na podstawie rozwizania zadania 26.1 budujemy publiczn metod horner(), obliczajc warto wielomianu reprezentowanego przez obiekt dla argumentu podanego jako parametr wywoania metody. public double horner(double x) { double y = 0.0; for(int i = w.length-1; i >= 0; --i) { y *= x; y += this.w[i]; } return y; }

Metod add(), która do wielomianu reprezentowanego przez wywoujcy j obiekt bdzie dodawa wielomian reprezentowany przez parametr a, konstruujemy na podstawie rozwizania zadania 26.3. Dziaanie wykonujemy na dwóch tablicach: this.w (wstawiamy w miejsce tablicy a) i a.w (w miejsce b). public Polynomial add(Polynomial a) { double[] s = new double[Math.max(this.w.length, a.w.length)]; int i = 0; for(i = 0; i < Math.min(this.w.length, a.w.length); ++i) s[i] = this.w[i]+a.w[i]; if (this.w.length > a.w.length) while (i < this.w.length) { s[i] = this.w[i]; ++i; } else if (this.w.length < a.w.length) while (i < a.w.length) { s[i] = a.w[i]; ++i; } else if(s[s.length-1] == 0) korekta(s); return new Polynomial(s); }

Podobnie skonstruujemy metod sub(), która od wielomianu reprezentowanego przez wywoujcy j obiekt bdzie odejmowa wielomian reprezentowany przez parametr a. Pamitajmy o uwadze (o zmianie znaków) z rozwizania zadania 26.4.

366

Programowanie w jzyku Java public Polynomial sub(Polynomial a) { double[] s = new double[Math.max(this.w.length, a.w.length)]; int i = 0; for(i = 0; i < Math.min(this.w.length, a.w.length); ++i) s[i] = this.w[i]-a.w[i]; if (this.w.length > a.w.length) while (i < this.w.length) { s[i] = this.w[i]; ++i; } else if (this.w.length < a.w.length) while (i < a.w.length) { s[i] = -a.w[i]; ++i; } else if(s[s.length-1] == 0) korekta(s); return new Polynomial(s); }

Na podstawie rozwizania zadania 26.5 zbudujemy metod mult(), która wielomian reprezentowany przez wywoujcy j obiekt bdzie mnoy przez liczb typu double podan jako parametr. public Polynomial mult(double a) { double[] tmp = new double[w.length]; for(int i = 0; i < w.length; ++i) tmp[i] = this.w[i]*a; return new Polynomial(tmp); }

Przeciajc metod mult(), zrealizujemy mnoenie wielomianu przez wielomian (na podstawie rozwizania zadania 26.6). public Polynomial mult(Polynomial a) { double[] tmp = new double[this.w.length+a.w.length-1]; for(int i = 0; i < this.w.length; ++i) for(int j = 0; j < a.w.length; ++j) tmp[i+j] += this.w[i]*a.w[j]; return new Polynomial(tmp); }

Na podstawie rozwizania zadania 26.7 zbudujemy metod derivative() (ang. derivative — pochodna), wyznaczajc pochodn wielomianu reprezentowanego przez obiekt wywoujcy metod. public Polynomial derivative() { double[] tmp = new double[this.w.length-1]; for(int i = 0; i < tmp.length; ++i) tmp[i] = this.w[i+1]*(i+1);; return new Polynomial(tmp); }

Natomiast wzorujc si na rozwizaniu zadania 26.8, utworzymy metod integral() (ang. integral — caka), wyznaczajc funkcj pierwotn wielomianu reprezentowanego przez obiekt.

Rozdzia 8. i Rozwizania zada

367

public Polynomial integral() { double[] tmp = new double[this.w.length+1]; for(int i = 0; i < this.w.length; ++i) tmp[i+1] = this.w[i]/(i+1); tmp[0] = 0; return new Polynomial(tmp); }

Analiz wierszy programu demonstrujcego moliwoci klasy Polynomial pozostawiamy Czytelnikowi. /** Zadanie Z26.9 */ import java.util.*; public class Z26_9 { public static void main(String[] args) { double[] a = {-1, 4, 2, 1, 0}; Polynomial w1 = new Polynomial(a); System.out.println("w1 = "+w1); System.out.println(Arrays.toString(a)); System.out.println("Wartoci wielomianu w1(x) dla x z przedziau z krokiem 0,25."); double x = 0.5; while (x 0) { w[i-1] = a[i]+w[i]*c; --i; } r = a[i]+w[i]*c; System.out.println("a:(x-c) = "+Arrays.toString(w)+", r = "+r); } }

Zadanie 26.11. Z26_11.java Na podstawie rozwizania zadania 26.10 moemy utworzy metod division(), obliczajc iloraz wielomianu przez dwumian (x–c) i zwracajc wynik w postaci nowego obiektu Polynomial. Powsta reszt z dzielenia w tym przypadku pomijamy. public Polynomial division(int c) { double[] tmp = new double[this.w.length-1]; int i = tmp.length-1; tmp[i] = this.w[i+1]; while (i > 0) { tmp[i-1] = this.w[i]+tmp[i]*c; --i; } return new Polynomial(tmp); }

Reszt z dzielenia wielomianu przez dwumian (x–c) zwróci nam metoda remainder(). Tym razem pomijamy uzyskany w trakcie oblicze iloraz (wielomian tmp) i zwracamy jedynie reszt (liczb typu double). public double remainder(int c) { double[] tmp = new double[this.w.length-1];

Rozdzia 8. i Rozwizania zada

369

int i = tmp.length-1; tmp[i] = this.w[i+1]; while (i > 0) { tmp[i-1] = this.w[i]+tmp[i]*c; --i; } return this.w[i]+tmp[i]*c; }

Stosujc obie zdefiniowane metody, moemy wykonywa dzielenie z reszt wielomianu przez dwumian o postaci (x–c). Przedstawia to nastpujcy przykad: /** Zadanie Z26.11 */ import java.util.Arrays; public class Z26_11 { public static void main(String[] args) { double[] a = {1, 0, 0, 1}; Polynomial w = new Polynomial(a); System.out.println("Wielomian w = "+w); double c = -1; System.out.println("w:(x-c) = "+w.division(-1)); System.out.println("r = "+w.remainder(-1)); } }

Zadanie 26.12. Z26_12.java Zadanie zostao rozwizane dla danych przykadowych. Kod potrzebny do wprowadzenia danych z klawiatury (stopnia wielomianu, tablicy wspóczynników t i granic cakowania a i b) pozostawiamy do napisania Czytelnikowi. W rozwizaniu zadania istotne s trzy kroki: utworzenie obiektu reprezentujcego wielomian Polynomial w = new Polynomial(t), wyznaczenie funkcji pierwotnej dla wielomianu Polynomial f = w.integral() i obliczenie wartoci caki oznaczonej double s = f.horner(b)-f.horner(a). /** Zadanie Z26.12 */ public class Z26_12 { public static void main(String[] args) { /* Dane przykadowe */ double[] t = {1, -3, 3, -2, 1}; double a = -2; double b = 3; /* Tworzenie obiektów i obliczenia */ Polynomial w = new Polynomial(t); System.out.println("Wielomian w = "+w); System.out.printf("Granice cakowania\na = %.2f\nb = %.2f\n", a, b); Polynomial f = w.integral(); // funkcja pierwotna double s = f.horner(b)-f.horner(a); // caka oznaczona System.out.printf("Caka oznaczona s = %.4f\n", s); } }

370

Programowanie w jzyku Java

Zadanie 26.13. Z26_13.java Jeli liczby x1 , x2 , ..., xn s jedynymi pierwiastkami wielomianu, to wielomian moemy przedstawi w postaci iloczynu w( x ) ( x  x1 ) ˜ ( x  x2 ) ˜ ... ˜ ( x  xn ) . Wykorzystamy ten wzór do wyznaczenia wspóczynników wielomianu w przypadku, gdy znane s jego pierwiastki. Zaczniemy od zbudowania wielomianu w( x ) 1 : double[] tmp = {1}; Polynomial w = new Polynomial(tmp);

Nastpnie bdziemy mnoy ten wielomian przez dwumiany o postaci ( x  xi ) dla i = 1, 2, …, n. Tworzymy tablic dwuelementow tmp, która posuy nam do budowania dwumianów o postaci (x–c). Ustalamy wspóczynnik stojcy przy x (tmp[1] = 1). Wprowadzamy z konsoli liczb pierwiastków n. W ptli (for(int i = 0; i < n; ++i)) wczytujemy kolejne pierwiastki (tmp[0] = -input.nextDouble() — zwrómy uwag na zmian znaku wczytanej wartoci) i wykorzystujemy je do zbudowania obiektu Polynomial reprezentujcego dwumian (new Polynomial(tmp)). Mnoymy wielomian w przez dwumian i podstawiamy wynik do zmiennej w (w = w.mult(new Polynomial(tmp)). Po wyjciu z ptli wywietlamy wynik. /** Zadanie Z26.13 */ import java.util.Scanner; public class Z26_13 { public static void main(String[] args) { Scanner input = new Scanner(System.in); double[] tmp = {1}; Polynomial w = new Polynomial(tmp); tmp = new double[2]; tmp[1] = 1; System.out.print("Liczba pierwiastków, n = "); int n = input.nextInt(); for(int i = 0; i < n; ++i) { System.out.print("Pierwiastek, x = "); tmp[0] = -input.nextDouble(); w = w.mult(new Polynomial(tmp)); } System.out.println("w = "+w); } }

27. Obliczenia statystyczne Zadanie 27.1. 27_1.java Wyznaczamy element maksymalny i element minimalny, a nastpnie obliczamy rónic midzy nimi.

Rozdzia 8. i Rozwizania zada

371

import java.util.Arrays; public class Z27_1 { public static void main(String[] args) { System.out.println("Próbka:"); double[] x = {1.35, 2.45, 2.05, 1.20, 2.15, 1.70, 1.45, 1.95, 2.00, 1.65, 1.65, 2.05, 1.75, 1.25, 2.25, 1.40}; System.out.println(Arrays.toString(x)); /* Element minimalny */ double minX = x[0]; for (double xi: x) if (xi < minX) minX = xi; System.out.println("Element minimalny: "+minX); /* Element maksymalny */ double maxX = x[0]; for (double xi: x) if (xi > maxX) maxX = xi; System.out.println("Element maksymalny: "+maxX); /* Rozstp badanej cechy */ double r = maxX-minX; System.out.println("Rozstp badanej cechy: "+r); } }

Element maksymalny i minimalny moemy wyznaczy w jednej ptli. Zamiast instrukcji warunkowych i porównywania mona zastosowa metody klasy Math. double minX = x[0]; double maxX = x[0]; for (double xi: x) { minX = Math.min(minX, xi); maxX = Math.max(maxX, xi); }

Moemy równie posortowa tablic w porzdku niemalejcym i wtedy pierwszy element bdzie elementem minimalnym, a ostatni maksymalnym. Arrays.sort(x); // sortowanie tablicy System.out.println("Element minimalny: "+x[0]); System.out.println("Element maksymalny: "+x[x.length-1]); System.out.println("Rozstp badanej cechy: "+(x[x.length-1]-x[0]));

Zadanie 27.2. Z27_2.java Ustalamy warto pocztkow sumy elementów (double sa = 0.0) i w ptli dodajemy do sumy kolejne elementy próbki. Po zakoczeniu sumowania dzielimy sum przez liczb elementów próbki i otrzymujemy warto redniej arytmetycznej badanej próbki. Wynik zaokrglamy do dwóch miejsc po przecinku. double sa = 0.0; for(double xi: x) sa += xi; sa /= n; System.out.println(" rednia arytmetyczna: "+zaokr(sa));

372

Programowanie w jzyku Java

Rozwizania zada 27.2 – 27.19 bd zbudowane wedug schematu (XX — oznacza jednolub dwucyfrowy numer zadania): import java.util.Arrays; public class Z27_XX { public static double zaokr(double x) { double prec = 100.0; return (int)(x*prec+0.5)/prec; } public static void main(String[] args) { System.out.println("Próbka:"); double[] x = {1.35, 2.45, 2.05, 1.20, 2.15, 1.70, 1.45, 1.95, 2.00, 1.65, 1.65, 2.05, 1.75, 1.25, 2.25, 1.40}; System.out.println(Arrays.toString(x)); int n = x.length; // liczba elementów /* Tu wstawimy rozwizanie zadania. */ } }

W odpowiedziach do zada podamy wycznie fragmenty kodu odpowiedzialne za rozwizanie problemu zawartego w zadaniu.

Zaokrglenie wyniku w tym i kolejnych zadaniach wykonujemy przy uyciu statycznej metody zaokr(): public static double zaokr(double x) { double prec = 100.0; return (int)(x*prec+0.5)/prec; }

Algorytm zaokrglania liczb przedstawimy na dwóch przykadach: x

x*100

x*100+0.5

(int)(x*100+0.5)

(int)(x*100+0.5)/100

2,7136

271,36

271,86

271

2,71

3,5481

354,81

355,31

355

3,55

Zadanie 27.3. 27_3.java Najpierw obliczamy iloczyn wszystkich n elementów próbki — ustalamy pocztkow warto iloczynu (double sg = 1.0) i nastpnie w ptli mnoymy t warto przez kolejne elementy (xi) próbki, przechowujc w zmiennej sg kolejne obliczone iloczyny (sg *= xi). Wartoci elementów próbki musz by nieujemne. Z iloczynu wszystkich elementów próbki obliczamy pierwiastek n-tego stopnia (sg = n

Math.pow(sg, 1.0/n)) i uzyskujemy redni geometryczn próbki ( g

n

– xi ). i 1

/* rednia geometryczna - wzór nr 1 */ double sg = 1.0;

Rozdzia 8. i Rozwizania zada

373

for(double xi: x) sg *= xi; sg = Math.pow(sg, 1.0/n); System.out.println(" rednia geometryczna: "+zaokr(sg));

Jeli wartoci elementów próbki s dodatnie, to moemy zastosowa wasnoci logan

rytmów log g

log n – xi i 1

g

e

1 n ¦ log x i ni 1

n 1 log – xi n i 1

1 n ¦ log xi , czyli rednia geometryczna ni 1

.

/* rednia geometryczna - wzór nr 2 */ double lnsg = 0; for(double xi: x) lnsg += Math.log(xi); lnsg /= n; double sg = Math.exp(lnsg); System.out.println(" rednia geometryczna: "+zaokr(sg));

Zadanie 27.4. 27_4.java rednia harmoniczna cigu liczb jest odwrotnoci redniej arytmetycznej odwrotnoci tych liczb. Wszystkie liczby musz by róne od zera. Suma odwrotnoci równie musi by róna od zera. Najpierw obliczamy sum odwrotnoci tych liczb (sh), potem wyraenie sh/n (redni arytmetyczn odwrotnoci) i jego odwrotno n/sh, która jest ostatecznym wynikiem (sh = n/sh). Zwrómy przy tym uwag na wykorzystanie zmiennej sh, która ma w czasie oblicze róne interpretacje. double sh = 0.0; for(double xi: x) sh += 1/xi; sh = n/sh; System.out.println(" rednia harmoniczna: "+zaokr(sh));

Zadanie 27.5. 27_5.java /* rednia potgowa rzdu 2. */ double sp2 = 0.0; for(double xi: x) sp2 += Math.pow(xi, 2); sp2 = Math.pow(sp2/n, 1.0/2); System.out.println(" rednia potgowa rzdu 2.: "+zaokr(sp2));

Podstawienie sp2 = Math.pow(sp2/n, 1.0/2); mona zastpi równowanym wzorem sp2 = Math.sqrt(sp2/n); (obliczanie pierwiastka kwadratowego). /* rednia potgowa rzdu 3. */ double sp3 = 0.0; for(double xi: x) sp3 += Math.pow(xi, 3); sp3 = Math.pow(sp3/n, 1.0/3); System.out.println(" rednia potgowa rzdu 3.: "+zaokr(sp3));

374

Programowanie w jzyku Java

W tym przykadzie równie wyraenie Math.pow(sp3/n, 1.0/3) mona zastpi wyraeniem Math.cbrt(sp3/n) (obliczanie pierwiastka trzeciego stopnia). W ogólnym przypadku jest to wyraenie o postaci Math.pow(sp/n, 1.0/r), gdzie r oznacza rzd redniej potgowej, a sp — jej warto. Warto jednak (przy duej iloci oblicze) zastanowi si nad zastpieniem metody obliczajcej potgi ( Math.pow()) szybszym mnoeniem lub wasn metod — obliczajc potgi o wykadniku cakowitym — o postaci: static double power(double a, int n) { double p = 1.0; for(int i = 0; i< n; ++i) p *= a; return p; }

Zadanie 27.6. 27_6.java Median moemy wyznaczy po posortowaniu próbki. /* Sortowanie próbki */ Arrays.sort(x); System.out.println("Posortowane:\n"+Arrays.toString(x));

Przy wyborze elementu rodkowego naley pamita o rozbienoci pomidzy indeksowaniem elementów próbki (od 1 do n) a indeksowaniem tablicy, rozpoczynajcym si od 0. double me; if (n%2 == 1) me = x[(n-1)/2]; // n jest nieparzyste, rodek posortowanej próbki else me = (x[n/2-1]+x[n/2])/2; // n parzyste, rednia wartoci rodkowych System.out.println("Mediana: "+me);

Zadanie 27.7. 27_7.java Zacznijmy od zdefiniowania struktury, która pozwoli nam na przechowywanie próbki w postaci szeregu rozdzielczego punktowego. W klasie Dane s dwa publiczne pola: double x, do przechowywania wartoci elementu próbki, oraz int n, zawierajce liczb powtórze tej wartoci. class Dane { public double x; int n; }

Próbk wprowadzamy do tablicy: double[] x = {1.35, 2.45, 2.05,1.35, 1.2, 1.35, 1.20, 2.15, 1.70, 1.45, 1.95, 2.00, 1.65, 1.65, 2.05, 1.75, 1.35, 2.25, 1.65};

Tablic sortujemy (naley importowa klas java.util.Arrays): Arrays.sort(x);

Rozdzia 8. i Rozwizania zada

375

Nastpnie musimy policzy, ile rónych wartoci zawiera próbka. Zewntrzna ptla typu while pozwala na przejrzenie wszystkich wartoci próbki (tablicy x), natomiast wewntrzna ptla pomija kolejne, powtarzajce si wartoci (tablica x jest posortowana w kolejnoci niemalejcej). Licznik (zmienna licznik) jest inkrementowany tylko wtedy, gdy nastpny element jest róny od biecego. int n = x.length; int i = 0; int licznik = 0; while (i < n) { while (i < n-1 && x[i+1] == x[i]) ++i; ++licznik; ++i; }

Teraz zmienna licznik zawiera liczb rónych wartoci w badanej próbce. Moemy utworzy tablic o odpowiednim rozmiarze i zbudowa szereg rozdzielczy punktowy. Dane[] y = new Dane[licznik]; i = 0; int j = 0; while (i < n) { /* przechowanie kolejnej wartoci próbki w szeregu rozdzielczym */ y[j] = new Dane(); y[j].x = x[i]; /* liczenie powtórze tej wartoci */ y[j].n = 1; while (i < n-1 && x[i+1] == x[i]) { ++i; ++y[j].n; } /* nastpna warto */ ++j; ++i; }

W tablicy y mamy uporzdkowany niemalejco, ze wzgldu na warto, szereg rozdzielczy. Pozostaje nam poszukiwanie dominanty. Zmienna boolean jest na koniec bdzie zawieraa informacj, czy w szeregu jest dominanta (na pocztek zakadamy jest = true). Zmienna dominanta (typu Dane) bdzie zawieraa warto dominanty (pole x), o ile ona istnieje, i liczb jej wystpie (pole n). Dane dominanta = new Dane(); /* warto pocztkowa, mniejsza od wszystkich wartoci próbki */ dominanta.x = y[0].x - 1; dominanta.n = 0; boolean jest = true; /* W pierwszym cyklu poniszej ptli, pierwszy element tablicy y zostanie uznany za dominant. */ for(Dane w: y) { /* Jeli liczba wystpie kolejnej wartoci jest równa liczbie wystpie wartoci uznawanej za dominant, to dominanta nie istnieje. */ if (w.n == dominanta.n)

376

Programowanie w jzyku Java jest = false; /* Znaleziono kolejn warto , która moe by dominant. */ else if (w.n > dominanta.n) { dominanta.x = w.x; dominanta.n = w.n; jest = true; } }

Pozostaje sformuowanie ostatecznej odpowiedzi: if (jest) { System.out.println("Dominanta D = "+dominanta.x); System.out.println("Liczba wystpie dominanty: "+dominanta.n); } else System.out.println("W próbce nie ma dominanty");

Zadanie 27.8. Z27_8.java redni arytmetyczn sa badanej próbki obliczymy w sposób przedstawiony w zadaniu 27.2. Do obliczenia wariancji (dyspersji) zastosujemy kolejno podane wzory: System.out.println("Obliczenie wariancji wedug wzoru:"); System.out.print("Wzór nr 1: "); double s2 = 0.0; for(double xi: x) s2 += Math.pow(xi-sa, 2); s2 /= n; System.out.println(s2); System.out.print("Wzór nr 2: "); s2 = 0.0; for (double xi: x) s2 += Math.pow(xi, 2); s2 /= n; s2 -= sa*sa; System.out.println(s2); System.out.print("Wzór nr 3: "); double a = 2.0; // dowolna liczba, np. 2.0 s2 = 0.0; for(double xi: x) s2 += Math.pow(xi-a, 2); s2 /= n; s2 -= Math.pow(sa-a, 2); System.out.println(s2);

Wykorzystan do obliczania kwadratów liczb metod Math.pow() warto zastpi mnoeniem lub metod sqr() zbudowan samodzielnie: static double sqr(double x) { return x*x; }

Rozdzia 8. i Rozwizania zada

377

Zadanie 27.9. 27_9.java Obliczymy redni arytmetyczn próbki i wariancj s2 (zmienna s2) na podstawie rozwizania zada 27.2 i 27.8 (jeden wybrany wzór) oraz odchylenie standardowe (pierwiastek kwadratowy z wariancji): double s = Math.sqrt(s2); System.out.println("Odchylenie standardowe: "+zaokr(s));

Zadanie 27.10. 27_10.java Odchylenie przecitne od staej a obliczymy, sumujc bezwzgldne wartoci odchyle xi (elementów tablicy) od staej wartoci a i dzielc otrzyman sum przez liczb elementów próbki x.length (rozmiar tablicy). double a = 2.0; // warto staej a double d = 0.0; for(double xi: x) d += Math.abs(xi-a); d /= x.length; System.out.print("Odchylenie przecitne od staej a = "+a); System.out.println(" jest równe "+zaokr(d));

Poniewa odchylenie przecitne próbki (od rónych wartoci) jest czsto obliczane, to zdefiniujemy metod: static double odchyleniePrzec(double[] x, double a) { double d = 0.0; for(double xi: x) d += Math.abs(xi-a); return d/x.length; }

i zastosujemy j do wykonania oblicze. System.out.print("Odchylenie przecitne od staej a = "+a); System.out.println(" jest równe "+zaokr(odchyleniePrzec(x, a)));

Metod t moemy wykorzysta równie w rozwizywaniu kolejnych zada — 27.11 i 27.12.

Zadanie 27.11. 27_11.java Obliczymy redni arytmetyczn sa próbki na podstawie rozwizania zadania 27.2, a nastpnie odchylenie przecitne d1 od redniej arytmetycznej: double d1 = 0.0; for(double xi: x) d1 += Math.abs(xi-sa); d1 /= n; System.out.print("Odchylenie przecitne od redniej arytmetycznej: "); System.out.println(zaokr(d1));

Moemy te zastosowa metod odchyleniePrzec(), zbudowan w rozwizaniu zadania 27.10:

378

Programowanie w jzyku Java System.out.print("Odchylenie przecitne od redniej arytmetycznej: "); System.out.println(zaokr(odchyleniePrzec(x, sa)));

Zadanie 27.12. 27_12.java Obliczymy median me próbki na podstawie rozwizania zadania 27.6, a nastpnie odchylenie przecitne d2 od mediany: double d2 = 0.0; for(double xi: x) d2 += Math.abs(xi-me); d2 /= n; System.out.print("Odchylenie przecitne od mediany: "); System.out.println(zaokr(d2));

Moemy te zastosowa metod odchyleniePrzec(), zbudowan w rozwizaniu zadania 27.10: System.out.print("Odchylenie przecitne od mediany: "); System.out.println(zaokr(odchyleniePrzec(x, me)));

Zadanie 27.13. 27_13.java Zaczniemy od posortowania próbki. Rozwaajc róne warianty dugoci próbki, wyznaczymy pooenie mediany (drugiego kwartyla Q2) lub indeksów elementów sucych do jej wyznaczenia. Dzielimy próbk na dwie czci: elementy mniejsze od mediany i median oraz median i elementy wiksze od mediany. Dla pierwszej czci wyznaczamy median — to bdzie dolny kwartyl (inaczej: pierwszy kwartyl) Q1. Górnym (trzecim) kwartylem Q3 jest mediana drugiej czci. Zwizek pomidzy kwartylami i wartociami próbki w posortowanej tablicy przedstawiono w tabeli. Liczebno próbki

Q1

n = 4k

ªnº x« » ¬4¼

ªn º ªnº x «  1»  x « » ¬2 ¼ ¬2¼ 2

ª 3n º x « 1» ¬4 ¼

n = 4k+1

ª n  1º x« ¬ 4 »¼

ª n  1º x« ¬ 2 »¼

ª 3n  3 º x« ¬ 4 »¼

n = 4k+2

ªn  2º ªn  2º x« x ¬ 4 »¼ «¬ 4 »¼ 2

ªn º ªnº x «  1»  x « » ¬2 ¼ ¬2¼ 2

ª 3n  6 º ª 3n  2 º x« x ¬ 4 »¼ «¬ 4 »¼ 2

n = 4k+3

ª n  3 º ª n  1º x« x ¬ 4 »¼ «¬ 4 »¼ 2

ª n  1º x« ¬ 2 »¼

ª 3n  5 º ª 3n  1º x« x ¬ 4 »¼ «¬ 4 »¼ 2

import java.util.Arrays; public class Z27_13 { static double zaokr(double x) {

Q2

Q3

Rozdzia 8. i Rozwizania zada

379

double prec = 1000.0; return (int)(x*prec+0.5)/prec; } public static void main(String[] args) { double[] x = {1.35, 2.45, 2.35, 1.20, 2.15, 1.70, 1.45, 1.95, 2.00, 1.65, 1.85, 2.05, 1.75, 1.25, 2.25, 2.05}; System.out.println("Próbka: \n"+Arrays.toString(x)); /* Sortowanie */ Arrays.sort(x); System.out.println("Próbka posortowana: \n"+Arrays.toString(x)); int n = x.length; double Q1 = 0.0, Q3 = 0.0; switch (n%4) { case 0: Q1 = x[n/4]; Q3 = x[3*n/4-1]; break; case 1: Q1 = x[(n-1)/4]; Q3 = x[(3*n-3)/4]; break; case 2: Q1 = (x[(n-2)/4]+x[(n+2)/4])/2; Q3 = (x[(3*n-6)/4]+x[(3*n-2)/4])/2; break; case 3: Q1 = (x[(n-3)/4]+x[(n+1)/4])/2; Q3 = (x[(3*n-5)/4]+x[(3*n-1)/4])/2; break; } double Q = (Q3-Q1)/2; System.out.println("Kwartyl dolny Q1: "+Q1); System.out.println("Kwartyl górny Q3: "+Q3); System.out.println("Odchylenie wiartkowe: "+Q); } }

Zadanie 27.14. 27_14.java Ze wzgldu na du liczb obliczanych potg o wykadniku naturalnym wykorzystamy metod power() z rozwizania zadania 27.6. /* Moment zwyky m2 rzdu 2. */ double m2 = 0.0; for(double xi: x) m2 += power(xi, 2); m2 /= n; System.out.print("Moment zwyky m2 rzdu 2."); System.out.println(" jest równy: "+zaokr(m2));

Powyszy fragment kodu moemy skopiowa i zmodyfikowa w celu obliczenia momentu zwykego m3 (trzeciego rzdu) i m4 (czwartego rzdu). Wygodniej jednak bdzie na podstawie tego kodu zbudowa metod obliczajc moment zwyky rzdu podanego jako drugi parametr:

380

Programowanie w jzyku Java static double momentZw(double[] x, int rz) { double m = 0.0; for(double xi: x) m += power(xi, rz); return m/x.length; }

i w ptli obliczy dane momenty zwyke: /* Momenty zwyke 2., 3. i 4. rzdu */ for(int r=2; r < 5; ++r) { System.out.printf("Moment zwyky rzdu "+r); System.out.println(" jest równy "+zaokr(momentZw(x, r))); }

Zadanie 27.15. 27_15.java W sposób znany z poprzednich zada najpierw obliczamy redni arytmetyczn sa badanej próbki, a nastpnie moment centralny zwyky. W obliczeniach wykorzystamy metod power() z zadania 27.6. /* Moment centralny M2 rzdu 2. */ double M2 = 0.0; for(double xi: x) M2 += power(xi-sa, 2); M2 /= n; System.out.print("Moment centralny M2 rzdu 2."); System.out.println(" jest równy: "+zaokr(M2));

W podobny sposób obliczymy momenty centralne M3 (trzeciego rzdu) i M4 (czwartego rzdu). Zamiast takiego rozwizania proponujemy metod: static double momentCent(double[] x, int rz, double sa) { double m = 0.0; for(double xi: x) m += power(xi-sa, rz); return m/x.length; }

i obliczenia w ptli: /* Momenty centralne 2., 3. i 4. rzdu */ for(int r=2; r < 5; ++r) { System.out.printf("Moment centralny rzdu "+r); System.out.println(" jest równy "+zaokr(momentCent(x, r, sa))); }

Ostatni (trzeci) parametr metody momentCent() jest redni arytmetyczn próbki. Moemy zbudowa metod bez tego parametru, która obliczy najpierw redni arytmetyczn, a potem moment centralny zwyky. static double momentCent(double[] x, int rz) { double sa = 0.0; // rednia arytmetyczna for(double xi: x) sa += xi; sa /= x.length;

Rozdzia 8. i Rozwizania zada

381

double m = 0.0; // moment centralny zwyky for(double xi: x) m += power(xi-sa, rz); return m/x.length; }

W tym przypadku nie bdzie potrzebne wczeniejsze liczenie redniej arytmetycznej w programie. for(int r=2; r < 5; ++r) { System.out.printf("Moment centralny rzdu "+r); System.out.println(" jest równy "+zaokr(momentCent(x, r))); }

Obie metody (z dwoma i trzema parametrami) mog istnie w tej samej klasie, pod jedn (przecion) nazw momentCent.

Zadanie 27.16. 27_16.java Zadanie rozwizujemy w sposób analogiczny do zadania 27.14. Porównujc wzór na 1 n l moment zwyky rzdu l ml xi , l  N ze wzorem na moment absolutny zwyky n i1

¦

rzdu l al

1 n

n

¦| x | , l

i

l  N , dostrzeemy rónic, któr naley uwzgldni w kodzie:

i 1

for(double xi: x) a += power(Math.abs(xi), rz);

Zadanie 27.17. 27_17.java Zadanie rozwizujemy w sposób analogiczny do zadania 27.15. Porównujc wzór na 1 n moment centralny rzdu l M l ( xi  x ) l , l  N ze wzorem na moment abson i1

¦

1 n | xi  x |l , l  N , dostrzeemy rónic, któr naley n i1 uwzgldni w kodzie. Zamiast:

lutny centralny rzdu l bl

¦

for(double xi: x) m += power(xi-sa, rz);

napiszemy: for(double xi: x) a += power(Math.abs(xi-sa), rz);

Zadanie 27.18. 27_18.java Obliczamy kolejno redni arytmetyczn sa (27.2), wariancj s2 (27.8) i odchylenie standardowe s (27.9). Na tej podstawie wyznaczymy: /* Wspóczynnik zmiennoci v */ double v = s/sa*100; System.out.println("Wspóczynnik zmiennoci: "+zaokr(v)+"%");

382

Programowanie w jzyku Java

Zadanie 27.19. 27_19.java Obliczamy redni arytmetyczn sa i odchylenie przecitne od redniej arytmetycznej d1. /* Wspóczynnik nierównomiernoci H */ double h = d1/sa*100; System.out.println("Wspóczynnik nierównomiernoci: "+zaokr(h)+"%");

Zadanie 27.20. Stat.java, Z27_20.java W klasie Stat (public class Stat {...}) umiecimy zestaw metod statycznych wykonujcych obliczenia na elementach tablicy jednowymiarowej double[] x (próbki) przekazanej jako parametr. Zaczniemy od metody zaokr() z jednym parametrem x, zaokrglajcej przekazany argument do dwóch miejsc po przecinku i zwracajcej zaokrglony wynik. public static double zaokr(double x) { double prec = 100.0; return (int)(x*prec+0.5)/prec; }

Przeciajc metod zaokr(), dodamy drugi parametr n — liczb cakowit wyraajc liczb miejsc po przecinku w wyniku. public static double zaokr(double x, int n) { double prec = Math.pow(10, n); return (int)(x*prec+0.5)/prec; }

Na podstawie rozwizania zadania 27.1 zbudujemy metody minX() i maxX() wyznaczajce warto minimaln i maksymaln z badanej próbki (tablicy). public static double minX(double[] x) { double min = x[0]; for(double xi: x) if (xi < min) min = xi; return min; } public static double maxX(double[] x) { double max = x[0]; for(double xi: x) if (xi > max) max = xi; return max; }

Majc warto minimaln i maksymaln, moemy wyznaczy rozstp. public static double rozstX(double[] x) { return maxX(x)-minX(x); }

Kolejna metoda oblicza redni arytmetyczn (zob. zadanie 27.2). public static double srednArytm(double[] x) { double sa = 0.0; for(double xi: x)

Rozdzia 8. i Rozwizania zada

383

sa += xi; return sa/x.length; }

W ten sposób na podstawie rozwizanych zada od 27.3 do 27.19 zbudujemy kolejne metody statyczne. Zredagowanie komentarzy dokumentacyjnych i utworzenie dokumentacji klasy pozostawiamy Czytelnikowi (zob. rozdzia 19., „Dokumentacja klasy”). W przykadzie pokazano rozwizania zada 27.1 i 27.2 wykorzystujce statyczne metody z klasy Stat. import java.util.Arrays; public class Z27_20 { public static void main(String[] args) { System.out.println("Próbka:"); double[] x = {1.35, 2.45, 2.05, 1.20, 2.15, 1.70, 1.45, 1.95, 2.00, 2.10, 1.50, 2.05}; System.out.println(Arrays.toString(x)); System.out.println("Warto minimalna: "+Stat.minX(x)); System.out.println("Warto maksymalna: "+Stat.maxX(x)); System.out.print("Rozstp badanej cechy w próbce: "); System.out.println(Stat.zaokr(Stat.rozstX(x))); System.out.print(" rednia arytmetyczna: "); System.out.println(Stat.zaokr(Stat.srednArytm(x))); } }

Zadanie 27.21. Statpr.java, Z27_21.java Klasa Statpr zawiera jedno prywatne pole pr bdce referencj do tablicy double[] zawierajcej badan próbk i konstruktor. import java.util.Arrays; public class Statpr { private double[] pr; public Statpr(double[] x) { pr = new double[x.length]; pr = Arrays.copyOf(x, x.length); } }

Konstruktor tworzy obiekt zawierajcy tablic o rozmiarze identycznym z rozmiarem tablicy przekazanej jako parametr (badana próbka) i kopiuje zawarto parametru do obiektu. Do klasy kopiujemy kody metod zaokr() (zob. rozwizanie zadania 27.20). public static double zaokr(double x) { double prec = 100.0; return (int)(x*prec+0.5)/prec; } public static double zaokr(double x, int n) { double prec = Math.pow(10, n); return (int)(x*prec+0.5)/prec; }

384

Programowanie w jzyku Java

Metody statyczne z klasy Stat (zob. rozwizanie zadania 27.20 lub rozwizania zada od 27.1 do 27.19) przeksztacamy na metody dziaajce na polu pr obiektu klasy Statpr. public double minX() { double min = pr[0]; for(double xi: pr) if (xi < min) min = xi; return min; } public double maxX() { double max = pr[0]; for(double xi: pr) if (xi > max) max = xi; return max; } public double rozstX() { return this.maxX()-this.minX(); } public double srednArytm() { double sa = 0.0; for(double xi: pr) sa += xi; return sa/pr.length; }

W ten sam sposób budujemy dalsze metody. Nie naley zapomnie o przesoniciu metody toString() z klasy Object (metoda ta uatwi wywietlanie danych w konsoli): @Override public String toString() { return Arrays.toString(pr); }

Komentarze dokumentacyjne i opracowanie dokumentacji pozostawiamy Czytelnikowi (zob. rozdzia 19.). W przykadzie pokazano rozwizania zada 27.1 i 27.2 wykorzystujce obiekt a klasy Stat. public class Z27_21 { static double[] x = {1.35, 2.45, 2.05, 1.20, 2.15, 1.70, 1.45, 1.95, 2.00, 2.10, 1.50, 2.05}; public static void main(String[] args) { Statpr a = new Statpr(x); System.out.println("Próbka:\n"+a); System.out.println("Warto minimalna: "+a.minX()); System.out.println("Warto maksymalna: "+a.maxX()); System.out.print("Rozstp badanej cechy w próbce: "); System.out.println(Statpr.zaokr(a.rozstX())); System.out.print(" rednia arytmetyczna: "); System.out.println(Statpr.zaokr(a.srednArytm())); } }

Rozdzia 8. i Rozwizania zada

385

28. Tablice wielowymiarowe i macierze Zadanie 28.1. Z28_1.java Deklarujemy tablic liczb cakowitych o trzech wierszach i dziesiciu kolumnach (int[][] a = new int[3][10]). Wiersze maj indeksy 0, 1 i 2, a kolumny 0, 1, 2, …, 9. W ptli for indeks i zmienia si od 0 do 9, co daje nam kolejno dostp do kolumn tablicy. W pierwszym wierszu podstawiamy a[0][i] = i+1 (liczby o 1 wiksze od indeksu, czyli 1, 2, …, 10), w drugim a[1][i] = a[0][i]*a[0][i] (kwadraty liczb z pierwszego wiersza) i w trzecim a[2][i] = a[1][i]*a[0][i] (iloczyn pierwszego i drugiego wiersza, czyli szecian pierwszego wiersza). Tablica dwuwymiarowa jest po prostu tablic tablic (tablic trzech wierszy, a kady wiersz jest tablic dziesiciu liczb cakowitych). Przekonamy si o tym podczas wywietlania zawartoci tablicy dwuwymiarowej na ekranie: for(int[] x: a) System.out.println(Arrays.toString(x));

W ptli for pobieramy z tablicy a jednowymiarowe tablice x (typu int[]), które wywietlamy w konsoli po ich zamianie na acuch znaków (Arrays.toString(x)). import java.util.Arrays; public class Z28_1 { public static void main(String[] args) { int[][] a = new int[3][10]; for(int i = 0; i < 10; ++i) { a[0][i] = i+1; a[1][i] = a[0][i]*a[0][i]; a[2][i] = a[1][i]*a[0][i]; } for(int[] x: a) System.out.println(Arrays.toString(x)); } }

Wynik wywietlany jest w postaci: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

Zamiast zamienia tablic x na acuch znaków, moemy ponownie zastosowa ptl for i uzyska dostp do jej elementów. Zagniedone ptle for i metoda printf() pozwol na przejrzyste wywietlenie tablicy dwuwymiarowej. for(int[] x: a) { for(int n: x) System.out.printf("%5d", n); System.out.println(); }

386

Programowanie w jzyku Java

Inn moliwoci, chyba najbardziej rozpowszechnion, jest wykorzystanie dostpu do elementów tablicy przy uyciu indeksów: for(int i = 0; i < a.length; ++i) { for(int j = 0; j < a[i].length; ++j) System.out.printf("%5d", a[i][j]); System.out.println(); }

Tablica jest obiektem i pole length zawiera rozmiar tablicy:  a.length — liczba wierszy tablicy dwuwymiarowej a,  a[i].length — liczba elementów i-tego wiersza tablicy a (liczba kolumn).

W tych dwóch przypadkach otrzymany rezultat przedstawia si nastpujco: 1 1 1

2 4 8

3 9 27

4 16 64

5 25 125

6 36 216

7 49 343

8 64 512

9 10 81 100 729 1000

Zadanie 28.2. Z28_2.java Deklarujemy tablic dwuwymiarow o dziesiciu wierszach, nie podajc liczby kolumn (int[][] a = new int[10][]). W ptli deklarujemy kady wiersz oddzielnie, ustalajc rozmiar (liczb kolumn) o 1 wikszy od indeksu wiersza (a[i] = new int[i+1]). Po zadeklarowaniu wiersza wypeniamy go kolejnymi liczbami naturalnymi (for(int j = 0; j i nie ma wiersza z elementem tmp[k][i] rónym od zera, to warto 0 pozostanie na gównej przektnej. private static double[][] upperTriangular(double[][] x) { if (x.length != x[0].length) throw new ArithmeticException("To nie jest macierz kwadratowa"); /* Kopia macierzy */ int n = x.length; double[][] tmp = new double[n][n]; for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) tmp[i][j] = x[i][j]; /* Tworzenie macierzy trójktnej górnej */ for(int i = 0; i < n-1; ++i) for(int j = i+1; j < n; ++j) { if (tmp[i][i] != 0.0) { double p = tmp[j][i]/tmp[i][i];

Rozdzia 8. i Rozwizania zada

399

for(int k = 0; k < n; ++k) tmp[j][k] -= tmp[i][k]*p; } else { for(int k = i+1; k < n; ++k) { if (tmp[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double temp = tmp[i][m]; tmp[i][m] = tmp[k][m]; tmp[k][m] = -temp; } break; } } } } return tmp; }

Jak ju wspomnielimy, przedstawiony algorytm zamiany macierzy kwadratowej na macierz trójktn górn nie zmienia wartoci wyznacznika macierzy. Wyznacznik macierzy trójktnej jest natomiast równy iloczynowi elementów nalecych do gównej przektnej, zatem przedstawiona metoda moe by wykorzystana do obliczenia wyznacznika. public class Z28_20 { /* Tu wstaw kod metody upperTriangular. */ public static void main(String[] args) { double[][] a = new double[6][6]; TDouble.setRandom(a, 10.0); System.out.println("Macierz A"); TDouble.printf("%8.2f", a); double[][] b = upperTriangular(a); System.out.println("Macierz trójktna górna B"); TDouble.printf("%8.2f", b); /* Wyznacznik macierzy trójktnej */ double det = 1.0; for(int i = 0; i < b.length; ++i) det *= b[i][i]; System.out.printf("det A = det B = %.2f\n", det); } }

Zadanie 28.21. Z28_21.java Macierz trójktna dolna to macierz kwadratowa, w której wszystkie elementy znajdujce si ponad gówn przektn maj warto równ 0. Sposób tworzenia macierzy trójktnej dolnej jest podobny do sposobu tworzenia macierzy trójktnej górnej (zob. rozwizanie zadania 28.20). Rónica polega na kolejnoci pobierania elementów z gównej przektnej macierzy — elementy pobieramy od ostatniego do drugiego (for(int i = n-1; i > 0; --i)). Wykonujemy odejmowanie wierszy (for(int j = i-1; j >= 0; --j)) i poszukiwanie wiersza z niezerowym elementem (for(int k = i-1; k >= 0; --k)) „od dou do góry”.

400

Programowanie w jzyku Java private static double[][] lowerTriangular(double[][] x) { if (x.length != x[0].length) throw new ArithmeticException("To nie jest macierz kwadratowa"); int n = x.length; double[][] tmp = new double[n][n]; for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) tmp[i][j] = x[i][j]; for(int i = n-1; i > 0; --i) for(int j = i-1; j >= 0; --j) { if (tmp[i][i] != 0.0) { double p = tmp[j][i]/tmp[i][i]; for(int k = 0; k < n; ++k) tmp[j][k] -= tmp[i][k]*p; } else { for(int k = i-1; k >= 0; --k) { if (tmp[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double temp = tmp[i][m]; tmp[i][m] = tmp[k][m]; tmp[k][m] = -temp; } break; } } } } return tmp; }

Przedstawiony algorytm zamiany macierzy kwadratowej na macierz trójktn doln nie zmienia wartoci wyznacznika macierzy. Wyznacznik macierzy trójktnej jest równy iloczynowi elementów nalecych do gównej przektnej.

Zadanie 28.22. Z28_22.java Macierz diagonalna to macierz kwadratowa, której wszystkie wspóczynniki lece poza gówn przektn s zerowe (jest to macierz trójktna górna i zarazem macierz trójktna dolna). Moemy zatem zastosowa kolejno metody upperTriangular() (zadanie 28.20) i lowerTriangular() (zadanie 28.21) — otrzymamy macierz diagonaln. W metodzie upperTriangular() moemy dokona kilku poprawek i uzyskamy metod wyznaczajc macierz diagonaln:  zmiana nazwy metody upperTriangular na diagonal,  zastpienie ptli for(int j = i+1; j < n; ++j) ptl for(int j = 0; j < n; ++j), co spowoduje odejmowanie od wszystkich wierszy macierzy wiersza o indeksie i pomnoonego przez wspóczynnik p = tmp[j][i]/tmp[i][i],  w powyszym odejmowaniu naley pomin odejmowanie wiersza od siebie

samego (j = i), wic operacj wykonujemy warunkowo: if (j != i) { double p = tmp[j][i]/tmp[i][i];

Rozdzia 8. i Rozwizania zada

401

for(int k = 0; k < n; ++k) tmp[j][k] -= tmp[i][k]*p; }

Po tych zmianach otrzymamy nastpujcy kod metody: private static double[][] diagonal(double[][] x) { if (x.length != x[0].length) throw new ArithmeticException("To nie jest macierz kwadratowa"); /* Kopia macierzy */ int n = x.length; double[][] tmp = new double[n][n]; for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) tmp[i][j] = x[i][j]; /* Wyznaczenie macierzy diagonalnej */ for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) { if (tmp[i][i] != 0.0) { if (j != i) { double p = tmp[j][i]/tmp[i][i]; for(int k = 0; k < n; ++k) tmp[j][k] -= tmp[i][k]*p; } } else { for(int k = i+1; k < n; ++k) { if (tmp[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double p = tmp[i][m]; tmp[i][m] = tmp[k][m]; tmp[k][m] = -p; } break; } } } } return tmp; }

Program demonstrujcy dziaanie moe by podobny jak w zadaniu 28.20 lub 28.21.

Zadanie 28.23. Z28_23.java Do wyznaczenia macierzy odwrotnej zastosujemy nastpujcy algorytm:  Bierzemy dan macierz kwadratow (A) i macierz jednostkow (I) tego

samego rzdu.  Stosujc te same przeksztacenia dla obu macierzy jednoczenie (mnoenie

wierszy przez liczb rón od zera, dodawanie do wiersza macierzy kombinacji liniowej innych wierszy), doprowadzamy macierz A do postaci macierzy diagonalnej z wartociami 1 na gównej przektnej. Macierz powstaa w wyniku przeksztace macierzy I jest macierz odwrotn do macierzy A (A–1).

402

Programowanie w jzyku Java

Jeli w wyniku przeksztace macierzy A otrzymamy macierz o elemencie 0 na gównej przektnej, to macierz A jest macierz osobliw (zdegenerowan); nie istniej wyznacznik det A = 0 i macierz odwrotna. W kodzie metody diagonal() (z rozwizania zadania 28.22) zmieniono nazw na inverse i dodano fragmenty dziaa (wykonywanych równolegle) na macierzy jednostkowej I (na listingu zmiany i uzupenienia w kodzie zaznaczono pogrubieniem). Po sprowadzeniu macierzy tmp do postaci diagonalnej sprawdzamy, czy nie jest to macierz osobliwa (0 na gównej przektnej, rzucamy wyjtek). W trakcie tej operacji odpowiednie wiersze obu macierzy dzielimy przez tmp[i][i], co doprowadza macierz tmp do macierzy jednostkowej, a macierz I do macierzy odwrotnej do wyjciowej postaci macierzy tmp. Zwracamy wynik znajdujcy si w macierzy I. private static double[][] inverse(double[][] x) { if (x.length != x[0].length) throw new ArithmeticException("To nie jest macierz kwadratowa"); int n = x.length; double[][] tmp = new double[n][n]; for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) tmp[i][j] = x[i][j]; double[][] I = new double[n][n]; for(int i = 0; i < n; ++i) I[i][i] = 1.0; for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) { if (tmp[i][i] != 0.0) { if (j != i) { double p = tmp[j][i]/tmp[i][i]; for(int k = 0; k < n; ++k) { tmp[j][k] -= tmp[i][k]*p; I[j][k] -= I[i][k]*p; } } } else { for(int k = i+1; k < n; ++k) { if (tmp[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double temp = tmp[i][m]; tmp[i][m] = tmp[k][m]; tmp[k][m] = -temp; temp = I[i][m]; I[i][m] = I[k][m]; I[k][m] = -temp; } break; } } } } for(int i = 0; i < n; ++i) if (tmp[i][i] != 0.0)

Rozdzia 8. i Rozwizania zada

403

for(int j = 0; j < n; ++j) I[i][j] /= tmp[i][i]; else throw new ArithmeticException("Macierz odwrotna nie istnieje"); return I; }

Spróbujemy uproci uzyskan metod. Oto istotny fragment kodu: for(int i = 0; i < n; ++i) { for(int j = 0; j < n; ++j) { if (tmp[i][i] != 0.0) { if (j != i) { double p = tmp[j][i]/tmp[i][i]; for(int k = 0; k < n; ++k) { tmp[j][k] -= tmp[i][k]*p; I[j][k] -= I[i][k]*p; } } } else { for(int k = i+1; k < n; ++k) { if (tmp[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double temp = tmp[i][m]; tmp[i][m] = tmp[k][m]; tmp[k][m] = -temp; temp = I[i][m]; I[i][m] = I[k][m]; I[k][m] = -temp; } break; } } throw new ArithmeticException("Macierz odwrotna nie istnieje");// 0 na przektnej macierzy diagonalnej } } double q = tmp[i][i]; for(int k = 0; k < n; ++k) { I[i][k] /= q; tmp[i][k] /= q; } } return I;

Analiz zmian pozostawiamy Czytelnikowi. Demonstrujc dziaanie metody, sprawdzimy, czy uzyskana macierz jest odwrotna. W tym celu pomnoymy macierz wyjciow przez macierz odwrotn. W rozwizaniu zadania 28.9 zbudowalimy metod product(), obliczajc iloczyn macierzy o elementach cakowitych. Na podstawie tej metody zbudujemy metod mnoc macierze o elementach rzeczywistych: public static double[][] product (double[][] x, double[][] y) { if (x[0].length != y.length) throw new ArithmeticException("Niezgodne wymiary macierzy");

404

Programowanie w jzyku Java double[][] tmp = new double[x.length][y[0].length]; for(int i = 0; i < x.length; ++i) for(int j = 0; j < y[0].length; ++j) for(int k = 0; k < y.length; ++k) tmp[i][j] += x[i][k]*y[k][j]; return tmp; }

Uywajc metody product(), moemy sprawdzi na przykadach dziaanie metody inverse(): public class Z28_23a { /* Tu wstaw kod metody inverse(). */ /* Tu wstaw kod metody product(). */ public static void main(String[] args) { double[][] a = new double[4][4]; TDouble.setRandom(a, 10.0); System.out.println("Macierz A"); TDouble.printf("%8.2f", a); double[][] b = inverse(a); System.out.println("Macierz odwrotna B"); TDouble.printf("%8.2f", b); System.out.println("Sprawdzenie A·B"); TDouble.printf("%8.2f", product(a, b)); System.out.println("Sprawdzenie B·A"); TDouble.printf("%8.2f", product(b, a)); double[][] c = {{1, 1, 1},{1, 1, 1}, {2, 2, 2}}; System.out.println("Macierz C"); TDouble.printf("%8.2f", c); System.out.println("Macierz odwrotna D"); double[][] d = inverse(c); TDouble.printf("%8.2f", d);; } }

Zadanie 28.24. Z28_24.java Rozwiemy ukad n równa liniowych o n niewiadomych: ­ a11 x1  a12 x2    a1n xn b1 °a21 x1  a22 x2    a2 n xn b 2 ° ®............................................... ° °¯an1 x1  an 2 x2    ann xn b n

Na pocztku programu wprowadzimy liczb równa ukadu (n). Wspóczynniki ukadu równa wprowadzimy do tablicy o n wierszach i n+1 kolumnach. W pierwszych n kolumnach umiecimy macierz podstawow ukadu wspórzdnych, a w ostatniej kolumnie umiecimy wyrazy wolne. Do wprowadzania danych uyjemy metody input() (z rozwizania zadania 28.3) z niewielkimi poprawkami: private static void input(double[][] x) { int n = x.length; for(int i = 0; i < n; ++i) { System.out.println("Podaj wspóczynniki równania"); for(int j = 0; j < n; ++j) {

Rozdzia 8. i Rozwizania zada

405

System.out.printf("a[%d][%d] = ", i+1, j+1); x[i][j] = cin.nextDouble(); } System.out.printf("b[%d] = ", i+1); x[i][n] = cin.nextDouble(); } }

Do obliczania wyznaczników uyjemy metody rekurencyjnej det() z rozwizania zadania 28.19. Poniewa tablica przechowujca wspóczynniki ukadu równa nie jest tablic kwadratow (liczba kolumn jest o jeden wiksza od liczby wierszy), to z metody det() usuwamy kontrol wymiaru. Wyznacznik bdzie liczony z pierwszych n kolumn macierzy, a n+1 kolumna (zawierajca wyrazy wolne) zostanie pominita. W ten sposób obliczymy gówny wyznacznik ukadu wspórzdnych (w). private static double det (double[][] x) { int st = x.length; double d = 0; if (st == 1) d = x[0][0]; else { int zn = 1; double[][] n = new double[st-1][st-1]; for (int i = 0; i < st; ++i) { for (int j = 0; j < st-1; ++j) { for (int k = 0; k < st-1; ++k) { if (k < i) n[j][k] = x[j+1][k]; else n[j][k] = x[j+1][k+1]; } } d += zn*x[0][i]*det(n); zn = -zn; } } return d; }

Pozostae wyznaczniki obliczymy (w ptli) w ten sam sposób, ale przed liczeniem wyznacznika w miejsce i-tej kolumny podstawimy (ostatni) kolumn wyrazów wolnych. Do tego celu utworzymy metod swapLast(): private static void swapLast(double[][] x, int col) { int n = x.length; for(int row = 0; row < n; ++row) { double tmp = x[row][col]; x[row][col] = x[row][n]; x[row][n] = tmp; } }

Po obliczeniu wyznacznika ponownie wywoamy metod swapLast(), przywracajc pierwotn posta macierzy. Po obliczeniu wyznaczników moemy poda rozwizanie ukadu równa. Moliwe s trzy przypadki:

406

Programowanie w jzyku Java 1. Wyznacznik gówny (w) jest róny od zera, wic ukad równa jest oznaczony

xi

wi dla i = 1, 2, …, n. w

2. Wyznacznik gówny jest równy 0 i wszystkie pozostae wyznaczniki s równe 0 (suma s bezwzgldnych wartoci tych wyznaczników jest równa zero), wic

ukad równa jest nieoznaczony. 3. Wyznacznik gówny jest równy 0 i co najmniej jeden z pozostaych wyznaczników nie jest równy 0 (suma s bezwzgldnych wartoci tych

wyznaczników nie jest zerem), zatem ukad równa jest sprzeczny. import java.util.Scanner; public class Z28_24 { private static Scanner cin = new Scanner(System.in); /* Tu wstaw kod metody det(). */ /* Tu wstaw kod metody swapLast(). */ /* Tu wstaw kod metody input(). */ public static void main(String[] args) { /* Liczba równa */ int n; do { System.out.print("Podaj liczb równa ukadu (2..9), n = "); n = cin.nextInt(); } while (n < 2 || n > 9); /* Wprowadzenie wspóczynników ukadu równa */ double[][] ur = new double[n][n+1]; input(ur); /* Obliczanie wyznaczników */ double w = det(ur); System.out.printf("Wyznacznik gówny W = %f\n", w); double[] wx = new double[n]; for(int i = 0; i < n; ++i) { swapLast(ur, i); wx[i] = det(ur); swapLast(ur, i); System.out.printf("Wyznacznik Wx[%d] = %f\n", i+1, wx[i]); } if (w != 0) { System.out.println("Ukad równa jest oznaczony"); for(int i = 0; i < n; ++i) System.out.printf("x[%d] = %f\n", i+1, wx[i]/w); } else { double s = 0.0; for(int i = 0; i < n; ++i) s += Math.abs(wx[i]); if (s == 0.0) System.out.println("Ukad równa jest nieoznaczony"); else System.out.println("Ukad równa jest sprzeczny"); } } }

Rozdzia 8. i Rozwizania zada

407

Zadanie 28.25. Z28_25.java Na pocztku programu wprowadzimy liczb równa ukadu (n). Wspóczynniki ukadu równa ­ a11 x1  a12 x2    a1n xn b1 °a21 x1  a22 x2    a2 n xn b 2 ° ®............................................... ° ¯°an1 x1  an 2 x2    ann xn b n

wprowadzimy do dwóch tablic (macierzy) — kwadratowej macierzy podstawowej ukadu o wymiarze n×n i prostoktnej o wymiarze n×1 (kolumna wyrazów wolnych). Do wprowadzania danych uyjemy metody input() (z rozwizania zadania 28.24) z poprawkami uwzgldniajcymi przechowywanie danych w dwóch macierzach: private static void input(double[][] x, double[][] y) { int n = x.length; for(int i = 0; i < n; ++i) { System.out.println("Podaj wspóczynniki równania"); for(int j = 0; j < n; ++j) { System.out.printf("a[%d][%d] = ", i+1, j+1); x[i][j] = cin.nextDouble(); } System.out.printf("b[%d] = ", i+1); y[i][0] = cin.nextDouble(); } }

Z rozwizania zadania 28.23 we miemy metod inverse() obliczajc macierz odwrotn oraz metod product() mnoc dwie macierze. Jeli macierz odwrotna istnieje, to ukad jest oznaczony, w przeciwnym wypadku (metoda inverse() rzuci wyjtek) mamy do czynienia z ukadem sprzecznym lub nieoznaczonym. import java.util.Scanner; public class Z28_25 { private static Scanner cin = new Scanner(System.in); /* Tu wstaw kod metody input(). */ /* Tu wstaw kod metody inverse() - zadanie 28.23. */ /* Tu wstaw kod metody product() - zadanie 28.23 */ public static void main(String[] args) { /* Liczba równa */ int n; do { System.out.print("Podaj liczb równa ukadu, n = "); n = cin.nextInt(); } while (n < 2); /* Wprowadzenie wspóczynników ukadu równa */ double[][] a = new double[n][n]; double[][] b = new double[n][1]; input(a, b); /* Obliczanie macierzy odwrotnej i rozwizanie ukadu */ try { double[][] x = product(inverse(a), b);

408

Programowanie w jzyku Java System.out.println("Ukad równa jest oznaczony"); for(int i = 0; i < n; ++i) System.out.printf("x[%d] = %f\n", i+1, x[i][0]); } catch (ArithmeticException e) { System.out.println("Ukad sprzeczny lub nieoznaczony"); } } }

Zadanie 28.26. Z28_26.java Na pocztku programu wprowadzimy liczb równa ukadu (n). Wspóczynniki ukadu równa wprowadzimy do tablicy o n wierszach i n+1 kolumnach (tak jak w rozwizaniu zadania 28.24). W pierwszych n kolumnach umiecimy macierz podstawow ukadu wspórzdnych, a w ostatniej kolumnie — wyrazy wolne. Do wprowadzania danych uyjemy metody input() z rozwizania zadania 28.4. Nastpnie bdziemy przeksztacali macierz zawierajc wspóczynniki równa ukadu w taki sposób, aby macierz podstawowa staa si macierz jednostkow. W ostatniej kolumnie otrzymamy rozwizanie ukadu. Jeli na gównej przektnej macierzy podstawowej pojawi si warto 0, to ukad jest sprzeczny lub nieoznaczony (moemy to rozstrzygn, porównujc zerowe wartoci z przektnej macierzy podstawowej z wartociami z kolumny wyrazów wolnych). Metoda solve(), rozwizujca ukad, jest modyfikacj metody inverse(), obliczajcej macierz odwrotn (zob. rozwizanie zadania 28.23). Metoda solve() nie sprawdza wymiaru macierzy (powinien by równy n×n+1). Najpierw macierz jest przeksztacana tak, aby macierz podstawowa staa si macierz diagonaln; te same operacje s wykonywane na kolumnie wyrazów wolnych. W tym momencie otrzymujemy n równa o postaci ax = b (gdzie a jest elementem przektnej macierzy podstawowej, b odpowiadajcym mu wyrazem wolnym). W ostatniej ptli rozwizujemy te równania (x = b/a) lub stwierdzamy, e a = 0 i równanie jest sprzeczne (b róne od 0) lub nieoznaczone (b = 0) — zwracamy wyjtek, nie informujc o powodach. Czytelnik moe ten fragment kodu rozwin. Jeli co najmniej jedno równanie jest sprzeczne, to cay ukad te jest sprzeczny. private static void solve(double[][] x) { int n = x.length; /* Sprowadzamy macierz podstawow do postaci diagonalnej. */ for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) { if (x[i][i] != 0.0) { if (j != i) { double p = x[j][i]/x[i][i]; for(int k = 0; k < n+1; ++k) x[j][k] -= x[i][k]*p; } } else { for(int k = i+1; k < n; ++k) { if (x[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double temp = x[i][m]; x[i][m] = x[k][m]; x[k][m] = -temp;

Rozdzia 8. i Rozwizania zada

409 } break;

} } } } /* Wyznaczamy rozwizanie ukadu. */ for(int i = 0; i < n; ++i) if (x[i][i] != 0.0) for(int j = 0; j < n; ++j) { x[i][n] /= x[i][i]; x[i][i] = 1.0; } else if (x[i][i] == x[i][n]) throw new ArithmeticException("Ukad sprzeczny lub nieoznaczony"); }

W przykadowym rozwizaniu nie ograniczamy liczby równa. W odrónieniu od metody wyznaczników budujcej wiele kopii macierzy metoda eliminacji przeksztaca macierz ukadu równa w miejscu, gdzie j utworzono (macierz ulega zmianie). Jeli bdzie nam potrzebna pocztkowa posta ukadu równa, to musimy przed wywoaniem metody solve() skopiowa dane do innej tablicy. import java.util.Scanner; public class Z28_26 { private static Scanner cin = new Scanner(System.in); /* Tu wstaw kod metody input(). */ /* Tu wstaw kod metody solve(). */ public static void main(String[] args) { /* Liczba równa */ int n; do { System.out.print("Podaj liczb równa ukadu, n = "); n = cin.nextInt(); } while (n < 2); /* Wprowadzenie wspóczynników ukadu równa */ double[][] ur = new double[n][n+1]; input(ur); /* Rozwizanie ukadu */ try { solve(ur); for(int i = 0; i < n; ++i) System.out.printf("x[%d] = %f\n", i+1, ur[i][n]); } catch (ArithmeticException e) { System.out.println("Ukad sprzeczny lub nieoznaczony"); } } }

Zadanie 28.27. Matrix.java, Z28_27.java W klasie Matrix korzystamy z metod pochodzcych z dwóch klas, Scanner i Random, z pakietu java.util. W tym celu tworzymy prywatne i statyczne obiekty cin (ang. console input) i rnd (ang. random). Ma to na celu uatwienie pracy z klas podczas jej

410

Programowanie w jzyku Java

tworzenia i testowania jej moliwoci (random() — wypenianie macierzy wylosowanymi wartociami) oraz w czasie wprowadzania danych (metoda input()) i wywietlania wyników (metoda printf()). Obiekt posiada prywatne pole M2 bdce referencj do dwuwymiarowej tablicy liczb typu double, zawierajcej elementy macierzy. Do dyspozycji mamy trzy konstruktory: tworzcy macierz na podstawie istniejcej tablicy dwuwymiarowej, tworzcy macierz o podanych wymiarach (wypenion zerami) i konstruktor kopiujcy. Oprócz wspomnianych metod (random(), input() i printf()) w klasie Matrix zdefiniowano metody umoliwiajce dostp do prywatnych danych (elementów tablicy M, czyli elementów macierzy). Metoda getAt() pozwala odczyta warto elementu z okrelonego wiersza i kolumny, a metoda setAt() nadaje okrelonemu elementowi podan warto. Wymiary macierzy moemy pozna, korzystajc z metod getRows() i getColumns(). Dziki tym metodom zewntrzne metody mog przeksztaca obiekty reprezentujce macierze (o ile takich operacji nie oferuj metody klasy Matrix). import java.util.*; public class Matrix { private static Scanner cin = new Scanner(System.in); private static Random rnd = new Random(); private double[][] M; public Matrix(double[][] x) { int r = x.length; // liczba wierszy (rows) int c = x[0].length; // liczba kolumn (columns) M = new double[r][c]; for(int i = 0; i < r; ++i) for(int j = 0; j < c; ++j) M[i][j] = x[i][j]; } public Matrix(int r, int c) { /* r liczba wierszy (rows), c liczba kolumn (columns) */ M = new double[r][c]; } public Matrix(Matrix x) { int r = x.M.length; int c = x.M[0].length; M = new double[r][c]; for(int i = 0; i < r; ++i) for(int j = 0; j < c; ++j) M[i][j] = x.M[i][j]; } public Matrix random() { for(int i = 0; i < M.length; ++i) 2

Gdy programujemy w Javie, jestemy przyzwyczajeni do zapisywania identyfikatorów staych wielkimi literami. W tym przypadku M nie oznacza staej, lecz jest identyfikatorem tablicy, która odpowiada macierzy reprezentowanej przez obiekt. W kilku nastpnych zadaniach bdziemy oznaczali macierze wielkimi literami (tak jak przyjmuje si w podrcznikach do matematyki).

Rozdzia 8. i Rozwizania zada for(int j = 0; j < M[0].length; ++j) M[i][j] = rnd.nextDouble(); return this; } public Matrix input() { for(int i = 0; i < M.length; ++i) for(int j = 0; j < M[i].length; ++j) { System.out.printf("M[%d][%d] = ", i, j); M[i][j] = cin.nextDouble(); } return this; } public Matrix printf(String format) { for(int i = 0; i < M.length; ++i) { for(int j = 0; j < M[0].length; ++j) System.out.printf(format, M[i][j]); System.out.println(); } return this; } public double getAt(int i, int j) { return M[i][j]; } public void setAt(int i, int j, double x) { M[i][j] = x; } public int getRows() { return M.length; } public int getColumns() { return M[0].length; } }

W przykadzie pokazujemy moliwoci tak zdefiniowanej klasy Matrix. class Z28_27 { public static void main(String[] args) { double[][] a = {{0, 3, -2, 2},{2, 1, -3, -1},{2, 1, -3, 4} }; Matrix A = new Matrix(a); System.out.println("Macierz A"); A.printf("%8.2f"); Matrix B = new Matrix(3, 4); System.out.println("Wypenienie macierzy B wartociami losowymi"); B.random().printf("%8.2f"); Matrix C = new Matrix(a); System.out.println("Konstruktor kopiujcy - C jest kopi A");

411

412

Programowanie w jzyku Java C.random().printf("%8.2f"); System.out.println("Liczba wierszy: "+C.getRows()); System.out.println("Liczba kolumn: "+C.getColumns()); System.out.println("Element C[0][1]: "+C.getAt(0, 1)); System.out.println("Podstawiam C[0][0] = -3.5"); C.setAt(0, 1, -3.5); System.out.println("Element C[0][0]: "+C.getAt(0, 1)); Matrix D = new Matrix(2, 2); System.out.println("Wprowadzanie danych z konsoli do macierzy D"); D.input(); System.out.println("Macierz D"); D.printf("%10.4f"); } }

Zadanie 28.28. Matrix.java, Z28_28.java Do klasy Matrix dodajemy metody add() (dodawanie), sub() (odejmowanie) i mult() (mnoenie) w dwóch wariantach — mnoenie macierzy przez macierz i mnoenie macierzy przez skalar. public Matrix add(Matrix x) { if (M.length != x.M.length || M[0].length != x.M[0].length) throw new ArithmeticException("Niezgodne wymiary macierzy"); Matrix tmp = new Matrix(this); for(int i = 0; i < M.length; ++i) for(int j = 0; j < M[0].length; ++j) tmp.M[i][j] = M[i][j]+x.M[i][j]; return tmp; } public Matrix sub(Matrix x) { if (M.length != x.M.length || M[0].length != x.M[0].length) throw new ArithmeticException("Niezgodne wymiary macierzy"); Matrix tmp = new Matrix(this); for(int i = 0; i < M.length; ++i) for(int j = 0; j < M[0].length; ++j) tmp.M[i][j] = M[i][j]-x.M[i][j]; return tmp; } public Matrix mult(Matrix x) { if (M[0].length != x.M.length) throw new ArithmeticException("Niezgodne wymiary macierzy"); Matrix tmp = new Matrix(M.length, x.M[0].length); for(int i = 0; i < M.length; ++i) for(int j = 0; j < x.M[0].length; ++j) for(int k = 0; k < x.M.length; ++k) tmp.M[i][j] += M[i][k]*x.M[k][j]; return tmp; } public Matrix mult(double x) { Matrix tmp = new Matrix(this); for(int i = 0; i < M.length; ++i)

Rozdzia 8. i Rozwizania zada

413

for(int j = 0; j < M[0].length; ++j) tmp.M[i][j] *= x; return tmp; }

Na macierzach wypenionych wylosowanymi wartociami pokazujemy wykonywanie zdefiniowanych w klasie Matrix dziaa na macierzach. class Z28_28 { public static void main(String[] args) { System.out.println("Wypenienie macierzy A wartociami losowymi"); Matrix A = new Matrix(3, 4).random().printf("%8.2f"); System.out.println("Wypenienie macierzy B wartociami losowymi"); Matrix B = new Matrix(3, 4).random().printf("%8.2f"); System.out.println("Suma macierzy, A+B = "); A.add(B).printf("%8.2f"); System.out.println("Suma macierzy, B+A = "); B.add(A).printf("%8.2f"); System.out.println("Rónica macierzy, A-B = "); A.sub(B).printf("%8.2f"); System.out.println("Rónica macierzy, B-A = "); B.sub(A).printf("%8.2f"); System.out.println("Macierz C"); Matrix C = new Matrix(3, 2).random().printf("%8.2f"); System.out.println("Macierz D"); Matrix D = new Matrix(2, 4).random().printf("%8.2f"); System.out.println("Iloczyn macierzy, C*D = "); C.mult(D).printf("%10.4f"); System.out.println("Macierz C"); C.printf("%10.4f"); System.out.println("Iloczyn macierzy przez skalar, 3*C = "); C.mult(3).printf("%10.4f"); } }

Zadanie 28.29. Z28_29.java Doczamy do klasy Matrix metody zwracajce macierz (kwadratow) reprezentowan przez obiekt w postaci macierzy trójktnej lub diagonalnej (na podstawie rozwizania zada 28.20, 28.21 i 28.22). Uzyskane macierze charakteryzuj si tym, e maj taki sam wyznacznik jak macierz wyjciowa i jest on równy iloczynowi elementów z gównej przektnej macierzy. Macierz trójktna górna — wszystkie elementy poniej gównej przektnej maj warto zero. public Matrix upperTriangular() { if (M.length != M[0].length) throw new ArithmeticException("To nie jest macierz kwadratowa"); int n = M.length;

414

Programowanie w jzyku Java Matrix tmp = new Matrix(this); for(int i = 0; i < n-1; ++i) for(int j = i+1; j < n; ++j) { if (tmp.M[i][i] != 0.0) { double p = tmp.M[j][i]/tmp.M[i][i]; for(int k = 0; k < n; ++k) tmp.M[j][k] -= tmp.M[i][k]*p; } else { for(int k = i+1; k < n; ++k) { if (tmp.M[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double temp = tmp.M[i][m]; tmp.M[i][m] = tmp.M[k][m]; tmp.M[k][m] = -temp; } break; } } } } return tmp; }

Macierz trójktna dolna — wszystkie elementy poniej gównej przektnej maj warto zero. public Matrix lowerTriangular() { if (M.length != M[0].length) throw new ArithmeticException("To nie jest macierz kwadratowa"); int n = M.length; Matrix tmp = new Matrix(this); for(int i = n-1; i > 0; --i) for(int j = i-1; j >= 0; --j) { if (tmp.M[i][i] != 0.0) { double p = tmp.M[j][i]/tmp.M[i][i]; for(int k = 0; k < n; ++k) tmp.M[j][k] -= tmp.M[i][k]*p; } else { for(int k = i-1; k >= 0; --k) { if (tmp.M[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double temp = tmp.M[i][m]; tmp.M[i][m] = tmp.M[k][m]; tmp.M[k][m] = -temp; } break; } } } } return tmp; }

Macierz diagonalna — wszystkie elementy poza gówn przektn maj warto zero. public Matrix diagonal() { if (M.length != M[0].length)

Rozdzia 8. i Rozwizania zada

415

throw new ArithmeticException("To nie jest macierz kwadratowa"); int n = M.length; Matrix tmp = new Matrix(this); for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) { if (tmp.M[i][i] != 0.0) { if (j != i) { double p = tmp.M[j][i]/tmp.M[i][i]; for(int k = 0; k < n; ++k) tmp.M[j][k] -= tmp.M[i][k]*p; } } else { for(int k = i+1; k < n; ++k) { if (tmp.M[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double p = tmp.M[i][m]; tmp.M[i][m] = tmp.M[k][m]; tmp.M[k][m] = -p; } break; } } } } return tmp; }

Macierz kwadratow o wylosowanych elementach przeksztacamy na posta trójktn (górn lub doln) i posta diagonaln. class Z28_29 { public static void main(String[] args) { System.out.println("Macierz A"); Matrix A = new Matrix(5, 5).random().printf("%8.2f"); System.out.println("Macierz trójktna górna"); A.upperTriangular().printf("%8.2f"); System.out.println("Macierz trójktna dolna"); A.lowerTriangular().printf("%8.2f"); System.out.println("Macierz diagonalna"); A.diagonal().printf("%8.2f"); } }

Moemy zbudowa dla macierzy trójktnych lub diagonalnych metod obliczajc wyznacznik macierzy: private static double determinant(Matrix x) { /* Tylko dla macierzy kwadratowych - trójktnych i diagonalnych */ int n = x.getRows(); double tmp = 1.0; for(int i = 0; i < n; ++i) tmp *= x.getAt(i, i); return tmp; }

416

Programowanie w jzyku Java

Demonstrujc dziaanie metody, moemy obliczy wyznacznik macierzy: System.out.println("Macierz trójktna górna"); System.out.printf("det A = %.4f\n", determinant(A.upperTriangular().printf("%8.2f")));

Zwrómy uwag na kolejno dziaa:  A.upperTriangular() — zamieniamy macierz A na macierz trójktn,  A.upperTriangular().printf("%8.2f") — zamieniamy macierz A na macierz

trójktn i wywietlamy j w konsoli,  determinant(A.upperTriangular().printf("%8.2f"))) — zamieniamy macierz A na macierz trójktn, wywietlamy j w konsoli i obliczamy

wyznacznik (nastpnie moemy go wywietli lub wykorzysta w innych obliczeniach). Oczywicie moemy skoncentrowa si wycznie na obliczeniu wyznacznika, np.: double w = determinant(A.lowerTriangular());

Wykonane operacje naturalnie nie zmieniaj macierzy (obiektu) A.

Zadanie 28.30. Z28_30.java Moemy skorzysta z rozwizania zadania 28.19. Przedstawiona tam metoda rekurencyjna pochania duo pamici, co ogranicza równie stopie macierzy obliczanego wyznacznika. Ponadto zapoyczymy pomys z zadania 28.29 i odpowiednio zmodyfikujemy metod upperTriangle(), dostosowujc j do obliczania wyznacznika. public double det() { if (M.length != M[0].length) throw new ArithmeticException("To nie jest macierz kwadratowa"); int n = M.length; Matrix tmp = new Matrix(this); for(int i = 0; i < n-1; ++i) { for(int j = i+1; j < n; ++j) { if (tmp.M[i][i] != 0.0) { double p = tmp.M[j][i]/tmp.M[i][i]; for(int k = 0; k < n; ++k) tmp.M[j][k] -= tmp.M[i][k]*p; } else { for(int k = i+1; k < n; ++k) { if (tmp.M[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double temp = tmp.M[i][m]; tmp.M[i][m] = tmp.M[k][m]; tmp.M[k][m] = -temp; } break; } } } } }

Rozdzia 8. i Rozwizania zada

417

double d = 1.0; for(int i = 0; i < n; ++i) d *= tmp.M[i][i]; return d; }

Dziaanie metody sprawdzimy na przykadzie macierzy z wylosowanymi wartociami elementów: class Z28_30 { public static void main(String[] args) { System.out.println("Macierz A"); Matrix A = new Matrix(5, 5).random().mult(10).printf("%8.2f"); System.out.printf("Wyznacznik det A = %f\n", A.det()); } }

Zadanie 28.31. Z28_31.java Na podstawie rozwizania zadania 28.23 budujemy w klasie Matrix metod inverse() zwracajc macierz odwrotn do macierzy (kwadratowej) reprezentowanej przez obiekt. public Matrix inverse() { if (M.length != M[0].length) throw new ArithmeticException("To nie jest macierz kwadratowa"); int n = M.length; Matrix tmp = new Matrix(this); Matrix I = new Matrix(n, n); for(int i = 0; i < n; ++i) I.M[i][i] = 1.0; for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) { if (tmp.M[i][i] != 0.0) { if (j != i) { double p = tmp.M[j][i]/tmp.M[i][i]; for(int k = 0; k < n; ++k) { tmp.M[j][k] -= tmp.M[i][k]*p; I.M[j][k] -= I.M[i][k]*p; } } } else { for(int k = i+1; k < n; ++k) { if (tmp.M[k][i] != 0.0) { for(int m = 0; m < n; ++m) { double temp = tmp.M[i][m]; tmp.M[i][m] = tmp.M[k][m]; tmp.M[k][m] = -temp; temp = I.M[i][m]; I.M[i][m] = I.M[k][m]; I.M[k][m] = -temp; } break; } } } }

418

Programowanie w jzyku Java for(int i = 0; i < n; ++i) if (tmp.M[i][i] != 0.0) for(int j = 0; j < n; ++j) I.M[i][j] /= tmp.M[i][i]; else throw new ArithmeticException("Macierz odwrotna nie istnieje"); return I; }

W przykadzie macierz kwadratow A wypeniamy wartociami losowymi i wyznaczamy macierz odwrotn B (B = A–1). Poprawno oblicze sprawdzamy, obliczajc iloczyny macierzy A·B i B·A. W obu przypadkach powinnimy otrzyma macierz jednostkow. Wyznaczniki macierzy odwrotnych powinny by liczbami odwrotnymi i ich iloczyn powinien wynosi 1. Uzyskanie takich wyników potwierdzi poprawno zbudowanych metod. class Z28_31 { public static void main(String[] args) { System.out.println("Macierz A"); Matrix A = new Matrix(5, 5).random().mult(10).printf("%8.2f"); System.out.println("Macierz odwrotna B"); Matrix B = A.inverse().printf("%8.2f"); System.out.println("Iloczyn macierzy A*B ="); A.mult(B).printf("%8.2f"); System.out.println("Iloczyn macierzy B*A ="); B.mult(A).printf("%8.2f"); System.out.printf("Wyznacznik det A = %f\n", A.det()); System.out.printf("Wyznacznik det B = %f\n", B.det()); System.out.printf("det A * det B = %f\n", A.det()*B.det()); } }

Zadanie 28.32. Z28_32.java Ukad n równa liniowych o n niewiadomych: ­ a11 x1  a12 x2    a1n xn b1 °a21 x1  a22 x2    a2 n xn b 2 ° ®............................................... ° ¯°an1 x1  an 2 x2    ann xn b n

moemy zapisa w postaci równania macierzowego (A·X = B): ª a11 «a « 21 « « ¬ a n1

a12 a22  an 2

 a1n º ª x1 º  a2 n »» «« x2 »» ˜   » «» » « »  ann ¼ ¬ xn ¼

ª b1 º «b » « 2» «» « » ¬bn ¼

Mnoc równanie lewostronnie przez macierz odwrotn do macierzy podstawowej ukadu, uzyskamy rozwizanie ukadu (X = A–1·B):

Rozdzia 8. i Rozwizania zada

ª x1 º «x » « 2» «» « » ¬ xn ¼

ª a11 «a « 21 « « ¬ a n1

a12 a22  an 2

419 1

 a1n º ª b1 º  a2 n »» ««b2 »» ˜   » «» » « »  ann ¼ ¬bn ¼

Wyraenie to moemy w atwy sposób zapisa przy uyciu obiektów i metod klasy Matrix (X = A.inverse().mult(B)). Podobnie wykonamy sprawdzenie, obliczajc A.mult(X) i porównujc z kolumn wyrazów wolnych B (wizualnie, po wywietleniu wyników w konsoli lub po zbudowaniu metody equals() w klasie Matrix). class Z28_32 { public static void main(String[] args) { /* Ukad równa - macierz odwrotna */ Matrix A = new Matrix(3, 3).random(); Matrix B = new Matrix(3, 1).random(); Matrix X; System.out.println("Ukad równa A*X = B"); System.out.println("Macierz gówna A = "); A.printf("%8.2f"); System.out.println("Kolumna wyrazów wolnych B = "); B.printf("%8.2f"); System.out.println("Rozwizanie ukadu X = "); X = A.inverse().mult(B).printf("%8.2f"); System.out.println("Sprawdzenie A*X = "); A.mult(X).printf("%8.2f"); } }

Zadanie 28.33. Z28_33.java Do klasy Matrix doczmy metod replaceCol(). Metoda ta wykonuje kopi obiektu (macierzy) i podstawia w miejscu wskazanej kolumny wartoci elementów z jednokolumnowej macierzy przekazanej jako parametr (liczba wierszy obu macierzy musi by równa). public Matrix replaceCol(int k, Matrix c) { if (k < 0 || k > M[0].length-1 || c.M.length != M.length || c.M[0].length != 1) throw new ArithmeticException("Niewaciwe dane"); int n = M.length; Matrix tmp = new Matrix(this); for(int i = 0; i < n; ++i) tmp.M[i][k] = c.M[i][0]; return tmp; }

Zdefiniowan metod replaceCol() wykorzystamy do rozwizania ukadu równa metod wyznaczników. Obliczmy wyznacznik gówny double w = A.det(). Jeli wyznacznik gówny jest róny od zera, to ukad jest oznaczony. W ptli obliczamy wyznaczniki dla kolejnych zmiennych — zastpujemy kolumn wspóczynników przy tej zmiennej przez kolumn wyrazów wolnych, liczymy wyznacznik i warto niewiadomej (Matrix Wx = new Matrix(A).replaceCol(i, B); X.setAt(i, 0, Wx.det()); X.setAt(i, 0, X.getAt(i, 0)/w);).

420

Programowanie w jzyku Java class Z28_33 { public static void main(String[] args) { /* Ukad równa - metoda wyznaczników */ int n = 4; Matrix A = new Matrix(n, n).random().mult(10); Matrix B = new Matrix(n, 1).random().mult(5); Matrix X = new Matrix(n, 1); System.out.println("Macierz gówna A = "); A.printf("%8.2f"); double w = A.det(); System.out.printf("Wyznacznik gówny W = %.4f\n", w); System.out.println("Kolumna wyrazów wolnych B = "); B.printf("%8.2f"); if (w != 0) { for(int i = 0; i < n; ++i) { System.out.printf("Macierz Wx[%d]\n", i); Matrix Wx = new Matrix(A).replaceCol(i, B). printf("%8.2f"); X.setAt(i, 0, Wx.det()); System.out.printf("Wyznacznik Wx[%d] = %.4f\n", i, X.getAt(i, 0)); X.setAt(i, 0, X.getAt(i, 0)/w); } System.out.println("Rozwizanie ukadu X = "); X.printf("%8.2f"); System.out.println("Sprawdzenie A*X = "); A.mult(X).printf("%8.2f"); } else System.out.println("Ukad sprzeczny lub nieoznaczony"); } }

Moemy tu dostrzec pewne komplikacje wynikajce z wywietlania wyników porednich; bez tego rachunek mógby wyglda tak: X.setAt(i, 0, new Matrix(A).replaceCol(i, B).det()/w)

Jeli wyznacznik gówny jest zerem, to wywietlilimy informacj, e ukad jest sprzeczny lub nieoznaczony. Czytelnik moe ten fragment rozbudowa o analiz wartoci wszystkich wyznaczników i orzeczenie, czy ukad jest sprzeczny (co najmniej jeden wyznacznik róny od zera), czy nieoznaczony (wszystkie wyznaczniki równe zero).

29. Obliczanie wartoci funkcji, rekurencja i inne zadania Zadanie 29.1. Z29_1.java Po uruchomieniu programu dla przykadowych danych zawartych w tablicy x zauwaymy, e metoda f() zwraca bezwzgldn warto liczby. Metod t moemy nazwa

Rozdzia 8. i Rozwizania zada

421

skrótem abs (jak postpilibymy w wikszoci jzyków programowania), pochodzcym od angielskiej nazwy absolute value (bezwzgldna warto liczby). class Z29_1 { public static double f(double x) { return (x > 0)?x:-x; } public static void main(String[] args) { double[] x = {-3.3, -2.15, -1.0, 0.0, 1.25, 3,1415, 7.5}; for(double a: x) System.out.println("a = "+a+",\tf(a) = "+f(a)); } }

Jedynie dla liczby 0,0 zamiast spodziewanej wartoci 0,0 otrzymamy –0,0. Wynika to z istnienia w typach liczb zmiennoprzecinkowych dwóch reprezentacji zera. Wspomnian niedogodno (dotyczc zera) moemy wyeliminowa, modyfikujc nieznacznie kod metody: static double abs(double x) { return (x >= 0)?x:-x; }

Zadanie 29.2. MinMax.java, Z29_2.java Budujemy klas MinMax zawierajc metody min() i max() z dwoma parametrami tego samego typu (double, float, int lub long): class MinMax { public static double min(double x, double y) { if (x = y) return x; else return y; } /* pozostae metody... */ }

Zamiast instrukcji warunkowej moemy zastosowa wyraenie warunkowe, co skróci zapis kodu ródowego: public static return (x } public static return (x }

double min(double x, double y) { = y)?x:y;

Podobnie moemy zmodyfikowa kod pozostaych metod.

422

Programowanie w jzyku Java

Dziaanie metod min() i max() moemy sprawdzi w programie: class Z29_2 { public static void main(String[] args) { /* Liczby typu double */ System.out.println(MinMax.min(2.5, -3.2)); System.out.println(MinMax.min(2.5, 5.2)); /* Liczby typu float */ float a = MinMax.min(-5.66f, 2.0f); System.out.println(a); System.out.println(MinMax.max(a, a/2)); /* ... */ } }

Zadanie 29.3. Z29_3.java Funkcja f(x) zwraca znak liczby: –1 dla liczb ujemnych, 0 dla 0 i 1 dla liczb dodatnich. Odpowiedni nazw mogoby by sowo znak, ac. signum lub stosowany w matematyce skrót sgn. Kod metody sgn() obliczajcej warto tej funkcji moemy zapisa, uywajc instrukcji warunkowych: static int sgn(double x) { if (x < 0) return -1; else if (x == 0.0) return 0; else return 1; }

lub wyraenia warunkowego: static int sgn(double x) { return (x < 0)?-1:(x == 0)?0:1; }

W taki sam sposób zdefiniujemy metod sgn() dla innych typów argumentów. public class Z29_3 { /* Tu wstaw kod metody sgn(). */ public static void main(String[] args) { System.out.println("Znak liczby -3.56: "+sgn(-3.56)); System.out.println("Znak liczby 0.0: "+sgn(0.0)); System.out.println("Znak liczby 4.2: "+sgn(4.2f)); } }

Zadanie 29.4. Z29_4.java Wyraenie x przyjmuje warto 1 dla x > 0 i –1 dla x < 0. Zatem funkcja f x zwraca x znak liczby (zob. rozwizanie zadania 29.3). Metod obliczajc warto tej funkcji moemy nazwa sgn (skrót od ac. signum):

Rozdzia 8. i Rozwizania zada

423

static int sgn(double x) { if (x == 0.0) return 0; else return (int)(Math.abs(x)/x); }

lub: static int sgn(double x) { return ((x == 0.0)?0:(int)(Math.abs(x)/x)); }

W podobny sposób zdefiniujemy metody dla innych typów argumentów. Poniewa wynik powinien by typu int, a warto wyraenia Math.abs(x)/x jest zgodna z typem argumentu x, musimy pamita o rzutowaniu tej wartoci na typ int.

Zadanie 29.5. Z29_5.java a) Funkcja f x, y zwraca maksimum dwóch liczb x i y i moemy t funkcj oraz odpowiadajc jej metod oznaczy skrótem max. public static double f(double x, double y) { return (x+y+Math.abs(x-y))/2; }

b) Funkcja g x, y zwraca minimum dwóch liczb x i y i moemy t funkcj oraz odpowiadajc jej metod oznaczy skrótem min. public static double g(double x, double y) { return (x+y-Math.abs(x-y))/2; }

c) Wród liczb x i –x wiksz jest liczba dodatnia, a zatem metoda h() zwraca bezwzgldn warto liczby x. public static double h(double x) { return f(x, -x); }

Test dziaania metod f() i g() przeprowadzimy na 9 parach liczb, natomiast metod h() przetestujemy dla 6 wartoci. class Z29_5 { /* Tu wstaw kod funkcji f, g, h. */ public static void main(String[] args) { double[] a = {-3.3, 0.0, 1.25}; double[] b = {-5.12, 0.25, 1.5}; for(double x: a) for(double y: b) { System.out.printf("f(%f, %f) = System.out.printf("g(%f, %f) = } for(double x: a) System.out.printf("h(%f) = %f\n", for(double x: b) System.out.printf("h(%f) = %f\n", } }

%f\n", x, y, f(x, y)); %f\n", x, y, g(x, y));

x, h(x)); x, h(x));

424

Programowanie w jzyku Java

Zadanie 29.6. Z29_6.java Na podstawie wzorów x 2 x ˜ x i x 3 x ˜ x ˜ x zbudujemy metody square() (kwadrat) i cube() (szecian). Metody tworzymy w dwóch wersjach: dla argumentów zmiennoprzecinkowych i dla argumentów cakowitych. class Z29_6 { public static double square(double x) { return x*x; } public static double cube(double x) { return x*x*x; } public static int square(int x) { return x*x; } public static int cube(int x) { return x*x*x; } public static void main(String[] args) { System.out.println("Kwadraty i szeciany liczb od 1 do 15"); for(int n = 1; n < 16; ++n) System.out.printf("%3d%8d%8d\n", n, square(n), cube(n)); System.out.println(); System.out.println("Kwadraty i szeciany liczb od 1.0 do 3.0"); double x = 1.0; while (x