понеделник, 18 юни 2012 г.

Побитови операции - метод за размяна битовете на число в C#

Битове
Предполагам голяма част от вас знаят, че информацията в компютрите се съхранява като последователност от нули и единици, т.е. така наречените битове. Ето защо операциите, свързани пряко с тях, са едни от най-бързо осъществяваните от компютърните програми. Известно е и, че работата с някои данни като например IP адрес са пряко свързани с разбирането на тези побитови пресмятания. Друг случай, в който се налага да боравим с побитови преобразования, е при оптимизация на сложни и обемни математически изчисления, извършвани от компютър.

Задачата, която ще разгледаме, показва как може да се разменят битовете на число в uint формат (32-битово положително число) в езика C# като поставяме ограничение да няма припокриване на първата и втората двойка битове. Тази задача беше част от разгледания материал на курса по C# Fundamentals в академията на Телерик.


Програмен код:


        public static uint BitsExchanger(uint number, byte p, byte q, byte range)
        {
            if ((p + range) > 31 || (q + range) > 31 ||
                Math.Abs(p - q) <= range)
            {
                throw new ArgumentException();
            }

            uint maskP = new uint();
            uint maskQ = new uint();
            for (int i = 0; i <= range; i++)
            {
                maskP = maskP | (uint)(1 << (p + i));
                maskQ = maskQ | (uint)(1 << (q + i));
            }

            uint subBitsP = number & maskP;
            uint subBitsQ = number & maskQ;

            number = (~maskQ & number) | (subBitsP << q - p);
            number = (~maskP & number) | (subBitsQ >> q - p);
            return number;
        }


Обяснение:


Методът BitsExchanger изисква като аргументи: числото, на което ще разменяме битовете (number), номера на началния бит на двете последователности от битове за разменяне (p и q) и броя битове след първия на тези две последователности (range). В началото проверяваме дали са изпълнени следните условия: номерът на бита да не излиза от 32-битовия формат и евентуално да няма препокриване на разменяните битове. Ако се въведе такава невалидна информация, функцията извежда ArgumentExceprion.

За самите преобразувания използваме две маски: maskP с единични битове на позициите от p до p+k и maskQ с единични битове на позициите от q до q+range. Маските се създават чрез използване на цикъл от 0 до range. В него се извършва операция побитово или | ) на маската с преместен с оператора << единичен бит на необходимите позиции. Чрез тях и операцията побитово и ( & ) извличаме първата последователност от битове (от p до p+range) в променлива subBitsP, а втората последователност от битове (от q до q+range) в друга променлива subBitsQ. Операцията всъщност занулява всички други битове, освен означените от маската като единици, които си запазват стойността.

За битове от p до p+range чрез използване на отрицанието на маската на maskQ (т.е. зануляване на битове от q до q+range) и използване на | (побитово или) с променливата subBitsP, преместената с q-p позиции чрез оператора <<. осъществяваме заменяне на първата поредица (от p до p+range) от битове с позициите на втората (от q до q+range). Правим подобна операция, но в обратната посока за преместването на втората последователност от битове.

Няма коментари:

Публикуване на коментар