Поразрядные операции

Последнее обновление: 10.12.2023

Особый класс операций представляют поразрядные операции. Они выполняются над отдельными разрядами числа. Они выполняются только над целыми числами (то есть над значениями типов byte, sbyte, int16, uint16, int, uint, int64, uint64, nativeint и unativeint.).

При данных операциях числа рассматриваются в двоичном представлении, например, 2 в двоичном представлении 10 и имеет два разряда, число 7 - 111 и имеет три разряда.

Рассмотрим все поразрядные операции языка F#:

  • &&&(логическое умножение)

    Умножение производится поразрядно, и если у обоих операндов значения соответствующих разрядов равно 1, то операция возвращает 1, иначе возвращается число 0. Например:

    let x1 = 2          //010
    let y1 = 5          //101
    let z1 = x1 &&& y1  //000
    printfn $"z1 = {z1}"  // z1 = 0
               
    let x2 = 4          //100
    let y2 = 5          //101
    let z2 = x2 &&& y2  //100
    printfn $"z2 = {z2}"  // z2 = 4
    

    В первом случае у нас два числа 2 и 5. 2 в двоичном виде представляет число 010, а 5 - 101. Поразрядно умножим числа (0*1, 1*0, 0*1) и в итоге получим 000.

    Во втором случае у нас вместо двойки число 4, у которого в первом разряде 1, так же как и у числа 5, поэтому в итоге получим (1*1, 0*0, 0 *1) = 100, то есть число 4 в десятичном формате.

  • ||| (логическое сложение)

    Похоже на логическое умножение, операция также производится по двоичным разрядам, но теперь возвращается единица, если хотя бы у одного числа в данном разряде имеется единица. Например:

    let x1 = 2          //010
    let y1 = 5          //101
    let z1 = x1 ||| y1  //111
    printfn $"z1 = {z1}"  // z1 = 7
               
    let x2 = 4          //100
    let y2 = 5          //101
    let z2 = x2 ||| y2  //101
    printfn $"z2 = {z2}"  // z2 = 5
    
  • ^^^ (логическое исключающее ИЛИ). Также эту операцию называют XOR. Если значения соответствующих разрядов обоих чисел разные, то возвращается 1, если одинаковые - возвращается 0:

    let x1 = 2          //010
    let y1 = 5          //101
    let z1 = x1 ^^^ y1  //111
    printfn $"z1 = {z1}"  // z1 = 7
               
    let x2 = 4          //100
    let y2 = 5          //101
    let z2 = x2 ^^^ y2  //001
    printfn $"z2 = {z2}"  // z2 = 1
    
  • ~~~ (логическое отрицание или инверсия)

    Еще одна поразрядная операция, которая инвертирует все разряды: если значение разряда равно 1, то оно становится равным нулю, и наоборот.

    let x = 12                  // 00001100
    let z = ~~~x                // 11110011   или -13
    printfn $"z = {z}"  // z = -13
    

Представление отрицательных чисел

Для записи чисел со знаком в F# применяется дополнительный код (two’s complement), при котором старший разряд является знаковым. Если его значение равно 0, то число положительное, и его двоичное представление не отличается от представления беззнакового числа. Например, 0000 0001 в десятичной системе 1.

Если старший разряд равен 1, то мы имеем дело с отрицательным числом. Например, 1111 1111 в десятичной системе представляет -1. Соответственно, 1111 0011 представляет -13.

Чтобы получить из положительного числа отрицательное, его нужно инвертировать и прибавить единицу:

let x = 12                  // 00001100
let z = ~~~x                // 11110011   или -13
let d = z + 1
printfn $"d = {d}"  // d = -12
Two complement in C#

Операции сдвига

Операции сдвига также производятся над разрядами чисел. Сдвиг может происходить вправо и влево.

  • x<<<y - сдвигает число x влево на y разрядов. Например:

    let x = 4                  // 100
    let z = x <<< 2           // сдвиг на 2 разряда влево - 10000
    printfn $"z = {z}"        // z = 16
    

    Здесь операция сдвигает число 4 (которое в двоичном представлении 100) на два разряда влево, то есть в итоге получается 10000 или число 16 в десятичном представлении.

  • x>>>y - сдвигает число x вправо на y разрядов. Например:

    let x = 16                  // 10000
    let z = x >>> 1   // сдвиг на 1 разряд вправо - 1000
    printfn $"z = {z}"        // z = 8
    

    Здесь операция сдвигает число 16 (которое в двоичном представлении 10000) на один разряд вправо, то есть в итоге получается 1000 или число 8 в десятичном представлении.

Таким образом, если исходное число, которое надо сдвинуть в ту или другую строну, делится на два, то фактически получается умножение или деление на два. Поэтому подобную операцию можно использовать вместо непосредственного умножения или деления на два.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850