1. Побитово ляво изместване

Java също има 3 оператора за побитово преместване : Ако наистина имате нужда, можете много просто да преместите всички битове на число няколко позиции наляво or надясно.

За да изместите битовете на число наляво, имате нужда от оператора за побитово ляво изместване . Ето How се пише:

a << b

Къде aе числото, чиито битове се изместват, и bе число, което показва колко пъти да се изместят битовете на числото aналяво. По време на тази операция добавените отдясно младши битове са нули.

Примери:

Пример Резултат
0b00000011 << 1
0b00000110
0b00000011 << 2
0b00001100
0b00000011 << 5
0b01100000
0b00000011 << 20
0b001100000000000000000000

Преместването на една цифра наляво има същия ефект като умножаването на число по 2.

Искате ли да умножите число по 16? 16 е същото като 2 4 . Така че премествате числото с 4 цифри наляво


2. Побитово изместване надясно

Битовете също могат да се изместват надясно. За да направите това, използвайте оператора за побитово надясно изместване . Ето How се пише:

a >> b

Къде aе числото, чиито битове се изместват, и bколко пъти трябва да се изместят битовете на числото aнадясно.

Примери:

Пример Резултат
0b11000011 >> 1
0b01100001
0b11000011 >> 2
0b00110000
0b11000011 >> 5
0b00000110
0b11000011 >> 20
0b00000000

Преместването на една цифра надясно има същия ефект като разделянето на число на 2.

По време на тази операция битовете от висок ред, добавени отляво, са нули, но не винаги !

важно!

Най-левият бит на число със знак се нарича знаков бит : ако числото е положително, то е 0; но ако числото е отрицателно, този бит е 1.

При изместване на битовете на число надясно, стойността на знаковия бит обикновено също би се изместила и знакът на числото би се загубил. Съответно, за отрицателни числа (където най-левият бит е 1), този бит получава специално отношение. Когато премествате битовете на число надясно, a 0се добавя отляво, ако най-левият бит е бил 0, и a 1се добавя отляво, ако най-левият бит е бил 1.

Но в горния пример това не изглежда да е резултатът. Защо? Тъй като целочислените литерали са ints и  всъщност означават . Тоест, най-левият бит е нула.0b111111110b00000000000000000000000011111111

Много програмисти са разочаровани от това поведение на дясно преместване и биха предпочели числото винаги да бъде подплатено с нули. Така че Java добави още един оператор за десен преместване .

Ето How се пише:

a >>> b

Къде a е числото, чиито битове се изместват, и b  колко пъти трябва да се изместят битовете на числото aнадясно. Този оператор винаги добавя нули отляво, независимо от първоначалната стойност на знаковия бит на числото a.



3. Работа с флагове

Програмистите създадоха почти изцяло нова област на изследване на базата на битови операции и операции за преместване: работа с флагове.

Когато компютрите имаха много малко памет, беше много популярно да се натъпква много информация в едно число. Числото се третира като масив от битове: int е 32 бита, а long е 64 бита.

Можете да запишете много информация в такъв номер, особено ако трябва да съхранявате логически ( trueor false) стойности. Единицата longе като booleanмасив, състоящ се от 64 елемента. Тези битове се наричаха флагове и се манипулираха чрез следните операции:

  • задайте флаг
    (направете определен бит equals на 1)
  • флаг за нулиране
    (направете определен бит equals на 0)
  • флаг за проверка
    (проверете стойността на определен бит)

И ето How се прави с побитови оператори.

Поставяне на флаг

За да зададете конкретен бит на 1, трябва да извършите побитова операция ИЛИ между числото, чийто бит искате да зададете, и специално създадено число, където само този бит е 1.

Да предположим например, че имате числото 0b00001010и трябва да зададете 5-ия бит на 1. В такъв случай трябва:

0b00001010 | 0b00010000 = 0b00011010

Ако петият бит вече беше зададен на единица, нищо нямаше да се промени.

Най-общо операцията по задаване на флаг може да се напише по следния начин

a | (1 << b)

Къде a е числото, чийто бит ще бъде зададен на 1. И b е позицията на бита, която трябва да бъде зададена. Използването на левия оператор за смяна е супер удобно тук, тъй като можете веднага да разберете с кой бит работим.

Нулиране на флаг

За да нулирате конкретен бит (т.е. да го зададете на 0), без да нарушавате други битове, трябва да извършите операция &между числото, чийто бит искате да нулирате (т.е. да зададете на 0) и специално създадено число, където всички битове са равни 1на за бита, който искате да нулирате.

Да предположим например, че имате числото 0b00001010и трябва да зададете 4-тия бит на 0. В такъв случай трябва:

0b00001010 & 0b11110111 = 0b00000010

Ако 4-тият бит вече беше зададен на нула, тогава нищо нямаше да се промени.

Най-общо операцията по нулиране на флаг може да се напише по следния начин

a & ~(1 << b)

Къде a е числото, чийто бит ще бъде нулиран на 0. И b е позицията на бита за изчистване.

За да получим число, при което всички битове са 1с изключение на този, който искаме да е нула, първо изместваме 1 b  позиции наляво и след това използваме побитовия NOTоператор, за да обърнем резултата.

Проверка на флаг

В допълнение към настройката or нулирането на конкретен флаг, понякога просто трябва да проверите дали даден флаг е зададен, т.е. дали даден бит е equals на 1. Това е доста лесно да се направи с побитово &.

Да предположим например, че трябва да проверите дали 4-тият бит е зададен на 1в числото 0b00001010. След това трябва да направите следното:

if ( (0b00001010 & 0b00001000) == 0b00001000 )

Най-общо операцията по проверка на флаг може да се напише по следния начин

(a & (1 << b)) == (1 << b)

Къде a е числото, чийто бит се проверява. И b дали позицията на бита трябва да бъде проверена.


4. Криптиране

Побитовата XORоперация често се използва от програмисти за просто криптиране. Като цяло такова криптиране изглежда така:

result = number ^ password;

Къде number са данните, които искаме да криптираме, password използва ли се специален номер като „парола“ за данните и result е криптираният номер.

number == (number ^ password) ^ password;

Важното тук е, че когато XORоператорът се приложи към число два пъти, той произвежда оригиналния номер, независимо от "паролата".

За да се възстановите number от encrypted result, трябва само да извършите операцията отново:

original number = result ^ password;

Пример:

class Solution
{
   public static int[] encrypt(int[] data, int password)
   {
     int[] result = new int[data.length];
     for (int i = 0; i <  data.length; i++)
       result[i] = data[i] ^ password;
     return result;
   }

   public static void main(String[] args)
   {
     int[] data =  {1, 3, 5, 7, 9, 11};
     int password = 199;

     // Encrypt the array of data
     int[] encrypted = encrypt(data, password);
     System.out.println(Arrays.toString(encrypted));

     // Decrypt the array of data
     int[] decrypted = encrypt(encrypted, password);
     System.out.println(Arrays.toString(decrypted));
   }
}