Сдвиг вправо без учета знака. Побитовые составные операции с присваиванием. Операции сравнения
Сдвиг вправо без учета знака Как было показано, при каждом выполнении операция > > автоматически заполняет старший бит его предыдущим содержимым. В результате знак значения сохраняется. Однако иногда это нежелательно. Например, при выполнении сдвига вправо в какомлибо значении, которое не является числовым, использование дополнительных знаковых разрядов может быть нежелательным. Эта ситуация часто встречается при работе со значениями пикселей и графическими изображениями. Как правило, в этих случаях требуется сдвиг нуля в позицию старшего бита независимо от его первоначального значения. Такое действие называют сдвигом вправо без учета знака. Для его выполнения используют операцию сдвига вправо без учета знака Java, > > >, которая всегда вставляет ноль в позицию старшего бита. Следующий фрагмент кода демонстрирует применение операции > > >. В этом примере значение переменной a установлено равным –1, все 32 бита двоичного представления которого равны 1. Затем в этом значении выполняется сдвиг вправо на 24 бита с заполнением старших 24 битов нулями и игнорированием обычно используемых дополнительных знаковых разрядов. В результате значение a становится равным 255. int a = -1; a = a > > > 24; Чтобы происходящее было понятнее, запишем эту же операцию в двоичной форме: 11111111 11111111 11111111 11111111 –1 в двоичном представлении типа int > > > 24 00000000 00000000 00000000 11111111 255 в двоичном представлении типа int Часто операция > > > не столь полезна, как хотелось бы, поскольку она имеет смысл только для 32- и 64-разрядных значений. Помните, что в выражениях тип меньших значений автоматически повышается до int. Это означает применение дополнительных знаковых разрядов и выполнение сдвига по отношению к 32-разрядным, а не 8- или 16-разрядным значениям. То есть программист может подразумевать выполнение сдвига вправо без учета знака применительно к значению типа byte и заполнение нулями, начиная с бита 7.
Однако в действительности это не так, поскольку фактически сдвиг будет выполняться в 32-разрядном значении. Этот эффект демонстрирует следующая программа. // Сдвиг без учета знака значения типа byte. class ByteUShift { static public void main(String args[]) { char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; byte b = (byte) 0xf1; byte c = (byte) (b > > 4); byte d = (byte) (b > > > 4); byte e = (byte) ((b & 0xff) > > 4); System. out. println(" b = 0x" + hex[(b > > 4) & 0x0f] + hex[b & 0x0f]); System. out. println(" b > > 4 = 0x" + hex[(c > > 4) & 0x0f] + hex[c & 0x0f]); System. out. println(" b > > > 4 = 0x" + hex[(d > > 4) & 0x0f] + hex[d & 0x0f]); System. out. println(" (b & 0xff) > > 4 = 0x" + hex[(e > > 4) & 0x0f] + hex[e & 0x0f]); } } Из следующего вывода этой программы видно, что операция > > > не выполняет никаких действий по отношению к значениям типа byte. Для этого примера в качестве значения переменной b было выбрано произвольное отрицательное значение типа byte. Затем переменной c присваивается значение переменной b типа byte, сдвинутое вправо на четыре позиции, которое в связи с применением дополнительных знаковых разрядов равно 0xff. Затем переменной d присваивается значение переменной b типа byte, сдвинутое вправо на четыре позиции без учета знака, которым должно было бы быть значение 0x0f, но в действительности, из-за применения дополнительных знаковых разрядов во время повышения типа b до int перед выполнением сдвига, равное 0xff. Последнее выражение устанавливает значение переменной e равным значению типа byte переменной b, замаскированному до 8 бит с помощью операции AND и затем сдвинутому вправо на четыре позиции, что дает ожидаемое значение, равное 0x0f. Обратите внимание, что операция сдвига вправо без учета знака не применялась к переменной d, поскольку состояние знакового бита после выполнения операции AND было известно.
b = 0xf1 b > > 4 = 0xff b > > > 4 = 0xff (b & 0xff) > > 4 = 0x0f Побитовые составные операции с присваиванием Подобно алгебраическим операциям, все двоичные побитовые операции имеют составную форму, которая объединяет побитовую операцию с операцией присваивания. Например, следующие два оператора, выполняющие сдвиг вправо на четыре позиции в значении переменной a, эквивалентны: a = a > > 4; a > > = 4; Аналогично, эквивалентны и следующие два оператора, которые присваивают переменной a результат выполнения побитовой операции a OR b: a = a | b; a |= b; Следующая программа создает несколько целочисленных переменных, а затем использует составные побитовые операции с присваиванием для манипулирования этими переменными: class OpBitEquals { public static void main(String args[]) { int a = 1; int b = 2; int c = 3; a |= 4; b > > = 1; c < < = 1; a ^= c; System. out. println(" a = " + a); System. out. println(" b = " + b); System. out. println(" c = " + c); } } Эта программа создает следующий вывод: a = 3 b = 1 c = 6 Операции сравнения Операции сравнения определяют отношение одного операнда с другим. В частности, они определяют равенство и порядок следования. · == Равно ·! = Не равно · > Больше · < Меньше · > = Больше или равно · < = Меньше или равно Результат выполнения этих операций – значение типа boolean. Наиболее часто операции сравнения используют в выражениях, которые управляют оператором if и различными операторами цикла. В Java можно сравнивать значения любых типов, в том числе целые значения, значения с плавающей точкой, символы и булевские значения, используя проверку равенства == и проверку неравенства! =. Обратите внимание, что Java равенство обозначают двумя знаками “равно”, а не одним. (Одиночный знак “равно” – символ операции присваивания. ) Сравнение с помощью операций упорядочения применимо только к числовым типам. То есть сравнение для определения того, какой из операндов больше или меньше другого, можно выполнять только для целочисленных операндов, операндов с плавающей точкой или символьных операндов. Как уже было отмечено, результат выполнения операции сравнения представляет собой значение типа boolean. Например, следующий фрагмент кода вполне допустим:
int a = 4; int b = 1; boolean c = a < b; В данном случае результат выполнения операции a < b (который равен false) сохраняется в переменной c. Те читатели, которые знакомы с языками C/C++, должны обратить внимание на следующее. В программах на C/C++ следующие типы операторов встречаются очень часто: int done; //... if(! done)... // Допустимо в C/C++ if(done)... // но не в Java. В Java-программе эти операторы должны быть записаны следующим образом: if(done == 0)... // Это стиль Java. if(done! = 0)... Это обусловлено тем, что в Java определение значений “истинно” и “ложно” отличается от их определений в языках C/C++. В C/C++ истинным считается любое ненулевое значение, а ложным – ноль. В Java значения true (истинно) и false (ложно) – нечисловые значения, которые никак не сопоставимы с нулевым или ненулевым значением. Поэтому, чтобы сравнить значение с нулевым или ненулевым значением, необходимо явно использовать одну или несколько операций сравнения.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|