【问题标题】:Convert int to a bit array in .NET将 int 转换为 .NET 中的位数组
【发布时间】:2011-07-20 07:06:14
【问题描述】:

如何将 int 转换为位数组?

如果我例如有一个值为 3 的 int 我想要一个长度为 8 的数组,如下所示:

0 0 0 0 0 0 1 1

这些数字中的每一个都位于数组中大小为 8 的单独插槽中。

【问题讨论】:

  • 等一下,您要将int 转换为byte 还是bit-array
  • 一个字节包含 8 位,所以是的,我想要一个包含 8 位的数组,每个插槽中都有一个。
  • 您想要true/false 值的数组,还是用12 填充的字符数组?
  • @Afra:我编辑了问题以消除混淆。混淆是因为在 C# 中有一种称为 byte 的类型。它与Int8 完全相同。它不是一个数组。这与intInt32 的类型非常相似。如果您不喜欢我的编辑,请随时将其回滚或更改为您认为合适的方式:)

标签: c# .net


【解决方案1】:

使用BitArray 类。

int value = 3;
BitArray b = new BitArray(new int[] { value });

如果要获取位数组,可以使用BitArray.CopyTo 方法和bool[] 数组。

bool[] bits = new bool[b.Count];
b.CopyTo(bits, 0);

请注意,这些位将从最低有效位到最高有效位存储,因此您可能希望使用Array.Reverse

最后,如果您想为每个位获取 0 和 1 而不是布尔值(我使用 byte 来存储每个位;比 int 浪费更少):

byte[] bitValues = bits.Select(bit => (byte)(bit ? 1 : 0)).ToArray();

【讨论】:

  • 这应该是公认的答案。此外,BitArray 支持索引运算符 (this[int index]),这使得使用位非常容易(我猜在O(1) 中)。
【解决方案2】:

转换 int 'x'

int x = 3;

一种方法,通过对 int 进行操作:

string s = Convert.ToString(x, 2); //Convert to binary in a string

int[] bits= s.PadLeft(8, '0') // Add 0's from left
             .Select(c => int.Parse(c.ToString())) // convert each char to int
             .ToArray(); // Convert IEnumerable from select to Array

或者,通过使用 BitArray 类-

BitArray b = new BitArray(new byte[] { x });
int[] bits = b.Cast<bool>().Select(bit => bit ? 1 : 0).ToArray();

【讨论】:

  • 谢谢!我最终得到了这段代码: string s = Convert.ToString(number, 2); char[] bits = s.PadLeft(8, '0').ToCharArray();
  • 如果您希望输出为布尔值怎么办?
  • @AaronFranke BitArray 为您提供布尔输出。
【解决方案3】:

使用Convert.ToString (value, 2)

在你的情况下

string binValue = Convert.ToString (3, 2);

【讨论】:

  • 然后是.ToCharArray(),因为他想要一个数组。
  • 确实,对于数组使用.ToCharArray(),我读得太快了:p
【解决方案4】:

我会在一个单行中实现它,如下所示:

using System;
using System.Collections;

namespace stackoverflowQuestions
{
    class Program
    {
        static void Main(string[] args)
        {    
            //get bit Array for number 20
            var myBitArray = new BitArray(BitConverter.GetBytes(20));
        }
    }
}

请注意BitArray 的每个元素都存储为布尔值,如下图所示:

所以下面的代码有效:

if (myBitArray[0] == false)
{
    //this code block will execute
}

但下面的代码根本无法编译:

if (myBitArray[0] == 0)
{
    //some code
}

【讨论】:

  • 这绝对是解决这个问题的最佳方法。 BitArray 构造函数获取 ByteArray 的参数。所以我们可以使用 Encoding.UTF8.GetBytes("hello world") 或任何其他数据
【解决方案5】:

我刚刚遇到了一个实例...

int val = 2097152;
var arr = Convert.ToString(val, 2).ToArray();
var myVal = arr[21];

...没有产生我想要的结果。在上面的“myVal”中,存储在数组中位置 21 的值是“0”。它应该是一个'1'。我不确定为什么我收到了一个不准确的值,这让我感到困惑,直到我在 C# 中找到了另一种将 INT 转换为位数组的方法:

int val = 2097152;
var arr = new BitArray(BitConverter.GetBytes(val));
var myVal = arr[21];

这产生了结果“true”作为“myVal”的布尔值。

我意识到这可能不是获取此值的最有效方法,但它非常直接、简单且易读。

【讨论】:

    【解决方案6】:

    要将您的整数输入转换为任意大小的 bool 数组,只需使用 LINQ。

    bool[] ToBits(int input, int numberOfBits) {
        return Enumerable.Range(0, numberOfBits)
        .Select(bitIndex => 1 << bitIndex)
        .Select(bitMask => (input & bitMask) == bitMask)
        .ToArray();
    }
    

    所以要将整数转换为最多 32 位的 bool 数组,只需像这样使用它:

    bool[] bits = ToBits(65, 8); // true, false, false, false, false, false, true, false
    

    您可能希望根据需要反转数组。

    Array.Reverse(bits);
    

    【讨论】:

      【解决方案7】:
      int value = 3;
      
      var array = Convert.ToString(value, 2).PadLeft(8, '0').ToArray();
      

      【讨论】:

      • 没有解释的代码清单不如有解释的代码清单有用。考虑添加一个,以便其他人可以从这段代码中学习。
      【解决方案8】:
          public static bool[] Convert(int[] input, int length)
          {
              var ret = new bool[length];
              var siz = sizeof(int) * 8;
              var pow = 0;
              var cur = 0;
      
              for (var a = 0; a < input.Length && cur < length; ++a)
              {
                  var inp = input[a];
      
                  pow = 1;
      
                  if (inp > 0)
                  {
                      for (var i = 0; i < siz && cur < length; ++i)
                      {
                          ret[cur++] = (inp & pow) == pow;
      
                          pow *= 2;
                      }
                  }
                  else
                  {
                      for (var i = 0; i < siz && cur < length; ++i)
                      {
                          ret[cur++] = (inp & pow) != pow;
      
                          pow *= 2;
                      }
                  }
              }
      
              return ret;
          }
      

      【讨论】:

        【解决方案9】:

        我最近发现了 C# Vector&lt;T&gt; 类,它使用硬件加速(即 SIMD:单指令多数据)将向量组件作为单指令执行操作。换句话说,它在一定程度上并行化了数组操作。

        由于您尝试将整数位掩码扩展为数组,因此您可能正在尝试做类似的事情。

        如果您处于unrolling your code 的位置,这将是一个值得强烈考虑的优化。但是,如果您只是很少使用它们,也请权衡一下against the costs。还要考虑内存开销,因为Vectors 真的 想要在连续内存上操作(在 CLR 中称为Span&lt;T&gt;),所以当你从数组中实例化您自己的向量。


        以下是如何进行屏蔽的示例:

        //given two vectors
        Vector<int> data1 = new Vector<int>(new int[] { 1, 0, 1, 0, 1, 0, 1, 0 });
        Vector<int> data2 = new Vector<int>(new int[] { 0, 1, 1, 0, 1, 0, 0, 1 });
        //get the pairwise-matching elements
        Vector<int> mask = Vector.Equals(data1, data2);
        //and return values from another new vector for matches
        Vector<int> whenMatched = new Vector<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8 });
        //and zero otherwise
        Vector<int> whenUnmatched = Vector<int>.Zero;
        
        //perform the filtering
        Vector<int> result = Vector.ConditionalSelect(mask, whenMatched, whenUnmatched);
        //note that only the first half of vector components render in the Debugger (this is a known bug)
        string resultStr = string.Join("", result);
        //resultStr is <0, 0, 3, 4, 5, 6, 0, 0>
        

        注意the VS Debugger is bugged,只显示向量的前半部分。

        所以用一个整数作为掩码,你可以试试:

        int maskInt = 0x0F;//00001111 in binary
        //convert int mask to a vector (anybody know a better way??)
        Vector<int> maskVector = new Vector<int>(Enumerable.Range(0, Vector<int>.Count).Select(i => (maskInt & 1<<i) > 0 ? -1 : 0).ToArray());
        

        请注意,(有符号整数)-1 用于向true 发出信号,它具有全为二进制表示。

        正向1 不起作用,如果需要,您可以将(int)-1 转换为uint 以启用二进制文件的每一位(但not by using Enumerable.Cast&lt;&gt;())。


        但是,由于我的系统中有 8 个元素的容量(支持 4x64 位块),这仅适用于 int32 最多 2^8 的掩码。 这取决于执行环境,基于硬件能力,所以总是使用Vector&lt;T&gt;.Capacity

        因此,您可以获得双倍容量,将 shorts 作为 ints 和 longs(尚不支持新的 Half 类型,也不支持“Decimal”,它们是对应的 float/double 类型到 @987654344 @和int128):

        ushort maskInt = 0b1111010101010101;
        Vector<ushort> maskVector = new Vector<ushort>(Enumerable.Range(0, Vector<ushort>.Count).Select(i => (maskInt & 1<<i) > 0 ? -1 : 0).Select(x => (ushort)x).ToArray());
        //string maskString = string.Join("", maskVector);//<65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 65535, 65535, 65535>
        Vector<ushort> whenMatched = new Vector<ushort>(Enumerable.Range(1, Vector<ushort>.Count).Select(i => (ushort)i).ToArray());//{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
        Vector<ushort> whenUnmatched = Vector<ushort>.Zero;
        
        Vector<ushort> result = Vector.ConditionalSelect(maskVector, whenMatched, whenUnmatched);
        string resultStr = string.Join("", result);//<1, 0, 3, 0, 5, 0, 7, 0, 9, 0, 11, 0, 13, 14, 15, 16>
        

        由于整数的工作方式,无论是有符号还是无符号(使用最高有效位来指示+/- 值),您可能也需要考虑这一点,例如将0b1111111111111111 转换为short 之类的值。如果你尝试做一些看起来很愚蠢的事情,编译器通常会阻止你,至少。

        short maskInt = unchecked((short)(0b1111111111111111));
        

        请确保不要将int32 的最重要位混淆为 2^31。

        【讨论】:

          【解决方案10】:

          使用&amp; (AND)


          位运算符

          以上答案都是正确有效的。如果你想用老派的方式来做,不使用BitArrayString.Convert(),你可以使用位运算符。

          按位 AND 运算符&amp; 接受两个操作数并返回一个值,其中每个位都是1,如果两个操作数都有1地方,或0 在其他情况下。它就像逻辑 AND (&amp;&amp;),但它需要整数操作数而不是布尔操作数。

          例如。 0101 &amp; 1001 = 0001

          利用这个原理,任何整数 AND 该整数的最大值就是它自己。

          byte b = 0b_0100_1011; // In base 10, 75.
          Console.WriteLine(b & byte.MaxValue); // byte.MaxValue = 255
          

          结果:75


          循环中的按位与

          我们可以利用这个优势,通过使用循环遍历正 32 位整数(即uint)中的每个位并将 AND 运算的结果放入strings 的数组,它们都将为“1”或“0”。

          只有一个特定数字 n1 等于 2 的 n 次方(我通常使用 Math.Pow() 方法)。 p>

          public static string[] GetBits(uint x) {
              string[] bits = new string[32];
              
              for (int i = 0; i < 32; i++) {
                  uint bit = x & Math.Pow(2, i);
                  if (bit == 1)
                      bits[i] = "1";
                  else
                      bits[i] = "0";
              }
          
              return bits;
          }
          

          如果您要输入 1000(相当于二进制 1111101000),您将得到一个包含 32 个字符串的数组,拼写为 0000 0000 0000 0000 0000 0011 1110 1000(空格只是为了便于阅读)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-03-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多