/// <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); }
public static void baseConvert(IList <int> from, IList <int> to, int fromBase, int newBase) { // проверяем, не кратное ли основание int?power; if (WhiteMath <int, CalcInt> .IsNaturalIntegerPowerOf(fromBase, newBase, out power) || WhiteMath <int, CalcInt> .IsNaturalIntegerPowerOf(newBase, fromBase, out power)) { convertPowered(from, to, fromBase, newBase, power.Value); } // в противном случае - не избежать последовательного деления. else { int k = 0; IList <int> divide = from; while (divide.CountSignificant() > 1 || divide[0] > 0) { int remainder; divide = LongIntegerMethods.DivideByInteger(fromBase, divide, newBase, out remainder); to[k++] = remainder; } } }
// --------------------------------------------------------------------- private static void MultiplyKaratsuba(int BASE, IList <int> result, IList <int> one, IList <int> two, int dim) { int half = dim / 2; // Отбрасываем при некотором значении if (dim <= karatsubaCutoffDimension) { LongIntegerMethods.MultiplySimple(BASE, result, one, two); return; } ListSegment <int> a = new ListSegment <int>(one, 0, half); ListSegment <int> b = new ListSegment <int>(one, half, one.Count - half); ListSegment <int> c = new ListSegment <int>(two, 0, half); ListSegment <int> d = new ListSegment <int>(two, half, two.Count - half); int[] ac = new int[dim]; int[] bd = new int[b.Count + d.Count]; int[] abcd = new int[b.Count + d.Count + 2]; MultiplyKaratsuba(BASE, ac, a, c, half); MultiplyKaratsuba(BASE, bd, b, d, half); int[] apb = new int[b.Count + 1]; int[] cpd = new int[d.Count + 1]; int[] acpbd = new int[b.Count + d.Count + 2]; LongIntegerMethods.Sum(BASE, apb, a, b); LongIntegerMethods.Sum(BASE, cpd, c, d); MultiplyKaratsuba(BASE, abcd, apb, cpd, half); LongIntegerMethods.Sum(BASE, acpbd, ac, bd); int[] difference = new int[b.Count + d.Count + 2]; if (LongIntegerMethods.Dif(BASE, difference, abcd, acpbd)) { Console.WriteLine("Lower-level difference error."); } SumPrivate(BASE, result, ac, 0, difference, half); SumPrivate(BASE, result, result, 0, bd, dim); return; }
//--------------------------------------------------------------- //---------------------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> /// Performs the division (with remainder) of two long integer numbers. /// The method would return the list containing the remainder digits. /// </summary> /// <returns>The list containing the remainder digits.</returns> /// <param name="BASE">The numberic base of the digits, ex. 10 000</param> /// <param name="result">The digits array to store the result. WARNING! Should be able to store AT LEAST one.Count - two.Count + 1 digits.</param> /// <param name="one">The digits array containing the first operand.</param> /// <param name="two">The digits array containing the second operand.</param> public static IList <int> Div(int BASE, IList <int> result, IList <int> one, IList <int> two) { Contract.Requires <ArgumentNullException>(result != null, "result"); Contract.Requires <ArgumentNullException>(one != null, "one"); Contract.Requires <ArgumentNullException>(two != null, "two"); Contract.Requires(Contract.ForAll(one, x => x >= 0)); // first contains only positive digits Contract.Requires(Contract.ForAll(two, x => x >= 0)); // second contains only positive digits Contract.Ensures(Contract.Result <IList <int> >() != null); // remainder's not null Contract.Ensures(Contract.ForAll(Contract.Result <IList <int> >(), x => x >= 0)); // remainder has positive digits Contract.Ensures(Contract.ForAll(result, x => x >= 0)); // quot has positive digits // Обнуляем результат result.FillByAssign(0); // ------------------ IList <int> u, v; int uShift, vShift, i; long temp, temp1, temp2; int scale; int qGuess, remainder; int borrow, carry; // Проверим, надо ли домножать. // Если да - увы, надо выделять дополнительную память. scale = BASE / (two[two.CountSignificant() - 1] + 1); if (scale > 1) { u = new int[one.Count + 2]; v = new int[two.Count + 2]; int[] scaleAr = new int[] { scale }; MultiplySimple(BASE, u, one, scaleAr); MultiplySimple(BASE, v, two, scaleAr); } else { // Число будет "портиться", поэтому нужно создать хоть копию. u = new int[one.CountSignificant() + 1]; General.ServiceMethods.Copy(one, 0, u, 0, u.Count - 1); // Делитель портиться не будет. v = two; } // ------------ int n = v.CountSignificant(); int m = u.CountSignificant() - n; // ------------ // Добавлено -1 for (vShift = m, uShift = n + vShift; vShift >= 0; --vShift, --uShift) { qGuess = (int)(((long)u[uShift] * BASE + u[uShift - 1]) / v[n - 1]); remainder = (int)(((long)u[uShift] * BASE + u[uShift - 1]) % v[n - 1]); while (remainder < BASE) { temp2 = (long)v[n - 2] * qGuess; temp1 = (long)remainder * BASE + u[uShift - 2]; if ((temp2 > temp1) || (qGuess == BASE)) { --qGuess; remainder += v[n - 1]; } else { break; } } // Теперь qGuess - правильное частное или на единицу больше q // Вычесть делитель B, умноженный на qGuess из делимого U, // начиная с позиции vJ+i carry = 0; borrow = 0; // цикл по цифрам two for (i = 0; i < n; i++) { // получить в temp цифру произведения B*qGuess temp1 = (long)v[i] * qGuess + carry; carry = (int)(temp1 / BASE); temp1 -= (long)carry * BASE; // Сразу же вычесть из U temp2 = (long)u[i + vShift] - temp1 + borrow; if (temp2 < 0) { u[i + vShift] = (int)(temp2 + BASE); borrow = -1; } else { u[i + vShift] = (int)temp2; borrow = 0; } } // возможно, умноженое на qGuess число B удлинилось. // Если это так, то после умножения остался // неиспользованный перенос carry. Вычесть и его тоже. temp2 = (long)u[i + vShift] - carry + borrow; if (temp2 < 0) { u[i + vShift] = (int)temp2 + BASE; borrow = -1; } else { u[i + vShift] = (int)temp2; borrow = 0; } // Прошло ли вычитание нормально ? if (borrow == 0) { // Да, частное угадано правильно result[vShift] = qGuess; } else { // Нет, последний перенос при вычитании borrow = -1, // значит, qGuess на единицу больше истинного частного result[vShift] = qGuess - 1; // добавить одно, вычтенное сверх необходимого B к U carry = 0; for (i = 0; i < n; i++) { temp = (long)u[i + vShift] + v[i] + carry; if (temp >= BASE) { u[i + vShift] = (int)(temp - BASE); carry = 1; } else { u[i + vShift] = (int)temp; carry = 0; } } u[i + vShift] = u[i + vShift] + carry - BASE; } // Обновим размер U, который после вычитания мог уменьшиться // i = u.Length - 1; // while ((i > 0) && (u[i] == 0)) // u.digits.RemoveAt(i--); } // Возвращаем остаток. // Только надо поделить на scale. int[] remDigits = new int[u.Count]; LongIntegerMethods.DivideByInteger(BASE, remDigits, u, scale); return(remDigits); }