Главная » Java » Арифметические операторы

0

Java поддерживает семь арифметических  операторов, которые работают с любыми числовыми типами:

+ сложение

- вычитание

* умножение

/ деление

% остаток

Java также поддерживает унарный минус (-) для изменения знака числа. Знак может быть изменен оператором следующего вида:

val = -val;

Кроме того, имеется и унарный плюс — например, +3. Унарный плюс включен для симметрии, без него было бы невозможно записывать константы вида +2.0.

5.15.1. Целочисленная арифметика

Целочисленная арифметика выполняется с дополнением по модулю 2 — то есть при выходе за пределы своего диапазона допустимых значений (int или long) величина приводится по модулю, равному величине диапазона. Таким образом, в целочисленной арифметике никогда не происходит переполнения, встречаются лишь выходы значения за пределы диапазона.

При целочисленном делении происходит округление по направлению к нулю (то есть 7/2 равно 3, а –7/2 равно –3). Деление и остаток для целых типов подчиняются следующему правилу:

(x/y)*y + x%y == x

Следовательно, 7%2 равно 1, а –7%2 равно –1. Деление на ноль или нахождение остатка от деления на 0 в целочисленной арифметике не допускается и приводит к запуску исключения ArithmeticException.

Арифметические  операции с символами представляют собой целочисленные операции после неявного приведения char к типу int.

5.15.2. Арифметика с плавающей точкой

Для работы с плавающей точкой (как для представления, так и для совершения операций) в Java используется стандарт IEEE 7541985. В соответствии с ним допускаются как переполнение в сторону бесконечности (значение превышает максимально

допустимое для double или float), так и вырождение в ноль (значение становится слишком

малым и неотличимым от нуля для double или float). Также имеется специальное представление NaN (“Not A Number”, то есть “не-число”) для результатов недопустимых операций — например, деления на ноль.

Арифметические  операции с конечными операндами работают в соответствии с общепринятыми нормами. Знаки выражений с плавающей точкой также подчиняются этим правилам; перемножение двух чисел с одинаковым знаком дает положительный

результат, тогда как при перемножении двух чисел с разными знаками результат будет отрицательным.

Сложение двух бесконечностей с одинаковым знаком дает бесконечность с тем же знаком. Если знаки различаются — ответ равен NaN. Вычитание бесконечностей с одинаковым знаком дает NaN; вычитание бесконечностей с разными знаками дает бесконечность, знак которой совпадает со знаком левого операнда. Например, (-(-)) равно . Результат любой арифметической  операции, в которой участвует величина NaN, также равен NaN. При переполнении получается бесконечность с соответствующим  знаком, а при вырождении — ноль с соответствующим  знаком. В стандарте IEEE имеется отрицательный ноль, который равен +0.0, однако 1f/0f равно положительной бесконечности, а 1f/-0f равно отрицательной бесконечности.

Если -0.0 == 0.0, как же отличить отрицательный ноль, полученный в результате вырождения, от положительного?  Его следует использовать в выражении, в котором участвует знак, и проверить результат. Например, если значение x равно отрицательному нулю, то выражение 1/x будет равно отрицательной бесконечности, а если положительному — то положительной бесконечности.

Операции с бесконечностями  выполняются по стандартным математическим правилам. Сложение (или вычитание) конечного числа с любой бесконечностью также дает бесконечность. Например, (-+x) дает – для любого конечного x.

Бесконечность может быть получена за счет соответствующей  арифметической  операции или использования имени бесконечности для объектов типа float или double: POSITIVE_INFINITY  или NEGATIVE_INFINITY. Например, Double.NEGATIVE_INFINITY представляет значение отрицательной бесконечности для объектов типа double.

Умножение бесконечности на ноль дает в результате NaN. Умножение бесконечности на ненулевое конечное число дает бесконечность с соответствующим  знаком.

Деление, а также деление с остатком может давать бесконечность или NaN, но никогда не приводит к исключениям. В таблице перечислены результаты арифметических  операций при различных значениях операндов:

x

y

x/y

x%y

Конечное

±0.0

NaN

Конечное

±0.0

x

±0.0

±0.0

NaN

NaN

Конечное

NaN

NaN       NaN

Во всех остальных отношениях нахождение остатка при делении с плавающей точкой происходит аналогично нахождению целочисленного остатка. Вычисление остатка методом Math.IEEERemainder  описано в разделе 14.8.

5.15.3. Арифметика с плавающей точкой и стандарт

IEEE-754

Арифметика с плавающей точкой в языке Java представляет собой подмножество стандарта IEEE-754-1985. Тем читателям, которым необходимо полное понимание всех связанных с этим аспектов, следует обратиться к спецификации языка Java “The Java Language Specification”. Вот краткая сводка ключевых отличий:

Непрерываемая арифметика: в Java отсутствуют какие-либо исключения или иные события, сигнализирующие  об исключительных  состояниях в смысле IEEE:

деление на ноль, переполнение, вырождение или потеря точности. В арифметике

Java не предусмотрены какие-либо действия при появлении значения NaN.

Округление: в арифметике Java происходит округление к ближайшему — неточный результат округляется к ближайшему представимому значению; при наличии двух одинаково близких значений предпочтение отдается тому, у которого младший бит равен 0. Это соответствует стандарту IEEE. Однако при преобразовании  числа с плавающей точкой к целому в Java происходит округление по направлению к нулю. Java не допускает выбираемых пользователем режимов округления для вычислений с плавающей точкой: округления вверх, вниз или по направлению к нулю.

Условные операции: в арифметике Java отсутствуют реляционные предикаты, которые бы реализовывали понятие упорядоченности,  за исключением !=. Тем не менее все возможные случаи, кроме одного, могут быть смоделированы программистом с использованием существующих операций отношения и логического отрицания. Исключением является отношение “упорядочено, но не равно”, которое при необходимости может быть представлено в виде x<y || x>y.

Расширенные форматы: арифметика Java не поддерживает никаких расширенных форматов, за исключением того, что double может выступать в качестве расширения формата с одинарной точностью. Наличие других расширенных форматов не является требованием стандарта.

5.15.4. Конкатенация строк

Оператор + может применяться для конкатенации строк. Приведем пример:

String boo = "boo";

String cry = boo + "hoo"; cry += "!"; System.out.println(cry);

А вот как выглядит результат работы:

boohoo!

Оператор + также используется для конкатенации объектов типа String со строковым представлением  любого примитивного типа или объекта. Например, следующий фрагмент заключает строку в кавычки-“елочки”  (guillemet characters), которые используются для цитирования во многих европейских языках:

public static String guillemete(String quote) {

return ‘"’ + quote + ‘"';

}

Неявное преобразование примитивных типов и объектов в строки происходит лишь при использовании + или += в выражениях со строками — и нигде более. Например, методу, вызываемому с параметром типа String, нужно передавать именно String — вы не сможете передать объект или float и рассчитывать на его неявное преобразование.

5.16. Операторы приращения и уменьшения

Операторы ++ и — применяются соответственно для приращения и уменьшения значений. Выражение i++ эквивалентно i = i + 1, если не считать того, что в первом случае i вычисляется всего один раз. Например, оператор

arr[where()]++;

всего один раз вызывает метод where и использует результат в качестве индекса массива.

С другой стороны, в операторе

arr[where()] = arr[where()] + 1;

метод where будет вызываться дважды: один раз при вычислении правостороннего индекса, а во второй раз — при вычислении левостороннего индекса. Если при каждом вызове where возвращается новое значение, результат будет отличаться от приведенного выше выражения, в котором использован оператор ++.

Операторы приращения и уменьшения могут быть либо префиксными, либо постфиксными — то есть стоять либо до, либо после своего операнда. Если оператор стоит перед операндом (префикс), то операция приращения/уменьшения выполняется до возвращения результата выражения. Если же оператор стоит после (постфикс), то операция выполняется после использования результата. Пример:

class IncOrder {

public static void main(String[] args) {

int i = 16;

System.out.println(++i + " " + i++ + " " + i);

}

}

Результат работы будет выглядеть так:

17 17 18

Первое выведенное значение равно i после выполнения префиксного приращения до 17; второе значение равно i после этого приращения, но до выполнения следующего, постфиксного приращения до 18; наконец, значение i выводится после его постфиксного приращения в середине оператора вывода.

Операции приращения и уменьшения ++ и — могут применяться к переменным типа char

для получения следующего или предыдущего символа в кодировке Unicode.

Источник: Арнольд К., Гослинг Д. – Язык программирования Java (1997)

По теме:

  • Комментарии