BigInteger в шестнадцатеричной/десятичной/восьмеричной/двоичной строки?

на 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

etc. Но я могу сделать это только с long значения и меньше. Есть ли какой-то метод для печати BigInteger с указанной базой? Я отправил это,BigInteger Анализирует Восьмеричную Строку?, вчера и получил решение о том, как преобразовать в основном все строки В значения BigInteger, но не имели успеха.

3 ответов


преобразование BigInteger до десятичной, шестнадцатеричной, двоичной, восьмеричной строки:

с BigInteger значение:
BigInteger bigint = BigInteger.Parse("123456789012345678901234567890");

База 10 и база 16

встроенные покрытия Base 10 (десятичные) и base 16 (шестнадцатеричные) просты:

// 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 является положительным значением-по существу, начальный ноль обеспечивает знак. Это необходимо (в отличие от других преобразований типов значений), потому что a 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();

остерегайтесь, однако, возвращенный байтовый массив в прямом порядке байтов, так что первый элемент массива является наименее значащий байт (LSB) и в BigInteger. СStringBuilder используется для построения выходной строки--которая начинается с наиболее значимой цифры (MSB)--массив байтов должен повторите в обратном порядке так что наиболее значимый байт преобразуется в первую.

таким образом, указатель индекса устанавливается на самую значительную цифру (последний элемент) в массиве байтов:

var idx = bytes.Length - 1;

чтобы захватить преобразованные байты, a StringBuilder создана:

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

на StringBuilder конструктор принимает емкость для StringBuilder. Емкость, необходимая для StringBuilder рассчитывается, принимая количество байтов для преобразования, умноженное на восемь (из каждого преобразованного байта получается восемь двоичных цифр).

первый байт преобразуется в двоичную строку:

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

в этот момент необходимо убедиться, что существует начальный ноль, если BigInteger - положительное значение (см. выше). Если первая преобразованная цифра не равна нулю, а bigint положительно, тогда a '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) строки сложнее. Проблема в том, что восьмеричные цифры представляют собой три бита, которые даже не кратны восьми битам, содержащимся в каждом элементе массива байтов, созданного BigInteger.ToByteArray(). Чтобы решить эту проблему, три байта из массива объединяются в куски по 24 бита. Каждый 24-битный фрагмент равномерно преобразуется в восемь восьмеричных символов.

первый 24-битный кусок требует некоторого математического модуля:

var extra = bytes.Length % 3;

это вычисление определяет, сколько байтов являются "дополнительными", когда весь массив байтов разделен на трехбайтовые (24-битные) куски. Первое преобразование в восьмеричный (наиболее значимые цифры) получает "дополнительные" байты, так что все остальные преобразования получат три байта каждый.

если нет "дополнительных" байтов, то первый кусок получает полные три байта:

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, 4, 8, 16), массив байтов, созданный BigInteger.ToByteArray() можно соответствующим образом разделить на куски битов и преобразовать.

однако, если число не является степенью двух, проблема становится гораздо более сложной и требует много циклов и раздела. Как таковая номерная база конверсии редки, я только охватил популярные вычислительные базы номеров здесь.


после хорошего долгого дня работы с 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


Это простой метод для преобразования 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 форма согласно основанию перед вводить его.