Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Работа с битами в long числах 
V
    Опции темы
Voyager
Дата 12.3.2008, 18:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 532
Регистрация: 8.2.2005

Репутация: 3
Всего: 18



Необходимо сделать методы, корректно устанавливающие, получающие биты в long числах.
Пока сделал вариант:

Код

public static long SetBit(long Src, byte Bit, bool Set)
        {
            if (Set)
                return Src ^ (1 << Bit);
                //return Src | (1 << Bit);
            else
                return Src & ~(1 << Bit);
        }

        public static bool GetBit(long Src, byte Bit)
        {
            return ((Src >> Bit) & 1) != 0;
        }

Но с long числами при больших значениях битов (<64) наблюдаются глюки, т.к. число становится отрицательным (знаковый 31-й бит все портит).


Это сообщение отредактировал(а) Voyager - 13.3.2008, 02:28
PM   Вверх
Voyager
Дата 13.3.2008, 02:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 532
Регистрация: 8.2.2005

Репутация: 3
Всего: 18



Придумал такой вариант, может кому пригодится.
Первый вариант:
Код

        static long SetBitA(long Src, byte Bit, bool Value)
        {
            int lo = (int)Src;
            int mid = (int)(Src >> 0x20);
            byte[] buffer = new byte[8];
            buffer[0] = (byte)lo;
            buffer[1] = (byte)(lo >> 8);
            buffer[2] = (byte)(lo >> 0x10);
            buffer[3] = (byte)(lo >> 0x18);
            buffer[4] = (byte)mid;
            buffer[5] = (byte)(mid >> 8);
            buffer[6] = (byte)(mid >> 0x10);
            buffer[7] = (byte)(mid >> 0x18);
            byte num = (byte)(Bit / 8);
            byte bit = (byte)(Bit % 8);
            if (Value)
                buffer[num] = (byte)(buffer[num] | (byte)(1 << bit));
            else
                buffer[num] = (byte)(buffer[num] & ~(byte)(1 << bit));
            return BitConverter.ToInt64(buffer, 0);
        }

        static bool GetBitA(long Src, byte Bit)
        {
            int lo = (int)Src;
            int mid = (int)(Src >> 0x20);
            byte[] buffer = new byte[8];
            buffer[0] = (byte)lo;
            buffer[1] = (byte)(lo >> 8);
            buffer[2] = (byte)(lo >> 0x10);
            buffer[3] = (byte)(lo >> 0x18);
            buffer[4] = (byte)mid;
            buffer[5] = (byte)(mid >> 8);
            buffer[6] = (byte)(mid >> 0x10);
            buffer[7] = (byte)(mid >> 0x18);
            byte num = (byte)(Bit / 8);
            byte bit = (byte)(Bit % 8);
            return ((buffer[num] & (byte)(1 << bit)) != 0);
        }

Второй:
Код

        public static long SetBit(long Src, byte Bit, bool Value)
        {
            byte[] buffer = BitConverter.GetBytes(Src);            
            byte num = (byte)(Bit / 8);
            byte bit = (byte)(Bit % 8);
            if (Value)
                buffer[num] = (byte)(buffer[num] | (byte)(1 << bit));
            else
                buffer[num] = (byte)(buffer[num] & ~(byte)(1 << bit));
            return BitConverter.ToInt64(buffer, 0);
        }

        public static bool GetBit(long Src, byte Bit)
        {
            byte[] buffer = BitConverter.GetBytes(Src);            
            byte num = (byte)(Bit / 8);
            byte bit = (byte)(Bit % 8);
            return ((buffer[num] & (byte)(1 << bit)) != 0);
        }


Это сообщение отредактировал(а) Voyager - 13.3.2008, 16:29
PM   Вверх
Ctrl
Дата 16.3.2008, 12:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 49
Регистрация: 12.2.2008
Где: Tula

Репутация: 6
Всего: 7



Извините за пост в закрытую тему, но наличие бага в исходном примере автора привело к неверным выводам:
 - знаковый бит не 31-й, а 63-й
 - на самом деле проблема рещается гораздо проще (см. мой пример)

Теперь о баге:
Код

return Src ^ (1 << Bit);

Баг в том что не учитывается неявный кастинг выражения (1<<Bit) к типу int, 
ну и кроме того значение Bit может быть недопустимым (>63).
CodeFix: (1<<Bit)  заменить на (0x1L <<(Bit & 0x3F))

Вот тестовый пример:
Код

using System;
using NUnit.Framework;

namespace LongBitsTest {
    class LongFlags {
        public static long SetBit(long source, byte index, bool setBit) {
            long mask = 1L << (index & 0x3F);
            return (setBit) ? source ^ mask : source & ~mask;
        }
        public static bool GetBit(long source, byte index) {
            long mask = 1L << (index & 0x3F);
            return (source & mask) != 0;
        }
    }
    class Program {
        static void Main(string[] args) {
            TestIt();
        }
        protected static void TestIt() {
            Assert.AreEqual(0x0000000020000000L, LongFlags.SetBit(0, 29, true));
            Assert.AreEqual(0x0000000080000000L, LongFlags.SetBit(0, 31, true));
            Assert.AreEqual(0x0000000200000000L, LongFlags.SetBit(0, 33, true));

            Assert.AreEqual(0, LongFlags.SetBit(0x0000000020000000L, 29, false));
            Assert.AreEqual(0, LongFlags.SetBit(0x0000000080000000L, 31, false));
            Assert.AreEqual(0, LongFlags.SetBit(0x0000000200000000L, 33, false));

            Assert.AreEqual(long.MinValue, LongFlags.SetBit(0, 63, true));
            Assert.AreEqual(0, LongFlags.SetBit(long.MinValue, 63, false));

            long testLong = 0x0000000080000001L;
            Assert.IsTrue(LongFlags.GetBit(testLong, 0));
            Assert.IsFalse(LongFlags.GetBit(testLong, 1));
            Assert.IsTrue(LongFlags.GetBit(testLong, 31));
            Assert.IsFalse(LongFlags.GetBit(testLong, 32));
        }
    }
}

PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0601 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.