1. Округлення дійсних чисел
Ми вже раніше обговорювали, що коли змінній типу int
присвоюється дійсне число, воно завжди округлюється до меншого цілого — дробова частина просто відкидається.
Однак легко уявити ситуацію, коли дробове число потрібно округлити просто до найближчого або навіть до більшого цілого. Що ж робити в такій ситуації?
Для цього та багатьох інших подібних випадків у мові Java є клас Math
, який містить методи round()
, ceil()
і floor()
.
Метод Math.round()
Метод Math.round()
округляє число до найближчого цілого:
long x = Math.round(дійсне_число)
Але, як то кажуть, є нюанс: результатом використання цього методу буде цілочисловий тип long
(а не int
). Адже дійсні числа можуть бути дуже великими, тому розробники Java вирішили використовувати найдовший цілочисловий тип, який є в Java — long
.
Ось чому для присвоєння результату змінній типу int
програміст повинен явно вказати компілятору, що він згоден із можливою втратою даних (якщо раптом число не вміститься в тип int
).
int x = (int) Math.round(дійсне_число)
Приклади:
Команда | Результат |
---|---|
|
|
|
|
|
|
Метод Math.ceil()
Метод Math.ceil()
округлює число вгору (до більшого цілого). Приклади:
Команда | Результат |
---|---|
|
|
|
|
|
|
Метод Math.floor()
Метод Math.floor()
округлює число вниз (до меншого цілого). Приклади:
Команда | Результат |
---|---|
|
|
|
|
|
|
Натомість для округлення числа до меншого цілого простіше використовувати звичайний оператор приведення типу — (int)
:
Команда | Результат |
---|---|
|
|
Якщо вам складно запам'ятати ці команди, у пригоді стане невеличкий урок англійської:
Math
— математикаRound
— круглий/округлюватиCeiling
— стеляFloor
— підлога
2. Будова чисел із рухомою крапкою
Тип double
може зберігати значення від -1.7*10308
до +1.7*10308
. Такий широчезний діапазон значень (порівняно з типом int
) пояснюється тим, що будова типу double
(і типу float
) суттєво відрізняється від будови цілих типів. Кожна змінна типу double
містить два числа: перше має назву «мантиса», а друге — «степінь».
Припустімо, ми маємо число 123456789
і зберегли його в змінній типу double
. Це число буде перетворено у форму 1.23456789*108
, і в змінній типу double
зберігатимуться два числа — 23456789
і 8
. Червоним виділено «значущу частину числа» (манти́су), синім — степінь.
Завдяки такому підходу можна зберігати і дуже великі, і дуже малі числа. Однак оскільки розмір числа обмежений 8 байтами (64 бітами) і частина бітів використовується для зберігання степеня (а також знака числа та знака степеня), максимальна довжина мантиси становить 15 цифр.
Це дуже спрощений опис будови дійсних чисел. Детальнішій опис див. тут.
3. Втрата точності під час операцій із дійсними числами
Виконуючи різні дії з дійсними числами, слід мати на увазі, що дійсні числа не є точними. Завжди є похибки округлення, похибки перетворення чисел з десяткової системи у двійкову, а найчастішою проблемою є втрата точності під час додавання/віднімання чисел надто різних розмірностей.
Для новачків у програмуванні остання ситуація є найменш очікуваною.
Якщо від числа 109
відняти 1/109
, ми знову ж таки отримаємо 109
.
Віднімання чисел надто різних розмірностей | Пояснення |
---|---|
|
Друге число надто мале, і його значуща частина ігнорується (виділено сірим). Помаранчевим виділено 15 значущих цифр. |
Ну що сказати? Програмування — це не математика.
4. Небезпека порівняння дійсних чисел
Ще одна небезпека чатує на програмістів під час порівняння дійсних чисел. Оскільки під час операцій із цими числами можуть накопичуватися похибки округлення, то можливі такі ситуації, коли дійсні числа мали б бути рівними між собою, однак вони не рівні. І навпаки: числа мають бути нерівними, а вони рівні.
Приклад:
Команда | Пояснення |
---|---|
|
Змінна a матиме значення 1000000000.0 Змінна c матиме значення 1000000000.0 (число у змінній b надто мале)
|
У наведеному вище прикладі а
і с
мають бути нерівними, однак вони рівні.
Або розглянемо інший приклад:
Команда | Пояснення |
---|---|
|
Змінна a матиме значення 1.0 Змінна b матиме значення 1.0
|
5. Цікавий факт про слово strictfp
У Java є спеціальне ключове слово strictfp
(strict floating point), якого немає в інших мовах програмування. А знаєте, навіщо воно потрібне? Воно погіршує точність операцій із дійсними числами. Послухайте історію про те, як воно виникло.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ