#c_sharp
private uint[] Bits; //Массив в котором хранятся коэффициенты разложения числа в обратном подядке private int Sign; //Отвечает за знак числа private int Length; //Длина массива public const Int64 Base = (long)UInt32.MaxValue + 1; //Основание системы счисление 2^32 public BigInt(UInt64 value) //Один из конструкторов { Sign = 1; if (value <= Int32.MaxValue) { Bits = new uint[] { (uint)value }; Length = 1; } else { Bits = new uint[2]; Bits[0] = unchecked((uint)value); Bits[1] = (uint)(value >> 32); Length = 2; } } public static BigInt Multiplication(BigInt x, BigInt y) //Сам алгоритм умножения "в столбик" { uint[] result = new uint[x.Length + y.Length]; ulong c = 0; for(int i = 0; i < y.Length; i++) { ulong d = 0; int j = 0; for(; j < x.Length; j++) { c = (d + ((ulong)x.Bits[j] * (ulong)y.Bits[i]) + result[i+j]) % Base; d = (d + ((ulong)x.Bits[j] * (ulong)y.Bits[i]) + result[i+j]) / Base; result[i + j] = (uint)c; } result[i + j] = (uint)d; } result = Normalize(result); return new BigInt(result, 1); } При умножении BigInt test = new BigInt(UInt64.MaxValue); test *= new BigInt(UInt64.MaxValue); Я получаю BigInt, в котором массив Bits = {1, 0, 4294967294, 4294967295} то есть в десятичной системе счисления 340282366920938463426481119288644075520. А как мне получить это число из массива Bits? То есть примерно что-то такое должно быть. public string ToString(BigInt value) { string result = ""; if (value.Sign == -1) result += "-"; //Сам алгоритм return result; }
Ответы
Ответ 1
Код основан на моей имплементации BigInteger: https://github.com/Zergatul/ZergatulLib/blob/master/Zergatul/Math/BigInteger.cs#L737 // деление числа в системе 2^32 на uint // возвращает частное в системе 2^32 // его длину // и остаток private static (uint[], int, uint) DivideByUInt32(uint[] dividend, uint divisor) { var quotient = new uint[dividend.Length]; long remainder = 0; for (int i = quotient.Length - 1; i >= 0; i--) { remainder = (remainder << 32) | dividend[i]; quotient[i] = (uint)(remainder / divisor); remainder = remainder % divisor; } int length = dividend.Length; while (length > 0 && quotient[length - 1] == 0) length--; return (quotient, length, (uint)remainder); } static void Main(string[] args) { uint[] x = new uint[] { 1, 0, 4294967294, 4294967295 }; // самое длинное число 10^RadixLength, которое помещается в uint const uint RadixUInt32 = 1000000000; const uint RadixLength = 9; int length = x.Length; var sb = new StringBuilder(); while (length > 0) // пока длина частного > 0 { uint remainder; // делим (x, length, remainder) = DivideByUInt32(x, RadixUInt32); // добавляем остаток в результат sb.Insert(0, remainder.ToString().PadLeft(RadixLength, '0')); } Console.WriteLine(sb.ToString()); } Результат: 000000340282366920938463426481119284349108225 Код придется доделать, но основная идея должна быть понятна. Операции с целыми числами сведены к минимуму, нужно оптимизировать работу с памятью (не использовать StringBuilder с динамическим размером, не создавать массив каждый раз в методе DivideByUInt32).
Комментариев нет:
Отправить комментарий