Разберемся с одним из подходов к вводу данных из стандартного потока через класс java.util.Scanner . Сделаем это на примере простой задачи с очень полезного сайта e-olimp.com

Задача

Введите из стандартного потока одно число. В предположении, что это положительное двузначное целое число выведите в стандартный поток вывода каждую его цифру отдельно (через пробел). Порядок цифр менять не следует.

Тесты

Никаких специфических случаев в алгоритме не предполагается. Делаем три теста — самое маленькое число допустимого диапазона, самое большое и какое-нибудь значение из середины диапазона.

Вход Выход
10 1 0
99 9 9
54 5 4

Решение

Воспользуемся классом java.util.Scanner, чтобы ввести данные в формате целого числа. И вычислим обе его цифры.

Вывод цифр двухзначного целого числа

Java

class Main{ public static void main (String args) throws java.lang.Exception { java.util.Scanner i = new java.util.Scanner(System.in); int n = i.nextInt(); System.out.println(n / 10 + " " + n % 10); } }

class Main {

public static void main (String args ) throws java . lang . Exception {

java . util . Scanner i = new java . util . Scanner (System . in ) ;

int n = i . nextInt () ;

System . out . println (n / 10 + " " + n % 10 ) ;

Пояснения

  1. Описываем переменную i типа java.util.Scanner и тут же присваиваем ей значение нового объекта этого класса. Конструктор изготавливает объект Scanner ‘а из стандартного потока ввода. Т.е. i становится надстройкой над стандартным потоком ввода. Это позволяет нам прочесть целое число, а не просто читать методом read () по одному байту.
  2. С помощью метода nextInt () читаем последовательность цифр и преобразуем её в целое число. Число запоминаем в переменной n.
  3. n / 10 — число десятков в числе. Десятков будет в десять раз меньше чем само число. Выполняется целочисленное деление — деление нацело.
  4. n % 10 — вычисляем остаток от деления на десять — число единиц — самая правая цифра числа.
  5. n / 10 + » » + n % 10 — вставляем между двумя целыми строку из одного пробела. В этом случае числа также преобразуются в строковое представление и все три строки сливаются — называется конкатенация строк. Так работает со строковыми данными операция «+».

Ускоряем ввод/вывод

При всем удобстве указанного подхода он довольно медленный и иногда задачи не заходят по времени. Значительно ускорить работу можно использовав StreamTokenizer и PrintWriter.
Это увеличит объем кода, но сэкономит время.

Ускорение ввода/вывода

Java

import java.io.*; import java.util.*; class Main { static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); static PrintWriter out = new PrintWriter(System.out); static int nextInt() throws IOException { in.nextToken(); return (int)in.nval; } public static void main(String args) throws java.lang.Exception { int n = nextInt(); out.println(n / 10 + " " + n % 10); out.flush(); } }

import java . io . * ;

import java . util . * ;

class Main {

static StreamTokenizer in = new StreamTokenizer (new BufferedReader (new InputStreamReader (System . in ) ) ) ;

static PrintWriter out = new PrintWriter (System . out ) ;

static int nextInt () throws IOException {

По приоритетности за унарными операторами следуют арифметические операторы. Эта группа включает в себя четыре наиболее распространённых оператора: сложение, вычитание, умножение, деление. И не только их. Существует также оператор деления по модулю, который обозначается знаком %. Арифметические операторы разделены на две группы. В первой, более приоритетной, группе находятся *, /, %. Во второй, соответственно, + и -.

Умножение и деление (* и /)

Операторы * и / выполняют умножение и деление над всеми примитивными числовыми типами и 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 , если делитель (правый операнд) ровняется нулю.

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); } }
Учеба на "Разработчика игр" + трудоустройство

Операторы в языке 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, который позволяет обойти подобные сиуации.