示例#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
        /// <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);
        }