JavaRush /Курси /Kotlin SELF /Знайомство з дробовими числами: Double і Float

Знайомство з дробовими числами: Double і Float

Kotlin SELF
Рівень 6 , Лекція 1
Відкрита

1. Типи Double і Float та їхні літерали

Коли ви лише починаєте програмувати, здається, що Int достатньо для всього: порахувати суму, відняти, помножити, порівняти. Але щойно в задачі зʼявляється дробова частина (відсотки, середні значення, вимірювання, швидкість, температура, «половинка» чогось), Int починає поводитися як дуже суворий бухгалтер: «дробів не існує, ось вам ціле число — і не сперечайтеся».

Дійсні числа потрібні там, де дробова частина — не прикраса, а суть. Наприклад, «середня швидкість 37.5 км/год», «знижка 12.5 %», «температура 36.6», «густина 1.225» — усе це погано виражається цілими числами. Теоретично можна зберігати «36.6» як «366» і памʼятати, що це десяті. Але це вже домовленість, яку легко забути. Ми навіть використаємо це як навчальний прийом (наприклад, зберігатимемо гроші в копійках), але лише усвідомлено.

У Kotlin (як і в багатьох мовах) для дробових обчислень є окремі типи. Сьогодні нас цікавлять два: Double і Float. Вони схожі за змістом («числа з дробовою частиною»), але різняться точністю — і тим, як часто ви обиратимете їх у звичайних задачах.

Double — основний вибір для дробів

Double — це головний робочий інструмент для дійсних чисел у Kotlin. Його часто беруть «за замовчуванням», коли потрібна дробова частина й немає специфічних обмежень. На практиці ви зустрічатимете Double постійно: у формулах, розрахунках, геометрії, відсотках — і майже всюди, де зʼявляються «нецілі» результати.

У Double є дуже зручна ознака: якщо ви пишете число з крапкою, Kotlin зазвичай сприймає його як Double. Наприклад, у документації Kotlin можна побачити приклад val PI = 3.14 — тип такого значення виводиться автоматично.

Закріпімо базову думку: літерал із крапкою (10.0, 2.5, 3.14) — це Double.

Мініприклад — просто подивімося на обчислення та виведення:

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
}

Зверніть увагу: я спеціально написав radius = 2.0, а не 2. Це не «для краси», а щоб одразу працювати у світі дробових чисел і не отримувати несподіванок під час ділення (до цього ми підійдемо в наступному розділі).

Float — теж дробовий тип, але літерал вимагає суфікса f

Float — це теж дійсне число, лише зазвичай менш точне й компактніше. Новачкам важливо зрозуміти не стільки «скільки там бітів», скільки два практичні факти: по‑перше, Float трапляється рідше в навчальних задачах, а по‑друге, Kotlin не дає випадково записати Float літералом без спеціальної позначки.

Головна думка: якщо ви хочете літерал типу Float, додайте суфікс f. Наприклад, 2.5f. Це не примха Kotlin, а спосіб змусити вас бути точними: «я справді хочу Float, я це обдумав і погоджуюся з вибором».

Такий стиль запису трапляється і в прикладах документації Kotlin: наприклад, -3.4f — це саме Float.

Мініприклад:

fun main() {
    val a: Float = 2.5f
    val b: Double = 2.5

    println("a = $a")    // a = 2.5
    println("b = $b")    // b = 2.5
}

І ще важливий момент, який ви майже напевно спіймаєте в перші дні: якщо ви напишете val x: Float = 2.5 без f, компілятор буде незадоволений. Він бачить 2.5 як Double, а Kotlin не любить «тихих» числових перетворень. І це добре: менше магії — менше несподіваних помилок.

Поки що запамʼятайте просте правило: якщо ви не впевнені, що вам потрібен Float, беріть Double. Float частіше використовують у задачах на кшталт графіки або великих масивів чисел, де важлива економія памʼяті. Але в наших перших програмах це зазвичай не критично.

Літерали: 10 і 10.0 — це різні типи

Зараз буде момент, коли мозок любить сказати «ага, зрозуміло», — а потім одразу помилитися в наступному рядку. У Kotlin два візуально схожі числа можуть мати різні типи просто тому, що в одного є крапка, а в іншого — немає. 10 — це ціле число (зазвичай Int), а 10.0 — уже дробове (Double).

Це важливо, тому що тип впливає на те, як працюють операції з числами. Особливо — ділення. Особливо — коли ви очікуєте дробовий результат, а отримуєте цілий і думаєте: «Хто вкрав мої 0.5

Мініприклад:

fun main() {
    val a = 10      // Int (ціле)
    val b = 10.0    // Double (дійсне)

    println("a = $a")   // a = 10
    println("b = $b")   // b = 10.0
}

Так, виведення вже натякає: 10.0 виглядає як число з дробовою частиною (навіть якщо дріб нульовий). Це корисно: ви візуально бачите, що працюєте в іншому «режимі».

Звідси простий (і дуже робочий) прийом: якщо ви хочете «перевести обчислення у світ дробів», достатньо десь у виразі додати .0. Звучить надто просто, але саме так часто й роблять у базових задачах, поки не переходять до інших перетворень типів.

2. Ділення: цілі проти дійсних

Ділення — головне джерело здивування в новачків. Причому здивування чесне: «Я ж у школі ділив/ділила, чому тут інакше?» Відповідь проста: компʼютер виконує ділення з урахуванням типів. Якщо ви ділите ціле на ціле, результат теж цілий. Дробова частина в такому діленні просто відкидається.

І це поводження не «помилка Kotlin», а стандартна арифметика цілих чисел у програмуванні: Int / Int -> Int. Щоб отримати дробовий результат, хоча б один операнд має бути Double або Float.

Мініприклад, який варто запамʼятати як пароль до дверей «у світ дробів»:

fun main() {
    val a = 5 / 2
    val b = 5.0 / 2

    println("a = $a")   // a = 2
    println("b = $b")   // b = 2.5
}

Тепер спробуймо написати невелику бізнес-логіку. Нехай у нас буде розрахунок чека. Щоб не займатися введенням дійсних чисел (це окрема тема), зберігатимемо гроші в центах як Int, а для виведення переводитимемо у «велику» валюту через ділення на 100.0.

Зверніть увагу: ділимо на 100.0, а не на 100. Це принципово.

fun main() {
    val totalCents = 2599          // 25.99 (умовних євро/доларів — неважливо)
    val total = totalCents / 100.0 // Double: 25.99

    println("totalCents = $totalCents")  // totalCents = 2599
    println("total = $total")            // total = 25.99
}

Якби ми написали totalCents / 100, вийшло б 25, і ви б втратили 99 центів. Програма радісно «заощадила» б користувачеві гроші, але, на жаль, лише в консолі.

Щоб це закріпити, додамо ще одну типову операцію: поділити чек на кількох людей. Кількість людей нехай вводиться як ціле — це нам уже знайомо.

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
}

Так, виведення «довге». Це нормально: ми поки що не округлюємо й не форматуємо значення. Наша мета зараз — зрозуміти, чому взагалі виходить не ціле число і як отримати дробовий результат. Гарне оформлення виведення буде пізніше: сьогодні ми «вчимося ходити», а не «танцювати».

Невелика схема‑нагадувалка, як думати про ділення:

flowchart TD
    A["Ви пишете ділення x / y"] --> B{"x і y — цілі Int?"}
    B -- "так" --> C["Результат теж Int дробова частина втрачається"]
    B -- "ні (є Double/Float)" --> D["Результат дійсний дробова частина зберігається"]

Якщо маєте сумніви, просто поставте собі запитання: «У цьому виразі є хоча б одне число з крапкою?» Якщо ні — велика ймовірність цілочисельної поведінки.

3. Науковий запис: 1e3 і 1e-3

Коли числа стають дуже великими або дуже малими, писати їх «напряму» незручно. Ніхто не хоче читати 0.000001 і рахувати нулі очима, особливо коли очі й так втомилися після десятого println. Для таких випадків є науковий запис (його ще називають експоненційним): 1e3 означає «1 помножити на 10 у степені 3».

У Kotlin такі літерали теж є дійсними числами (зазвичай Double). Це зручно: ви можете записувати коефіцієнти, допуски, масштаби та інші «малі/великі» значення коротко й читабельно.

Мініприклад:

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
}

Чому це корисно саме вам, новачкам? Тому що у формулах часто трапляються масштабувальні коефіцієнти. Наприклад, «перевести міліметри в метри» — це помножити на 1e-3. «Перевести кілограми в грами» — помножити на 1e3. І такий запис набагато рідше провокує помилку «не туди поставив/поставила нуль».

Водночас не лякайтеся, якщо Kotlin іноді виводить число назад у вигляді 1.0E-3 або чогось подібного. Це лише формат відображення. Число те саме — просто надруковане компактніше.

4. Що обрати: Double чи Float

Вам хочеться отримати чітке правило, щоб не мучитися? Маєте добру новину: на рівні наших задач воно справді просте. Якщо ви пишете звичайну консольну програму, рахуєте відсотки, середнє, переводите одиниці вимірювання, обчислюєте площу круга або ділите чек на друзів, обирайте Double. Це найзвичніший і «широкий» варіант.

Float варто брати, коли у вас є для цього конкретна причина. Найчастіше причина звучить так: «у нас дуже багато чисел, і ми економимо памʼять» або «ми працюємо в середовищі, де прийнято використовувати Float (наприклад, у деяких графічних розрахунках)». Але зазвичай до цього доходять пізніше — коли ви вже впевнено пишете код і розумієте, де саме це потрібно.

Якщо хочеться надійніше зафіксувати це в голові, можна користуватися простою таблицею (не як шпаргалкою на іспит, а як нагадуванням «що я взагалі роблю»):

Тип Як виглядає літерал Приклад Коли потрібен на початку
Int
без крапки
10
лічильники, кількість, індекси
Double
з крапкою / e
10.0, 1e3
дробові розрахунки «за замовчуванням»
Float
з крапкою + f
2.5f, -3.4f
рідко; лише якщо є причина

І останнє важливе правило, яке сьогодні можна вважати «залізним»: якщо вам потрібен дробовий результат — переконайтеся, що вираз обчислюється як Double (або Float). Найпростіший шлях — використати хоча б один літерал із крапкою: 100.0, 5.0, 2.0. Це звучить майже як практичний прийом, але на перших порах він рятує від величезної кількості помилок.

5. Типові помилки

Помилка №1: очікувати, що 5 / 2 дасть 2.5.
Це класика. Проблема в тому, що обидва числа — цілі, а отже результат теж цілий. Лікується дуже просто: хоча б одне число робимо дійсним, наприклад 5.0 / 2 або 5 / 2.0. Корисна звичка — у задачах із середніми значеннями та відсотками одразу писати «базові» числа як Double (з крапкою), щоб не забути.

Помилка №2: намагатися присвоїти Float без суфікса f.
val x: Float = 2.5 виглядає логічно «по-людськи», але Kotlin бачить 2.5 як Double і не хоче «мовчки» перетворювати одне в інше. Правильний запис: 2.5f. Якщо ви не впевнені, що вам потрібен саме Float, краще взагалі не чіпати його й узяти Double — так менше підстав сперечатися з компілятором.

Помилка №3: ділити гроші/відсотки цілочисельно й «втрачати хвіст».
Коли ви зберігаєте гроші в копійках (Int) і переводите у «велику» валюту, важливо ділити на 100.0, а не на 100. Ділення на 100 дасть ціле число й відкине залишок. Ця помилка особливо підступна тим, що програма працює «нормально», просто результат стає неправильним, а це не завжди помітно одразу.

Помилка №4: лякатися наукового запису й сприймати його як «інший тип».
1e-3 — це не особливий секретний тип, а звичайний літерал дійсного числа. Він означає «помножити на 10 у степені -3». Якщо у виведенні ви побачили формат на кшталт 1.0E-3, це теж нормально: Kotlin (точніше, стандартне виведення чисел) іноді друкує малі значення в експоненційному вигляді, щоб не малювати багато нулів.

Помилка №5: обирати Float «просто тому, що коротше».
Іноді здається, що Float — це «легший Double», отже краще. На практиці в навчальних задачах це частіше створює зайві складнощі: літерали вимагають f, помилки типів зʼявляються частіше, а виграшу ви не відчуваєте. Тому поки діє спокійне правило: за замовчуванням Double, Float — лише за усвідомленої потреби.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ