【问题标题】:How can a create a byte from 8 Bool values in C#如何在 C# 中从 8 个 Bool 值创建一个字节
【发布时间】:2021-09-19 21:46:53
【问题描述】:

我需要读取 8 个布尔值并从中创建一个字节,这是如何完成的? 而不是硬编码以下 1 和 0 - 我如何从 c# 中的一系列布尔值创建二进制值?

byte myValue = 0b001_0000;

【问题讨论】:

标签: c#


【解决方案1】:

有很多方法可以做到这一点,例如从数组构建它:

bool[] values = ...;
byte result = 0;
for(int i = values.Length - 1; i >= 0; --i)  // assuming you store them "in reverse"
    result = result | (values[i] << (values.Length - 1 - i));

【讨论】:

    【解决方案2】:

    我使用 Linq 的解决方案:

    public static byte CreateByte(bool[] bits)
            {
                if (bits.Length > 8)
                {
                    throw new ArgumentOutOfRangeException();
                }
                return (byte)bits.Reverse().Select((val, i) => Convert.ToByte(val) << i).Sum();
            }
    

    对 Reverse() 的调用是可选的,取决于您希望索引 0 是 LSB(不带 Reverse)还是 MSB(带 Reverse)

    【讨论】:

      【解决方案3】:
              var values = new bool[8];
              values [7] = true;            
              byte result = 0;
              for (var i = 0; i < 8; i++)
              {
                 //edited to bit shifting because of community complains :D
                 if (values [i]) result |= (byte)(1 << i);
              }
              // result => 128
      

      【讨论】:

      • Math.Pow(2, i) 是获得 2ⁱ 的最糟糕方式。请改用1 &lt;&lt; i
      • 不,还不错,只是慢了^^
      • 它缓慢且不精确。虽然指数高达 63,但整数误差为零,所以它很慢。
      【解决方案4】:

      这可能有点矫枉过正,但我​​想玩 SIMD。它可能写得更好,但我不太了解 SIMD。

      如果您想要反转生成的位顺序,只需从 SIMD 方法中删除改组部分并将 (7 - i) 更改为 i

      对于那些不熟悉 SIMD 的人来说,这种方法比普通的 for 循环快大约 3 倍。

      public static byte ByteFrom8Bools(ReadOnlySpan<bool> bools)
      {
          if (bools.Length < 8)
              Throw();
                  
          static void Throw() // Throwing in a separate method helps JIT produce better code, or so I've heard
          {
              throw new ArgumentException("Not enough booleans provided");
          }
      
          // these are JIT compile time constants, only one of the branches will be compiled
          // depending on the CPU running this code, eliminating the branch entirely
          if(Sse2.IsSupported && Ssse3.IsSupported)
          {
              // copy out the 64 bits all at once
              ref readonly bool b = ref bools[0];
              ref bool refBool = ref Unsafe.AsRef(b);
              ulong ulongBools = Unsafe.As<bool, ulong>(ref refBool);
      
              // load our 64 bits into a vector register
              Vector128<byte> vector = Vector128.CreateScalarUnsafe(ulongBools).AsByte();
      
              // this is just to propagate the 1 set bit in true bools to the most significant bit
              Vector128<byte> allTrue = Vector128.Create((byte)1);
              Vector128<byte> compared = Sse2.CompareEqual(vector, allTrue);
      
              // reverse the bytes we care about, leave the rest in their place
              Vector128<byte> shuffleMask = Vector128.Create((byte)7, 6, 5, 4, 3, 2, 1, 0, 8, 9, 10, 11, 12, 13, 14, 15);
              Vector128<byte> shuffled = Ssse3.Shuffle(compared, shuffleMask);
      
              // move the most significant bit of each byte into a bit of int
              int mask = Sse2.MoveMask(shuffled);
      
              // returning byte = returning the least significant byte from int
              return (byte)mask;
          }
          else
          {
              // fall back to a more generic algorithm if there aren't the correct instructions on the CPU
              byte bits = 0;
              for (int i = 0; i < 8; i++)
              {
                  bool b = bools[i];
                  bits |= (byte)(Unsafe.As<bool, byte>(ref b) << (7 - i));
              }
              return bits;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2012-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-24
        • 1970-01-01
        • 2011-01-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多