Tag Archives: остаток от деления. Операции над примитивными типами в Java
По приоритетности за унарными операторами следуют арифметические операторы. Эта группа включает в себя четыре наиболее распространённых оператора: сложение, вычитание, умножение, деление. И не только их. Существует также оператор деления по модулю, который обозначается знаком %. Арифметические операторы разделены на две группы. В первой, более приоритетной, группе находятся *, /, %. Во второй, соответственно, + и -.
Умножение и деление (* и /)
Операторы * и / выполняют умножение и деление над всеми примитивными числовыми типами и char. При делении на ноль возникает ArithmeticException .
Вы, наверное, недоумеваете, зачем я вам рассказываю про умножение и деление известное вам с первого класса. Однако, в программировании мы имеем дело с некоторыми ограничениями, связанными с представлением чисел в компьютере. Эти ограничения накладываются на все числовые форматы, от byte до double . Но наиболее заметны они для целочисленного типа int .
Если вы умножаете или делите два числа, результат вычисляется посредством целочисленной арифметики и сохраняется либо в int , либо в long . Если числа очень большие, то результат будет больше максимального числа, которое можно представить в этих числах. А значит, результат не сможет правильно закодироваться компьютером и не будет иметь смысла. Например, тип byte используется для представления чисел в диапазоне от -128 до 127. Если мы умножим 64 и 4, то результат 256, имеющий в двоичной записи 100000000 девять символов, будет закодирован, как 0, потому что byte использует лишь 8 символов.
Рассмотрим деление. Если вы делите в целочисленной арифметике, результат должен быть обязательно целочисленным. И значит, дробная часть будет потеряна. Например, 7/4 даёт нам 1.75, но в целочисленной арифметике это будет 1.
Таким образом, если вы имеете дело со сложными выражениями, вы можете выбирать последовательность умножений и делений. Но имейте в виду, что умножение может привести к переполнению , а деление - к потере точности . Народная мудрость считает, что выполнение сначала умножений, а потом делений в большинстве случаев выдаёт правильный результат. Рассмотрим пример:
1. int a = 12345, b = 234567, c, d;
2. long e, f;
3.
4. c = a * b / b; // должно равняться а=12345
5. d = a / b * b; // тоже должно равняться а=12345
6. System.out.println(“a is “ + a +
7. “\nb is “ + b +
8. “\nc is “ + c +
9. “\nd is “ + d);
10.
11. e = (long)a * b / b;
12. f = (long)a / b * b;
13. System.out.println(
14. “\ne is “ + e +
15. “\nf is “ + f);
Результат работы данного фрагмента выдаст следующее:
A is 12345
b is 234567
c is -5965
d is 0
e is 12345
f is 0
Пусть вас не смущают числовые значения данного примера. Важно то, что при выполнении умножения первым мы получили переполнение (c is -5965 ), когда закодировали его в тип int . Однако мы можем получить правильный результат, если закондируем его в более длинный тип, как, например, long . В обоих случаях применение первым деления будет катастрофическим для результата, независимо от длины его типа.
Деление по модулю %
Результат деления по модулю - остаток от деления. Например, 7/4 равно 1 с остатком 3. Поэтому 7%4 = 3. Обычно операнды имеют целочисленный тип, но иногда оператор применяется и к числам с плавающей точкой. Также следует знать некоторые особенности данного оператора, когда операнды отрицательные.
При негативных или дробных операндах правило такое: вычитайте правый операнд из левого до тех пор, пока последний не станет меньше первого. Примеры:
17%5 = ? 17-5=12>5; 12-5=7>5; 7-5=2<5. Значит 17%5 = 2
21%7? 21-7=14>7; 14-7=7=7; 7-7=0<7. Значит 21%7 = 0
7.6%2.9? 7.6-2.9=4.7>2.9; 4.7-2.9=1.8<2.9. Значит 7.6%2.9=1.8
Заметьте: знак результата (положительный или отрицательный) целиком и полностью определён знаком левого операнда, то есть делимого.
Когда деление по модулю производится над дробными числами, то суть этой операции состоит в том, чтобы вычесть делитель несколько раз. Результат может быть также дробным числом.
Простое правило для отрицательных операндов такое: отбросьте знак минуса от операндов, произведите деление по модулю с положительными операндами, а затем поставьте перед результатом минус, если левый операнд (делимое) был отрицательным.
Деление по модулю, как и нормальное деление, может выбросить исключение ArithmeticException , если делитель (правый операнд) ровняется нулю.
Учеба на "Разработчика игр" + трудоустройство
Операторы в языке Java
Для обозначения операций сложения, вычитания, умножения и деления в языке Java используются обычные арифметические операторы + - * /.
Оператор / обозначает целочисленное деление, если оба его аргумента являются целыми числами. В противном случае этот оператор обозначает деление чисел с плавающей точкой. Остаток от деления целых чисел (т.е. функция mod) обозначается символом %.
Например, 15/2 равно 7, 15%2 равно 1, а 15 . 0/2 равно 7 . 5.
Заметим, что целочисленное деление на 0 возбуждает исключительную ситуацию, в то время как результатом деления на 0 чисел с плавающей точкой является бесконечность или NaN.
Арифметические операторы можно использовать для инициализации переменных.
int n = 5;
int а = 2 * n; // Значение переменной а равно 10.
В операторах присваивания удобно использовать сокращенные бинарные арифметические операторы.
Например, оператор
х + = 4;
эквивалентен оператору
х = х + 4;
(Сокращенные операторы присваивания образуются путем приписывания символа арифметической операции, например * или %, перед символом =, например *=или %=.)
Одной из заявленных целей языка Java является машинная независимость.
Вычисления должны приводить к одинаковому результату, независимо от того, какая виртуальная машина их выполняет. Для арифметических вычислений над числами с плавающей точкой это неожиданно оказалось трудной задачей. Тип double для хранения числовых значений использует 64 бит, однако некоторые процессоры применяют 80-разрядные регистры с плавающей точкой. Эти регистры обеспечивают дополнительную точность на промежуточных этапах вычисления, Рассмотрим в качестве примера следующее выражение:
double w = х * у / z;
Многие процессоры компании Intel вычисляют выражение х * у и сохраняют этот промежуточный результат в 80-разрядном регистре, затем делят его на значение переменной z и в самом конце округляют ответ до 64 бит. Так можно повысить точность вычислений, избежав переполнения. Однако этот результат может оказаться иным, если в процессе всех вычислений используется 64-разрядный процессор.
По этой причине в первоначальном описании виртуальной машины Java указывалось, что все промежуточные вычисления должны округляться. Это возмутило компьютерное сообщество. Переполнение могут вызвать не только округленные вычисления. На самом деле они выполняются медленнее, чем более точные вычисления, поскольку операции округления занимают определенное время. В результате разработчики языка Java изменили свое мнение, стремясь разрешить конфликт между оптимальной производительностью и отличной воспроизводимостью результатов.
По умолчанию разработчики виртуальной машины теперь позволяют использовать расширенную точность в промежуточных вычислениях. Однако методы, помеченные ключевым словом strictfp,должны использовать точные операции над числами с плавающей точкой, что гарантирует воспроизводимость результатов. Например, метод main можно пометить ключевыми словами, как показано ниже:
public static strictfp void main(String args)
В этом случае все команды внутри метода main будут выполнять точные операции над числами с плавающей точкой.
Детали выполнения этих операций тесно связаны с особенностями работы процессоров Intel. По умолчанию промежуточные результаты могут использовать расширенный показатель, но не расширенную мантиссу. (Микросхемы компании Intel поддерживают округление мантиссы без потери производительности.) Следовательно, единственное различие между вычислениями по умолчанию и точными вычислениями состоит в том, что точные вычисления могут приводить к переполнению, а вычисления по умолчанию - нет.
Если при чтении этого замечания ваш взгляд потускнел, не волнуйтесь. Для большинства программистов этот вопрос совершенно не важен. Переполнение при вычислениях чисел с плавающей точкой в большинстве случаев не возникает. В этой книге мы не будем использовать ключевое слово strictfp.
Операторы инкрементации и декрементации
Программисты, конечно, знают, что одной из наиболее распространенных операций с числовыми переменными является добавление или вычитание единицы. В языке Java, как и в языках С и C++, есть операторы инкрементации и декрементации: оператор х++ добавляет единицу к текущему значению переменной х, а оператор х- - вычитает из него единицу.
Например, код
int n = 12;
n++;
делает значение переменной n равным 13.
Поскольку эти операторы изменяют значение переменной, их нельзя применять к самим числам. Например, оператор 4++ является недопустимым.
Существует два вида этих операторов. Выше показана "постфиксная" форма оператора, в которой символы операции размещаются после операнда. Есть и "префиксная" форма- ++n.
Оба этих оператора увеличивают значение переменной на единицу. Разница между ними проявляется, только когда эти операторы используются внутри выражений. Префиксная форма оператора инкрементации сначала добавляет единицу к значению переменной, в то время как постфиксная форма использует старое значение этой переменной.
int m = 7;
int n = 7;
int а = 2 * ++m; // Теперь значение а равно 16, a m - 8.
int b = 2 * n++; // Теперь значение b равно 14, a n - 8.
(Поскольку именно оператор ++ дал имя языку C++, это послужило поводом к первой шутке о нем. Недоброжелатели указывают, что даже имя этого языка содержит в себе ошибку: "Кроме всего прочего, этот язык следовало бы назвать ++С, потому что мы хотим использовать этот язык только после его улучшения".)
Последнее обновление: 30.10.2018
Большинство операций в Java аналогичны тем, которые применяются в других си-подобных языках. Есть унарные операции (выполняются над одним операндом), бинарные - над двумя операндами, а также тернарные - выполняются над тремя операндами. Операндом является переменная или значение (например, число), участвующее в операции. Рассмотрим все виды операций.
В арифметических операциях участвуют числами. В Java есть бинарные арифметические операции (производятся над двумя операндами) и унарные (выполняются над одним операндом). К бинарным операциям относят следующие:
операция сложения двух чисел:
Int a = 10; int b = 7; int c = a + b; // 17 int d = 4 + b; // 11
операция вычитания двух чисел:
Int a = 10; int b = 7; int c = a - b; // 3 int d = 4 - a; // -6
операция умножения двух чисел
Int a = 10; int b = 7; int c = a * b; // 70 int d = b * 5; // 35
операция деления двух чисел:
Int a = 20; int b = 5; int c = a / b; // 4 double d = 22.5 / 4.5; // 5.0
При делении стоит учитывать, так как если в операции участвуют два целых числа, то результат деления будет округляться до целого числа, даже если результат присваивается переменной float или double:
Double k = 10 / 4; // 2 System.out.println(k);
Чтобы результат представлял числос плавающей точкой, один из операндов также должен представлять число с плавающей точкой:
Double k = 10.0 / 4; // 2.5 System.out.println(k);
получение остатка от деления двух чисел:
Int a = 33; int b = 5; int c = a % b; // 3 int d = 22 % 4; // 2 (22 - 4*5 = 2)
Также есть две унарные арифметические операции, которые производятся над одним числом: ++ (инкремент) и -- (декремент). Каждая из операций имеет две разновидности: префиксная и постфиксная:
++ (префиксный инкремент)
Предполагает увеличение переменной на единицу, например, z=++y (вначале значение переменной y увеличивается на 1, а затем ее значение присваивается переменной z)
Int a = 8; int b = ++a; System.out.println(a); // 9 System.out.println(b); // 9
++ (постфиксный инкремент)
Также представляет увеличение переменной на единицу, например, z=y++ (вначале значение переменной y присваивается переменной z, а потом значение переменной y увеличивается на 1)
Int a = 8; int b = a++; System.out.println(a); // 9 System.out.println(b); // 8
-- (префиксный декремент)
уменьшение переменной на единицу, например, z=--y (вначале значение переменной y уменьшается на 1, а потом ее значение присваивается переменной z)
Int a = 8; int b = --a; System.out.println(a); // 7 System.out.println(b); // 7
-- (постфиксный декремент)
z=y-- (сначала значение переменной y присваивается переменной z, а затем значение переменной y уменьшается на 1)
Int a = 8; int b = a--; System.out.println(a); // 7 System.out.println(b); // 8
Приоритет арифметических операций
Одни операции имеют больший приоритет чем другие и поэтому выполняются вначале. Операции в порядке уменьшения приоритета:
++ (инкремент), -- (декремент)
* (умножение), / (деление), % (остаток от деления)
+ (сложение), - (вычитание)
Приоритет операций следует учитывать при выполнении набора арифметических выражений:
Int a = 8; int b = 7; int c = a + 5 * ++b; System.out.println(c); // 48
Вначале будет выполняться операция инкремента ++b , которая имеет больший приоритет - она увеличит значение переменной b и возвратит его в качестве результата. Затем выполняется умножение 5 * ++b , и только в последнюю очередь выполняется сложение a + 5 * ++b
Скобки позволяют переопределить порядок вычислений:
Int a = 8; int b = 7; int c = (a + 5) * ++b; System.out.println(c); // 104
Несмотря на то, что операция сложения имеет меньший приоритет, но вначале будет выполняться именно сложение, а не умножение, так как операция сложения заключена в скобки.
Ассоциативность операций
Кроме приоритета операции отличаются таким понятием как ассоциативность . Когда операции имеют один и тот же приоритет, порядок вычисления определяется ассоциативностью операторов. В зависимости от ассоциативности есть два типа операторов:
Левоассоциативные операторы, которые выполняются слева направо
Правоассоциативные операторы, которые выполняются справа налево
Так, некоторые операции, например, операции умножения и деления, имеют один и тот же приоритет. Какой же тогда будет результат в выражении:
Int x = 10 / 5 * 2;
Стоит нам трактовать это выражение как (10 / 5) * 2 или как 10 / (5 * 2) ? Ведь в зависимости от трактовки мы получим разные результаты.
Поскольку все арифметические операторы (кроме префиксного инкремента и декремента) являются левоассоциативными, то есть выполняются слева направо. Поэтому выражение 10 / 5 * 2 необходимо трактовать как (10 / 5) * 2 , то есть результатом будет 4.
Операции с числами с плавающей точкой
Следует отметить, что числа с плавающей точкой не подходят для финансовых и других вычислений, где ошибки при округлении могут быть критичными. Например:
Double d = 2.0 - 1.1; System.out.println(d);
В данном случае переменная d будет равна не 0.9, как можно было бы изначально предположить, а 0.8999999999999999. Подобные ошибки точности возникают из-за того, что на низком уровне для представления чисел с плавающей точкой применяется двоичная система, однако для числа 0.1 не существует двоичного представления, также как и для других дробных значений. Поэтому если в таких случаях обычно применяется класс BigDecimal, который позволяет обойти подобные сиуации.
1. Основные арифметические операции
В следующей таблице перечислены основные арифметические операции, применяемые в языке Java:
Рассмотрим некоторые правила работы с арифметическими операциями:
- Выражения вычисляются слева направо, если не добавлены круглые скобки или одни операции имеют более высокий приоритет.
- Операции *, /, и % имеют более высокий приоритет чем + и -.
Пример 1. Арифметические операции над целочисленными значениями
Например, в этом коде, переменные a и b будут иметь разные значения:
Public class BasicIntMath { public static void main(String args) { int a = 4 + 5 - 2 * 3; int b = 4 + (5 - 2) * 3; System.out.println("a = " + a); System.out.println("b = " + b); } }
Результат выполнения:
A = 3 b = 13
- Операция унарного вычитания изменяет знак своего единственного операнда.
- Операция унарного сложения просто возвращает значение своего операнда. Она в принципе не является необходимой, но возможна.
Пример 2. Унарные операции сложения и вычитания
public class UnarySignOperation { public static void main(String args) { double a = -6; double b = +6; System.out.println(a); System.out.println(b); } }- Когда операция деления выполняется над целочисленным типом данных, ее результат не будет содержать дробный компонент.
Пример 3. Деление целочисленных чисел
public class IntDivision { public static void main(String args) { int a = 16 / 5; System.out.println(a); } }Результат выполнения этой программы:
- Операнды арифметических операций должны иметь числовой тип. Арифметические операции нельзя выполнять над логическими типами данных, но допускается над типами данных char , поскольку в Java этот тип, по существу, является разновидностью типа int .
Пример 4. Арифметические операции над переменными типа char
public class BasicCharMath1 { public static void main(String args) { char c = "n"; System.out.println(c); System.out.println(c + 1); System.out.println(c / 5); } }Результат выполнения:
N 111 22
Пример 5. Арифметические операции над переменными типа char
public class BasicCharMath2 { public static void main(String args) { char c1 = "1"; char c2 = "\u0031"; char c3 = 49; System.out.println(c1 + c2 + c3); } }Результат выполнения:
Оператор деления по модулю — обозначается символом %. Этот оператор возвращает остаток от деления первого числа на второй. При делении целого числа результатом будет тоже целое число.
Пример 6. Деление по модулю
public class DivisionByModule { public static void main(String args) { int a = 6 % 5; double b = 6.2 % 5.0; System.out.println(a); System.out.println(b); } }Результат выполнения:
1 1.2000000000000002
2. Составные арифметические операции с присваиванием
В Java имеются специальные операции, объединяющие арифметические операции с операцией присваивания. Рассмотрим следующее выражение:
А = а + 4;
B Java эту операцию можно записать следующим образом:
А += 4;
Составные операции с присваиванием позволяют не только уменьшить объем кода, но и позволяют выполнять автоматическое преобразование чего не делают обычные операции.
Пример 5. Составные арифметические операции с присваиванием
public class CompoundOperations { public static void main(String args) { int a = 1; int b = 2; int c = 3; a += 3; b *= 2; c += a * b; System.out.println(a); System.out.println(b); System.out.println(c); } }Большинство операций над примитивными типами выполняется не с помощью методов, а с помощью специальных символов, называемых знаком операции .
Операция присваивания
Присвоение переменной значения константы, другой переменной или выражения (переменных и/или констант, разделенных знаками операций), называется операцией присваивания и обозначается знаком "= ", например: x = 3 ; y = x; z = x; В Java допустимо многократное использование операции присваивания в одном выражении, например: x1 = x2 = x3 = 0 ; Эта операция выполняется справа налево, т.е. сначала переменной x3 присваивается значение 0 , затем переменной x2 присваивается значение переменной x3 (0), и, наконец, переменной x1 присваивается значение переменной x2 (0). Знаки операций, аргументами которых являются числа, разделяются на две категории: унарные (unary) знаки операций с одним аргументом и бинарные (binary) с двумя аргументами.Унарные операции
В Java определены следующие унарные операции:- унарный минус " - " – меняет знак числа или выражения на противоположный;
- унарный плюс " + " – не выполняет никаких действий над числом или выражением;
- побитовое дополнение " ~ " (только для целых) – инвертирует все биты поля числа (меняет 0 на 1 и 1 на 0);
- инкремент " ++ " (только для целых) – увеличивает значение переменной на 1;
- декремент " -- " (только для целых) – уменьшает значение переменной на 1.
Арифметические бинарные операции
В Java определены следующие арифметические бинарные операции :- сложение " + ";
- вычитание " - ";
- умножение " * ";
- деление " / ";
- вычисление остатка от деления целых чисел " % " (возвращает остаток от деления первого числа на второе, причем результат будет иметь тот же знак, что и делимое), например, результат операции 5%3 будет равен 2 , а результат операции (-7)%(-4) будет равен -3 . В Java операция может использоваться и для вещественных переменных (типа float или double).
Побитовые операции
- Побитовые операции рассматривают исходные числовые значения как поля битов и выполняют над ними следующие действия:
- установка бита в i -ой позиции поля результата в 1 , если оба бита в i -ых позициях операндов равны 1 , или в 0 в противном случае – побитовое И (" & ");
- установка бита в i -ой позиции поля результата в 1 , если хотя бы один бит в i -ых позициях операндов равен 1 , или в 0 в противном случае – побитовое ИЛИ (" | ");
- установка бита в i -ой позиции поля результата в 1 , если биты в i -ых позициях операндов не равны друг другу, или в 0 в противном случае – побитовое исключающее ИЛИ (" ^ ");
- сдвиг влево битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом не меняется) – побитовый сдвиг влево с учетом знака " << ";
- сдвиг вправо битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом не меняется) – побитовый сдвиг вправо с учетом знака " >> ";
- сдвиг вправо битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом также сдвигается) – побитовый сдвиг вправо без учета знака " >>> ".
Побитовое И
int x = 112 ; int y = 94 ; int z; z = x & y; // z=80: 00000000 00000000 00000000 01010000Побитовое ИЛИ
int x = 112 ; // x: 00000000 00000000 00000000 01110000 int y = 94 ; // y: 00000000 00000000 00000000 01011110 int z; z = x | y; // z = 126: 00000000 00000000 00000000 01111110Побитовое исключающее ИЛИ
int x = 112 ; // x: 00000000 00000000 00000000 01110000 int y = 94 ; // y: 00000000 00000000 00000000 01011110 int z; z = x ^ y; // z = 46: 00000000 00000000 00000000 00101110Сдвиг влево с учетом знака
int x = 31 , z; // x: 00000000 00000000 00000000 00011111 z = x << 2 ; // z = 124: 00000000 00000000 00000000 01111100Сдвиг вправо с учетом знака
int x = - 17 , z; z = x >> 2 ; // z = -5: 11111111 11111111 11111111 11111011Сдвиг вправо без учета знака
int x = - 17 , z; // x: 11111111 11111111 11111111 11101111 z = x >>> 2 ; // z = 1073741819 // z: 00111111 11111111 11111111 11111011
Комбинированные операции
В Java для бинарных арифметических операций можно использовать комбинированные (составные) знаки операций: идентификатор операция = выражение Это эквивалентно следующей операции: идентификатор = идентификатор операция выражение Примеры:- Выражение x += b означает x = x + b .
- Выражение x -= b означает x = x - b .
- Выражение x *= b означает x = x * b .
- Выражение x /= b означает x = x / b .
- Выражение x %= b означает x = x % b .
- Выражение x &= b означает x = x & b .
- Выражение x |= b означает x = x | b .
- Выражение x ^= b означает x = x ^ b .
- Выражение x <<= b означает x = x << b .
- Выражение x >>= b означает x = x >> b .
- Выражение x >>>= b означает x = x >>> b .
Операции сравнения
В Java определены следующие операции сравнения:- " == " (равно), " != " (не равно),
- " > " (больше), " >= " (больше или равно),
- " < " (меньше) " <= " (меньше или равно)
Булевские операции
Булевские операции выполняются над булевскими переменными и их результатом также является значение типа boolean . В Java определены следующие булевские операции:- отрицание "!" – замена false на true , или наоборот;
- операция И "&" – результат равен true , только, если оба операнда равны true , иначе результат – false ;
- операция ИЛИ " | " – результат равен true , только, если хотя бы один из операндов равен true , иначе результат – false .
- операция исключающее ИЛИ " ^ " – результат равен true , только, если операнды не равны друг другу, иначе результат – false .
Условная операция
Условная операция записывается в форме выражение-1?выражение-2:выражение-3 . При этом сначала вычисляется выражение выражение-1 , которое должно дать булевское значение, а затем, если выражение-1 имеет значение true , вычисляется и возвращается выражение-2 как результат выполнения операции, либо (если выражение-1 имеет значение false), вычисляется и, как результат выполнения операции, возвращается выражение-3 . Пример условной операции: x= n> 1 ? 0 : 1 ; Переменной x будет присвоено значение 0 , если n>1 (выражение n>1 имеет значение true) или 1 , если n≤1 (выражение n>1 имеет значение false).Старшинство операций
Операции в выражениях выполняются слева направо, однако, в соответствии со своим приоритетом. Так операции умножения в выражении y = x + z* 5 ; будет выполнена раньше, чем операция сложения, поскольку приоритет операции умножения выше, чем приоритет операции сложения. Приоритеты операций (в порядке уменьшения приоритета) в Java приведены в табл. 1.Круглые скобки повышают старшинство операций, которые находятся внутри них. Так, если в приведенное выше выражение вставить скобки: y = (x + z) * 5 ; то сначала будет выполнена операция сложения, а затем операция умножения. Иногда скобки используют просто для того, чтобы сделать выражение более читаемым, например: (x > 1 ) && (x <= 5 ) ;