/// <summary> /// Performs the division (with remainder) of two long integer numbers. /// </summary> /// <param name="one">The first LongInt number.</param> /// <param name="two">The second LongInt number.</param> /// <param name="remainder">The reference to contain the remainder.</param> /// <returns>The result of integral division.</returns> public static LongInt <B> Div(LongInt <B> one, LongInt <B> two, out LongInt <B> remainder) { Contract.Requires <ArgumentNullException>(one != null, "one"); Contract.Requires <ArgumentNullException>(two != null, "two"); Contract.Ensures(Contract.ForAll(Contract.Result <LongInt <B> >().Digits, x => (x >= 0))); // Проверка на тупые случаи - деление на большее число или деление на единичную цифру. if (one.Length < two.Length) { remainder = one.Clone() as LongInt <B>; return(new LongInt <B>()); // zero number should be returned } if (two.Length == 1) { LongInt <B> result = new LongInt <B>(one.Length); result.Digits.AddRange(new int[one.Length]); int rem = LongIntegerMethods.DivideByInteger(LongInt <B> .BASE, result.Digits, one.Digits, two[0]); // Разберемся с negativeness. remainder = (LongInt <B>)rem; // convert the result to LongInt... result.Negative = one.Negative ^ two.Negative; remainder.Negative = one.Negative; result.DealWithZeroes(); remainder.DealWithZeroes(); return(result); } LongInt <B> res = new LongInt <B>(); res.Digits.AddRange(new int[one.Length - two.Length + 1]); remainder = new LongInt <B>(two.Length); // ----- big bada-boom! IList <int> remDigits = LongIntegerMethods.Div(LongInt <B> .BASE, res.Digits, one.Digits, two.Digits); // -------------------- remainder.Digits.AddRange(remDigits); // deal with negativeness res.Negative = one.Negative ^ two.Negative; remainder.Negative = one.Negative; // deal with zeroes res.DealWithZeroes(); remainder.DealWithZeroes(); return(res); }
// THIS SHOULD BE OPTIMIZED FOR KARATSUBA MULTIPLICATION BY METHOD BELOW // --------------------------------------------------------------------- /// <summary> /// The Karatsuba multiplying algorithm. /// The lengths of numbers are completed to the nearest bigger power of 2. /// </summary> /// <param name="one"></param> /// <param name="two"></param> /// <returns></returns> public static LongInt <B> MultiplyKaratsuba(LongInt <B> one, LongInt <B> two) { LongInt <B> bigger = one.Length > two.Length ? one : two; int twoPower = 1; // Последовательное умножение на два, пока // не достигнем нужной длины. while (bigger.Length > twoPower) { twoPower <<= 1; } LongInt <B> result = new LongInt <B>(); result.Negative = one.Negative ^ two.Negative; result.Digits.AddRange(new int[twoPower * 2]); one.Digits.AddRange(new int[twoPower - one.Length]); two.Digits.AddRange(new int[twoPower - two.Length]); MultiplyKaratsuba(LongInt <B> .BASE, result.Digits, one.Digits, two.Digits, twoPower); result.DealWithZeroes(); one.DealWithZeroes(); two.DealWithZeroes(); return(result); }
/// <summary> /// Returns the next non-negative <c>LongInt<<typeparamref name="B"/>></c> /// number which is less than <paramref name="maxExclusive"/>. /// </summary> /// <param name="maxExclusive">The upper exclusive bound of generated numbers.</param> /// <returns> /// A non-negative <c>LongInt<<typeparamref name="B"/>></c> number which /// is less than <paramref name="maxExclusive"/>. /// </returns> public LongInt <B> Next(LongInt <B> maxExclusive) { Contract.Requires <ArgumentNullException>(maxExclusive != null, "maxExclusive"); Contract.Requires <ArgumentOutOfRangeException>(maxExclusive > 0, "The maximum exclusive bound should be a positive number."); LongInt <B> basePowered = LongInt <B> .CreatePowerOfBase(maxExclusive.Length); LongInt <B> upperBound; if (this.lastMaxExclusive != maxExclusive) { // Мы будем генерировать ВСЕ цифры от 0 до BASE - 1. // НО: // Мы отбрасываем верхнюю границу, где приведение по модулю maxExclusive // даст нам лишнюю неравномерность. // Мы можем использовать только интервал, содержащий целое число чисел maxExclusive. // Тогда спокойно приводим по модулю и наслаждаемся равномерностью. // Например, если мы генерируем цифирки по основанию 10, и хотим число от [0; 12), // то нам нужно отбрасывать начиная с floor(10^2 / 12) * 12 = 96. upperBound = Max_BinarySearch((LongInt <B>) 1, LongInt <B> .BASE, (res => LongInt <B> .Helper.MultiplyFFTComplex(res, maxExclusive) <= basePowered)) * maxExclusive; // upperBound = multiplication(basePowered / maxExclusive, maxExclusive); this.lastMaxExclusive = maxExclusive; this.lastBound = upperBound; } else { upperBound = this.lastBound; } LongInt <B> result = new LongInt <B>(); REPEAT: result.Digits.Clear(); for (int i = 0; i < maxExclusive.Length; i++) { result.Digits.Add(intGenerator.Next(0, LongInt <B> .BASE)); } result.DealWithZeroes(); if (result >= upperBound) { ++TotalRejected; goto REPEAT; } // Возвращаем остаток от деления. // return result % maxExclusive; LongInt <B> divisionResult = Max_BinarySearch((LongInt <B>) 0, LongInt <B> .BASE, (res => LongInt <B> .Helper.MultiplyFFTComplex(res, maxExclusive) <= result)); return(result - LongInt <B> .Helper.MultiplyFFTComplex(divisionResult, maxExclusive)); }
public static LongInt <B> MultiplyFFTComplex(LongInt <B> one, LongInt <B> two, out double maxRoundError, out double maxImaginaryPart, out long maxLong) { LongInt <B> res = new LongInt <B>(one.Length + two.Length); res.Negative = one.Negative ^ two.Negative; long[] resultOverflowProne = new long[one.Length + two.Length]; MultiplyFFTComplex(LongInt <B> .BASE, resultOverflowProne, one.Digits, two.Digits, out maxRoundError, out maxImaginaryPart, out maxLong); for (int i = 0; i < resultOverflowProne.Length; i++) { res.Digits.Add((int)resultOverflowProne[i]); } res.DealWithZeroes(); return(res); }
//--------------------------------------------------------------- //---------------------NUMBER MULTIPLICATION--------------------- //--------------------------------------------------------------- /// <summary> /// Performs a simple, square-complex multiplication of two LongInt numbers. /// </summary> /// <param name="one"></param> /// <param name="two"></param> /// <returns></returns> public static LongInt <B> MultiplySimple(LongInt <B> one, LongInt <B> two) { // the resulting number can have double length. LongInt <B> res = new LongInt <B>(one.Length + two.Length); res.Digits.AddRange(new int[one.Length + two.Length]); res.Negative = one.Negative ^ two.Negative; // The big one LongIntegerMethods.MultiplySimple(LongInt <B> .BASE, res.Digits, one.Digits, two.Digits); // Cut the leading zeroes res.DealWithZeroes(); return(res); }
/// <summary> /// Computes the product of two long integer numbers using NTT in finite fields. /// /// The numbers are not necessarily required to be of two's power long; /// this algorithm performs all needed operations automatically. /// </summary> /// <param name="one"></param> /// <param name="two"></param> public static LongInt <B> MultiplyNTT(LongInt <B> one, LongInt <B> two) { Contract.Requires <ArgumentNullException>(one != null, "one"); Contract.Requires <ArgumentNullException>(two != null, "two"); LongInt <B> result = new LongInt <B>(one.Length + two.Length); long[] longResult = new long[one.Length + two.Length]; MultiplyNTT(LongInt <B> .BASE, longResult, one.Digits, two.Digits); for (int i = 0; i < longResult.Length; i++) { result.Digits.Add((int)longResult[i]); } result.Negative = one.Negative ^ two.Negative; result.DealWithZeroes(); return(result); }
/// <summary> /// Returns the next non-negative <c>LongInt<<typeparamref name="B"/>></c> /// number which is not bigger than <paramref name="maxInclusive"/>. /// </summary> /// <param name="maxInclusive">The upper inclusive bound of generated numbers.</param> /// <returns> /// A non-negative <c>LongInt<<typeparamref name="B"/>></c> number which /// is not bigger than <paramref name="maxInclusive"/>. /// </returns> public LongInt <B> NextInclusive(LongInt <B> maxInclusive) { Contract.Requires <ArgumentNullException>(maxInclusive != null, "maxInclusive"); Contract.Requires <ArgumentOutOfRangeException>(!maxInclusive.Negative, "The maximum inclusive number should not be negative."); // Будем генерировать числа длины такой же, как maxInclusive. // Все цифры - от 0 до BASE - 1 LongInt <B> result = new LongInt <B>(); result.Digits.Clear(); result.Digits.AddRange(new int[maxInclusive.Length]); bool flag = true; // есть ли ограничение по цифрам REPEAT: for (int i = maxInclusive.Length - 1; i >= 0; i--) { result.Digits[i] = intGenerator.Next(0, LongInt <B> .BASE); if (flag) { if (result[i] > maxInclusive[i]) { ++TotalRejected; goto REPEAT; } else if (result[i] < maxInclusive[i]) { flag = false; } } } result.DealWithZeroes(); return(result); }
/// <summary> /// Returns the next non-negative <c>LongInt<<typeparamref name="B"/>></c> /// number which is less than <paramref name="maxExclusive"/>. /// </summary> /// <param name="maxExclusive">The upper exclusive bound of generated numbers.</param> /// <returns> /// A non-negative <c>LongInt<<typeparamref name="B"/>></c> number which /// is less than <paramref name="maxExclusive"/>. /// </returns> public LongInt <B> Next(LongInt <B> maxExclusive) { Contract.Requires <ArgumentNullException>(maxExclusive != null, "maxExclusive"); Contract.Requires <ArgumentOutOfRangeException>(maxExclusive > 0, "The maximum exclusive bound should be a positive number."); // Мы будем генерировать ВСЕ цифры от 0 до BASE - 1. // НО: // Мы отбрасываем верхнюю границу, где приведение по модулю maxExclusive // даст нам лишнюю неравномерность. // Мы можем использовать только интервал, содержащий целое число чисел maxExclusive. // Тогда спокойно приводим по модулю и наслаждаемся равномерностью. // Например, если мы генерируем цифирки по основанию 10, и хотим число от [0; 12), // то нам нужно отбрасывать начиная с floor(10^2 / 12) * 12 = 96. LongInt <B> upperBound = (LongInt <B> .CreatePowerOfBase(maxExclusive.Length) / maxExclusive) * maxExclusive; LongInt <B> result = new LongInt <B>(); REPEAT: result.Digits.Clear(); for (int i = 0; i < maxExclusive.Length; i++) { result.Digits.Add(intGenerator.Next(0, LongInt <B> .BASE)); } result.DealWithZeroes(); if (result >= upperBound) { ++TotalRejected; goto REPEAT; } return(result % maxExclusive); }
/// <summary> /// Returns the next non-negative <c>LongInt<<typeparamref name="B"/>></c> /// number which is not bigger than <paramref name="maxInclusive"/>. /// </summary> /// <param name="maxInclusive">The upper inclusive bound of generated numbers.</param> /// <returns> /// A non-negative <c>LongInt<<typeparamref name="B"/>></c> number which /// is not bigger than <paramref name="maxInclusive"/>. /// </returns> public LongInt <B> NextInclusive(LongInt <B> maxInclusive) { Contract.Requires <ArgumentNullException>(maxInclusive != null, "maxInclusive"); Contract.Requires <ArgumentException>(!maxInclusive.Negative, "The maximum inclusive bound should not be negative."); LongInt <B> result = new LongInt <B>(); result.Digits.Clear(); result.Digits.AddRange(new int[maxInclusive.Length]); // Флаг, сигнализирующий о том, что мы пока генерируем // только цифры нашей верхней границы. // Как только сгенерировали что-то меньшее, все остальное // можно генерировать в пределах от 0 до BASE-1. bool flag = true; for (int i = result.Length - 1; i >= 0; i--) { if (flag) { result[i] = intGenerator.Next(0, maxInclusive[i] + 1); if (result[i] < maxInclusive[i]) { flag = false; } } else { result[i] = intGenerator.Next(0, LongInt <B> .BASE); } } result.DealWithZeroes(); return(result); }