如何设置/获取UInt64的位?

时间:2018-08-10 14:42:46

标签: c# binary

我正在使用UInt64来存储位。一个示例为UInt64 val = 0b0001_0000。现在,我希望能够确定是否在特定位置设置了位。例如,我想知道在val中是否设置了第4位(使用从零开始的索引)。如果要对此进行硬编码,则可以使用AND和OR运算符对一个临时变量进行操作,清除除第4个位以外的所有位并检查该值。但是,我想实现一种更动态的方法来执行此操作,因此不需要使用诸如0b0001_0000之类的一堆不同的位文字来进行检查。

我尝试解析动态创建的类似"0b0001_0000"的字符串,但是我对UInt64Byte等并不满意。

2 个答案:

答案 0 :(得分:0)

对于所有int,long,uint,ulong等,您都可以使用Left(<<)或Right(>>)运算符将位导航到更大的数值。

请参阅MSDN文档上的本文:Left Shift OperatorRight Shift Operator

就像这样(我从“左移运算符”页面获取了示例):

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
*/

更新

更好的是,从此站点Bit Processing in C看到完整的实现(基于BYTE结构-只需将其更改为LONG或ULONG):

更新2

我最终享受了Bit Processing in 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(); }
    }
}

答案 1 :(得分:0)

使用移位运算符将索引转换为无符号long:

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

检查未签名的long是否已将相同的位设置为1:

   ( 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