Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Работа с битами в языке C#

Anna | 18.06.2014 | нет комментариев
Недавно возникла у меня задача, в ходе решения которой нужно было считывать из бинарного файла целые числа разного формата. Отлично было бы если бы это были 8, 16, 32 либо 64-разрядные знаковые либо беззнаковые числа, тогда дозволено было сразу без задач считать из файла значение надобного формата, но на практике пришлось иметь дело со знаковыми и беззнаковыми числами произвольной разрядности (от 2 до 64 разрядов на число, т.е., скажем, в 8 байтах могут располагаться 2 числа, первое с 0 разряда по 28, а второе с 29 по 63 разряды, при этом первое знаковое, а второе беззнаковое).Если увлекательно увидеть мои скромные наработки по работе с битами-умоляю под кат.

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

Выходит, имея немножко навыка программирования за плечами, я решил реализовать все описанные выше функции в статическом классе.

Для просмотра и метаморфозы значения отдельных битов, я реализовал 2 статических способа GetBitи SetBit, 1-й в качестве параметров принимает байт у которого нужно посмотреть значение бита и, собственно, сам номер бита, во втором добавляется еще и значение устанавливаемого бита в виде булевской переменной. Реализация способов довольно банальна:

///<summary>
/// Возвращает бит в num байте val
///</summary>
///<param name="val">Входнойбайт</param>
///<param name="num">Номербита, начинаяс 0</param>
///<returns>true-битравен 1, false- битравен 0</returns>
public static bool GetBit(byte val,int num)
{
          if ((num> 7) || (num< 0))//Проверка входных данных
          {
               throw new ArgumentException();
           }
     return ((val>>num)&1)>0;//собственно все вычисления
}

///<summary>
/// Устанавливает значение определенного бита в байте
///</summary>
///<param name="val">Входнойбайт</param>
///<param name="num">Номербита</param>
///<param name="bit">Значениебита: true-битравен 1, false- битравен 0 </param>
///<returns>Байт, с измененным значением бита</returns>
public static byte SetBit(byte val, int num,bool bit)
{
            if ((num> 7) || (num< 0))//Проверка входных данных
            {
               throw new ArgumentException();
            }
  byte tmpval = 1;
  tmpval = (byte)(tmpval<<num);//устанавливаем необходимый бит в единицу
  val = (byte)(val& (~tmpval));//сбрасываем в 0 необходимый бит

           if (bit)// если бит требуется установить в 1
            {
               val = (byte)(val | (tmpval));//то устанавливаем необходимый бит в 1
            }
return val;
 }

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

///<summary>
/// Изменяет порядок битов на обратный
///</summary>
///<param name="val">Входнойбайт</param>
///<returns>Байт с обратным порядком битов</returns>
Public static byte Reverse(byte val)
  {
     int i = 0;
     byterez = 0;

     for (i = 0; i < 8; i  )
     {
         rez = (byte)(rez<< 1);
               if (((val>> i) & 1) > 0)
                {
                    rez = (byte)(rez | 1);
                }
      }
     return rez;
}

Но самое увлекательное было приведение чисел произвольной разрядности к виду внятному машине, в случае если бы они все были беззнаковыми, задач бы не было- считал надобное число байтов, преобразовал в необходимый формат и отсек непотребные биты, но так как встречались как знаковые так и беззнаковые числа пришлось немножко выкручиваться, т.к. знаковый бит не будет осознан как знаковый и числа сами по себе хранятся в дополнительном коде:

///<summary>
/// Преобразует массив байтов в Int64, начиная с бита firstbit и заканчивая битом lastbit, с учетом знаковости числа
///</summary>
///<paramname="bytes">Массив байтов, начиная со старшей части числа</param>
///<param name="firstbit">Младшийбитчисла</param>
///<param name="lastbit">Старшийбитчисла</param>
///<paramname="issigned">Показывает со знаком ли число</param>
///<returns>Итог реформирования Int64</returns>
public static Int64 HandleBytes(byte[] bytes, int firstbit, int lastbit,bool issigned)
 {
     if ((bytes == null) ||
     (firstbit< 0) ||
     (firstbit> 63) ||
     (lastbit< 0) ||
     (lastbit> 63) ||
    (((lastbit - firstbit) == 63) && (!issigned)) ||//если число без знака и при этом 64-разрядное, то такое число физически невозможно воротить в Int64
   (bytes.Length> 8) ||
    (bytes.Length< 1)||
    (firstbit>lastbit))
       {
            throw new ArgumentException();
       }
   Int64 rezult = 0,//переменная для итога
   tmp = 0;//переменная для промежуточных вычислений

//Заполняем переменную итога входным массивом байтов
    foreach (byte tmp1 in bytes)
    {
       rezult = rezult<< 8;
       rezult = rezult | tmp1;
     }

      rezult = rezult>>firstbit;//отсекаем непотребные младшиебиты
      if (firstbit != lastbit)
      {
          tmp = (long)(Math.Pow(2, lastbit - firstbit));//1 в знаковом бите, остальные 0
          if ((issigned)&&((rezult&tmp)>0))//если число знаковое и негативно
          {
             //это все нужно потому что числа сами по себе записываются в дополнительном коде
              tmp = tmp - 1;//все 1 начиная с младшего бита и до знакового бита, не включая знаковый бит
              rezult = ~rezult;// инвертируем биты
              rezult = rezult&tmp;// отсекам старшие непотребные биты
              rezult  ;
              rezult *=-1;

            }
          else// если число беззнаковое либо знаковое, но имеет правильное значение
           {
            tmp = tmp   (tmp - 1);//все 1 начиная с младшего бита и до знакового бита, включая знаковый бит
            rezult = rezult&tmp;//отсекаем непотребные биты
            }

       }
      else//Если младший и старший биты равны, то необходимо легко воротить один бит
      {
          rezult = rezult& 1;
       }
   return rezult;
 }

В качестве параметров способ принимает массив байтов, число байт от 1 до 8, старшая часть в 0. firstbit –номер младшего бита числа, lastbit –номер старшего бита числа, issigned- указывает знаковое число либо беззнаковое. Таким образом если число знаковое и располагается в разрядах 3-18, то вызов способа будет выглядеть HandleBytes(bytes, 3, 18,true).

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

Верю хоть кому-то это будет хоть немножко пригодно.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB