前往
大廳
主題

位元(bit)操作及2進制與16進制數值表示法

Yang | 2022-10-23 16:19:58 | 巴幣 0 | 人氣 250

移位運算(>> / <<),邏輯運算(AND / OR)(& / |),位元補充(~),2進制數值表示(0b),16進制數值表示(0x),相關功能包裝與使用範例紀錄於此

Byte內的位元位置通常從0開始,代稱為:
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0

CheckBit,檢查指定的位元其值是否不為0
GetBit,取出指定的位元值,屏蔽其他位元值
AddBit,指定的位元其值設定為1
RemoveBit,指定的位元其值設定為0

public class BitOperator
{
    public static readonly uint[] BitValue = {
        (uint)Math.Pow(2, 0),
        (uint)Math.Pow(2, 1),
        (uint)Math.Pow(2, 2),
        (uint)Math.Pow(2, 3),
        (uint)Math.Pow(2, 4),
        (uint)Math.Pow(2, 5),
        (uint)Math.Pow(2, 6),
        (uint)Math.Pow(2, 7),
        (uint)Math.Pow(2, 8),
        (uint)Math.Pow(2, 9),
        (uint)Math.Pow(2, 10),
        (uint)Math.Pow(2, 11),
        (uint)Math.Pow(2, 12),
        (uint)Math.Pow(2, 13),
        (uint)Math.Pow(2, 14),
        (uint)Math.Pow(2, 15),
        (uint)Math.Pow(2, 16),
        (uint)Math.Pow(2, 17),
        (uint)Math.Pow(2, 18),
        (uint)Math.Pow(2, 19),
        (uint)Math.Pow(2, 20),
        (uint)Math.Pow(2, 21),
        (uint)Math.Pow(2, 22),
        (uint)Math.Pow(2, 23),
        (uint)Math.Pow(2, 24),
        (uint)Math.Pow(2, 25),
        (uint)Math.Pow(2, 26),
        (uint)Math.Pow(2, 27),
        (uint)Math.Pow(2, 28),
        (uint)Math.Pow(2, 29),
        (uint)Math.Pow(2, 30),
        (uint)Math.Pow(2, 31),
    };

    public static bool CheckBit(in byte value, in int position)
    {
        if (position < 0 || position >= sizeof(byte) * 8)
        {
            throw new IndexOutOfRangeException($"{nameof(position)}={position}");
        }

        return (value & BitValue[position]) > 0;
    }

    public static byte GetBit(in byte value, in int position)
    {
        if (position < 0 || position >= sizeof(byte) * 8)
        {
            throw new IndexOutOfRangeException($"{nameof(position)}={position}");
        }

        return (byte)(value & BitValue[position]);
    }

    public static byte AddBit(in byte value, in int position)
    {
        if (position < 0 || position >= sizeof(byte) * 8)
        {
            throw new IndexOutOfRangeException($"{nameof(position)}={position}");
        }

        return (byte)(value | BitValue[position]);
    }

    public static byte RemoveBit(in byte value, in int position)
    {
        //return CheckBit(value, position) ? (byte)(value - BitValue[position]) : value;
        return (byte)(value & ~BitValue[position]);
    }

    public static bool CheckBit(in uint value, in int position)
    {
        if (position < 0 || position >= sizeof(uint) * 8)
        {
            throw new IndexOutOfRangeException($"{nameof(position)}={position}");
        }

        return (value & BitValue[position]) > 0;
    }

    public static uint GetBit(in uint value, in int position)
    {
        if (position < 0 || position >= sizeof(uint) * 8)
        {
            throw new IndexOutOfRangeException($"{nameof(position)}={position}");
        }

        return value & BitValue[position];
    }

    public static uint AddBit(in uint value, in int position)
    {
        if (position < 0 || position >= sizeof(uint) * 8)
        {
            throw new IndexOutOfRangeException($"{nameof(position)}={position}");
        }

        return value | BitValue[position];
    }

    public static uint RemoveBit(in uint value, in int position)
    {
        //return CheckBit(value, position) ? value - BitValue[position] : value;
        return value & ~BitValue[position];
    }
}

單元測試與註解說明:

Convert.ToString(10,2).PadLeft(8,'0')
"00001010"
Convert.ToString(0b_0000_1010,2).PadLeft(8,'0')
"00001010"
Convert.ToString(0b_0000_1010 >> 1,2).PadLeft(8,'0')
"00000101"
Convert.ToString(0b_0000_1010 << 1,2).PadLeft(8,'0')
"00010100"
Convert.ToString(0b_0000_1010 >> 3,2).PadLeft(8,'0')
"00000001"
Convert.ToString(0b_0000_1010 >> 4,2).PadLeft(8,'0')
"00000000"
Convert.ToString(0b_0000_1010 >> 5,2).PadLeft(8,'0')
"00000000"
Convert.ToString(0b_0000_1010 << 3,2).PadLeft(8,'0')
"01010000"
Convert.ToString(0b_0000_1010 << 4,2).PadLeft(8,'0')
"10100000"

//移位運算的回傳值型態看來預設是int
Convert.ToString(0b_0000_1010 << 5,2).PadLeft(8,'0')
"101000000"
Convert.ToString((byte)0b_0000_1010 << 5,2).PadLeft(8,'0')
"101000000"
Convert.ToString(0b_0000_1010 << (byte)5,2).PadLeft(8,'0')
"101000000"
Convert.ToString((byte)(0b_0000_1010 << 5),2).PadLeft(8,'0')
"01000000"

Convert.ToString((byte)(0b_0000_1010 << 6),2).PadLeft(8,'0')
"10000000"
Convert.ToString((byte)(0b_0000_1010 << 7),2).PadLeft(8,'0')
"00000000"
Convert.ToString((byte)(0b_0000_1010 << 8),2).PadLeft(8,'0')
"00000000"

BitOperator.CheckBit(0b_0000_1010, 4)
false
BitOperator.CheckBit(0b_0000_1010, 3)
true
BitOperator.CheckBit(0b_0000_1010, 2)
false
BitOperator.CheckBit(0b_0000_1010, 1)
true
BitOperator.CheckBit(0b_0000_1010, 0)
false

//16進制數值型態是uint
Convert.ToString(0xF0000000,2)
"11110000000000000000000000000000"
BitOperator.CheckBit(0xF0000000, 31)
true
BitOperator.CheckBit(0xF0000000, 30)
true
BitOperator.CheckBit(0xF0000000, 29)
true
BitOperator.CheckBit(0xF0000000, 28)
true
BitOperator.CheckBit(0xF0000000, 27)
false
BitOperator.CheckBit(0xF0000000, 26)
false
BitOperator.GetBit(0b_0000_1010, 4)
0
BitOperator.GetBit(0b_0000_1010, 3)
8
BitOperator.GetBit(0b_0000_1010, 2)
0
BitOperator.GetBit(0b_0000_1010, 1)
2
BitOperator.GetBit(0b_0000_1010, 0)
0
BitOperator.GetBit(0xF0000000, 31)
2147483648
BitOperator.GetBit(0xF0000000, 30)
1073741824
BitOperator.GetBit(0xF0000000, 29)
536870912
BitOperator.GetBit(0xF0000000, 28)
268435456
BitOperator.GetBit(0xF0000000, 27)
0

Convert.ToString(BitOperator.AddBit(0b_0000_1010, 7),2).PadLeft(8,'0')
"10001010"
Convert.ToString(BitOperator.AddBit(0b_1000_1010, 7),2).PadLeft(8,'0')
"10001010"
Convert.ToString(BitOperator.RemoveBit(0b_0000_1010, 7),2).PadLeft(8,'0')
"00001010"
Convert.ToString(BitOperator.RemoveBit(0b_1000_1010, 7),2).PadLeft(8,'0')
"00001010"
Convert.ToString(BitOperator.AddBit(BitOperator.AddBit(0b_0000_1010, 4),3),2).PadLeft(8,'0')
"00011010"
Convert.ToString(BitOperator.AddBit(BitOperator.AddBit(0b_0001_1010, 4),3),2).PadLeft(8,'0')
"00011010"
Convert.ToString(BitOperator.RemoveBit(BitOperator.RemoveBit(0b_0000_1010, 4),3),2).PadLeft(8,'0')
"00000010"
Convert.ToString(BitOperator.RemoveBit(BitOperator.RemoveBit(0b_0001_1010, 4),3),2).PadLeft(8,'0')
"00000010"

單元測試正常

位元操作常見於資料壓縮與資料加密領域,另外在自定義的資料格式中,還能利用沒用到的位元位置偷塞其他密文,譬如定義00000000代表false,00000001代表true,就有7個bits能再設計其他用途,別浪費

位元操作也能實現簡單的對稱式金鑰加密,為資料做加鹽處理(salt),這部分範例稍後補上
送禮物贊助創作者 !
0
留言

創作回應

更多創作