Чтение онлайн

ЖАНРЫ

Программирование на Java

Вязовик Н.А.

Шрифт:

Дробные типы

Дробные типы – это float и double . Их длина - 4 и 8 байт, соответственно. Оба типа знаковые. Ниже в таблице сведены их характеристики:

Таблица 4.2. Дробные типы данных.

Название типа

Длина (байты)

Область значений

float

4

3.40282347e+38f; 1.40239846e-45f

double

8

1.79769313486231570e+308; 4.94065645841246544e-324

Для

целочисленных типов область значений задавалась верхней и нижней границами, весьма близкими по модулю. Для дробных типов добавляется еще одно ограничение – насколько можно приблизиться к нулю, другими словами – каково наименьшее положительное ненулевое значение. Таким образом, нельзя задать литерал заведомо больший, чем позволяет соответствующий тип данных, это приведет к ошибке overflow. И нельзя задать литерал, значение которого по модулю слишком мало для данного типа, компилятор сгенерирует ошибку underflow.

// пример вызовет ошибку компиляции

float f = 1e40f;

// значение слишком велико, overflow

double d = 1e-350;

// значение слишком мало, underflow

Напомним, что если в конце литерала стоит буква F или f, то литерал рассматривается как значение типа float. По умолчанию дробный литерал имеет тип double, при желании это можно подчеркнуть буквой D или d.

Над дробными аргументами можно производить следующие операции:

* операции сравнения (возвращают булево значение)

<, <=, >, >=

==, !=

* числовые операции (возвращают числовое значение)

унарные операции + и -

арифметические операции +, -, *, /, %

операции инкремента и декремента (в префиксной и постфиксной форме): ++ и --

* оператор с условием ?:

* оператор приведения типов

* оператор конкатенации со строкой +

Практически все операторы действуют по тем же принципам, которые предусмотрены для целочисленных операторов (оператор деления с остатком % рассматривался в предыдущей лекции, а операторы ++ и -- также увеличивают или уменьшают значение переменной на единицу). Уточним лишь, что операторы сравнения корректно работают и в случае сравнения целочисленных значений с дробными. Таким образом, в основном необходимо рассмотреть вопросы переполнения и преобразования типов при вычислениях.

Для дробных вычислений появляется уже два типа переполнения – overflow и underflow. Тем не менее, Java и здесь никак не сообщает о возникновении подобных ситуаций. Нет ни ошибок, ни других способов обнаружить их. Более того, даже деление на ноль не приводит к некорректной ситуации. А значит, дробные вычисления вообще не порождают никаких ошибок.

Такая свобода связана с наличием специальных значений дробного типа. Они определяются спецификацией IEEE 754 и уже перечислялись в лекции 3:

* положительная и отрицательная бесконечности (positive/negative infinity);

* значение "не число", Not-a-Number, сокращенно NaN ;

* положительный и отрицательный нули.

Все

эти значения представлены как для типа float, так и для double.

Положительную и отрицательную бесконечности можно получить следующим образом:

1f/0f // положительная бесконечность,

// тип float

– 1d/0d // отрицательная бесконечность,

// тип double

Также в классах Float и Double определены константы POSITIVE_INFINITY и NEGATIVE_INFINITY. Как видно из примера, такие величины получаются при делении конечных величин на ноль.

Значение NaN можно получить, например, в результате следующих действий:

0.0/0.0 // деление ноль на ноль

(1.0/0.0)0.0 // умножение бесконечности на ноль

Эта величина также представлена константами NaN в классах Float и Double.

Величины положительный и отрицательный ноль записываются очевидным образом:

0.0 // дробный литерал со значением

// положительного нуля

+0.0 // унарная операция +, ее значение -

// положительный ноль

– 0.0 // унарная операция -, ее значение -

// отрицательный ноль

Все дробные значения строго упорядочены. Отрицательная бесконечность меньше любого другого дробного значения, положительная – больше. Значения +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 ), то результатом будет бесконечность соответствующего знака.

print(1e20f*1e20f);

print(-1e200*1e200);

В результате получаем:

Infinity

– Infinity

Если результат, напротив, получается слишком мал ( underflow ), то он просто округляется до нуля. Так же поступают и в том случае, когда количество десятичных знаков превышает допустимое:

print(1e-40f/1e10f);

// underflow для float

print(-1e-300/1e100);

// underflow для double

float f=1e-6f;

print(f);

f+=0.002f;

print(f);

f+=3;

print(f);

f+=4000;

print(f);

Результатом будет:

0.0

– 0.0

1.0E-6

0.002001

3.002001

4003.002

Как видно, в последней строке был утрачен 6-й разряд после десятичной точки.

Другой пример (из спецификации языка Java):

double d = 1e-305 Math.PI;

print(d);

for (int i = 0; i < 4; i++)

Поделиться с друзьями: