在.NET 中将 int 转换为位数组

如何将 int 转换为 bit 数组?

如果我有一个整型数,它的值是3,我想要一个数组,它的长度是8,看起来像这样:

0 0 0 0 0 0 1 1

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

144126 次浏览

使用 Convert.ToString (value, 2)

所以在你的情况下

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

使用 BitArray类。

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

如果希望获得位的数组,可以使用带有 bool[]数组的 BitArray.CopyTo方法。

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();

转换 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();
int value = 3;


var array = Convert.ToString(value, 2).PadLeft(8, '0').ToArray();

我只是碰到了一个例子。

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’的布尔值。

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

如下所示,我将通过一行程序来实现它:

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的每个元素都存储为 bool,如下面的快照所示:

enter image description here

因此,下面的代码是可行的:

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

但是下面的代码根本不能编译:

if (myBitArray[0] == 0)
{
//some code
}
    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;
}

要将整数输入转换为任意大小的 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);

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

由于您试图将整数位掩码展开为数组,因此可能正在尝试类似的操作。

如果您处于 展开你的代码点,则需要认真考虑这个优化。但是如果你只是很少使用它们,也要称这个 抵消成本的重量。还要考虑内存开销,因为 Vectors 真的想要操作连续内存(在 CLR 中称为 Span<T>) ,所以当你从数组中实例化你自己的向量时,内核可能不得不在引擎盖下转动位。


下面是一个如何做掩蔽的例子:

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

注意,VS 调试器被窃听了只显示了向量分量的前半部分。

因此,如果使用整数作为掩码,可以尝试:

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发信号,true具有所有 true的二进制表示形式。

正的 1不起作用,如果需要,您可以将 (int)-1强制转换为 uint以获得启用的每一位二进制(但是 使用 Enumerable.Cast<>())。


然而,由于我的系统中有8个元素的容量(支持4x64位块) ,这只适用于 int32掩码到2 ^ 8的情况。基于 这取决于执行环境的硬件能力,所以 一直都是使用 Vector<T>.Capacity

因此,你可以得到两倍的容量,短的整数作为长(新的 一半类型尚不支持,也不是“ Decimal”,这是相应的 float/double类型的 int16int128) :

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。

使用 &(AND)


按位运算符

以上答案都是正确有效的。如果你想用传统的方法,不使用 BitArray或者 String.Convert(),你可以使用按位运算符。

< em > 按位 AND操作符 &接受两个操作数,并返回一个值,其中每个位都是 1(如果两个操作数在该位都有一个 1) ,或者在其他情况下每个位都有一个 0。它类似于逻辑 AND (&&) ,但它采用整数操作数而不是布尔操作数。

前任

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

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

结果: 75


循环中的按位 AND

我们可以利用这一点,通过使用一个循环,从一个正32位整数(即 uint)中获取特定的位,并将 AND 操作的结果放入一个 string数组中,这个数组将全部为“1”或“0”。

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

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(空格只是为了便于阅读)。