BigInteger的为十六进制/十进制/八进制/二进制字符串?(BigInteger to Hex

2019-07-17 14:39发布

在Java中,我能做到

BigInteger b = new BigInteger(500);

然后格式化为我高兴

b.toString(2); //binary
b.toString(8); //octal
b.toString(10); //decimal
b.toString(16); //hexadecimal

在C#中,我可以做

int num = int.Parse(b.ToString());
Convert.ToString(num,2) //binary
Convert.ToString(num,8) //octal

等,但我只能做long值和较小的。 有打印的BigInteger与指定的基本某种方法? 我贴这个, BigInteger的解析至八进制字符串转换? ,昨天并获得如何基本上所有字符串转换为BigInteger的值的解决方案,但还没有成功的输出。

Answer 1:

转换BigInteger为十进制,十六进制,二进制,八进制字符串:

让我们先从一个BigInteger值:

BigInteger bigint = BigInteger.Parse("123456789012345678901234567890");

基座10和基座16

内置底座10(十进制)和基部16(十六进制)coversions很容易:

// Convert to base 10 (decimal):
string base10 = bigint.ToString();

// Convert to base 16 (hexadecimal):
string base16 = bigint.ToString("X");

前导零(正与负的BigInteger值)

注意,这ToString("X")确保十六进制字符串有一个前导零时的值BigInteger是积极的。 这不同于通常的行为ToString("X")从其中前导零被抑制其他值类型转换时。

例:

var positiveBigInt = new BigInteger(128);
var negativeBigInt = new BigInteger(-128);
Console.WriteLine(positiveBigInt.ToString("X"));
Console.WriteLine(negativeBigInt.ToString("X"));

结果:

080
80

有这种行为的目的作为国内领先的零表示BigInteger为正值-本质上,前导零提供标志。 这是必要的(相对于其它值类型转换),因为一个BigInteger没有固定的大小; 因此,不存在指定的符号位。 前导零标识为正值,而不是一个负一。 这允许“往返” BigInteger通过值出来ToString()通过与回Parse() 这种行为是对讨论的BigInteger结构上MSDN页面。

扩展方法:对BigInteger的二进制,十六进制和八进制

下面是一个包含扩展方法,将一类BigInteger情况下,以二进制,十六进制和八进制字符串:

using System;
using System.Numerics;
using System.Text;

/// <summary>
/// Extension methods to convert <see cref="System.Numerics.BigInteger"/>
/// instances to hexadecimal, octal, and binary strings.
/// </summary>
public static class BigIntegerExtensions
{
  /// <summary>
  /// Converts a <see cref="BigInteger"/> to a binary string.
  /// </summary>
  /// <param name="bigint">A <see cref="BigInteger"/>.</param>
  /// <returns>
  /// A <see cref="System.String"/> containing a binary
  /// representation of the supplied <see cref="BigInteger"/>.
  /// </returns>
  public static string ToBinaryString(this BigInteger bigint)
  {
    var bytes = bigint.ToByteArray();
    var idx = bytes.Length - 1;

    // Create a StringBuilder having appropriate capacity.
    var base2 = new StringBuilder(bytes.Length * 8);

    // Convert first byte to binary.
    var binary = Convert.ToString(bytes[idx], 2);

    // Ensure leading zero exists if value is positive.
    if (binary[0] != '0' && bigint.Sign == 1)
    {
      base2.Append('0');
    }

    // Append binary string to StringBuilder.
    base2.Append(binary);

    // Convert remaining bytes adding leading zeros.
    for (idx--; idx >= 0; idx--)
    {
      base2.Append(Convert.ToString(bytes[idx], 2).PadLeft(8, '0'));
    }

    return base2.ToString();
  }

  /// <summary>
  /// Converts a <see cref="BigInteger"/> to a hexadecimal string.
  /// </summary>
  /// <param name="bigint">A <see cref="BigInteger"/>.</param>
  /// <returns>
  /// A <see cref="System.String"/> containing a hexadecimal
  /// representation of the supplied <see cref="BigInteger"/>.
  /// </returns>
  public static string ToHexadecimalString(this BigInteger bigint)
  {
    return bigint.ToString("X");
  }

  /// <summary>
  /// Converts a <see cref="BigInteger"/> to a octal string.
  /// </summary>
  /// <param name="bigint">A <see cref="BigInteger"/>.</param>
  /// <returns>
  /// A <see cref="System.String"/> containing an octal
  /// representation of the supplied <see cref="BigInteger"/>.
  /// </returns>
  public static string ToOctalString(this BigInteger bigint)
  {
    var bytes = bigint.ToByteArray();
    var idx = bytes.Length - 1;

    // Create a StringBuilder having appropriate capacity.
    var base8 = new StringBuilder(((bytes.Length / 3) + 1) * 8);

    // Calculate how many bytes are extra when byte array is split
    // into three-byte (24-bit) chunks.
    var extra = bytes.Length % 3;

    // If no bytes are extra, use three bytes for first chunk.
    if (extra == 0)
    {
      extra = 3;
    }

    // Convert first chunk (24-bits) to integer value.
    int int24 = 0;
    for (; extra != 0; extra--)
    {
      int24 <<= 8;
      int24 += bytes[idx--];
    }

    // Convert 24-bit integer to octal without adding leading zeros.
    var octal = Convert.ToString(int24, 8);

    // Ensure leading zero exists if value is positive.
    if (octal[0] != '0' && bigint.Sign == 1)
    {
      base8.Append('0');
    }

    // Append first converted chunk to StringBuilder.
    base8.Append(octal);

    // Convert remaining 24-bit chunks, adding leading zeros.
    for (; idx >= 0; idx -= 3)
    {
      int24 = (bytes[idx] << 16) + (bytes[idx - 1] << 8) + bytes[idx - 2];
      base8.Append(Convert.ToString(int24, 8).PadLeft(8, '0'));
    }

    return base8.ToString();
  }
}

乍看之下,这些方法似乎比必要的更加复杂。 额外的复杂性有一点,着实增加,以确保适当的前导零存在于转换后的字符串。

让我们来看看每个扩展方法,看看他们是如何工作的:

BigInteger.ToBinaryString()

下面是如何使用此扩展方法的转换BigInteger二进制字符串:

// Convert BigInteger to binary string.
bigint.ToBinaryString();

每个这些扩展方法的基本核心是BigInteger.ToByteArray()方法。 此方法转换一个BigInteger字节数组,这是我们如何能得到的二进制表示BigInteger值:

var bytes = bigint.ToByteArray();

要注意,虽然,返回的字节数组是在little-endian顺序,所以第一个数组元素是的至少-显著字节(LSB) BigInteger 。 由于StringBuilder用于建立输出串-这开始于最显著位(MSB) - 字节数组必须被反向迭代 ,使得最显著字节首先被转换。

因此,索引指针被设置到字节数组中的最显著位(最后一个元素):

var idx = bytes.Length - 1;

为了捕获所转换的字节,一个StringBuilder创建:

var base2 = new StringBuilder(bytes.Length * 8);

StringBuilder构造函数采用了容量StringBuilder 。 所需容量StringBuilder通过取字节为转换由8相乘的数目来计算(8个二进制数字转换从每个字节的结果)。

然后,第一字节被转换为二进制字符串:

var binary = Convert.ToString(bytes[idx], 2);

在这一点上,有必要确保前导零存在,如果BigInteger是正值(见上面的讨论)。 如果第一转换位数是不是零,并且bigint为正,则一个'0'被附加到StringBuilder

// Ensure leading zero exists if value is positive.
if (binary[0] != '0' && bigint.Sign == 1)
{
  base2.Append('0');
}

接着,将转换后的字节附加到StringBuilder

base2.Append(binary);

转换的剩余字节,一个循环迭代中以相反的顺序字节数组的剩余部分:

for (idx--; idx >= 0; idx--)
{
  base16.Append(Convert.ToString(bytes[idx], 2).PadLeft(8, '0'));
}

请注意,每个转换的字节被填充在左边用在必要的零(“0”),以使转换后的字符串是八个二进制字符。 这是非常重要的。 如果没有这种填充,十六进制值“101”将被转换成“11”的二进制值。 前导零确保转换是“100000001”。

当所有的字节被转换,所述StringBuilder包含完整的二进制串,其通过扩展方法返回:

return base2.ToString();

BigInteger.ToOctalString

转换BigInteger为八进制(基数8)字符串是更复杂的。 问题是八进制数字表示三个比特是不是偶数倍数在由创建的字节数组的每个元素保持的8位的BigInteger.ToByteArray() 。 为了解决这个问题,从该阵列的三个字节被组合成的24位的块。 每个24位块均匀地转换到八个进制字符。

第24位块需要一些数学模:

var extra = bytes.Length % 3;

该计算确定多少个字节当整个字节数组被分成三字节(24位)的块是“额外”。 第一次转换为八进制(最高显著位)获得“额外”字节,这样所有剩余的转换将各自获得3个字节。

如果没有“额外”字节,则第一块得到一个完整的三个字节:

if (extra == 0)
{
  extra = 3;
}

第一个块被装入一个整数变量称为int24保持高达24比特。 块的每个字节被加载。 作为附加的字节加载,在先前的位int24由8位左移,以腾出空间:

int int24 = 0;
for (; extra != 0; extra--)
{
  int24 <<= 8;
  int24 += bytes[idx--];
}

一个24位的块,以八进制的转换是通过完成:

var octal = Convert.ToString(int24, 8);

再次,第一个数字必须是一个前导零如果BigInteger是正值:

// Ensure leading zero exists if value is positive.
if (octal[0] != '0' && bigint.Sign == 1)
{
  base8.Append('0');
}

第一转换块被附加到StringBuilder

base8.Append(octal);

剩余的24位的块被转换在一个循环中:

for (; idx >= 0; idx -= 3)
{
  int24 = (bytes[idx] << 16) + (bytes[idx -1] << 8) + bytes[idx - 2];
  base8.Append(Convert.ToString(int24, 8).PadLeft(8, '0'));
}

像二进制转换中,每个转换的八进制串是左用零填充,使得“7”变成“00000007”。 这确保了零将不会从转换后的字符串的中间被丢弃(即,“17”而不是“100000007”)。

转换为基数X?

一个转换BigInteger到其他基地数量可能会远远复杂得多。 只要数碱是2的幂(即,2,4,8,16)由创建的字节数组BigInteger.ToByteArray()可以适当地分割成比特和转换块。

但是,如果基数不是2的幂,这个问题变得更加复杂,并且需要循环和分裂的一个很好的协议。 因此基数转换是罕见的,我只在这里涵盖了流行的计算数量基地。



Answer 2:

与BigInteger的工作了好长一段日子后,我做的事情,以输出二进制字符串的一个更好的办法,试试这个! (适用于负数)

// Important note: when parsing hexadecimal string, make sure to prefix
// with 0 if the number is positive. Ex: 0F instead of F, and 01A3 instead of 1A3.
// If the number is negative, then the first bit should be set to 1.

var x = BigInteger.Parse("0F", NumberStyles.HexNumber); // Or: BigInteger.Parse("15")

var biBytes = x.ToByteArray();

var bits = new bool [8 * biBytes.Length];

new BitArray(x.ToByteArray()).CopyTo(bits, 0);

bits = bits.Reverse().ToArray(); // BigInteger uses little endian when extracting bytes (thus bits), so we inverse them.

var builder = new StringBuilder();

foreach(var bit in bits)
{
    builder.Append(bit ? '1' : '0');
}

string final = Regex.Replace(builder.ToString(), @"^0+", ""); // Because bytes consume full 8 bits, we might occasionally get leading zeros.

Console.WriteLine(final);

输出1111



Answer 3:

这是一个转换的简单方法BigInteger所有基础:

public static string ToNBase(BigInteger a, int n)
        {
            StringBuilder sb = new StringBuilder();
            while (a > 0)
            {
                sb.Insert(0,a % n);
                a /= n;
            }
            return sb.ToString();
        }

它完美的基地2-10。 如果你想让它产生的十六进制或其他较高基数的字符串,您必须修改a % b根据插入之前底座的形式。



文章来源: BigInteger to Hex/Decimal/Octal/Binary strings?