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 (наприклад, у деяких графічних розрахунках)». Але зазвичай до цього доходять пізніше — коли ви вже впевнено пишете код і розумієте, де саме це потрібно.
Якщо хочеться надійніше зафіксувати це в голові, можна користуватися простою таблицею (не як шпаргалкою на іспит, а як нагадуванням «що я взагалі роблю»):
| Тип | Як виглядає літерал | Приклад | Коли потрібен на початку |
|---|---|---|---|
|
без крапки | |
лічильники, кількість, індекси |
|
з крапкою / e | |
дробові розрахунки «за замовчуванням» |
|
з крапкою + f | |
рідко; лише якщо є причина |
І останнє важливе правило, яке сьогодні можна вважати «залізним»: якщо вам потрібен дробовий результат — переконайтеся, що вираз обчислюється як 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 — лише за усвідомленої потреби.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ