1. Typy Double i Float oraz ich litery
Gdy dopiero zaczynasz programowac, wydaje sie, ze Int wystarcza do wszystkiego: policzyc sume, odjac, pomnozyc, porownac. Ale gdy tylko w zadaniu pojawia sie czesc ulamkowa (procenty, srednie wartosci, pomiary, predkosc, temperatura, „polowka” czegos), Int zaczyna zachowywac sie jak bardzo surowy ksiegowy: „ulamek nie istnieje, oto masz liczbe calkowita — i nie dyskutuj”.
Liczby rzeczywiste sa potrzebne tam, gdzie czesc ulamkowa to nie ozdoba, tylko sens. Na przyklad: „srednia predkosc 37.5 km/h”, „znizka 12.5%”, „temperatura 36.6”, „gestosc 1.225” — to wszystko slabo wyraza sie liczbami calkowitymi. Teoretycznie mozna przechowywac „36.6” jako „366” i pamietac, ze to dziesiate czesci, ale to juz umowa, o ktorej latwo zapomniec. Nawet bedziemy to wykorzystywac jako chwyt dydaktyczny (np. przechowywac pieniadze w groszach), ale tylko swiadomie.
W Kotlin (jak i w wielu jezykach) do obliczen ulamkowych sa osobne typy. Dzis interesuja nas dwa: Double i Float. Sa podobne znaczeniowo („liczby z czescia ulamkowa”), ale roznia sie dokladnoscia i tym, jak czesto bedziesz je wybierac w typowych zadaniach.
Double — podstawowy wybor dla ulamkow
Double to glowne narzedzie robocze do liczb rzeczywistych w Kotlin. Czesto bierze sie go „domyslnie”, gdy potrzebna jest czesc ulamkowa i nie ma szczegolnych ograniczen. W praktyce bedziesz spotykac Double caly czas: we wzorach, obliczeniach, geometrii, procentach i prawie wszedzie tam, gdzie wynik nie jest „caly”.
Double ma bardzo wygodna ceche: jesli zapisujesz liczbe z kropka, Kotlin zwykle interpretuje ja jako Double. Na przyklad, w dokumentacji Kotlin mozna zobaczyc przyklad val PI = 3.14 — typ takiej wartosci jest wywnioskowany automatycznie.
Utrwalmy podstawowa mysl: litera z kropka (10.0, 2.5, 3.14) — to Double.
Mini-przyklad — po prostu spojrzymy na obliczenia i wynik:
fun main() {
val pi = 3.14
val radius = 2.0
val area = pi * radius * radius
println("pi = $pi") // pi = 3.14
println("area = $area") // area = 12.56
}
Zauwaz: specjalnie napisalem radius = 2.0, a nie 2. To nie „dla urody”, tylko po to, by od razu pracowac w swiecie liczb ulamkowych i nie dostawac niespodzianek przy dzieleniu (do tego przejdziemy w nastepnym rozdziale).
Float — tez typ ulamkowy, ale litera wymaga sufiksu f
Float to tez liczba rzeczywista, tylko zwykle mniej dokladna i bardziej kompaktowa. Dla poczatkujacego wazne jest zrozumienie nie tyle „ile bitow”, co dwoch faktow praktycznych: po pierwsze, Float rzadziej pojawia sie w zadaniach edukacyjnych, a po drugie, Kotlin nie pozwala przypadkiem zapisac litery Float bez specjalnego oznaczenia.
Glowna mysl: jesli chcesz litere typu Float, musisz dodac sufiks f. Na przyklad 2.5f. To nie kaprys Kotlin, tylko sposob, by zmusic cie do swiadomej decyzji: „naprawde chce Float, przemyslalem to, zgadzam sie”.
Taki zapis pojawia sie tez w przykladach dokumentacji Kotlin: na przyklad -3.4f — to wlasnie Float.
Mini-przyklad:
fun main() {
val a: Float = 2.5f
val b: Double = 2.5
println("a = $a") // a = 2.5
println("b = $b") // b = 2.5
}
I jeszcze jeden wazny moment, na ktory prawie na pewno trafisz w pierwszych dniach: jesli napiszesz val x: Float = 2.5 bez f, kompilator bedzie niezadowolony. Widze 2.5 jako Double, a Kotlin nie lubi „cichych” konwersji liczbowych. To dobrze: mniej magii — mniej nieoczekiwanych bugow.
Na razie zapamietaj prosta zasade: jesli nie jestes pewien, ze potrzebujesz Float, bierz Double. Float czesciej bywa uzywany w zadaniach typu grafika albo duze tablice liczb, gdzie wazna jest oszczednosc pamieci, ale w naszych pierwszych programach zwykle nie jest to krytyczne.
Litery: 10 i 10.0 — to rozne typy
Teraz bedzie moment, w ktorym mozg lubi powiedziec „aha, jasne” — i od razu pomylic sie w nastepnej linijce. W Kotlin dwie wizualnie podobne liczby moga byc roznymi typami tylko dlatego, ze jedna ma kropke, a druga nie. 10 to liczba calkowita (zwykle Int), a 10.0 jest juz ulamkowa (Double).
To wazne, bo typ wplywa na to, jak dzialaja operacje na liczbach. Zwlaszcza dzielenie. Zwlaszcza gdy oczekujesz wyniku ulamkowego, a dostajesz calkowity i myslisz: „Kto ukradl moje 0.5?”
Mini-przyklad:
fun main() {
val a = 10 // Int (liczba calkowita)
val b = 10.0 // Double (liczba rzeczywista)
println("a = $a") // a = 10
println("b = $b") // b = 10.0
}
Tak, wynik juz podpowiada: 10.0 wyglada jak liczba z czescia ulamkowa (nawet jesli ulamek jest zerowy). To przydatne: wizualnie widzisz, ze pracujesz w innym „trybie”.
Stad prosty (i bardzo praktyczny) trik: jesli chcesz „przeniesc obliczenia do swiata ulamkow”, wystarczy gdzies w wyrazeniu dodac .0. Brzmi zbyt prosto, ale wlasnie tak czesto robi sie w podstawowych zadaniach, zanim przejdzie sie do innych konwersji typow.
3. Dzielenie: calkowite kontra rzeczywiste
Dzielenie to glowne zrodlo zaskoczen u poczatkujacych. I to zaskoczenie jest uczciwe: „Przeciez w szkole dzielilem, czemu tu jest inaczej?” Odpowiedz jest prosta: komputer wykonuje dzielenie z uwzglednieniem typow. Jesli dzielisz liczbe calkowita przez liczbe calkowita, wynik tez jest calkowity. Czesc ulamkowa w takim dzieleniu jest po prostu odcinana.
I to zachowanie nie jest „bledem Kotlin”, tylko standardowa arytmetyka liczb calkowitych w programowaniu: Int / Int -> Int. Aby uzyskac wynik ulamkowy, przynajmniej jeden operand musi byc typu Double albo Float.
Mini-przyklad, ktory warto zapamietac jak haslo do drzwi „do swiata ulamkow”:
fun main() {
val a = 5 / 2
val b = 5.0 / 2
println("a = $a") // a = 2
println("b = $b") // b = 2.5
}
A teraz sprobujmy napisac mala logike biznesowa. Niech bedzie obliczanie paragonu, ale zeby nie zajmowac sie wprowadzaniem liczb ulamkowych (to osobny temat), bedziemy przechowywac pieniadze w centach jako Int, a do wyswietlenia przeliczymy je na euro przez dzielenie przez 100.0.
Zauwaz: dzielimy przez 100.0, a nie przez 100. To kluczowe.
fun main() {
val totalCents = 2599 // 25.99 (umowne euro/dolary — bez znaczenia)
val total = totalCents / 100.0 // Double: 25.99
println("totalCents = $totalCents") // totalCents = 2599
println("total = $total") // total = 25.99
}
Gdybysmy napisali totalCents / 100, wyszloby 25 i stracilbys 99 centow. Program radosnie „zaoszczedzilby” uzytkownikowi pieniadze, ale niestety tylko w konsoli.
Zeby to utrwalic, dodajmy jeszcze jedna typowa operacje: podzielic rachunek na kilka osob. Liczba osob niech bedzie wczytywana jako calkowita — to juz znamy.
fun main() {
val totalCents = 2599
val people = 3
val total = totalCents / 100.0
val perPerson = total / people
println("total = $total") // total = 25.99
println("perPerson = $perPerson") // perPerson = 8.663333333333334
}
Tak, wynik jest „dlugi”. To normalne: na razie nie zaokraglamy ani nie formatujemy tego ladnie. Naszym celem jest teraz zrozumiec, czemu w ogole wyszla liczba niecalkowita i jak dojsc do ulamkowego wyniku. Ladne wyswietlanie bedzie pozniej — dzis „uczymy sie chodzic”, a nie „tanczyc”.
Mala sciagawka, jak myslec o dzieleniu:
flowchart TD
A["Piszesz dzielenie x / y"] --> B{"Czy x i y to calkowite Int?"}
B -- "tak" --> C["Wynik tez Int czesc ulamkowa znika"]
B -- "nie (jest Double/Float)" --> D["Wynik rzeczywisty czesc ulamkowa zostaje"]
Jesli masz watpliwosci, po prostu zadaj sobie pytanie: „Czy w tym wyrazeniu jest choc jedna liczba z kropka?” Jesli nie — jest duza szansa na zachowanie calkowitoliczbowe.
4. Zapis naukowy: 1e3 i 1e-3
Gdy liczby staja sie bardzo duze albo bardzo male, niewygodnie jest zapisywac je „wprost”. Nikt nie chce czytac 0.000001 i liczyc zera oczami, zwlaszcza gdy oczy i tak sa zmeczone po dziesiatym println. W takich sytuacjach jest zapis naukowy (nazywany tez wykladniczym): 1e3 oznacza „1 pomnozyc przez 10 do potegi 3”.
W Kotlin takie litery to tez liczby rzeczywiste (zwykle Double). To wygodne: mozesz krotko i czytelnie zapisywac wspolczynniki, tolerancje, skale i inne „male/duze” wartosci.
Mini-przyklad:
fun main() {
val big = 1e3 // 1000.0
val small = 1e-3 // 0.001
println("big = $big") // big = 1000.0
println("small = $small") // small = 0.001
}
Czemu to jest przydatne wlasnie dla ciebie, poczatkujacego? Bo we wzorach czesto wystepuja wspolczynniki skali. Na przyklad „zamienic milimetry na metry” — to pomnozyc przez 1e-3. „zamienic kilogramy na gramy” — to pomnozyc przez 1e3. Taki zapis znacznie mniej prowokuje blad typu „zero w zlym miejscu”.
Nie przestrasz sie tez, jesli Kotlin czasem wypisze liczbe z powrotem w postaci 1.0E-3 albo podobnej. To tylko format wyswietlania. Liczba jest ta sama — po prostu wydrukowana bardziej kompaktowo.
5. Co wybrac: Double czy Float
Chcesz miec jasna zasade, zeby nie cierpiec? Mam dobra wiadomosc: na poziomie naszych zadan jest ona naprawde prosta. Jesli piszesz zwykly program konsolowy, liczysz procenty, srednia, przeliczasz jednostki, liczysz pole kola albo dzielisz rachunek ze znajomymi, wybieraj Double. To najbardziej typowa i „szeroka” opcja.
Float warto brac wtedy, gdy masz ku temu konkretna przyczyne. Najczesciej brzmi ona jak „mamy bardzo duzo liczb i oszczedzamy pamiec” albo „pracujemy w srodowisku, w ktorym standardem jest Float (np. niektore obliczenia graficzne)”. Ale takie historie zwykle zaczynaja sie pozniej — gdy juz pewnie piszesz kod i rozumiesz, gdzie dokladnie ci to potrzebne.
Jesli chcesz to sobie utrwalic w glowie, mozesz korzystac z prostej tabeli (nie jako sciagi na egzamin, tylko jako przypomnienia „co ja w ogole robie”):
| Typ | Jak wyglada litera | Przyklad | Kiedy potrzebny na poczatku |
|---|---|---|---|
|
bez kropki | |
liczniki, ilosc, indeksy |
|
z kropka / e | |
obliczenia ulamkowe „domyslnie” |
|
z kropka + f | |
rzadko; tylko gdy jest powod |
I ostatnia wazna zasada, ktora dzis mozna uznac za „zelazna”: jesli potrzebujesz wyniku ulamkowego — upewnij sie, ze wyrazenie liczy sie jako Double (albo Float). Najprostsza droga — uzyc przynajmniej jednej litery z kropka: 100.0, 5.0, 2.0. Brzmi prawie jak lifehack, ale na poczatku ratuje przed ogromna liczba bledow.
6. Typowe bledy
Blad Nr 1: oczekiwac, ze 5 / 2 da 2.5.
To klasyk. Problem polega na tym, ze obie liczby sa calkowite, a wiec wynik tez jest calkowity. Leczenie jest proste: przynajmniej jedna liczbe robimy rzeczywista, np. 5.0 / 2 albo 5 / 2.0. Dobra praktyka: w zadaniach o srednich i procentach od razu zapisywac „bazowe” liczby jako Double (z kropka), zeby o tym nie zapomniec.
Blad Nr 2: probowac przypisac Float bez sufiksu f.
val x: Float = 2.5 wyglada logicznie po ludzku, ale Kotlin widzi 2.5 jako Double i nie chce „po cichu” zamieniac jednego w drugie. Poprawny zapis: 2.5f. Jesli nie jestes pewien, czy potrzebujesz Float, lepiej w ogole go nie ruszac i wziac Double — bedzie mniej powodow do sporow z kompilatorem.
Blad Nr 3: dzielic pieniadze/procenty calkowitoliczbowo i „gubic ogon”.
Gdy przechowujesz pieniadze w groszach (Int) i przeliczasz je na franki szwajcarskie, wazne jest, aby dzielic przez 100.0, a nie przez 100. Dzielenie przez 100 da liczbe calkowita i odrzuci reszte. Ten blad jest szczegolnie podstepny, bo program dziala „normalnie” — po prostu wynik jest bledny, a blednosc nie zawsze jest od razu widoczna.
Blad Nr 4: bac sie zapisu naukowego i traktowac go jak „inny typ”.
1e-3 to nie zadny specjalny tajny typ, tylko zwykla litera liczby rzeczywistej. Oznacza „pomnozyc przez 10 do potegi -3”. Jesli w wyniku zobaczysz format w rodzaju 1.0E-3, to tez jest normalne: Kotlin (a dokladniej standardowe wypisywanie liczb) czasem drukuje male wartosci w postaci wykladniczej, zeby nie rysowac wielu zer.
Blad Nr 5: wybierac Float „tylko dlatego, ze krotsze”.
Czasem wydaje sie, ze Float to „lzejszy Double”, wiec lepszy. W praktyce w zadaniach edukacyjnych czesciej tworzy to dodatkowe trudnosci: litery wymagaja f, bledy typow pojawiaja sie czesciej, a zysku nie czujesz. Dlatego na razie obowiazuje spokojna zasada: domyslnie Double, Float — tylko przy swiadomej potrzebie.
GO TO FULL VERSION