CodeGym /Kursy /Kotlin SELF /Pierwsze kroki z liczbami ulamkowymi: Double i Float

Pierwsze kroki z liczbami ulamkowymi: Double i Float

Kotlin SELF
Poziom 6, Lekcja 1
Dostępny

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
Int
bez kropki
10
liczniki, ilosc, indeksy
Double
z kropka / e
10.0, 1e3
obliczenia ulamkowe „domyslnie”
Float
z kropka + f
2.5f, -3.4f
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.

1
Zadanie
Kotlin SELF, poziom 6, lekcja 1
Niedostępne
Czujniki pogodowe
Czujniki pogodowe
1
Zadanie
Kotlin SELF, poziom 6, lekcja 1
Niedostępne
Dwie średnie
Dwie średnie
1
Zadanie
Kotlin SELF, poziom 6, lekcja 1
Niedostępne
Przejście na system metryczny
Przejście na system metryczny
1
Zadanie
Kotlin SELF, poziom 6, lekcja 1
Niedostępne
Prędkość kuriera
Prędkość kuriera
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION