Курс Програмування на Лекція №4 Типи даних
Для цілих типів область значень задавалася верхньою і нижньою межами, дуже близькими по модулю. Для дробових типів додається ще одне обмеження – наскільки можна наблизитися до нуля, тобто – яке найменше позитивне ненульове значення. Таким чином, не можна задати літерал наперед більший, ніж дозволяє відповідний тип даних, це призведе до помилки overflow. І не можна задати літерал, значення якого за модулем занадто мало для цього типу, компілятор згенерує помилку underflow.
Нагадаємо, що якщо в кінці літерала стоїть буква F або f, то літерал розглядається як значення типу float. За замовчуванням дробовий літерал має тип double, за бажанням це можна підкреслити буквою D або d.
Над дробовими аргументами можна виконувати такі операції:
- операції порівняння (повертають булеве значення)
- , >=
- ==, !=
Практично всі оператори діють за тими ж принципами, які передбачені для цілих операторів (оператор поділу з залишком % розглядався в попередній лекції, а оператори ++ і - також збільшують або зменшують значення змінної на одиницю). Уточнимо лише, що оператори порівняння коректно працюють і у разі порівняння цілісних значень із дробовими. Таким чином, в основному необхідно розглянути питання переповнення та перетворення типів під час обчислень.
Для дробових обчислень з'являється два типи переповнення – overflow і underflow . Проте Java і тут ніяк не повідомляє про виникнення подібних ситуацій. Немає помилок, ні інших способів виявити їх. Більше того, навіть поділ на нуль не призводить до некоректної ситуації. Отже, дробові обчислення взагалі не породжують жодних помилок.
Така свобода пов'язана знаявністю спеціальних значень дробового типу. Вони визначаються специфікацією IEEE 754 і вже перераховувалися в лекції 3:
- позитивна та негативна нескінченності (positive/negative infinity);
- значення "не число", Not-a-Number, скорочено NaN;
- позитивний та негативний нулі.
Всі ці значення представлені як для типу float, так і для double.
Позитивну та негативну нескінченності можна отримати таким чином:
Також у класах Float та Double визначено константи POSITIVE_INFINITY та NEGATIVE_INFINITY . Як видно з прикладу, такі величини виходять при розподілі кінцевих величин на нуль.
Значення NaN можна отримати, наприклад, внаслідок таких дій:
Ця величина також представлена константами NaN у класах Float та Double.
Величини позитивний та негативний нуль записуються очевидним чином:
Усі дробові значення суворо упорядковані. Негативна нескінченність менша за будь-яке інше дробове значення, позитивна – більше. Значення +0.0 і -0.0 вважаються рівними, тобто вираз 0.0==-0.0 істинно, а 0.0-0.0 - хибно. Однак інші оператори розрізняють їх, наприклад, вираз 1.0/0.0 дає позитивну нескінченність, а 1.0/-0.0 негативну.
Єдиний виняток - значення NaN. Якщо хоча б один із аргументів операції порівняння дорівнює NaN, то результат свідомо буде false (для оператора != відповідно завжди true). Отже, єдине значення x , у якому вираз x!=x істинно,– саме NaN .
Повертаємося до питання переповнення у числових операціях. Якщо отримуване значення занадто велике по модулю ( overflow ), результатом буде нескінченність відповідного знака.
В результаті отримуємо:
Якщорезультат, навпаки, виходить занадто малий (underflow), він просто округляється до нуля. Так само роблять і в тому випадку, коли кількість десяткових знаків перевищує допустиму:
Як видно, в останньому рядку було втрачено 6-й розряд після десяткової точки.
Інший приклад (із специфікації мови Java):
Таким чином, як і для цілих значень, явне виписування в коді літералів, які занадто великі ( overflow ) або занадто малі ( underflow ) для використовуваних типів, призводить до помилки компіляції (див. лекцію 3). Якщо переповнення виникає в результаті виконання операції, то повертається одне зі спеціальних значень.
Тепер перейдемо до перетворення типів. Якщо хоча б один аргумент має тип double, то значення всіх аргументів призводять до цього типу і результат операції також матиме тип double. Обчислення буде зроблено з точністю 64 біти.
Якщо ж аргументів типу double немає, а хоча б один аргумент має тип float, то всі аргументи наводяться до float, обчислення проводиться з точністю в 32 біти і результат має тип float.
Ці твердження вірні й у випадку, якщо один із аргументів цілісний. Якщо хоча б один із аргументів має значення NaN, то і результатом операції буде NaN.