На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (2) 1 [2]  все  ( Перейти к последнему сообщению )  
> Преобразование двоичного числа в десятичное со знаком
    Цитата tumanovalex @

    ExpandedWrap disabled
      number<<=1;
      if(sbit[i] == '1') number |= 1;

    Ты число собираешь побитово.
    Когда надо добавить ещё один бит - всё что у тебя уже есть сдвигаешь на один разряд влево.
    При этом добавляется ещё один бит и он равен нулю.
    Если в массиве у тебя единица - устанавливаешь новый бит в единицу при помощи ИЛИ.

    Цитата tumanovalex @
    ExpandedWrap disabled
      if(len!=sizeof(number)*8)
      {
          number<<=sizeof(number)*8-len;
          number>>=sizeof(number)*8-len;
      }

    Здесь смотрим - если в массиве было такое же количество бит как и в переменной-результате, ничего делать не надо.
    Код выполняется если в массиве бит меньше чем разрадность переменной-результата (или больше, хотя это не предусмотрено).
    Лучше заменить на:
    ExpandedWrap disabled
      if(len<sizeof(number)*8)
      {
          number<<=sizeof(number)*8-len;
          number>>=sizeof(number)*8-len;
      }


    Для простого примера - допустим результат у тебя в char 8 бит, а передали только 3 символа в строке.
    Допустим передали -1 как "111".
    Тогда после преобразования ты получишь 00000111 - это 7.
    Чтобы получить правильный знаковый результат нам надо размножить знаковый бит (старший) в старшие разряды.
    Самый простой способ - сделать это арифметическим сдвигом (битовый сдвиг для знаковых чисел).
    Сдвигаем влево на 5 бит, получим 11100000.
    Теперь сдвигаем вправо на 5 бит - т.е. по сути возвращаем число на место, но при этом арифметический сдвиг новые биты слева заполняет знаковым битом.
    Получаем 11111111 - т.е. -1 как и хотели.

    И в моём коде везде long можно заменить на long long или __int64 - тогда можно будет преобразовывать до 64 бит, а так как есть только 32.
    Если в строке больше символов, то используются только младшие.
    Т.е. в моём коде результат 32 бита, если передать 64 символа в строке - в результат сконвертируется только 32 младших бита.
    Сообщение отредактировано: cppasm -
      Спасибо большое за подробное объяснение! Вроде бы все понятно, но вот самому до этого додуматься, к сожалению, не удалось. Остался только один вопрос: почему при выводе элементов массива narr выводится мусор - числа более 32767? Я подсчитал - выводится кроме заданных при инициализации чисел еще 11 чисел!
      Сообщение отредактировано: tumanovalex -
        Ну это вообще элементарно :)

        Цитата tumanovalex @

        ExpandedWrap disabled
          int narr[] = {-1, 1, -2, 2, -4, 4, -8, 8, -16, 16, -64, 64, -128, 128, -32767, 32767}, i = 0, j = 1, num;
          // ...
          while(narr[i])
          {
              // ...
          }

        У тебя цикл закончится когда в массиве встретится элемент равный нулю.
        А он у тебя там есть? Правильно - нету.
        Поэтому выводиться будут числа за массивом (мусор) пока в памяти не встретится 0.
        Либо замени условие цикла, к примеру на
        ExpandedWrap disabled
          while(i<sizeof(narr)/sizeof(narr[0]))

        Либо просто добавь в конец массива 0:
        ExpandedWrap disabled
          int narr[] = { -1, 1, -2, 2, -4, 4, -8, 8, -16, 16, -64, 64, -128, 128, -32767, 32767, 0 }, i = 0, j = 1, num;
        Сообщение отредактировано: cppasm -
          Спасибо большое! Я думал, что для числовых массивов не нужно ставить завершающий ноль. А если в массив должно входить число 0? Тогда только с помощью while? Век живи, век учись. Неисперпаемый язык С/C++!!!
            не знаю на сколько это гууд, но можно сделать например так
            ExpandedWrap disabled
                  int a1[] = {0, 1, 2, 3, 4};
                  int *a2[] = {&a1[0], &a1[1], &a1[2], &a1[3], NULL};
                  int i = 0;
                  while(a2[i])
                  {
                      printf("%d", *(a2[i]));
                      ++i;
                  }
              tumanovalex, причём тут язык? Ты сам написал такую логику - цикл останавливается по достижению нуля. Смени условие выхода, и нуль в конце будет не нужен.
                Да, похоже с годами я становлюсь только старше. Сам же сделал while(narr[i]), т.е. пока истинно, то выполнять. Еще раз проанализировал код cppasm:
                ExpandedWrap disabled
                    for(i=0; i<len; i++) {
                      number<<=1;
                      if(sbit[i] == '1') number |= 1;
                    }
                только пожалуй сейчас понял его нюансы. Очень хороший код. Интересно, это он сам придумал или этот код есть в какой-нибудь книге?
                  Цитата tumanovalex @
                  Интересно, это он сам придумал или этот код есть в какой-нибудь книге?
                  Это азы, известные любому, знакомому с битовой арифметикой.
                    Понятно, мне нужно побольше читать и практиковаться.
                      Знаковое десятичное в двоичное:

                      ExpandedWrap disabled
                        //--------------------------------
                        #include <bitset>
                        #include <string>
                        //--------------------------------
                         string mystring;
                         bitset <32> bs;
                         bs = IntTostdBitSet("-1607");
                         mystring = bitstring.to_string<char, char_traits<char>, allocator<char> >();
                        //--------------------------------
                        bitset<32> IntTostdBitSet(int dnum)
                        {
                         int bitpos = 0, absdnum = abs(dnum);
                         bitset <32> bs, bsone;
                         
                         bsone.set(0);
                         //основной код
                         while(absdnum > 0)
                         {
                          bs[(bitpos++)] = absdnum % 2;
                          absdnum = absdnum/2;
                         }
                         //обратный и дополнительный код
                         if(dnum < 0)
                         {
                          //обратный код
                          bs.flip();
                          //дополнительный код
                          bs = bs | bsone;
                         }
                         return bs;
                        }
                      1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                      0 пользователей:


                      Рейтинг@Mail.ru
                      [ Script execution time: 0,0342 ]   [ 15 queries used ]   [ Generated: 18.07.25, 08:35 GMT ]