Пример #1
0
            /// <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);
            }
Пример #2
0
        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;
                }
            }
        }
Пример #3
0
            // ---------------------------------------------------------------------

            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;
            }
Пример #4
0
            //---------------------------------------------------------------
            //---------------------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);
            }
Пример #5
0
        /// <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);
        }