Здравствуйте, 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);
}
}
}