如何在C#中将整数转换为二进制字符串?

10

我正在编写一个数字转换器。如何在C#中将整数转换为二进制字符串,而不使用内置函数(Convert.ToString根据给定的值执行不同的操作)?

  • 二进制 -> 符号大小
  • 二进制 -> 反码
  • 二进制 -> 补码
9个回答

20

简单的解决方案:

IntToBinValue = Convert.ToString(6, 2);

这绝对是我找到的最直接的答案! - Radityo Ardi
1
不幸的是,这似乎对无符号类型无效... - Danvil

17

今天几乎所有的计算机都使用二进制补码(two's complement)表示法,因此如果您进行直接转换,您将得到这个数的二进制补码字符串:

public string Convert(int x) {
  char[] bits = new char[32];
  int i = 0;

  while (x != 0) {
    bits[i++] = (x & 1) == 1 ? '1' : '0';
    x >>= 1;
  }

  Array.Reverse(bits, 0, i);
  return new string(bits);
}

这是你进行剩余两种转换的基础。对于符号-大小(sign-magnitude)表示法,只需要提前提取符号并转换其绝对值:

byte sign;
if (x < 0) {
  sign = '1';
  x = -x;
} else {
  sign = '0';
}
string magnitude = Convert(x);

对于一的补数,在数字为负时减去1:

if (x < 0)
  x--;
string onec = Convert(x);

6
至少部分答案是使用decimal.GetBits(someValue)将十进制转换为二进制表示形式。
然后,可以使用BitConverter.GetBytes对从decimal.GetBits()返回的元素进行转换,将整数转换为字节。
您可能会发现decimal.GetBits()文档很有用。
不过,我不确定如何从字节转换为十进制。
更新:根据作者的更新: BitConverter包含用于将数字转换为字节的方法,这对于获取二进制表示形式很方便。 GetBytes()ToInt32()方法对于每个方向的转换都很方便。如果您觉得更容易解释为1和0的十六进制字符串,则ToString()重载很方便。

如果BitConverter.GetBytes能够将位转换回字节,那么从字节到整数的转换只需要使用BitConverter.GetInt32(byte[] bytes)即可。 - Jimmy Hoffa
@Jimmy - 谢谢。对我来说缺失的一环是理解如何从字节数组或Int32数组转换为decimal类型。 - kbrimington

5
   var a = Convert.ToString(4, 2).PadLeft(8, '0');

2

简化的.NET 8+版本

从.NET 8开始,二进制格式说明符(B)(终于)被引入,使得任何额外的转换功能(内置或自定义)都变得过时了(除非你想做一些非常特定的事情,比如在每个字节或半字节之间添加下划线)。现在,它只是默认的整数数值类型的ToString()方法的标准数值格式字符串的一部分:

int i = 42;
string binary = i.ToString("B"); // 101010

int j = 0x0f0f;
// you can specify the number of digits in the result string, for example 16:
string itsSoSimpleNow = $"{j:B16}"; // 0000111100001111

// this was not possible with Convert.ToString(...) before
ulong k = ulong.MaxValue;
string evenUlongsWorkFinally = k.ToString("B"); // 11...11

你可以使用 Bb 作为说明符,它们没有区别 :) 如果你现在被困在旧版的.NET中(或者真的想自定义) 到目前为止,我还没有看到一个简单的基于ASCII的解决方案,所以这里有一个:
public static string ToBinaryString(ulong u)
{
    Span<byte> ascii = stackalloc byte[64];
    for (int i = 0; i < 64; i++)
    {
        // we want the MSB to be on the left, so we need to reverse everything
        // other than that we simply grab the ith bit (from the LSB) 
        // and simply OR that to the ASCII character '0' (0x30).
        // if the bit was 0 the result is '0' itself, otherwise
        // if the bit was 1 then the result is '0' | 1 (0x30 | 1) which 
        // yields 0x31 which is also conveniently the ASCII code for '1'.
        ascii[63 - i] = (byte)((u & (1uL << i)) >> i | '0');
    }
    return Encoding.ASCII.GetString(ascii);
}

上面的示例使用了`ulong`(部分原因是因为这在`.NET 7`上不能与`Convert.ToString(..., 2)`方法一起使用),但你也可以使用其他整数类型。只需确保首先将值转换为相应的无符号类型,因为我们不希望进行有符号的位移。显然,你可能需要根据你的类型的位大小来更改大小。所以对于`Int32`,你可以使用以下代码:
public static string ToBinaryString(int value)
{
    // note the cast to unsigned here.
    // we don't want any funny negative values in here.
    // the result will be the two's complement binary representation of negative values
    uint u = (uint)value; 
    Span<byte> ascii = stackalloc byte[32];
    for (int i = 0; i < 32; i++)
    {
        ascii[31 - i] = (byte)((u & (1u << i)) >> i | '0');
    }
    return Encoding.ASCII.GetString(ascii);
}

1
这是我的代码: (上面的部分将32位二进制字符串转换为32位整数,下面的部分将32位整数转换回32位二进制字符串)。 希望这能帮到你。
        string binaryString = "011100100111001001110011";
        int G = 0;

        for (int i = 0; i < binaryString.Length; i++)
            G += (int)((binaryString[binaryString.Length - (i + 1)] & 1) << (i % 32));

        Console.WriteLine(G); //‭7500403‬
        binaryString = string.Empty;

        for (int i = 31; i >= 0; i--)
        {
            binaryString += (char)(((G & (1 << (i % 32))) >> (i % 32)) | 48);
        }

        Console.WriteLine(binaryString); //00000000011100100111001001110011

针对二进制字符串中负数最左边字符的小错误进行了修复。应该是(uint)G & (1而不是G & (1。修复后代码如下:binaryString += (char)((((uint)G & (1 << (i % 32))) >> (i % 32)) | 48);即可解决问题。如果不进行修复,在处理正数时仍然可以正常工作。 - user12515980

0

这里有一个优雅的解决方案:

// Convert Integer to binary and return as string
private static string GetBinaryString(Int32 n)
{
    char[] b = new char[sizeof(Int32) * 8];

    for (int i = 0; i < b.Length; i++)
        b[b.Length-1 - i] = ((n & (1 << i)) != 0) ? '1' : '0';

    return new string(b).TrimStart('0');
}

0

您可以从头开始逐位构建数字表示。

不确定您不想使用哪些内置函数,但是您可以逐个字符构建字符串吗?

  1. 从大于该数字的最高2的幂开始。
  2. 将“1”推入您的字符串中。
  3. 从该2的幂中减去该数字。
  4. 取下一个较低的2的幂。 如果达到一半,请停止。 您完成了。
  5. 如果剩下的数字大于此2的幂,则返回步骤2。 如果不是,则将“0”推入字符串并返回步骤4。

对于补码和反码,需要进行额外的计算步骤

或者这对您的需求来说太基础了吗?


0

这是一个不安全的实现:

    private static unsafe byte[] GetDecimalBytes(decimal d)
    {
        byte* dp = (byte*) &d;
        byte[] result = new byte[sizeof(decimal)];
        for (int i = 0; i < sizeof(decimal); i++, dp++)
        {
            result[i] = *dp;
        }
        return result;
    }

这里是回滚操作:

    private static unsafe decimal GetDecimal(Byte[] bytes)
    {
        if (bytes == null)
            throw new ArgumentNullException("bytes");

        if (bytes.Length != sizeof(decimal))
            throw new ArgumentOutOfRangeException("bytes", "length must be 16");

        decimal d = 0;
        byte* dp = (byte*)&d;
        byte[] result = new byte[sizeof(decimal)];
        for (int i = 0; i < sizeof(decimal); i++, dp++)
        {
            *dp = bytes[i];
        }
        return d;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接