что такое унарный минус
Унарные операторы в Java
Уже завтра в OTUS скоро стартует новая профессиональная программа по подготовке к сертификации Oracle Java Programmer (OCAJP). Предлагаем вам посмотреть запись бесплатного Demo-урока «Типы данных Java: Идентификаторы и примитивы» и продолжаем публиковать серию статей Владислава Родина — руководителя группы разработки, преподавателя в МФТИ и foxminded.
Введение
Приоритет операторов
Оператор принимает на вход аргументы и возвращает некоторые значения. Выделяют унарные, бинарные и тернарные операторы. Например, !false — унарный, a + b — бинарный, а? : — является единственным оператором, принимающим на вход три аргумента.
Первое, что необходимо помнить, это приоритет выполнения операторов:
Работа с унарными операторами
Про бинарные операторы мы говорили в прошлый раз. Сегодня обсудим унарные операторы, что следует из названия статьи. На экзамене могут предлагать достаточно сложные выражения для вычисления которых необходимо помнить порядок их выполнения.
Операторы смены знака и логической инверсии
Оператор логической инверсии ! применяется только к переменным типа boolean и превращает значение из true в false и наоборот. Например:
Оператор смены знака — применяется только к числам и меняет знак на противоположный:
Java в отличии от того же C четко разделяет целочисленные типы данных и boolean, в связи с чем применение оператора смены знака к boolean либо же применение оператора логической инверсии приводят к ошибкам компиляции:
Операторы инкремента и декремента
Операторы инкремента ++ и декремента — применяются к целочисленным переменным и обладают двумя вариациям: post-инкремент (декремент) и pre-инкремент (декремент), в коде i++ (i—) и ++i (—i) соответственно. Разница между вариациями в том, что ++i увеличивает переменную и возвращает новое значение, а i++ возвращает старое значение, а только затем увеличивает переменную. Разницу более наглядно можно увидеть в таком куске кода:
На экзамене могут предлагаться различные хитрые задания, где таких операторов вагон и маленькая тележка. Например, может быть предложено такое задание.
Что будет выведено в результате выполнения данной программы?
Проблема заключается в том, что x меняется несколько раз в одной строке.
Для решения таких задач можно разбирать выражение слева направо, подставляя в выражение то, что возвращают операторы, и фиксируя отдельно значение изменяемой переменной. Например, вот так:
Как видите, применяются все обозначенные выше правила применения операторов. В результате выведено будет следующее:
Базовые операторы, математика
В этой главе мы начнём с простых операторов, а потом сконцентрируемся на специфических для JavaScript аспектах, которые не проходят в школьном курсе арифметики.
Термины: «унарный», «бинарный», «операнд»
Прежде, чем мы двинемся дальше, давайте разберёмся с терминологией.
Унарным называется оператор, который применяется к одному операнду. Например, оператор унарный минус «-» меняет знак числа на противоположный:
Бинарным называется оператор, который применяется к двум операндам. Тот же минус существует и в бинарной форме:
Формально, в последних примерах мы говорим о двух разных операторах, использующих один символ: оператор отрицания (унарный оператор, который обращает знак) и оператор вычитания (бинарный оператор, который вычитает одно число из другого).
Математика
Поддерживаются следующие математические операторы:
Первые четыре оператора очевидны, а про % и ** стоит сказать несколько слов.
Взятие остатка %
Возведение в степень **
В выражении a ** b оператор возведения в степень умножает a на само себя b раз.
Математически, оператор работает и для нецелых чисел. Например, квадратный корень является возведением в степень 1/2 :
Сложение строк при помощи бинарного +
Давайте рассмотрим специальные возможности операторов JavaScript, которые выходят за рамки школьной арифметики.
Обычно при помощи плюса ‘+’ складывают числа.
Но если бинарный оператор ‘+’ применить к строкам, то он их объединяет в одну:
Обратите внимание, если хотя бы один операнд является строкой, то второй будет также преобразован в строку.
Как видите, не важно, первый или второй операнд является строкой.
Вот пример посложнее:
Например, вычитание и деление:
Приведение к числу, унарный +
Плюс + существует в двух формах: бинарной, которую мы использовали выше, и унарной.
Унарный, то есть применённый к одному значению, плюс + ничего не делает с числами. Но если операнд не число, унарный плюс преобразует его в число.
Необходимость преобразовывать строки в числа возникает очень часто. Например, обычно значения полей HTML-формы — это строки. А что, если их нужно, к примеру, сложить?
Бинарный плюс сложит их как строки:
Поэтому используем унарный плюс, чтобы преобразовать к числу:
С точки зрения математика, такое изобилие плюсов выглядит странным. Но с точки зрения программиста тут нет ничего особенного: сначала выполнятся унарные плюсы, которые приведут строки к числам, а затем бинарный ‘+’ их сложит.
Почему унарные плюсы выполнились до бинарного сложения? Как мы сейчас увидим, дело в их приоритете.
Приоритет операторов
В том случае, если в выражении есть несколько операторов – порядок их выполнения определяется приоритетом, или, другими словами, существует определённый порядок выполнения операторов.
Из школы мы знаем, что умножение в выражении 1 + 2 * 2 выполнится раньше сложения. Это как раз и есть «приоритет». Говорят, что умножение имеет более высокий приоритет, чем сложение.
В JavaScript много операторов. Каждый оператор имеет соответствующий номер приоритета. Тот, у кого это число больше, – выполнится раньше. Если приоритет одинаковый, то порядок выполнения – слева направо.
Отрывок из таблицы приоритетов (нет необходимости всё запоминать, обратите внимание, что приоритет унарных операторов выше, чем соответствующих бинарных):
Приоритет | Название | Обозначение |
---|---|---|
… | … | … |
17 | унарный плюс | + |
17 | унарный минус | — |
16 | возведение в степень | ** |
15 | умножение | * |
15 | деление | / |
13 | сложение | + |
13 | вычитание | — |
… | … | … |
3 | присваивание | = |
… | … | … |
Присваивание
Присваивание = возвращает значение
Тот факт, что = является оператором, а не «магической» конструкцией языка, имеет интересные последствия.
Вызов x = value записывает value в x и возвращает его.
Благодаря этому присваивание можно использовать как часть более сложного выражения:
В примере выше результатом (a = b + 1) будет значение, которое присваивается переменной a (то есть 3 ). Потом оно используется для дальнейших вычислений.
Забавное применение присваивания, не так ли? Нам нужно понимать, как это работает, потому что иногда это можно увидеть в JavaScript-библиотеках.
Однако писать самим в таком стиле не рекомендуется. Такие трюки не сделают ваш код более понятным или читабельным.
Присваивание по цепочке
Рассмотрим ещё одну интересную возможность: цепочку присваиваний.
Опять-таки, чтобы код читался легче, лучше разделять подобные конструкции на несколько строчек:
Польза от такого стиля особенно ощущается при быстром просмотре кода.
Сокращённая арифметика с присваиванием
Часто нужно применить оператор к переменной и сохранить результат в ней же.
Эту запись можно укоротить при помощи совмещённых операторов += и *= :
JavaScript: Математические операторы
Оператор ** ( возведение в степень ) имеет два операнда. Первый операнд является основанием степени, второй операнд – показателем степени, в результате оператор возвращает основание, возведённое в указанную степень:
Все математические операторы преобразуют операнды по тем же правилам, что и функция Number().
Оператор | Тип оператора | А | О | Типы значений |
---|---|---|---|---|
— … + … | Унарный минус Унарный плюс | справа налево справа налево | 1 1 | число → число число → число |
Оператор + ( унарный плюс ) преобразует значение своего операнда в число и возвращает преобразованное значение. При использовании с числовым операндом он не выполняет никаких действий:
Унарные плюс и минус преобразуют операнды по тем же правилам, что и функция Number().
Инкремент и декремент
Оператор ++ ( инкремент ) увеличивает значение своего операнда на единицу. Если значение операнда не является числом, оператор автоматически преобразует его в число, увеличивает на единицу и возвращает результат, который присваивается обратно операнду.
Инкремент имеет две формы – постфиксную (оператор ставится после операнда) и префиксную (оператор ставится перед операндом). Если он используется в постфиксной форме, то сначала возвращается исходное значение операнда, и только затем значение операнда увеличивается на единицу:
В префиксной форме оператор инкремент сразу увеличивает значение своего операнда на единицу:
Инкремент и декремент преобразуют операнды по тем же правилам, что и функция Number().
Сюрпризы унарного минуса
Другие статьи из серии «Конспекты начинающего программиста»:
Небольшая предыстория
При изучении темы «Операторы» унарные операторы обычно рассматриваются в начале или где-то бегло по ходу, поскольку они вроде простые и излагать там особо нечего. В данном же случае обнаружились некоторые сюрпризы, о которых не говорится в учебнике по Swift. Поэтому представляется удобным выделить их в отдельный текст.
Всё началось с того, что захотелось вживую в XCode прописать примеры из учебника. И вот что из этого вышло.
Что такое унарный минус?
Пример 1: Каждый раз новые константы
И далее в учебнике даётся следующий пример, который цитируется во многих других текстах:
Пример 2: Меняем знак на одной и той же переменной
После прочтения учебника складывается впечатление, что ничего особенного здесь нет и все как в арифметике (см. выше). Но если мы попробуем проделать ту же операцию без создания каждый раз новой константы, то столкнемся с неведомым. Начнём следующий пример:
Пока всё идёт в штатном режиме. Но если попробуем пойти дальше и ещё раз сменим знак, то получим сюрприз:
Почему это происходит?
Гипотез было несколько. Первая уже названа: что в первом примере на каждое применение унарного минуса создавалась новая константа, а во втором примере унарный минус использовался на одной и той же переменной. Но что потом делать с этой гипотезой не понятно, потому что она просто закрывает все дальнейшие вопросы, ничего не объясняя.
Вторая гипотеза: унарный минус действует только один раз, а второе его применение использует значение не из предыдущей строки, а из строки, где переменная объявляется. Кстати, если продолжать ставить минусы, то значение не меняется, везде будет минус 1. Это тоже такая гипотеза методом «научного тыка»: а вдруг что-то произойдет, если ставить минусы дальше? Не происходит!
Следующее экспериментальное действие: а если просто указать переменную без минуса, что тогда будет? По идее в песочнице должно появиться значение переменной на данный момент. Т.е. мы его меняли, меняли, а теперь хотим посмотреть, какое текущее значение у этой переменной. Смотрим:
И снова сюрприз: мы-то ожидали, что значение переменной изменилось во 2-й строке (а потом и в 3-й, и в 4-й), что оно теперь минус один, а на самом деле оно просто один, без минуса! И опять непонятно почему это происходит?
То ли минус действует только на одну операцию, там где применяется, то ли повторное указание переменной без минуса автоматом переводит число из отрицательного в положительное, по типу плюс по умолчанию, который даже не показывается.
Следующее предположение: а что если нужно поставить второй минус? Может один минус это просто повторение операции смены положительного числа на отрицательное, а чтобы сменить отрицательное на положительное надо ещё один минус? По ходу вспоминается, что где-то упоминались двойные операторы, типа два плюса или два минуса, но сейчас пока не до них, просто пробуем:
Бинго!
Мы своего добились! Применили два минуса и на выходе получили плюс! На всякий случай для страховки проверяем, т.е. указываем просто переменную a:
Отлично! Всё сохраняется, значение нашей переменной снова положительное. Вопросы конечно оставались: почему унарный минус так себя ведёт? Единственное объяснение: он почему-то действует только тогда, когда применяется, но само изменённое значение дальше не сохраняется.
Пример 3. Гештальт
И вот, как это часто бывает, долгие раздумья над каким-то вопросом вдруг приводят к новому повороту. Как говорится, гештальт созрел. Сначала была мысль, что один и тот же знак, минус, используется и как унарный оператор, и как бинарный арифметический. Разница только в синтаксисе: бинарному нужны 2 операнда и он пишется с пробелами, унарному нужен только один операнд и он пишется без пробела от операнда.
Затем настойчивые мысли о том, почему значение не сохраняется, вывели на оператор присвоения. Т.е. унарный минус значение меняет, но оно не сохраняется, т.е. оно НЕ ПРИСВАИВАЕТСЯ переменной! Отсюда логично напрашивается использовать оператор присвоения.
Делаем простой развёрнутый пример со сменой знака и сразу же проверяем текущее значение переменной (9-я и 10-я строки):
Ура ещё раз!
Значение переменной изменилось в 9-й строке, а в 10-й видно, что оно сохранилось! Т.е. впервые, когда мы просто указываем название переменной, её значение в строке 10 отличается от значения в первой строке!
И кстати, с этой точки зрения можно заметить, что в 8-й строке мы не можем утверждать, что новое значение переменной сохранилось, как мы радовались этому немного ранее. Скорее всего в этой строке показывалось не изменённое с плюса на минус и потом с минуса на плюс значение переменной, а всё то же значение из первой строки. Т.е. все предыдущие изменения знака в переменной не сохранялись, потому что не использовался оператор присвоения. И только когда мы используем оператор присвоения, только тогда изменённое значение сохраняется и число в переменной остаётся с другим знаком.
Резюме по унарному минусу
В ходе своего учебного расследования 🙂 мы выяснили как минимум 3 вещи:
Не берусь судить, бывают ли такие ситуации, когда такое нужно сделать, но в программировании всякое возможно. Так что пусть будет, может когда и пригодится.
Если же нам нужно сохранить измененное значение, тогда следует использовать ещё и оператор присвоения. Т.е. изменить знак числа и присвоить это измененное число переменной.
Это можно сделать либо способом, где изменённое значение присваивается той же переменной:
либо так, как показано в учебнике, т.е. присваивая изменённые значения новым переменным / константам:
Пару слов об унарном плюсе
Об унарном плюсе говорить действительно почти нечего. Он просто возвращает исходное значение без изменений. Например:
Как сказано в учебнике: хотя оператор унарного плюса не выполняет никаких действий, он придаёт коду единообразие, позволяя зрительно отличать положительные значения от отрицательных. Но что-то мне сдаётся по типу нововведений в Swift 3, что потом с этим унарным плюсом может что-то и произойти для единообразия.
Унарный логический оператор
Его действие: он изменяет, инвертирует значение логической переменной с true на false или с false на true.
Синтаксис: унарный логической оператор также как и унарный минус ставится перед названием переменной без пробела.
И далее, также как в случае с унарным минусом, новое значение логической переменной не сохраняется и действует только в момент использования унарного логического оператора. Т.е. если мы попытаемся ещё раз изменить значение переменной с false на true, то у нас ничего не получится.
Чтобы поменять значение переменной второй раз, т.е. от false перейти к true, нужно использовать круглые скобки:
А если мы хотим не только изменить значение логической переменной на противоположное, но ещё и сохранить его, то нам нужно изменённое значение присвоить или той же переменной, или новой (см. строки с 5-ой по 8-ю):
И последнее по унарному логическому оператору: он используется только в префиксном варианте, т.е. ставится только перед названием переменной или перед булевым значением.
В принципе всё логично, постфиксные операторы как-то выбивались из общего строя. Теперь без них будет проще: есть префиксные и всё понятно и единообразно. А вы как считаете?
Другие статьи из серии «Конспекты начинающего программиста»:
Небольшая предыстория
При изучении темы «Операторы» унарные операторы обычно рассматриваются в начале или где-то бегло по ходу, поскольку они вроде простые и излагать там особо нечего. В данном же случае обнаружились некоторые сюрпризы, о которых не говорится в учебнике по Swift. Поэтому представляется удобным выделить их в отдельный текст.
Всё началось с того, что захотелось вживую в XCode прописать примеры из учебника. И вот что из этого вышло.
Что такое унарный минус?
Пример 1: Каждый раз новые константы
И далее в учебнике даётся следующий пример, который цитируется во многих других текстах:
Пример 2: Меняем знак на одной и той же переменной
После прочтения учебника складывается впечатление, что ничего особенного здесь нет и все как в арифметике (см. выше). Но если мы попробуем проделать ту же операцию без создания каждый раз новой константы, то столкнемся с неведомым. Начнём следующий пример:
Пока всё идёт в штатном режиме. Но если попробуем пойти дальше и ещё раз сменим знак, то получим сюрприз:
Почему это происходит?
Гипотез было несколько. Первая уже названа: что в первом примере на каждое применение унарного минуса создавалась новая константа, а во втором примере унарный минус использовался на одной и той же переменной. Но что потом делать с этой гипотезой не понятно, потому что она просто закрывает все дальнейшие вопросы, ничего не объясняя.
Вторая гипотеза: унарный минус действует только один раз, а второе его применение использует значение не из предыдущей строки, а из строки, где переменная объявляется. Кстати, если продолжать ставить минусы, то значение не меняется, везде будет минус 1. Это тоже такая гипотеза методом «научного тыка»: а вдруг что-то произойдет, если ставить минусы дальше? Не происходит!
Следующее экспериментальное действие: а если просто указать переменную без минуса, что тогда будет? По идее в песочнице должно появиться значение переменной на данный момент. Т.е. мы его меняли, меняли, а теперь хотим посмотреть, какое текущее значение у этой переменной. Смотрим:
И снова сюрприз: мы-то ожидали, что значение переменной изменилось во 2-й строке (а потом и в 3-й, и в 4-й), что оно теперь минус один, а на самом деле оно просто один, без минуса! И опять непонятно почему это происходит?
То ли минус действует только на одну операцию, там где применяется, то ли повторное указание переменной без минуса автоматом переводит число из отрицательного в положительное, по типу плюс по умолчанию, который даже не показывается.
Следующее предположение: а что если нужно поставить второй минус? Может один минус это просто повторение операции смены положительного числа на отрицательное, а чтобы сменить отрицательное на положительное надо ещё один минус? По ходу вспоминается, что где-то упоминались двойные операторы, типа два плюса или два минуса, но сейчас пока не до них, просто пробуем:
Бинго!
Мы своего добились! Применили два минуса и на выходе получили плюс! На всякий случай для страховки проверяем, т.е. указываем просто переменную a:
Отлично! Всё сохраняется, значение нашей переменной снова положительное. Вопросы конечно оставались: почему унарный минус так себя ведёт? Единственное объяснение: он почему-то действует только тогда, когда применяется, но само изменённое значение дальше не сохраняется.
Пример 3. Гештальт
И вот, как это часто бывает, долгие раздумья над каким-то вопросом вдруг приводят к новому повороту. Как говорится, гештальт созрел. Сначала была мысль, что один и тот же знак, минус, используется и как унарный оператор, и как бинарный арифметический. Разница только в синтаксисе: бинарному нужны 2 операнда и он пишется с пробелами, унарному нужен только один операнд и он пишется без пробела от операнда.
Затем настойчивые мысли о том, почему значение не сохраняется, вывели на оператор присвоения. Т.е. унарный минус значение меняет, но оно не сохраняется, т.е. оно НЕ ПРИСВАИВАЕТСЯ переменной! Отсюда логично напрашивается использовать оператор присвоения.
Делаем простой развёрнутый пример со сменой знака и сразу же проверяем текущее значение переменной (9-я и 10-я строки):
Ура ещё раз!
Значение переменной изменилось в 9-й строке, а в 10-й видно, что оно сохранилось! Т.е. впервые, когда мы просто указываем название переменной, её значение в строке 10 отличается от значения в первой строке!
И кстати, с этой точки зрения можно заметить, что в 8-й строке мы не можем утверждать, что новое значение переменной сохранилось, как мы радовались этому немного ранее. Скорее всего в этой строке показывалось не изменённое с плюса на минус и потом с минуса на плюс значение переменной, а всё то же значение из первой строки. Т.е. все предыдущие изменения знака в переменной не сохранялись, потому что не использовался оператор присвоения. И только когда мы используем оператор присвоения, только тогда изменённое значение сохраняется и число в переменной остаётся с другим знаком.
Резюме по унарному минусу
В ходе своего учебного расследования 🙂 мы выяснили как минимум 3 вещи:
Не берусь судить, бывают ли такие ситуации, когда такое нужно сделать, но в программировании всякое возможно. Так что пусть будет, может когда и пригодится.
Если же нам нужно сохранить измененное значение, тогда следует использовать ещё и оператор присвоения. Т.е. изменить знак числа и присвоить это измененное число переменной.
Это можно сделать либо способом, где изменённое значение присваивается той же переменной:
либо так, как показано в учебнике, т.е. присваивая изменённые значения новым переменным / константам:
Пару слов об унарном плюсе
Об унарном плюсе говорить действительно почти нечего. Он просто возвращает исходное значение без изменений. Например:
Как сказано в учебнике: хотя оператор унарного плюса не выполняет никаких действий, он придаёт коду единообразие, позволяя зрительно отличать положительные значения от отрицательных. Но что-то мне сдаётся по типу нововведений в Swift 3, что потом с этим унарным плюсом может что-то и произойти для единообразия.
Унарный логический оператор
Его действие: он изменяет, инвертирует значение логической переменной с true на false или с false на true.
Синтаксис: унарный логической оператор также как и унарный минус ставится перед названием переменной без пробела.
И далее, также как в случае с унарным минусом, новое значение логической переменной не сохраняется и действует только в момент использования унарного логического оператора. Т.е. если мы попытаемся ещё раз изменить значение переменной с false на true, то у нас ничего не получится.
Чтобы поменять значение переменной второй раз, т.е. от false перейти к true, нужно использовать круглые скобки:
А если мы хотим не только изменить значение логической переменной на противоположное, но ещё и сохранить его, то нам нужно изменённое значение присвоить или той же переменной, или новой (см. строки с 5-ой по 8-ю):
И последнее по унарному логическому оператору: он используется только в префиксном варианте, т.е. ставится только перед названием переменной или перед булевым значением.
В принципе всё логично, постфиксные операторы как-то выбивались из общего строя. Теперь без них будет проще: есть префиксные и всё понятно и единообразно. А вы как считаете?