Главная страница

АБОБА. Справочник по программированию на Java Методическое пособие


Скачать 242.41 Kb.
НазваниеСправочник по программированию на Java Методическое пособие
АнкорАБОБА
Дата20.02.2022
Размер242.41 Kb.
Формат файлаdocx
Имя файла12642_java_method_1.docx
ТипСправочник
#368066
страница17 из 67
1   ...   13   14   15   16   17   18   19   20   ...   67

Сдвиг влево


Операция сдвига влево, <<, сдвигает все биты значения влево на указанное число позиций. Она имеет следующую общую форму:

значение << число

Здесь число – количество позиций, на которое нужно сдвинуть влево биты в значении значение. То есть операция << смещает влево биты указанного значения на количество позиций, указанных в число. При каждом сдвиге влево самый старший бит сдвигается за пределы допустимого диапазона (и утрачивается), а ноль дописывается справа.

Это означает, что при применении операции сдвига влево к операнду типа int биты утрачиваются, как только они сдвигаются за пределы 31 позиции. Если операнд имеет тип long, биты теряются после сдвига за пределы 63 позиции.

Автоматическое повышение типа, выполняемое в среде Java, приводит к непредвиденным результатам при выполнении сдвига в значениях типа byte и short. Как вы уже знаете, тип значений byte и short повышается до int при вычислении выражений. Более того, результат вычисления такого выражения также имеет тип int. Это означает, что результатом выполнения сдвига влево значения типа byte или short будет значение типа int, и сдвинутые влево биты не будут отброшены до тех пор, пока они не будут сдвинуты за пределы 31 позиции. Более того, при повышении до типа int отрицательное значение типа byte или short получит дополнительный знаковый разряд. Следовательно, старшие биты будут заполнены единицами. Поэтому выполнение операции применительно к значению типа byte или short предполагает необходимость отбрасывания старших байтов результата типа int. Например, при выполнении сдвига влево в значении типа byte вначале будет осуществляться повышение типа значения до int, и лишь затем сдвиг. Это означает, что для получения требуемого сдвинутого значения типа byte необходимо отбросить три старших байта результата. Простейший способ достижения этого – обратное приведение результата к типу byte. Следующая программа демонстрирует эту концепцию.

// Сдвиг влево значения типа byte.

class ByteShift {

public static void main(String args[]) {

byte a = 64, b;

int i;

i = a << 2;

b = (byte) (a << 2);

System.out.println("Первоначальное значение a: " + a);

System.out.println("i and b: " + i + " " + b);

}

}

Эта программа генерирует следующий вывод:

Первоначальное значение a: 64

i and b: 256 0

Поскольку для выполнения вычислений тип переменной a повышается до int, сдвиг влево на две позиции значения 64 (0100 0000) приводит к значению i, равному 256 (1 0000 0000). Однако переменная b содержит значение, равное 0, поскольку после сдвига младший байт равен 0. Единственный единичный бит оказывается сдвинутым за пределы допустимого диапазона.

Поскольку каждый сдвиг влево на одну позицию, по сути, удваивает исходное значение, программисты часто используют это в качестве эффективной замены умножения на 2. Однако при этом следует соблюдать осторожность. При сдвиге единичного бита в старшую позицию (бит 31 или 63) значение становится отрицательным. Следующая программа демонстрирует это применение операции сдвига влево.

// Применение сдвига влево в качестве быстрого метода умножения на 2.

class MultByTwo {

public static void main(String args[]) {

int i;

int num = 0xFFFFFFE;

for(i=0; i<4; i++) {

num = num << 1;

System.out.println(num);

}

}

}

Программа генерирует следующий вывод:

536870908

1073741816

2147483632

-32

Начальное значение было специально выбрано таким, чтобы после сдвига влево на 4 позиции оно стало равным -32. Как видите, после сдвига единичного бита в позицию 31 число интерпретируется как отрицательное.

Сдвиг вправо


Операция сдвига вправо, >>, сдвигает все биты значения вправо на указанное количество позиций. В общем виде ее можно записать следующим образом:

значение >> число

Здесь число указывает количество позиций, на которое нужно сдвинуть вправо биты в значении значение. То есть операция >> перемещает все биты в указанном значении вправо на количество позиций, указанное в число.

Следующий фрагмент кода выполняет сдвиг вправо на две позиции в значении 32, в результате чего значение переменной a становится равным 8:

int a = 32;

a = a >> 2; // теперь a содержит 8

Когда какие-либо биты в значении “сдвигаются прочь”, они теряются. Например, следующий фрагмент кода выполняет сдвиг вправо на две позиции в значении 35, что приводит к утрате двух младших битов и повторной установке значения переменной a равным 8:

int a = 35;

a = a >> 2; // a по-прежнему содержит 8

Чтобы лучше понять, как выполняется эта операция, рассмотрим ее применение к двоичным представлениям:

00100011 35

>> 2

00001000 8

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

При выполнении сдвига вправо старшие (расположенные в крайних левых позициях)биты, освобожденные в результате сдвига, заполняются предыдущим содержимым старшего бита. Этот эффект называется дополнительным знаковым разрядом и служит для сохранения знака отрицательных чисел при их сдвиге вправо. Например, результат выполнения операции -8>>1 равен –4, что в двоичном представлении выглядит так:

11111000 –8

>>1

11111100 –4

Интересно отметить, что результат сдвига вправо значения –1 всегда равен –1, поскольку дополнительные знаковые разряды добавляют новые единицы к старшим битам.

Иногда при выполнении сдвига вправо появление дополнительных знаковых разрядов нежелательно. Например, следующая программа преобразует значение byte в соответствующее шестнадцатеричное строковое представление. Обратите внимание, что для обеспечения возможности использования значения в качестве индекса массива шестнадцатеричных символов сдвинутое значение маскируется посредством его объединения со значением 0x0f операцией AND, что приводит к отбрасыванию любых битов дополнительных знаковых разрядов.

// Маскирование дополнительных знаковых разрядов.

class HexByte {

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;

System.out.println("b = 0x" + hex[(b >> 4) & 0x0f] + hex[b & 0x0f]);

}

}

Вывод этой программы выглядит следующим образом:

b = 0xf1
1   ...   13   14   15   16   17   18   19   20   ...   67


написать администратору сайта