Информация об изменениях

Сообщение Re[5]: Хранение массива целых чисел от 03.04.2024 17:02

Изменено 03.04.2024 17:08 _FRED_

Истправил опечатку в имени идентификатора

Re[5]: Хранение массива целых чисел
Здравствуйте, merge, Вы писали:

_FR>>Например, числа записывать не в десятичном формате, а в 52-ричном (английский алфавит с прописными и заглавными буквами) или даже ещё больше, набор символов можно выбрать произвольный.

M>а есть готовые алгоритмы или либы для этого?

Да это школьная задачка:
internal static class NumberFormatter
{
  // 64-base alphabet: 10 digits, lower and upper letters (2x26), and @, and #
  private const string Characters = "0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ#abcdefghijklmnopqrstuvwxyz";

  private static readonly int Base = Characters.Length;
  private static readonly double LogBase = Math.Log(Base);

  private static readonly Encoding ThisEncoding = Encoding.ASCII;
  private static readonly byte[] ByteArray = ThisEncoding.GetBytes(Characters);
  private static readonly string[] StringsArray = Array.ConvertAll(Characters.ToArray(), ch => ch.ToString());

  private const int StackAllockLimit = 22; // 22 symbols in enough to represent UInt128.MaxValue with base 64

  public static string ToString<T>(T number) where T : IBinaryInteger<T>, IMinMaxValue<T> {
    var typedBase = T.CreateChecked(Base);
    if(number < typedBase) {
      var index = Int32.CreateChecked(number);
      return StringsArray[index];
    }//if

    var bufferArray = default(byte[]); // For huge numbers ;o)
    var length = GetResultLength(number);
    var buffer = length <= StackAllockLimit ? stackalloc byte[length] : (bufferArray = ArrayPool<byte>.Shared.Rent(length));
    try {
      var index = length - 1; // Populating the buffer from the last symbol to the first
      while(number > T.Zero) {
        (number, var modulo) = T.DivRem(number, typedBase);
        var characterIndex = Int32.CreateChecked(modulo);

        Debug.Assert(index >= 0, $"index {{{index}}} < 0");
        buffer[index] = ByteArray[characterIndex];
        index--;
      }//while

      return ThisEncoding.GetString(buffer);
    } finally {
      if(bufferArray is not null) {
        ArrayPool<byte>.Shared.Return(bufferArray, clearArray: true /* To be sure :o) Can be omitted in a trusted environment */);
      }//if
    }//try

    static int GetResultLength(T number) {
      var value = number < T.MaxValue ? number + T.One : number;
      var doubleValue = Double.CreateChecked(value);
      return (int)Math.Ceiling(Math.Log(doubleValue) / LogBase);
    }
  }
}
Re[5]: Хранение массива целых чисел
Здравствуйте, merge, Вы писали:

_FR>>Например, числа записывать не в десятичном формате, а в 52-ричном (английский алфавит с прописными и заглавными буквами) или даже ещё больше, набор символов можно выбрать произвольный.

M>а есть готовые алгоритмы или либы для этого?

Да это школьная задачка:
internal static class NumberFormatter
{
  // 64-base alphabet: 10 digits, lower and upper letters (2x26), and @, and #
  private const string Characters = "0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ#abcdefghijklmnopqrstuvwxyz";

  private static readonly int Base = Characters.Length;
  private static readonly double LogBase = Math.Log(Base);

  private static readonly Encoding ThisEncoding = Encoding.ASCII;
  private static readonly byte[] ByteArray = ThisEncoding.GetBytes(Characters);
  private static readonly string[] StringsArray = Array.ConvertAll(Characters.ToArray(), ch => ch.ToString());

  private const int StackAllocLimit = 22; // 22 symbols in enough to represent UInt128.MaxValue with base 64

  public static string ToString<T>(T number) where T : IBinaryInteger<T>, IMinMaxValue<T> {
    var typedBase = T.CreateChecked(Base);
    if(number < typedBase) {
      var index = Int32.CreateChecked(number);
      return StringsArray[index];
    }//if

    var bufferArray = default(byte[]); // For huge numbers ;o)
    var length = GetResultLength(number);
    var buffer = length <= StackAllocLimit ? stackalloc byte[length] : (bufferArray = ArrayPool<byte>.Shared.Rent(length));
    try {
      var index = length - 1; // Populating the buffer from the last symbol to the first
      while(number > T.Zero) {
        (number, var modulo) = T.DivRem(number, typedBase);
        var characterIndex = Int32.CreateChecked(modulo);

        Debug.Assert(index >= 0, $"index {{{index}}} < 0");
        buffer[index] = ByteArray[characterIndex];
        index--;
      }//while

      return ThisEncoding.GetString(buffer);
    } finally {
      if(bufferArray is not null) {
        ArrayPool<byte>.Shared.Return(bufferArray, clearArray: true /* To be sure :o) Can be omitted in a trusted environment */);
      }//if
    }//try

    static int GetResultLength(T number) {
      var value = number < T.MaxValue ? number + T.One : number;
      var doubleValue = Double.CreateChecked(value);
      return (int)Math.Ceiling(Math.Log(doubleValue) / LogBase);
    }
  }
}