Побитовый сдвиг java: Побитовые операции в Java | Примеры использования
java битные операции > > > сдвиг
Почему если
int x = -1 // binary: 11111111111111111111111111111111
x = x >>> 31;
у нас есть 00000000000000000000000000000001
но если
int x = -1
x = x >>> 32;
у нас есть 11111111111111111111111111111111 (опять -1)
но не 00000000000000000000000000000000 ?
java
int
bits
operation
Поделиться
Источник
ses
11 февраля 2013 в 17:37
3 ответа
- LC3 Assembly побитовый сдвиг вправо
Что мне нужно сделать, так это реализовать как побитовый сдвиг влево, так и побитовый сдвиг вправо с использованием LC-3 Assembly . В принципе, каждый бит должен быть перемещен на одно пространство в направлении сдвига, и ноль заполняет созданное пустое пространство. Примеры: Сдвиг Вправо:. ..
- 48-битные побитовые операции в Javascript?
Мне было поручено перенести Java Java.util.Random() на JavaScript, и я столкнулся с огромным падением производительности/неточностью, используя побитовые операторы в Javascript на достаточно больших числах. Некоторые беглые исследования утверждают, что bitwise operators in JavaScript are…
13
Из раздела 15.19 из JLS :
Если повышенный тип левого операнда — int, то только пять
в качестве расстояния сдвига используются младшие биты правого операнда
. Это похоже на то, как если бы правый операнд был подвергнут
побитовому логическому оператору AND&
(§15.22.1) со значением маски0x1f
. Таким образом , фактически используемое расстояние сдвига всегда находится в
(0b11111)
диапазоне0 to 31
включительно.
Выделено мной. Так:
x >>> n
эквивалентно:
x >>> n & 0x1f // or x >>> n % 32
Таким образом, x >>> 32
эквивалентно x >>> 32 & 0x1f
<==> x >>> 0
== x
.
Таким образом, эмпирическое правило состоит в том, что всякий раз, когда вы сдвигаете число на кратное 32
( int
равно 32 bits
), вы получаете обратно то же самое значение.
Поделиться
Rohit Jain
11 февраля 2013 в 17:39
2
При применении операции сдвига битов учитываются только самые младшие 5 битов правого операнда. Начиная с 32 === 0 // mod 32, результат не смещается.
Поделиться
Marko Topolnik
11 февраля 2013 в 17:39
0
Провел целый день, ломая голову над тем, почему длинный l = i << 32 вел себя странно, затем написал несколько базовых тестов, имел момент WTF, а затем перешел к длинному l = (long) i << 32, чтобы он работал.
Мое единственное дополнение к ответу Рохита — это причина, по которой это так. Из IA-32 руководства разработчика программного обеспечения Intel Architecture Software 3:
8086 не маскирует количество сдвигов. Однако все остальные процессоры IA-32 (начиная с процессора Intel 286) маскируют количество сдвигов до 5 бит, что приводит к максимальному количеству 31. Эта маскировка выполняется во всех режимах работы (включая режим virtual-8086) для уменьшения максимального времени выполнения инструкций
Поделиться
sr33
16 июня 2017 в 23:20
- Побитовые операции на 128 битах в java
У меня есть двоичное представление двух адресов IPv6 Например: Первая строка-это двоичное представление ‘2001:4E8:0:4000:0:0:0:0’ ‘00100000000000010000010011101000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000’ Двоичное представление второй строки. 2*N) из-за процесса разбиения каждой цифры на одно число. Я…
Java операции двоичного сдвига
Я нашел этот вопрос java в интернете, и у меня было несколько вопросов по этому поводу. Какие утверждения являются точными: а) > > выполняет сдвиг со знаком, в то время как >>> выполняет сдвиг без…
LC3 Assembly побитовый сдвиг вправо
Что мне нужно сделать, так это реализовать как побитовый сдвиг влево, так и побитовый сдвиг вправо с использованием LC-3 Assembly . В принципе, каждый бит должен быть перемещен на одно пространство…
48-битные побитовые операции в Javascript?
Мне было поручено перенести Java Java.util.Random() на JavaScript, и я столкнулся с огромным падением производительности/неточностью, используя побитовые операторы в Javascript на достаточно больших…
Побитовые операции на 128 битах в java
У меня есть двоичное представление двух адресов IPv6 Например: Первая строка-это двоичное представление ‘2001:4E8:0:4000:0:0:0:0’. ..
128 битные переменные операции
В c++ (Linux, без использования boost). У меня есть 2 64-битные переменные (long long) (скажем, x и y). когда я делаю x*y, результат может быть 128 бит. Как я могу его хранить ? есть ли переменная,…
побитовый сдвиг влево в Java дает те же значения…?
Я пишу алгоритм левого сдвига в Java и делаю некоторые вычисления левого сдвига вручную. Все эти числа набираются как байт , кстати. Допустим, я работаю с 8-битными целыми числами от -128 до 127….
java: расстояние сдвига для int ограничено 31 битом
Есть идеи, почему расстояние сдвига для int в java ограничено 31 битом (5 нижних битов правого операнда)? http://docs.oracle.com/у JavaSE/технические…
32 битные операции на 8 битной архитектуре
Я просто хочу спросить вас, можно ли получить 32-битные операции на 8-битной архитектуре и если да — то как? Я думал об этом в течение некоторого времени, и лучшая идея, которая у меня есть, — это. =
Побитовое исключающее OR с присваиванием »= Сдвиг вправо с присваиванием >»= Сдвиг вправо с заполнением нулями с присваиванием «= Сдвиг влево с присваиванием Поскольку побитовые операции манипулируют битами в целочисленном значении, важно понимать, какое влияние подобные манипуляции могут оказывать на значение. В частности, важно знать, как среда Java хранит целочисленные значения, и как она представляет отрицательные числа. Поэтому, прежде чем продолжить рассмотрение операций, кратко рассмотрим эти два вопроса.
Все целочисленные типы представляются двоичными числами различной длины. Например, значение типа byte, равное 42, в двоичном представлении имеет вид 00101010.
Все целочисленные типы (за исключением char) — целочисленные типы со знаком. Это означает, что они могут представлять как положительные, так и отрицательные значения. В Java применяется кодирование, называемое двоичным дополнением, при котором отрицательные числа представляются посредством инвертирования всех битов значения (изменения 1 на 0 и наоборот) и последующего добавления 1 к результату. Например, -42 представляется путем инвертирования все битов в двоичном представлении числа 42, что дает значение 11010101, и добавления 1, что приводит к значению 11010110, или -42. Чтобы декодировать отрицательное число, необходимо вначале инвертировать все биты, а затем добавить 1 к результату. Например, инвертирование значения -42, или 11010110, приводит к значению 00101001, или 41, после добавления 1 к которому мы получаем 42.
Причина, по которой в Java (и большинстве других компьютерных языков) применяют двоичное дополнение, становится понятной при рассмотрении перехода через нуль. Если речь идет о значении типа byte, ноль представляется значением 00000000. В случае применения единичного дополнения простое инвертирование всех битов создает значение, равное 11111111, которое представляет отрицательный ноль. Проблема в том, что отрицательный ноль — недопустимое значение в целочисленной математике. Применение двоичного дополнения для представления отрицательных значений позволяет решить эту проблему. При этом к дополнению добавляется 1, что приводит к числу 100000000. Единичный бит оказывается сдвинутым влево слишком далеко, чтобы умещаться в значении типа byte. Тем самым достигается требуемое поведение, когда -0 эквивалентен 0, а 11111111 — код значения, равного -1. Хотя в приведенном примере мы использовали значение типа byte, тот же базовый принцип применяется и ко всем целочисленным типам Java.
Поскольку в Java для хранения отрицательных значений используется двоичное дополнение — и поскольку в Java все целочисленные значения являются значениями со знаком — применение побитовых операций может легко приводить к неожиданным результатам. Например, установка самого старшего бита равным 1 может привести к тому, что результирующее значение будет интерпретироваться как отрицательное число, независимо от того, к этому результату вы стремились или нет. Во избежание неприятных сюрпризов следует помнить, что независимо от того, как он был установлен, старший бит определяет знак целого числа.
Руководство по Java Core. Базовые операторы. – PROSELYTE
Для манипулирования переменными в языке Java предусмотренно множество операторов. Все операторы мы модем поделить на такие группы:
- Арифметические операторы
- Операторы сравнения
- Битовые операторы
- Логические операторы
- Операторы присваивания
- Другие
Рассмотрим эти группы отдельно.
Арифметические операторы
Этот тип операторов используется для математических операций.
Представим, что у нас есть две целочисленные переменные (int) A = 50, B = 20.
Примеры:
+ (Сложение) A + B = 70 – (Вычитание) A – B = 30 * (Умножение) A * B = 1000 / (Деление) A / B = 2 % (Остаток от деления) A % B = 10 ++ (Инкремент) A++ = 51 — (Декремент) B– = 19 Операторы сравнения
Результатом оператора сравнения является логический тип boolean, который говорит нам, является ли данное утверждение правдой (true) или ложью (false).
Представим, что у нас есть две целочисленные переменные (int) A = 50, B = 20.
Примеры:
== (Равен) (A == B) -> false != (Не равен) (A != B) -> true > (Больше, чем) (A > B) -> true < (Меньше, чем) (A < B) -> false >= (Больше, чем или равно) (A >= B) -> true <= (Меньше, чем или равно) (A <= B) -> false Битовые операторы
В языке Java существует ряд битовых операторов, которые поддерживают целочисленные типы данных. B) -> 0010 0110
~ (Побитовое дополнение) ( ~A ) -> 1100 1101 << (Побитовый сдвиг влево) (A << 1) -> 100 (0110 0100) >> (Побитовый сдвиг вправо) (B >> 2) -> 5 (0000 0101) >>> (Побитовый сдвиг вправо с присвоением) ( A >>> 3) -> 6 (0000 0110) Логические операторы
В языке Java поддерживаются 3 логических оператора, все они приведены таблице ниже.
Представим, что у нас есть две логические переменные (boolean) T = true и F = false.
&& (Логическое ‘И’) (A && B) -> false || (Логическое ‘ИЛИ’) (A || B) -> true ! (Логическое ‘НЕ’) !(A || B) -> false Операторы присваивания
В языке Java есть 11 операторов присваивания. Рассмотрим их на примерах.
Представим, что у нас есть две целочисленные переменные (int) A = 50, B = 20 и некая переменная С, значение которой, пока не присвоено.
= С = A + B ( C == 70 ) += A += B (A == 70) -= A -= B (A == 30) *= B *= A (B == 1000) /= A /= B (A == 2) %= A %= B (A == 10) <<= B <<= 2 (B == 80) >>= A >>= 2 (A == 12) &= B &= 2 (B = B & 2 ) ^= A ^= 2 (A == 48) |= A |= 3 (A == 51) Другие
К другим операторам в языке Java относится только 1. Это тернарный оператор ветвления IF.
Более подробно мы рассмотрим IF далее, а пока приведём общую форму записи:
Допустим у нас есть логическая переменная (boolean) isActive, значение которой нам неизвестно.
Пример:
int a = (isActive) ? 100 : 200.
Разъяснение:
Если isActive = true, тогда a = 100.
Если isActive = false, тогда a = 200.
В этом уроке мы рассмотрели операторы для манипулирования переменными в языке Java.
Более подробно с операторами в языке Java можно ознакомиться в спецификации языка Java (Java Language Specification).
В следующем уроке мы рассмотрим массивы в языке Java и их виды.
2.4. Операторы сдвига > и >>>(Выпуск 7)
В Java есть операторы сдвига. Операторы << и >> позаимствованы из С/C++. Кроме того, Java обладает своим новым оператором сдвига >>>.
Операторы сдвига присущи системам, которые могут выравнивать биты, прочтённые из IO портов или зартсываемые в IO порты. Это также быстрое умножение или деление на степень двойки. Преимущество операторов сдвига в Java — это независимость от платформы. Поэтому вы можете использовать их не беспокоясь ни о чём.
Сдвиг — это, по сути, простейшая операция: мы берём последовательность битов и двигаем её влево или вправо. Больше всего конфуза вызывает оператор >>>. Но о нём мы поговорим чуть позже.
Операторы сдвига могут применяться лишь к целым числам, то есть к типам int или long. Следующая таблица иллюстрирует базовый механизм сдвига.
Таблица показывает фундаментальную идею сдвига: перемещение битов относительно их позиций. Это как очередь в магазине: как только один человек совершил покупку и отшёл, вся очередь сдвинулась и позиции всех участников очереди изменились.
Однако, глядя на таблицу, возникают три вопроса вопроса:
- Что происходит, если мы сдвигаем влево и при этом часть бинарной записи выходит за границу слева, а часть — остаётся пустой справа?
- Что происходит, когда справа — выход за границы, а слева — пустое место?
- Какое истинное значение принимает знак «?»?.
Ответим на часть этих вопросов. Биты, вышедшие за границы, просто теряются. Мы о них забываем.
В некоторых языках, типа ассемблер, есть операция ротации, когда при сдвиге вышедшие за границы биты не теряются, но ставятся на освободившееся место (вместо вопросиков). Однако языки высокого уровня, типа Java, не имеют в своём арсенале такой операции.
Сдвиг отрицательных чисел
Ответ на вопрос о значении символов «?» в приведенной выше таблице требует отдельного рассмотрения.
В случае сдвига влево << и беззнакового сдвига вправо >>> новые биты просто устанавливаются в ноль. В случае сдвига вправо со знаком >> новые биты принимают значение старшего (самого левого) бита перед сдвигом. Следующая таблица демонстрирует это:
Таблица 2: Сдвиг положительных и отрицательных чисел
Исходные данные 192
Бинарное представление 00000000 00000000 00000000 11000000 Сдвиг вправо на 1 бит 00000000 00000000 00000000 01100000 Сдвиг вправо на 7 бит 00000000 00000000 00000000 00000001 Исходные данные -192
Бинарное представление 11111111 11111111 11111111 01000000 Сдвиг вправо на 1 бит 11111111 11111111 11111111 10100000 Сдвиг вправо на 7 бит 11111111 11111111 11111111 11111110 Заметьте: в том, случае, где старший бит был 0 перед сдвигом, новые биты стали тоже 0. Там где старший бит перед сдвигом был 1, новые биты тоже заполнились 1.
Это правило может показаться странным на первый взгляд. Но оно имеет под собой очень серьёзное обоснование. Если мы сдвигаем бинарное число влево на одну позицию, то в десятичной записи мы умножаем его на два. Если мы сдвигаем влево на n позиций, то умножение происходит на 2n, то есть на 2, 4, 8, 16 и т.д.
Сдвиг вправо даёт деление на степени двойки. При этом, добавление слева нулей на появившиеся биты на самом деле даёт деление на степени двойки лишь в случае положительных чисел. Но для отрицательных чисел всё совсем по другому!
Как известно, старший бит отрицательных чисел равен единице, 1. Для того, чтобы сохранить старшинство единицы при сдвиге, то есть сохранить отрицательный знак результата деления отрицательного числа на положительное (степень двойки), нам нужно подставлять единицы на освободившиеся места.
Если мы посмотрим на Таблицу 2, то заметим, что 192, сдвинутое на 1 бит вправо — это 192/2=96, а сдвинутое на 7 битов вправо — это 192/27=192/128=1 по законам целочисленной арифметики. С другой стороны, -192 сдвинутое на 1 бит вправо — это 192/2=-96 и т.д.
Есть, однако пример, когда реультат сдвига вправо отличается от результата целочисленного деления на 2. Это случай, когда аргумент = -1. При целочисленном делении мы имеем: -1/2=0. Но результат сдвига вправо нам даёт -1. Это можно трактовать так: целочисленное деление округляет к нулю, а сдвиг округляет к -1.
Таким образом, сдвиг вправо имеет две ипостаси: одна (>>>) просто сдвигает битовый паттерн «в лоб», а другая (>>) сохраняет эквивалентность с операцией деления на 2.
Зачем же Java потребовался беззнаковый сдвиг вправо (сдвиг «в лоб»), когда ни в С, ни в С++ его не существует? Ответ прост, потому что в С и С++ сдвиг всегда беззнаковый. То есть >>>> в Java — это и есть сдвиг вправо в C и C++. Но, поскольку в Java все численные типы со знаком (за исключением char), то и результаты сдвигов должны иметь знаки.
Сокращение (reduction) правого операнда
На самом деле у операторов сдвига есть правый операнд — число позиций, на которое нужно произвести сдвиг. Для корректного сдвига это число должно быть меньше, чем количество битов в результате сдвига. Если число типа int (long), то сдвиг не может быть сделан более, чем на 32 (64) бита.
Оператор же сдвига не делает никаких проверок данного условия и допускает операнды, его нарушающие. При этом правый операнд сокращается по модулю от нужного количества битов. Например, если вы захотите сдвинуть целое число на 33 бита, то сдвиг произойдёт на 33%32=1 бит. В результатае такого сдвига мы легко можем получить аномальные результаты, то есть результаты, которых мы не ожидали. Например, при сдвиге на 33 бита мы ожидаем получить 0 или -1 (в знаковой арифметике). Но это не так.
Почему Java сокращает правый операнд оператора сдвига или грустная история о заснувшем процессоре
Одной из главной причин введения сокращения было то, что процессоры сами сокращают подобным образом правый операнд оператора сдвига. Почему?
Несколько лет назад был создан мощнейший процессор с длинными регистрами и операциями ротации и сдвигам на любое количество битов. Именно потому, что регистры были длинными, корректное выполнение этих операций требовало несколько минут.
Основным применением данных процессоров был контроль систем реального времени. В данных системах самый быстрый ответ на внешнее событие должно занимать не более задержки на прерывание (interrupt latency). Отдельные инскрукции таких процессоров были неделимы. Поэтому выполнение длинных операций (сдвига на несколько бит и ротации) нарушало эффективную работу процессора.
Следующая версия процессора имплементировала эти операции уже по-другому: размер правого операнда сократился. Задержка на прерывание восстанавилась. И многие процессоры переняли данную практику.
Арифметическое распространение (
promotion) операндов
Апифметическое распространение операндов происходит перед применением оперции сдвига и гарантирует, что операнды по крайней мере типа int. Это явление имеет особый эффект на беззнаковый сдвиг вправо, когда сдвигаемое число меньше, чем int: мы получаем не тот результат, который ожидали.
Следующая таблица показывает пример аномалии:
Таблица 3: Арифметическое распространение для беззнакового сдвига вправо, когда операнд меньше, чем int
Исходные данные (-64 в десятичной записи) 11000000
Распространение до int 11111111 11111111 11111111 11000000 Сдвиг вправо на 4 битa 00001111 11111111 11111111 11111100 Сокращение до байта 11111100 Ожидаемый результат был 00001100 Вопрос 15 (побитовые операции)
«Какая арифметическая операция выполняется при побитовом сдвиге вправо/влево?»
1. Для целых числовых типов данных — long, int, short, char и byte, определен дополнительный набор операторов, с помощью которых можно проверять и модифицировать состояние отдельных битов соответствующих значений. b = 0011 0001
~a = 1100 00113. Оператор выполняет сдвиг влево всех битов своего левого операнда на число позиций, заданное правым операндом. При этом часть битов в левых разрядах выходит за границы и теряется, а соответствующие правые позиции заполняются нулями.
3.1.При применении оператора сдвига влево к операнду типа int биты теряются, как только они сдвигаются за пределы 31 позиции. Если операнд имеет тип long, биты теряются после сдвига за пределы 63 позиции.
3.2. Автоматическое повышение типа, используемое в Java, может привести к странным результатам при выполнении сдвига в значениях типа byte, short. При вычислении выражений тип значений byte и short повышается до типа int. Это означает, что результатом выполнения сдвига влево значения типа byte или short будет значение int, и сдвинутые влево позиции не будут отброшены до тех пор, пока они не будут сдвинуты за пределы 31 позиции. Более того, при повышении до типа int отрицательное значение типа byte или short получит дополнительный знаковый разряд. Следовательно, старшие биты будут заполнены единицами. Поэтому при выполнении сдвига влево в значении типа byte сначала будет повышение до типа int и лишь затем сдвиг. Поэтому для получения требуемого сдвинутого значения типа byte необходимо отбросить три старших байта результата. Простейший способ достижения этого — обратное приведение результата к типу byte.
byte x = 64;
byte y;
int i;
i = x
y = (byte) (xРезультат:
i равно: 256
y равно: 0Поскольку для выполнения вычислений тип переменной повышается до int, сдвиг влево на две позиции значение 64 (0100 0000) приводит к значению 256 (1 0000 0000). Однако, переменная y содержит значение не 256, а 0, поскольку после сдвига крайний единичный бит оказывается сдвинутым за пределы допустимого диапазона.
3.3. Приёмом сдвига влево часто пользуются в программах, где происходит много сложных вычислений. По сути, это замена операции умножения на 2, которая в силу особенностей процессора гораздо эффективнее. Но при этом следует соблюдать осторожность, так как при сдвиге единичного бита в старшую позицию (бит 31 или 63) значение становится отрицательным.
4. Оператор >> означает сдвиг вправо. Он перемещает все биты своего левого операнда вправо на число позиций, заданное правым операндом. Когда биты левого операнда выдвигаются за самую правую позицию слова, они теряются. При сдвиге вправо освобождающиеся старшие (левые) разряды сдвигаемого числа заполняются предыдущим содержимым знакового разряда. Такое поведение называют расширением знакового разряда, из-за него знаки отрицательных чисел сохраняются при сдвиге.
4.1. Примеры выполнения операций сдвига:
A
A >> 2 равно 0011 1100 >> 2 равно 0000 1111 равно 154. 2. Иногда требуется, чтобы при сдвиге вправо расширение знакового разряда не происходило, а освобождающиеся левые разряды просто заполнялись бы нулями. Для этого используется оператор >>>:
int x = -17, z1, z2;
// x: 11111111 11111111 11111111 11101111
z1 = x >> 2;
// z1 = -5: 11111111 11111111 11111111 11111011
z2 = x >>> 2;
// z2 = 1073741819 : 00111111 11111111 11111111 111110114.3 При каждом сдвиге вправо выполняется деление на два с отбрасыванием любого остатка. Данная операция намного эффективнее, чем обычное деление на два, поэтому часто используется в сложных вычислениях. При этом нужно быть уверенным, что никакие биты не будут сдвинуты за пределы правой границы.
4.3.1. Обратите внимание, что результат сдвига вправо значения -1 всегда равен -1, поскольку дополнительные знаковые разряды добавляют новые единицы к старшим битам.
5. Как и бинарные арифметические операторы побитовые операции имеют составные формы, которые объединяет побитовый оператор с оператором присваивания.
XOR Устанавливает каждый бит в 1, если только один из двух битов равен 1 ~ NOT Инвертирует все биты << Сдвиг влево с нулевым заполнением Сдвигает влево, вставляя нули справа и позволяя крайним левым битам упасть >> Подпись вправо Сдвигает вправо, вставляя копии крайнего левого бита слева и позволяя крайним правым битам отпасть >>> Сдвиг вправо с нулевым заполнением Сдвигает вправо, вставляя нули слева, и позволяет крайним правым битам отпасть Примеры
Операция Результат Такой же, как Результат 5 & 1 1 0101 & 0001 0001 5 | 1 5 0101 | 0001 0101 ~ 5 10 ~0101 1010 5 << 1 10 0101 << 1 1010 5 ^ 1 4 0101 ^ 0001 0100 5 >> 1 2 0101 >> 1 0010 5 >>> 1 2 0101 >>> 1 0010 JavaScript использует 32-битные побитовые операнды
JavaScript хранит числа как 64-битные числа с плавающей запятой,
но все побитовые операции выполняются с 32-битными двоичными числами.Перед выполнением побитовой операции JavaScript преобразует числа в 32-битные целые числа со знаком.
После выполнения побитовой операции результат конвертируется обратно в 64-битные числа JavaScript.
В приведенных выше примерах используются 4-битные двоичные числа без знака. Из-за этого ~ 5 возвращает 10.
Поскольку JavaScript использует 32-битные целые числа со знаком, он не вернет 10. Он вернет -6.
00000000000000000000000000000101 (5)
11111111111111111111111111111010 (~5 = -6)
Целое число со знаком использует крайний левый бит как знак минус.
Побитовое AND JavaScript
Когда побитовое AND выполняется для пары битов, он возвращает 1, если оба бита равны 1.
Один битный пример:
Операция Результат 0 & 0 0 0 & 1 0 1 & 0 0 1 & 1 1 4 битный пример:
Операция Результат 1111 & 0000 0000 1111 & 0001 0001 1111 & 0010 0010 1111 & 0100 0100 Побитовое OR
Когда для пары битов выполняется побитовое OR, оно возвращает 1, если один из битов равен 1:
Один битный пример:
Операция Результат 0 | 0 0 0 | 1 1 1 | 0 1 1 | 1 1 4 битный пример:
Операция Результат 1111 | 0000 1111 1111 | 0001 1111 1111 | 0010 1111 1111 | 0100 1111 Побитовое XOR JavaScript
Когда побитовое XOR выполняется для пары битов, он возвращает 1, если биты различны:
Один битный пример:
Операция Результат 0 ^ 0 0 0 ^ 1 1 1 ^ 0 1 1 ^ 1 0 4 битный пример:
Операция Результат 1111 ^ 0000 1111 1111 ^ 0001 1110 1111 ^ 0010 1101 1111 ^ 0100 1011 Поразрядное AND (&) JavaScript
Побитовое AND возвращает 1, только если оба бита равны 1:
Десятичный Двоичный 5 00000000000000000000000000000101 1 00000000000000000000000000000001 5 & 1 00000000000000000000000000000001 (1) Побитовое OR (|) JavaScript
Побитовое OR возвращает 1, если один из битов равен 1:
Десятичный Двоичный 5 00000000000000000000000000000101 1 00000000000000000000000000000001 5 | 1 00000000000000000000000000000101 (5) Побитовое XOR (^) JavaScript
Побитовое XOR возвращает 1, если биты разные:
Десятичный Двоичный 5 00000000000000000000000000000101 1 00000000000000000000000000000001 5 ^ 1 00000000000000000000000000000100 (4) Побитовое NOT (~) JavaScript
Десятичный Двоичный 5 00000000000000000000000000000101 ~5 11111111111111111111111111111010 (-6) JavaScript (нулевое заполнение) Побитовый сдвиг влево (<<)
Это сдвиг влево с нулевым заполнением. Один или несколько нулевых бит вставляются справа, а крайние левые биты отпадают:
Десятичный Двоичный 5 00000000000000000000000000000101 5 << 1 00000000000000000000000000001010 (10) JavaScript (сохранение знака) Побитовый сдвиг вправо (>>)
Это знак, сохраняющий правый сдвиг. Копии крайнего левого бита вставляются слева, а крайние правые биты отваливаются:
Десятичный Двоичный -5 11111111111111111111111111111011 -5 >> 1 11111111111111111111111111111101 (-3) JavaScript (нулевое заполнение) сдвиг вправо (>>>)
Это сдвиг вправо с нулевым заполнением. Один или несколько нулевых битов вставляются слева, а крайние правые биты отваливаются:
Десятичный Двоичный 5 00000000000000000000000000000101 5 >>> 1 00000000000000000000000000000010 (2) Двоичные числа
Двоичные числа с одним набором битов легко понять:
Двоичное представление Десятичное значение 00000000000000000000000000000001 1 00000000000000000000000000000010 2 00000000000000000000000000000100 4 00000000000000000000000000001000 8 00000000000000000000000000010000 16 00000000000000000000000000100000 32 00000000000000000000000001000000 64 Установка еще нескольких битов показывает двоичный паттерн:
Двоичное представление Десятичное значение 00000000000000000000000000000101 5 (4 + 1) 00000000000000000000000000001101 13 (8 + 4 + 1) 00000000000000000000000000101101 45 (32 + 8 + 4 + 1) Двоичные числа JavaScript хранятся в формате дополнения до двух.
Это означает, что отрицательное число является побитовым NOT числа плюс 1:
Двоичное представление Десятичное значение 00000000000000000000000000000101 5 11111111111111111111111111111011 -5 00000000000000000000000000000110 6 11111111111111111111111111111010 -6 00000000000000000000000000101000 40 11111111111111111111111111011000 -40 Преобразование десятичного числа в двоичное
Преобразование двоичного числа в десятичное
#9 Java: Побитовые операторы(операторы присваивания + приоритет выполнения). | тотСамыйАйтишник
Java: План и дорожная карта развития + СОДЕРЖАНИЕ.
№8 Java: Явные и неявные приведения примитивных типов.
Приветствую Тебя, мой дорогой друг. В этой статье разберем еще один вид операторов, так называемые «Побитовые операторы». Надеюсь, ты знаком с двоичной системой счисления, так как, она нам определенно очень пригодится. Будем выполнять действия над отдельными битами наших операндов. Ну, а если ты не знаком с двоичной системой, то вкратце тебе расскажу (более обширную информацию можно получить на wiki). Но каждый уважающий себя Айтишник(а это на минуточку программисты всех мастей, админы и другие сказочные существа) обязаны знать как работать с двоичной системой.
Калькулятор и побитовые операции.
Калькулятор и побитовые операции.
Итак, значения в двоичной системе счисления, представляют собой ряд чисел состоящих из 1 и 0. К примеру из привычной тебе десятичной системы, число 13 в двоичной будет выглядеть так 1101. В бинарной(так ее еще по другому называют) расчет с права-налево, самый младший разряд начинается с единицы и с каждым битом увеличивается в два раза.
Двоичная система для чисел 1 байт.
Двоичная система для чисел 1 байт.
Так как из 13 получилось 1101? Нам нужно найти один байт или сумму байт равное нашему значению. Остановимся на первых четырех, так как далее идут значения больше 13. Итак, 8, 4, 2, 1 среди этого нужно просуммировать так, чтобы получить 13. Очевидно, взять необходимо разряды под номерами 4(значение 8), 3(значение 4) и 1(значение 1) и суммируем 8+4+1=13. Те разряды которые мы отобрали, вместо 0 поставить 1
Двоичная система для чисел 1 байт.
Двоичная система для чисел 1 байт.
И получаем наше число в двоичной системе счисления.
Двоичная система для чисел 1 байт.
Двоичная система для чисел 1 байт.
Это очень кратко, если нужна будет статья про двоичной системе, напишите в комментариях.
Вернемся к нашей теме «Побитовые операторы».
В Java побитовые операции выполняются только над целыми числами, следовательно, применимы только к определенным типам данных, таким как: «byte«, «char«, «short«, «int«, «long«. При использовании побитовых операций, результат будет приведен к типу «int«, а если один из операндов «long«, то и результат будет типа «long«.
1. Унарный оператор «~»(символ тильда) дополнение(NOT) — данный оператор зеркально изменяет переданное значение, то есть 0 на 1, а 1 на 0. К примеру наше число 13 = 1101, ~1101 = 0010 если перевести в десятичную, получится число 2. Проверим себя, вызовем калькулятор Windows, переведем его в режим «Программист«(слайд №1). Установим в десятичную систему «Dec«, выберем количество байт и сделаем «1 байт«(слайд №2). Вводим число 13, видим дублируются данные в двоичной системе «0000 1101«, а мы знаем что 1 байт это 8 бит, соответственно у нас 8 разрядов «00001101«. Произведем наше действие, в калькуляторе кнопка «Not» жмем(слайд №3). Видим результат -14, не совсем верный результат, так как мы использовали 4 разряда, а калькулятор все 8, первым четырем разрядам вместо 0 поставил 1, следовательно, в нашей ситуации смотреть нужно на последние 4 разряда, вот там наша правильная противоположность. Но сколько это «0010«? Очищаем окно результата кнопкой на калькуляторе «С«. Выбираем двоичную систему «Bin» и набираем «10«(слайд №4). Видим что калькулятор выводит «0000 0010» наши последние четыре разряда «0010» и переводим обратно в десятичную «Dec» результат число 2(слайд №5).
Калькулятор.Калькулятор.Калькулятор.
Давай попробуем в Java, воспользуемся методом «toBinaryString» класса «Integer«(о ссылочных типах данных, будем говорить следующей статье) и передадим в метод нашу переменную «varInt» со значением 13. Метод «toBinaryString» отобразит наше число в двоичной системе «1101«, помним что тип данных «int» занимает 4 байта, а это 32 разряда, следовательно, первые слева 28 нулей метод не показывает(если бы показал, то выглядело бы так «00000000000000000000000000001101«). Осталось применить нашу операцию, в результате опять видим 14, с прошлого примера с калькулятором, мы понимаем что первые 28 нулей преобразовались в единицу и смотреть нужно на 4 последних бита, а там «0010» наше число 2.
Результат в Java.
Результат в Java.
Для данного оператора не предусмотрен оператор присвоения(то есть более короткой версии «~=» нет).
2. Побитовая конъюнкция (AND) «&» (символ амперсанд) — данный оператор используется как выключение отдельных битов.
Побитовая конъюнкция (AND).
Побитовая конъюнкция (AND).
Для примера используем числа 13 = 1101 и 10 = 1010, пробуем рассчитать справа на лево «1101 & 1010 = 1&0=0, 0&1=0, 1&0=0, 1&1=1″ ответ «1000» что соответствует десятичному числу 8.
На калькуляторе кнопочка «And«. Вводи в десятичной системе число 13 жми «And» и набирай число 10, равно 8.
Калькулятор.
Калькулятор.
Ну а теперь, попробуем в Java.
Результат в Java.
Результат в Java.
Предусмотрен оператор присвоения «&=«. Но и не забываем про приоритет, в выражении «varInt &= varInt2 + 1« вначале будет выполнено то что справа «varInt2 + 1«, после «varInt = varInt & 11«, то есть выражение примет вид «varInt = varInt & (varInt2 + 1)«.
Результат в Java.
Результат в Java.
3. Побитовая дизъюнкция (OR) «|» (символ вертикальной черты) — если у операндов в вычисляемой позиции имеется хоть один разряд равный 1, то результат будет 1.
Побитовая дизъюнкция (OR).
Побитовая дизъюнкция (OR).
Для примера используем числа 13 = 1101 и 10 = 1010, пробуем рассчитать справа на лево «1101 | 1010 = 1|0=1, 0|1=1, 1|0=1, 1|1=1″ ответ «1111» что соответствует десятичному числу 15.
На калькуляторе кнопочка «Or«. Вводи в десятичной системе число 13 жми «Or» и набирай число 10, равно 15.
Калькулятор.
Калькулятор.
Идем в Java.
Результат в Java.
Результат в Java.
Предусмотрен оператор присвоения «|=«. Но и не забываем про приоритет, в выражении «varInt |= varInt2 + 1« вначале будет выполнено то что справа «varInt2 + 1«, после «varInt = varInt | 11«, то есть выражение примет вид «varInt = varInt | (varInt2 + 1)«. (varInt2 + 1)«.
Результат в Java.
Результат в Java.
5.Побитовый сдвиг влево, символ «<<» — данная операция как бы побитовое умножение, то есть она добавляет в правую часть нули в зависимости от значения второго операнда, тем самым происходит смещение бит в лево для первого операнда.
Для примера используем числа 5 = 0101 и 2 = 0010, 5<<2, к первому операнду, справа должны добавить два нуля и произвести сдвиг на два разряда влево, результат получается «010100» что, соответствует 20 в десятичной системе.
На калькуляторе кнопочка «Lsh«. Вводи в десятичной системе число 5 жми «Lsh» и набирай число 2, равно 20.
Калькулятор.
Калькулятор.
Идем в Java.
Результат в Java.
Результат в Java.
5.Побитовый сдвиг вправо, символ «>>» — данная операция как бы побитовое деление, эта же операция наоборот добавляет в левую часть нули в зависимости от значения второго операнда, тем самым происходит смещение бит в право для первого операнда.
Для примера используем числа 5 = 0101 и 2 = 0010, 5>>2, к первому операнду, слева должны добавить два нуля и произвести сдвиг на два разряда в право, результат получается «0001« что, соответствует 1 в десятичной системе.
На калькуляторе кнопочка «Rsh«. Вводи в десятичной системе число 5 жми «Rsh» и набирай число 2, равно 1.
Калькулятор.
Калькулятор.
Идем в Java.
Результат в Java.
Результат в Java.
Табличка приоритетности операций, в ней видно что побитовые операторы имеют меньший приоритет по сравнению с арифметическими.
Приоритет операторов.
Приоритет операторов.
Пока на это все, следующей статье порешаем задачки по операторам. До встречи.
статья № 10 Java: Логические операторы.
Поставь лайк если понравилась статья, тебе всего лишь «клик», а мне радости полные штаны =). Подписывайся на канал, будет много интересных публикаций =).
битовый сдвиг (левый сдвиг, правый сдвиг)
битовый сдвиг (левый сдвиг, правый сдвиг) | Торт для интервью
Сдвиг бит перемещает каждую цифру в
двоичное представление числа слева или справа. Есть три основных типа смен:Левый сдвиг
При сдвиге влево старший бит теряется, и
На другом конце вставлен 0 бит.Оператор сдвига влево обычно записывается как «<<».
0010 << 1 → 0100 0010 << 2 → 1000
Один сдвиг влево умножает двоичное число на 2:
0010 << 1 → 0100 0010 это 2 0100 это 4
Логические сдвиги вправо
При сдвиге вправо с логическим сдвигом вправо ,
наименее значимый бит теряется, а 0
вставлен на другом конце.1011 >>> 1 → 0101
1011 >>> 3 → 0001Для положительных чисел один логический сдвиг вправо делит
число на 2, выбрасывая остатки.0101 >>> 1 → 0010
0101 это 5
0010 — 2Арифметические сдвиги вправо
При переключении вправо с арифметической вправо
shift , наименее значимый бит теряется и
старший бит скопирован .Языки обрабатывают арифметику и логический сдвиг вправо.
различные пути. Java предоставляет два оператора сдвига вправо: >> делает
арифметический сдвиг вправо и >>>
выполняет логический сдвиг вправо.1011 >> 1 → 1101
1011 >> 3 → 11110011 >> 1 → 0001
0011 >> 2 → 0000Первые два числа имели 1 как наибольшую
значащий бит, поэтому было вставлено больше единиц
во время смены. Последние два числа имели 0
как самый старший бит, поэтому сдвиг вставлен
больше 0-х.Если число закодировано с использованием
два дополнения,
то арифметический сдвиг вправо сохраняет знак числа,
в то время как логический сдвиг вправо делает число положительным.// Арифметический сдвиг
1011 >> 1 → 1101
1011 это -5
1101 это -3// Логический сдвиг
1111 >>> 1 → 0111
1111 это -1
0111 это 7Скоро интервью?
Пройдите бесплатный 7-дневный ускоренный курс по электронной почте. Вы научитесь, , как мыслить алгоритмически, , чтобы вы могли разбить сложное собеседование
вопросов.Никакого предварительного обучения информатике не требуется — мы быстро научим вас, пропуская все
чрезмерно академический материал.tzp6 «,» email «: null,» date_joined «:» 2021-05-30T17: 27: 59.565336 + 00: 00 «,» first_name «:» «,» last_name «:» «,» full_name «:» «, «short_name»: «friend», «is_anonymous»: true, «is_on_last_question»: false, «percent_done»: 0, «num_questions_done»: 0, «num_questions_remaining»: 46, «is_full_access»: false, «is_student»: false, «first_payment_date»: null, «last_payment_date»: null, «num_free_questions_left»: 3, «terms_has_agreed_to_latest»: false, «primary_content_language»: «», «предпочтительный_editor_language»: «»: «is_staff_proread», false , «num_auth_providers»: 0, «auth_email»: «»}×
Войти / зарегистрироваться
Всего за пару кликов.
Мы никогда не будем публиковать сообщения у вас на стене или писать сообщения вашим друзьям.
Где мне ввести свой пароль?
На самом деле не поддерживает вход по паролю. Никогда не было. Только методы OAuth, указанные выше. Почему?
- Легко и быстро. Нет потока «сброса пароля». Нет пароля, который нужно забыть.
- Это позволяет нам избежать хранения паролей, к которым могут получить доступ хакеры, и использовать их, чтобы попытаться войти в электронную почту или банковские счета наших пользователей.
- Одному человеку становится сложнее поделиться платной учетной записью Interview Cake с несколькими людьми.
« Я действительно надеялся получить от вас свои деньги за то, что не получил предложения от компании, но в итоге получил предложение от Google после практики с вашей платформой. Спасибо за помощь !!
—
Адам
. . .
битовых манипуляций в Java — побитовые операции и битовые сдвиги
Java позволяет вам управлять целыми числами на битовом уровне, что означает работу с определенными битами, которые представляют собой целое число.В некоторых случаях это может быть действительно удобно.
Побитовые операторы
Вы, несомненно, знакомы с арифметическими операторами, такими как + — * / или%. Вы также наверняка знаете логические операторы, такие как & или |. Оказывается, есть еще один, немного менее известный набор операторов, которые манипулируют числами на битовом уровне. Внутри каждое число хранится в двоичном формате — это 0 и 1.
Эти операторы могут выполняться с целочисленными типами и их вариантами — то есть
- байт (8 бит)
- короткий (16 бит)
- int (32 бит)
- длинный (64 бит)
- и даже char (16 бит)
Унарный оператор поразрядного дополнения [~]
Это причудливое имя в основном означает отрицание битов.Он берет каждый бит числа и меняет его значение. То есть — 0 становится 1 и наоборот. Унарный означает, что ему нужен только один операнд. Оператор ~ и он просто помещается перед числом:
.
или
Например, возьмем ~ 42:
- Двоичное представление 42 — это 101010.
- Поскольку 42 — это int, оно представляется как 32-битное значение, то есть 32 единицы или нули.
- Таким образом, все позиции слева от 101010 фактически заполнены нулями до 32 бит.
- То есть 00000000 00000000 00000000 00101010
- Перевернутое значение числа выше будет 11111111 11111111 11111111 11010101
Побитовое И [&]
В отличие от оператора побитового дополнения, другим побитовым операторам требуется два операнда.
A и B означает, что все биты обоих чисел сравниваются один за другим, и результирующее число вычисляется на основе значений битов из чисел A и B. Побитовое И аналогично логическому И в том смысле, что оно приводит к 1 только когда два сравниваемых бита равны 1.B
1 0 0 1 1 0 1 0 1 1 1 1 1 1 0 0 0 0 0 0 Операторы битового сдвига
Сдвиг влево с подписью [
<<]
Знаковый левый сдвиг принимает два операнда.Он берет битовую комбинацию первого операнда и сдвигает ее влево на количество разрядов, заданное вторым операндом. Например, 5 << 3: Что происходит в этом случае - Каждый бит в двоичном представлении целого числа 5 сдвигается на 3 позиции влево. Все места слева заполнены нулями. То есть:
00000000 00000000 00000000 00000101
становится
00000000 00000000 00000000 00101000
Вы можете заметить, что целочисленный результат 5 << 3 равен 40. н. .
Есть еще несколько интересных аспектов:
- Несмотря на то, что вы можете использовать сдвиг байта, короткого символа или символа, они повышаются до 32-битного целого числа перед сдвигом
- Операторы битового сдвига никогда не вызывают исключения
- Правый операнд (количество позиций для сдвига) уменьшается по модулю 32. То есть 5 << 35 эквивалентно 5 << 3.
Отрицательные целые числа в Java
На самом деле существует два типа сдвига вправо.Подпись и без подписи. Разница в том, как они относятся к отрицательным числам. Чтобы понять разницу, необходимо знать, как в Java представлены отрицательные числа. Само по себе двоичное представление не дает информации о том, отрицательно ли число. Должно быть специальное правило, чтобы определить, как представлять отрицательные числа в двоичном формате. Есть несколько подходов к этой проблеме.
Одно из решений состоит в том, что крайний левый (наиболее значимый) бит является битом знака. Это означает, что его значение указывает, является ли число положительным или отрицательным.Однако у этого есть некоторые недостатки, такие как то, что есть два способа представления нуля.
Java использует другой подход, который называется с дополнением до двух . Отрицательные числа представляются путем инвертирования (переворота) всех битов и последующего добавления 1. Тем не менее, если крайний левый бит равен 0, число положительное. В противном случае — отрицательно.
Подпись, сдвиг вправо [>>]
Знаковый сдвиг вправо перемещает все биты на заданное количество позиций вправо. Однако он сохраняет знак. n -1 в случае нечетных чисел.
Беззнаковый сдвиг вправо [>>>]
В отличие от сдвига со знаком, сдвиг без знака не принимает во внимание биты знака, он просто сдвигает все биты вправо и дополняет результат нулями слева. Это означает, что для отрицательных чисел результат всегда положительный. Знаковые и беззнаковые сдвиги вправо имеют одинаковый результат для положительных чисел. 5
& = х & = 5 x = x & 5 << = x << = 5 х = х << 5 >> = х >> = 5 х = х >> 5 >>> = х >>> = 5 х = х >>> 5 Обратите внимание, что нет составного оператора присваивания для унарного оператора поразрядного дополнения [~].
Заключение
Манипуляции с битами в некоторых случаях могут быть очень удобными и действительно эффективными. Однако за повышение производительности приходится платить. Читабельность сильно страдает, это может вызвать недоумение для тех, кто не знаком с концепцией манипуляции с битами. Если сценарий, который вы используете, не критичен к производительности, вы можете подумать, действительно ли компромисс между производительностью и удобочитаемостью стоит того, и, возможно, переписать свое решение в более удобочитаемом виде.Не используйте битовые манипуляции везде, где это возможно, только потому, что вы узнали новую крутую концепцию.
Краткое руководство по побитовым операторам в Java
Оператор сдвига влево и вправо
Битовый сдвиг — это побитовая операция, при которой порядок последовательности битов перемещается для эффективного выполнения математической операции. Битовый сдвиг перемещает каждую цифру в двоичном представлении числа влево или вправо на количество пробелов, указанное вторым операндом.
Эти операторы могут применяться к целым типам, таким как
int
,long
,short
,byte
илиchar
.Есть три вида смен:
- Сдвиг влево:
<<
- оператор сдвига влево, отвечающий требованиям как логических, так и арифметических сдвигов. - Арифметический / знаковый сдвиг вправо:
>>
- это арифметический (или знаковый) оператор сдвига вправо. - Логический / беззнаковый сдвиг вправо:
>>>
- логический (или беззнаковый) оператор сдвига вправо.
В Java все целочисленные типы данных подписаны, а
<<
и>>
представляют собой исключительно арифметические сдвиги.Вот пример сдвига влево:
6 = 000000006 = 000000006 = 00000000 000000000000000000000000 000000000000000000000000 000001100000011000000110
Сдвиг этой битовой комбинации на одну позицию влево (
6 << 1
) приводит к числу 12:6 << 1 = 000000006 << 1 = 000000006 << 1 = 00000000 000000000000000000000000 000000000000000000000000 000011000000110000001100
Как видите, цифры смещены влево на одну позицию, а последняя цифра справа заполнена нулем.36 * 2 3 → 6 * 86 * 86 * 8
Хорошо оптимизированные компиляторы будут использовать это правило для замены умножения сдвигами, когда это возможно, поскольку сдвиги выполняются быстрее.
Bit Shifting | Программирование игр Java 1.4 (библиотека игр и графики Wordware)
Битовый сдвиг позволяет сдвигать биты целочисленного значения влево или вправо. Ниже приводится таблица операторов битового сдвига и описание того, что они делают.
Оператор
Описание
<<
Сдвигает биты влево, добавляя нули справа
битов вправо, копируя знаковый бит (крайний левый бит) слева >>>
Сдвигает биты вправо, добавляя нули слева
Эти операторы являются двоичными и возьмем два операнда.Левый операнд - это целочисленное значение, по которому выполняется сдвиг, а правый операнд - это количество битов, на которое нужно сдвинуть. Сдвиг влево на степени двойки будет выполнять целочисленное деление, а сдвиг вправо на степени двойки будет умножать значение. Например, предположим, что у нас есть десятичное значение 2, которое будет представлено в двоичном виде значением 00000010 в байтах. Альтернативой прямому умножению этого значения на 8 может быть побитовый сдвиг значения на три позиции влево.
число байтов = 2; // двоичный 00000010
Затем мы могли бы сдвинуть биты влево на три позиции, как показано ниже:
number = number << 3;
При сдвиге битов на три позиции влево и заполнении нулями справа наша двоичная запись будет 00010000, что является десятичным значением 2 4 , равным 16.Это то же самое, что умножить 2 на 2 3 .
Примечание Предыдущий код битового сдвига значения переменной number также мог быть выполнен с использованием оператора присваивания левого сдвига, как показано ниже:
number << = 3;
Язык Java - Операторы сдвига (> и >>>)
Пример
Язык Java предоставляет три оператора для выполнения побитового сдвига 32- и 64-битных целочисленных значений.Все это бинарные операторы, где первый операнд является значением, которое нужно сдвинуть, а второй операнд говорит, насколько далеко нужно сдвинуть.
Оператор
<<
или сдвиг влево сдвигает значение, заданное первым операндом , на влево на количество битовых позиций, заданное вторым операндом. Пустые позиции в правом конце заполняются нулями.Оператор арифметического сдвига «>>» или сдвигает значение, заданное первым операндом , вправо на на количество битовых позиций, заданное вторым операндом.Пустые позиции в левом конце заполняются копированием самого левого бита. Этот процесс известен как расширение знака .
Оператор логического сдвига вправо '>>>' или сдвигает значение, заданное первым операндом , вправо на на количество битовых позиций, заданное вторым операндом. Пустые позиции в левом конце заполняются нулями.
Примечания:
Эти операторы требуют значение
int
илиlong
в качестве первого операнда и создают значение того же типа, что и первый операнд.(Вам нужно будет использовать явное приведение типа при присвоении результата сдвига переменнойбайта
,short
илиchar
.)Если вы используете оператор сдвига с первым операндом, который представляет собой
байт
,char
иликороткий
, он повышается доint
, и операция создаетint
.)Второй операнд уменьшается на по модулю числа битов операции , чтобы получить величину сдвига.Для получения дополнительной информации о математической концепции mod см. Примеры модуля.
Биты, сдвинутые влево или вправо в результате операции, отбрасываются. (В Java нет примитивного оператора поворота.)
Оператор арифметического сдвига эквивалентен делению числа (дополнение до двух) на степень 2.
Оператор сдвига влево эквивалентен умножению числа (дополнения до двух) на степень двойки.
Следующая таблица поможет вам увидеть эффекты трех операторов сдвига. (Числа были выражены в двоичной системе счисления для облегчения визуализации.)
Operand1 Operand2 <<
>>
>>>
0
0b0000000000001011 0b0000000000001011 0b0000000000001011 0b0000000000001011 1 0b0000000000010110 0b0000000000000101 0b0000000000000101 0b0000000000001011 2 0b0000000000101100 0b0000000000000010 0b0000000000000010 0b0000000000001011 05 0b1011000000000000 0b0000000000000000 0b0000000000000000 0b0000000000001011 31 0b1000000000000000 0b0000000000000000 0b0000000000000000 0b0000000000001011 32 0b0000000000001011 0b0000000000001011 0b0000000000001011 ... ... ... ... ... 0b1000000000001011 0 000 0 000 0 05 0b1000000000001011 0b1000000000001011 0b1000000000001011 1 0b0000000000010110 0b1100000000000101 0b0100000000000101 0b1000000000001011 2 0b0000000000101100 0b1110000000000010 0b00100000000000100 0b1000000000001011 31 711 11 178 0b0000000000000001 Примеры использования операторов сдвига в Bitmanagement
И ИЛИ XOR НЕ СДВИГАЕТСЯ
Побитовые операторы Java
Побитовые операторы Java - это операторы низкого уровня, что означает, что они работают на битовом уровне и используются для управления отдельными битами битового шаблона. («побитовый xor или нечетный оператор»).
Побитовые операторы нельзя использовать с операндами с плавающей запятой, логическими значениями, массивами или объектами. Когда побитовые
,
и| Операторы
применяются клогическим значениям
, они ведут себя аналогично&&
и||
и в результате получается логическое значениеи
и| Операторы
не оцениваются методом «короткого замыкания».То есть сначала оцениваются оба аргумента, а затем вычисляется результат. Мы снова обсудим вычисление короткого замыкания в логических операторах.Таблица 1 демонстрирует поразрядные операторы Java, предполагая, что A и B - это два бита, содержащие либо 0, либо 1, тогда следующие побитовые операции могут выполняться с A и B.
Таблица 1: Демонстрация побитовых операторов А B A и B A | B A ^ B ~ ~ В 0 0 0 0 0 1 1 0 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 1 0 0 0 Теперь давайте обсудим все побитовые операторы один за другим более подробно.
Побитовое дополнение (~)
Побитовое дополнение (~) или побитовое НЕ - это унарный оператор, который инвертирует каждый бит своего единственного операнда, преобразуя единицы в нули и нули в единицы. Например, следующая программа инвертирует все биты
b
и очищает флагf
в наборе изфлагов
с помощью побитового оператора НЕ.класс bitwiseOperator { public static void main (String args []) { байт b = ~ 12; // ~ 00000110 ==> 11111001 или -13 десятичное int flags = 28; int f = 4; flags = flags & ~ f; // Снимаем флаг f в наборе флагов, теперь он равен 24 Система.out.println ("b:" + b); System.out.println ("флаги:" + флаги); } } ВЫХОД ====== b: -13 флаги: 24
Побитовое И (&)
Поразрядный оператор И (&) - это бинарный оператор, который работает с двумя целочисленными операндами, выполняя логическую операцию И над их отдельными битами. Результат будет 1, только если соответствующие биты равны 1 в обоих операндах. Побитовое И - отличный способ проверить, равен ли конкретный бит 1 или 0 в целочисленном значении.Следующая программа демонстрирует побитовый оператор AND.
класс bitwiseOperator { public static void main (String args []) { int flags = 28; int f = 4; // Проверяем, установлен ли флаг f if ((flags & f)! = 0) // 011100 & 000100 ==> 000100 или 4 { System.out.println ("флаг f установлен в flags:" + (flags & f)); } еще { System.out.println ("флаг f не установлен в flags:" + (flags & f)); } } } ВЫХОД ====== флаг f устанавливается в flags: 4
Побитовое ИЛИ (|)
Оператор побитового ИЛИ (|) - это бинарный оператор, который работает с двумя целочисленными операндами, выполняя логическую операцию ИЛИ над их отдельными битами.Результат равен 1, если соответствующий бит равен 1 в одном или обоих операндах. Он имеет нулевой бит только тогда, когда оба соответствующих бита операнда равны нулю. Следующая программа демонстрирует побитовый оператор ИЛИ.) - это бинарный оператор, который работает с двумя целочисленными операндами, выполняя логическую операцию XOR (исключающее ИЛИ) над их отдельными битами.num2;
System.out.println («XOR для« + num1 + »и« + num2 + »равно:« + xorResult »);
}
}ВЫХОД
======
XOR 10 и 7: 13Побитовые операции с символьными переменными
Значения символов в Java можно преобразовывать в различные целочисленные типы и обратно; поэтому к ним можно применять побитовые операции. Тем не менее, я не вижу большого применения применения побитовых операций к типам
char
, но ради знаний, да, поразрядные операторы могут применяться к типамchar
в Java.Следующая программа демонстрирует поразрядные операции с переменнымиchar и
.класс bitwiseOperator { public static void main (String args []) { char ch2 = 'a', ch3 = 'b'; // Побитовое дополнение // ~ 97 ==> -98 System.out.println ("~ ch2:" + ~ ch2); // Побитовое И // 97 & 98 ==> 96 System. 98 ==> 3 Система.ch3: 3
Операторы сдвига битов Java
В дополнение к указанным выше побитовым операторам Java предоставляет три разновидности операторов побитового сдвига: сдвиг влево (<<), сдвиг вправо (>>) и сдвиг вправо с заполнением нулями (>>>). Заметное различие между сдвигом вправо и сдвигом вправо с заполнением нулями состоит в том, что при побитовой операции сдвига вправо свободные биты с левой стороны заполняются самым левым битом (то есть битом знака), он может быть нулем или единицей.Это сделано для сохранения знака операнда. Свободные биты заполняются нулем, если число положительное, или единицей, если число отрицательное. При сдвиге вправо с заполнением нулями свободные биты слева всегда заполняются нулем независимо от знака. Предположим, что X - целое число типа
int
, содержащее десятичное значение 15 и -15, тогда оно дает следующие результаты при применении различных операций сдвига (см. Таблицу 2):Операторы сдвига имеют синтаксис:
var <оператор сдвига> количество бит, на которое нужно сдвинуть
Например, X = X << 2;Таблица 2: Демонстрация операторов побитового сдвига X (в десятичной системе)
Перед работойShift
OperationX (в десятичной системе)
После операции15 X = X << 2 60 15 Х = Х >> 2 3 15 Х = Х >>> 2 3 -15 X = X << 2 -60 -15 Х = Х >> 2 -4 -15 х = Х >>> 2 1073741820 Приложения битовых операторов Java
Побитовые операторы очень помогают, если нам нужно выполнять операции с отдельными битами, а не со всем числом.Маскирование - это метод, который можно использовать для извлечения определенного бита. Например, если вы хотите проверить, равен ли 5-й бит данного целого числа 0 или 1, вы можете сделать это как
int x = 23; // пятый бит равен единице, поскольку двоичный из 23 равен 10111 int FridayBit = (х & 16) / 16; System.out.println ("Пятый бит" + x + "равен" + FridayBit ");
Мы также можем проверить, является ли данное целое число нечетным или четным, не применяя модуль или операцию деления. Если
(x & 1)
дает 1, то нечетное, иначе четное.Вычисление знака числа без ветвления также может выполняться поразрядными операторами. Мы знаем, что если самый левый бит целого числа равен нулю, то число положительно, иначе - отрицательно. Мы можем узнать значение самого левого бита, который также называется старшим значащим битом (MSB).
целое число = 17; знак int; знак = число >>> 31; // размер int составляет 32 бита в Java
Мы также можем определить, является ли целое число степенью двойки, следующим образом:
целое число = 32; логическое isPowOfTwo = (число & (число -1)) == 0; Система.out.println (num + "степень двойки?" + isPowOfTwo);
Есть еще много таких полезных приложений побитовых операторов. Мы не можем охватить их все в таком коротком тексте.
Последнее слово
В этом руководстве мы обсудили побитовые операторы и операторы сдвига в Java. Надеюсь, вам понравилось читать это руководство по различным операторам Java. Пожалуйста, напишите нам, если у вас есть какие-либо предложения / комментарии или вы столкнетесь с какой-либо ошибкой на этой странице.Спасибо за прочтение!
Список литературы
Использование операторов Java Bit Manipulation
Программистам иногда приходится опускаться до уровня битов и байтов при работе с низкоуровневыми данными. Это особенно заметно при разработке программного обеспечения для тестового оборудования, сетей, операционных систем или при установлении прямой связи с оборудованием. В любом случае Java предоставляет возможности для обширных манипуляций с битами, и их можно использовать по своему усмотрению.В этой статье представлена справочная информация, относящаяся к этой возможности и использованию побитовых операторов, доступных в Java.
Биты и байты
Бит происходит от фразы «двоичная цифра», представленной 0 или 1. Эти два, казалось бы, простых числа могут нести большой объем информации при объединении. 0 в основном означает выкл / ложь , а 1 означает вкл / истина . Говоря простым языком, переключатель может сигнализировать одно из двух: выключено (0) или включено (1).Теперь использование двух переключателей поочередно / вместе дает 2 2 = 4 таких сигнала - 00, 01, 10, 11. Три переключателя будут обеспечивать 2 3 = 8 сигналов - 000, 001, 010, 011, 100, 101, 110, 111. Четыре переключателя, 16 сигналов и так далее. Отдельные биты, объединенные в группу из восьми, называются байтом и (8 бит = 1 байт). Количество сигналов, обеспечиваемых 8-битной или 1-байтовой обработкой, составляет 2 8 = 256. По мере увеличения количества байтов единица измерения становится килобайт (2 10 ), мегабайт (2 20 ), гигабайт (2 30 ) и т. Д.
Компьютеры представляют все данные внутри как последовательность битов. Точнее, это даже не биты, а электрические заряды, представленные как имеющие определенные напряжения как 1 / on / true , а его отсутствие или недостаток как 0 / off / false . Эта простая идея дает значительный импульс для формулирования сигнальной схемы в математическом выражении и решает ее, как любую математическую задачу. Благодаря этому удобству сигналы преобразуются в двоичные числа. Существует раздел математики, который специально занимается двоичной логикой, называется Boolean Algebra , в честь английского математика и логика Джорджа Буля.Булева алгебра обеспечивает принципы двоичной арифметики, которые можно идеально использовать в качестве инструмента при создании логических схем.
Когда мы говорим двоичную арифметику , основными операторами, используемыми с двоичными операциями, являются И, ИЛИ и НЕ. Кроме того, существуют другие производные операторы, такие как NAND (NOT AND), NOR (NOT OR), Ex-OR / XOR (Exclusive-OR) и Ex-NOR / XNOR (Exclusive-NOR). Таблица истинности с основными операторами показана на рисунке 1:
.
Рисунок 1: Таблица истинности
Другие производные операторы - NAND, NOR и Ex-NOR - представляют собой не что иное, как оператор NOT, добавленный к результату этих основных операторов.
Типы данных
В Java есть тип данных, называемый байтом , , для хранения восьмибитовой последовательности. Если требуется хранить информацию более восьми битов, существует множество других типов данных, но побитовые операторы работают только с целыми операндами, такими как byte, char, short, int и long . В указанном порядке каждая из них может хранить больше битовых последовательностей, чем предыдущая. Побитовые операторы не работают с операндами с плавающей запятой.), сдвиг влево (<<), сдвиг вправо со знаком (>>), сдвиг вправо без знака (>>>) и побитовое дополнение (~). Они действуют, как указано выше, с помощью таблиц истинности. Операторы сдвига влево и вправо будут объяснены позже в статье.
Побитовый оператор против логического оператора
Следует отметить, что операторы короткого замыкания, такие как логическое И (&&) и логическое ИЛИ (||), не следует путать с операторами побитового И (&) и побитового ИЛИ (|), потому что они имеют разное значение.Логические операторы могут быть названы операторами ленивого вычисления , тогда как побитовые операторы стремятся к операторам жадного вычисления. Это означает, что побитовые операторы AND (&) и OR (|) оценивают обе стороны операции. С другой стороны, логические операторы AND (&&) и OR (||) оценивают левую часть операции; если это истинно , они оценивают только правую сторону.
Запутывает то, что в большинстве случаев они приводят к одному и тому же выводу.Вот пример, чтобы проиллюстрировать это.
пакет org.mano.example; общедоступный класс BitwiseOperatorDemo { public static void main ( String [] args ) { Система. out .println ((false | ложь) ? «истина»: «ложь» ) ; Система. out .println ((false | правда) ? «истина»: «ложь» ) ; Система. из .println ((true | ложь) ? «истина»: «ложь» ) ; Система. из .println ((true | правда) ? «истина»: «ложь» ) ; Система. out .println ((false || ложь) ? «истина»: «ложь» ) ; Система. out .println ((false || правда) ? «истина»: «ложь» ) ; Система. из .println ((true || ложь) ? «истина»: «ложь» ) ; Система. из .println ((true || правда) ? «истина»: «ложь» ) ; Система. из .println ( «-----------------------------------------» ) ; Система. из .println ((ложные и ложные) ? «истина»: «ложь» ) ; Система. out .println ((false & true) ? «истина»: «ложь» ) ; Система. out .println ((true & false) ? «истина»: «ложь» ) ; Система. из .println ((true и true) ? «истина»: «ложь» ) ; Система. out .println ((false && ложь) ? «истина»: «ложь» ) ; Система. out .println ((false && правда) ? «истина»: «ложь» ) ; Система. из .println ((true && ложь) ? «истина»: «ложь» ) ; Система. из .println ((true && правда) ? «истина»: «ложь» ) ; }
Выход
ложь правда правда правда ложный правда правда правда ----------------------------------------- ложный ложный ложный правда ложный ложный ложный правда
Обратите внимание на следующий пример; это проясняет разницу.Операции логического И и логического ИЛИ даже не вызывают функцию f2 (), если возвращаемое значение метода f1 () не истинно. Но это не относится к операторам поразрядного И и побитового ИЛИ. В любом случае оцениваются обе стороны операции.
пакет org.mano.example; общедоступный класс BitwiseOperatorDemo { public static void main ( String [] args ) { если ( f1 () | f2 ()) Система. из .println ( "побитовое ИЛИ" ) ; , если (! f1 () и f2 ()) Система. из .println ( "побитовое И" ) ; Система. из .println ( «-----------------------------------» ) ; если ( f1 () || f2 ()) Система. из .println ( «логическое ИЛИ» ) ; если (! f1 () && f2 ()) Система. из .println ( «логическое И» ) ; } общедоступное статическое логическое значение f1 () { Система. out .println ( «Функция f1 активирована» ) ; вернуть истину ; } общедоступное статическое логическое значение f2 () { Система.) операторы бит за битом сравнивают два операнда.
- Оператор AND (&) устанавливает бит результата в 1, только если оба бита операнда равны 1.
- Оператор ИЛИ (|), с другой стороны, устанавливает бит результата в 1, когда один или оба бита операнда равны 1.
- Оператор Ex-OR устанавливает бит результата в 1, если соответствующий бит ровно одного из его операндов равен 1.
- Оператор сдвига влево (<<) сдвигает биты своего левого операнда влево в соответствии с числом, указанным в правом операнде.Нули вставляются справа.
- Оператор сдвига вправо со знаком (>>) сдвигает бит своего левого операнда вправо в соответствии с количеством битов, указанным в правом операнде. Поскольку оператор поддерживает бит со знаком операнда, отрицательный операнд сдвигает 1t слева; в противном случае добавляются нули. Этот метод поддерживает бит операнда со знаком.
- Оператор сдвига вправо без знака (>>>) аналогичен оператору сдвига влево, за исключением только обратного направления.Это означает, что оператор сдвигает биты в своем левом операнде вправо на количество битов, указанное в правом операнде. 0 вводятся слева.
- Оператор поразрядного дополнения (~) устанавливает все биты 0 в своем операнде в 1 и все 1 в 0.
Быстрый пример
пакет org.mano.example; общедоступный класс BitwiseOperatorDemo { public static void main ( String [] args ) { int a = -10; int b = -6; Система. из . Print ( a + ":" ) ; показатьБиты ( a ) ; Система. из . Print ( b + ":" ) ; показатьБиты ( b ) ; Система. из . Print ( "AND (a & b):" ) ; showBits ( a & b ) ; Система. из .б ) ; Система. из .print ( "левый сдвиг (a << 2):" ) ; showBits ( a << 2 ) ; Система. из . Print ( "со знаком, сдвиг вправо (a >> 2): ") ; показатьБиты ( a >> 2 ) ; Система. из . Print ( ", сдвиг вправо (a >>> 2): ") ; showBits ( a >>> 2 ) ; Система. из .print ( "Дополнение (~ a):" ) ; показатьБиты ( ~ ) ; } public static void showBits (int param ) { int mask = 1 << 31; для (int i = 1; i <= 32; i ++, param << = 1 ) { Система. из . Print (( param & mask ) == 0? «0»: «1» ) ; если ( i% 8 == 0 ) Система.б): 00000000 00000000 00000000 00001100 левый сдвиг (a << 2): 11111111 11111111 11111111 11011000 знаковый сдвиг вправо (a >> 2): 11111111 11111111 11111111 11111101 сдвиг вправо (a >>> 2): 00111111 11111111 11111111 11111101 Дополнение (~ a): 00000000 00000000 00000000 00001001
Класс BitSet
Java предоставляет специальный класс BitSet в пакете java.util для работы с битами. Этот класс можно использовать для более удобного выполнения операций манипулирования битами.Обратитесь к статье «Изучение Java BitSet» для получения более подробной информации о его использовании.
Заключение
Поразрядная операция может использоваться так же, как и любой другой оператор в Java. Единственная разница между ним и другими операциями состоит в том, что он оценивается побитовым значением. Иногда можно комбинировать побитовые операции с другими бинарными операторами. Однако обратите внимание, что побитовые операторы работают только с целыми типами: byte, char, short, int и long .Типы с плавающей запятой, такие как float и double , нельзя использовать с побитовыми операторами.
.