Как установить / получить биты UInt64?

Я использую UInt64 для хранения битов. Примером может быть UInt64 val = 0b0001_0000. Теперь я хочу иметь возможность определить, установлен ли бит в определенной позиции. Например, я хотел бы знать, установлен ли 4-й бит (с использованием индексации с нуля) в val. Если бы я жестко закодировал это, я мог бы просто использовать операторы AND и OR для работы с временной переменной, очищая все биты, кроме четвертого, и проверяя значение. Однако я хотел бы реализовать более динамичный способ сделать это, поэтому мне не нужно использовать кучу разных битовых литералов, таких как 0b0001_0000, для небольшой проверки.

Я пробовал разобрать строку типа "0b0001_0000", которая создается динамически, но мне не повезло с UInt64, Byte и т. д.

Если вы хотите проверить, установлен ли бит, используйте x & (1 << bitNumber) != 0, чтобы установить его, используйте x |= 1 << bitNumber для расчета битовых масок на лету.

ckuri 10.08.2018 16:49

Или используйте класс BitArray

adjan 10.08.2018 16:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
1 022
2

Ответы 2

вы используете оператор Left (<<) или Right (>>) для перехода по битам к большему числовому значению для всех int, long, uint, ulong и т. д.

См. Эту статью в документации MSDN: Оператор левого сдвига и Оператор правого сдвига

Вот так (я взял пример со страницы оператора левого сдвига):

class MainClass
{
    static void Main()
    {
        int i = 1;
        long lg = 1;
        // Shift i one bit to the left. The result is 2.
        Console.WriteLine("0x{0:x}", i << 1);
        // In binary, 33 is 100001. Because the value of the five low-order
        // bits is 1, the result of the shift is again 2. 
        Console.WriteLine("0x{0:x}", i << 33);
        // Because the type of lg is long, the shift is the value of the six
        // low-order bits. In this example, the shift is 33, and the value of
        // lg is shifted 33 bits to the left.
        //     In binary:     10 0000 0000 0000 0000 0000 0000 0000 0000 
        //     In hexadecimal: 2    0    0    0    0    0    0    0    0
        Console.WriteLine("0x{0:x}", lg << 33);
    }
}
/*
Output:
0x2
0x2
0x200000000
*/

ОБНОВИТЬ:

А еще лучше посмотрите эту полную реализацию (основанную на структуре BYTE - просто измените ее на LONG или ULONG) с этого сайта Битовая обработка в C:

ОБНОВЛЕНИЕ 2:

В итоге мне очень понравилась статья Битовая обработка в C, я реализовал ее класс (основанный на байтах) и немного улучшил, превратив его в класс со множеством методов и интерфейсов. Вот оно:

namespace System
{
    public class BitCheck8 : global::System.IEquatable<byte>, global::System.IEquatable<global::System.BitCheck8>, global::System.Collections.Generic.IEnumerable<bool>, global::System.Collections.Generic.IDictionary<int, bool>
    {
        public const byte Empty = 0x0;
        protected byte Control;
        protected static global::System.ArgumentOutOfRangeException OutOfRange() { return new global::System.ArgumentOutOfRangeException("pos", "Argument [Pos] not between 0-7"); }
        public static bool IsBitSet(byte b, int pos) { if (pos < 0 || pos > 7) { throw global::System.BitCheck8.OutOfRange(); } else { return (b & (1 << pos)) != 0; } }
        public static byte SetBit(byte b, int pos) { if (pos < 0 || pos > 7) { throw global::System.BitCheck8.OutOfRange(); } else { return (byte)(b | (1 << pos)); } }
        public static byte UnsetBit(byte b, int pos) { if (pos < 0 || pos > 7) { throw global::System.BitCheck8.OutOfRange(); } else { return (byte)(b & ~(1 << pos)); } }
        public static byte ToggleBit(byte b, int pos) { if (pos < 0 || pos > 7) { throw global::System.BitCheck8.OutOfRange(); } else { return (byte)(b ^ (1 << pos)); } }
        public static string ToBinaryString(byte b) { return global::System.Convert.ToString(b, 2).PadLeft(8, '0'); }
        public virtual bool IsReadOnly { get { return false; } }
        public byte Base { get { return this.Control; } set { if (!this.IsReadOnly) { this.Control = value; } } }
        public bool IsBitSet(int pos) { return global::System.BitCheck8.IsBitSet(this.Control, pos); }
        public void SetBit(int pos) { if (!this.IsReadOnly) { this.Control = global::System.BitCheck8.SetBit(this.Control, pos); } }
        public void UnsetBit(int pos) { if (!this.IsReadOnly) { this.Control = global::System.BitCheck8.UnsetBit(this.Control, pos); } }
        public void ToggleBit(int pos) { if (!this.IsReadOnly) { this.Control = global::System.BitCheck8.ToggleBit(this.Control, pos); } }
        public void Clear() { if (!this.IsReadOnly) { this.Control = global::System.BitCheck8.Empty; } }
        public override string ToString() { return global::System.BitCheck8.ToBinaryString(this.Control); }
        public bool this[int pos] { get { return this.IsBitSet(pos); } set { if (value) { this.SetBit(pos); } else { this.UnsetBit(pos); } } }
        public bool Check0 { get { return this[0]; } set { this[0] = value; } }
        public bool Check1 { get { return this[1]; } set { this[1] = value; } }
        public bool Check2 { get { return this[2]; } set { this[2] = value; } }
        public bool Check3 { get { return this[3]; } set { this[3] = value; } }
        public bool Check4 { get { return this[4]; } set { this[4] = value; } }
        public bool Check5 { get { return this[5]; } set { this[5] = value; } }
        public bool Check6 { get { return this[6]; } set { this[6] = value; } }
        public bool Check7 { get { return this[7]; } set { this[7] = value; } }
        public global::System.Collections.Generic.IEnumerator<bool> GetEnumerator() { for (int pos = 0; pos < 8; pos++) { yield return this.IsBitSet(pos); } }
        global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
        bool global::System.IEquatable<byte>.Equals(byte b) { return this.Control == b; }
        public override bool Equals(object obj) { return base.Equals(obj); }
        public bool Equals(global::System.BitCheck8 obj) { return base.Equals(obj); }
        public override int GetHashCode() { return base.GetHashCode(); }
        void global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<int, bool>>.Add(global::System.Collections.Generic.KeyValuePair<int, bool> item) { this[item.Key] = item.Value; }
        bool global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<int, bool>>.Contains(global::System.Collections.Generic.KeyValuePair<int, bool> item) { return this[item.Key]; }
        int global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<int, bool>>.Count { get { return 8; } }
        bool global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<int, bool>>.Remove(global::System.Collections.Generic.KeyValuePair<int, bool> item) { return false; }
        void global::System.Collections.Generic.IDictionary<int, bool>.Add(int Key, bool Value) { this[Key] = Value; }
        bool global::System.Collections.Generic.IDictionary<int, bool>.ContainsKey(int Key) { return (Key > -1 && Key < 8); }
        bool global::System.Collections.Generic.IDictionary<int, bool>.Remove(int Key) { return false; }
        global::System.Collections.Generic.IEnumerator<global::System.Collections.Generic.KeyValuePair<int, bool>> global::System.Collections.Generic.IEnumerable<global::System.Collections.Generic.KeyValuePair<int, bool>>.GetEnumerator() { for (int pos = 0; pos < 8; pos++) { yield return new global::System.Collections.Generic.KeyValuePair<int, bool>(pos, this[pos]); } }
        void global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<int, bool>>.CopyTo(global::System.Collections.Generic.KeyValuePair<int, bool>[] array, int index) { global::System.Array.Copy(new global::System.Collections.Generic.KeyValuePair<int, bool>[] { new global::System.Collections.Generic.KeyValuePair<int, bool>(0, this[0]), new global::System.Collections.Generic.KeyValuePair<int, bool>(1, this[1]), new global::System.Collections.Generic.KeyValuePair<int, bool>(2, this[2]), new global::System.Collections.Generic.KeyValuePair<int, bool>(3, this[3]), new global::System.Collections.Generic.KeyValuePair<int, bool>(4, this[4]), new global::System.Collections.Generic.KeyValuePair<int, bool>(5, this[5]), new global::System.Collections.Generic.KeyValuePair<int, bool>(6, this[6]), new global::System.Collections.Generic.KeyValuePair<int, bool>(7, this[7]) }, 0, array, index, 8); }
        global::System.Collections.Generic.ICollection<int> global::System.Collections.Generic.IDictionary<int, bool>.Keys { get { return (global::System.Collections.Generic.ICollection<int>)new int[] { 0, 1, 2, 3, 4, 5, 6, 7 }; } }
        global::System.Collections.Generic.ICollection<bool> global::System.Collections.Generic.IDictionary<int, bool>.Values { get { return (global::System.Collections.Generic.ICollection<bool>)new bool[] { this[0], this[1], this[2], this[3], this[4], this[5], this[6], this[7] }; } }
        public static bool operator ==(global::System.BitCheck8 obj1, global::System.BitCheck8 obj2) { return (obj1 != null && obj2 != null && obj1.Control == obj2.Control); }
        public static bool operator !=(global::System.BitCheck8 obj1, global::System.BitCheck8 obj2) { return (obj1 == null || obj2 == null || obj1.Control != obj2.Control); }
        public static bool operator ==(global::System.BitCheck8 obj1, byte obj2) { return (obj1 != null && obj1.Control == obj2); }
        public static bool operator !=(global::System.BitCheck8 obj1, byte obj2) { return (obj1 == null || obj1.Control != obj2); }

        bool global::System.Collections.Generic.IDictionary<int, bool>.TryGetValue(int Key, out bool Value)
        {
            Value = false;
            if (Key > -1 && Key < 8)
            {
                Value = this.IsBitSet(Key);
                return true;
            } else { return false; }
        }

        public static global::System.BitCheck8 operator +(global::System.BitCheck8 obj1, byte obj2)
        {
            if (obj1 == null) { return new global::System.BitCheck8(obj2); }
            else
            {
                global::System.BitCheck8 a = new global::System.BitCheck8(obj1.Control);
                for (int pos = 0; pos < 8; pos++) { if (global::System.BitCheck8.IsBitSet(obj2, pos)) { a[pos] = true; } }
                return a;
            }
        }

        public static global::System.BitCheck8 operator -(global::System.BitCheck8 obj1, byte obj2)
        {
            if (obj1 == null) { return new global::System.BitCheck8(obj2); }
            else
            {
                global::System.BitCheck8 a = new global::System.BitCheck8(obj1.Control);
                for (int pos = 0; pos < 8; pos++) { if (!global::System.BitCheck8.IsBitSet(obj2, pos)) { a[pos] = false; } }
                return a;
            }
        }

        public static global::System.BitCheck8 operator +(global::System.BitCheck8 obj1, global::System.BitCheck8 obj2) { return (obj2 == null ? obj1 : (obj1 + obj2.Control)); }
        public static global::System.BitCheck8 operator -(global::System.BitCheck8 obj1, global::System.BitCheck8 obj2) { return (obj2 == null ? obj1 : (obj1 - obj2.Control)); }

        public BitCheck8(bool Check0, bool Check1 = false, bool Check2 = false, bool Check3 = false, bool Check4 = false, bool Check5 = false, bool Check6 = false, bool Check7 = false)
        {
            this.Control = 0x0;
            this[0] = Check0;
            this[1] = Check1;
            this[2] = Check2;
            this[3] = Check3;
            this[4] = Check4;
            this[5] = Check5;
            this[6] = Check6;
            this[7] = Check7;
        }

        public BitCheck8(byte check) { this.Control = check; }
        public BitCheck8() { this.Clear(); }
    }
}

Используйте оператор битового сдвига, чтобы преобразовать индекс в беззнаковый длинный:

ulong bitIndexValue = 1ul << index;
//    bitIndexValue = 0b0001                       if index equals 0
//    bitIndexValue = 0b0010                       if index equals 1
//    bitIndexValue = 0b0100                       if index equals 2

Убедитесь, что у вашего unsigned long один и тот же бит установлен в единицу:

   ( value    & bitIndexValue) == bitIndexValue;
// ( 0b0101   &    0b0100    ) ==    0b0100        if index equals 2

Вот полный метод:

static bool CheckBit(ulong value, byte index)
{
    if (index < 0 || index > 63) throw new ArgumentOutOfRangeException("index");
    ulong bitIndexValue = 1UL << index;
    return (value & bitIndexValue) == bitIndexValue;
}

И как им пользоваться:

Assert.IsTrue(CheckBit(4ul, 2));  // 0b0100    does contain        0b0100
Assert.IsTrue(CheckBit(5ul, 2));  // 0b0101    does contain        0b0100
Assert.IsFalse(CheckBit(8ul, 2)); // 0b1000    does not contain    0b0100

Другие вопросы по теме