Exemplo n.º 1
0
 /// <summary>
 /// Вычитание с учетом знака
 /// </summary>
 /// <param name="value">Вычитаемое</param>
 /// <returns>Разность</returns>
 public BigInteger Substract(BigInteger value)
 {
     if (this.sign && value.sign)
     {
         return(this.AbsSubstract(value));
     }
     else if (!this.sign && value.sign)
     {
         BigInteger ans = this;
         ans.ChangeSign(true);
         ans = ans.AbsAdd(value);
         ans.ChangeSign(false);
         return(ans);
     }
     else if (this.sign && !value.sign)
     {
         BigInteger ans = value;
         ans.ChangeSign(true);
         ans = this.AbsAdd(ans);
         return(ans);
     }
     else
     {
         BigInteger ans1 = value;
         BigInteger ans2 = this;
         ans1.ChangeSign(true);
         ans2.ChangeSign(true);
         ans1 = ans1.Substract(ans2);
         return(ans1);
     }
 }
Exemplo n.º 2
0
        /// <summary>
        /// Делим большое число на большое с учетом знака
        /// </summary>
        /// <param name="q">Частное q[m]..q[0]</param>
        /// <param name="r">Остаток r[n - 1]..r[0]</param>
        /// <param name="u">u[m + n - 1]..u[0] — делимое по основанию b</param>
        /// <param name="v">v[n - 1]..v[0] — делитель по основанию b</param>
        /// <returns></returns>
        private static int Divide(out BigInteger q, out BigInteger r, BigInteger u, BigInteger v)
        {
            int ans = AbsDivide(out q, out r, u, v);

            if ((u.sign && v.sign) || (!u.sign && !v.sign))
            {
                return(ans);
            }
            q.ChangeSign(!q.sign);
            r.ChangeSign(!r.sign);
            return(ans);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Умножение с учетом знака
        /// </summary>
        /// <param name="value">На что умножаем</param>
        /// <returns>Произведение</returns>
        public BigInteger Multiply(int value)
        {
            BigInteger ans = this.AbsMultiply(Math.Abs(value));

            if (this.sign && value >= 0 || !this.sign && value < 0)
            {
                return(ans);
            }

            ans.ChangeSign(false);
            return(ans);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Умножение больших чисел с учетом знака
        /// </summary>
        /// <param name="value">На что умножаем</param>
        /// <returns>Произведение</returns>
        public BigInteger Multiply(BigInteger value)
        {
            BigInteger a = this;
            BigInteger b = value;
            BigInteger ans;

            if (a.sign && b.sign)
            {
                return(a.AbsMultiply(b));
            }
            else if (!a.sign && !b.sign)
            {
                a.ChangeSign(true);
                b.ChangeSign(true);
                ans = a.AbsMultiply(b);
                a.ChangeSign(false);
                b.ChangeSign(false);
                return(ans);
            }
            else if (!a.sign)
            {
                a.ChangeSign(true);
                b      = a.AbsMultiply(b);
                b.sign = false;
                a.ChangeSign(false);
                return(b);
            }
            else
            {
                b.sign = true;
                a      = a.AbsMultiply(b);
                a.sign = false;
                b.sign = false;
                return(a);
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Деление большого числа на маленькое с учетом знака
        /// </summary>
        /// <param name="v">Делитель</param>
        /// <param name="r">Остаток</param>
        /// <returns>Частное</returns>
        public BigInteger Divide(int v, out int r)
        {
            if (v == 0)
            {
                throw new Exception("divide by zero");
            }
            BigInteger ans = this.AbsDivide(Math.Abs(v), out r);

            if ((this.sign && v > 0) || (!this.sign && v < 0))
            {
                return(ans);
            }
            ans.ChangeSign(false);
            r = -r;
            return(ans);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Сложение с учетом знака
        /// </summary>
        /// <param name="value">С чем складываем</param>
        /// <returns>Результат</returns>
        public BigInteger Add(BigInteger value)
        {
            if (this.sign && value.sign)
            {
                return(this.AbsAdd(value));
            }
            if (!this.sign && value.sign)
            {
                return(value.AbsSubstract(this));
            }
            if (this.sign && !value.sign)
            {
                return(this.AbsSubstract(value));
            }
            BigInteger ans = this.AbsAdd(value);

            ans.ChangeSign(false);
            return(ans);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Вычитание
        /// </summary>
        /// <param name="value">Вычитаемое</param>
        /// <returns>Разность</returns>
        public BigInteger AbsSubstract(BigInteger value)
        {
            //Если второе число больше первого
            if (this.CompareTo(value) == -1)
            {
                BigInteger tmp = value.Substract(this);
                tmp.ChangeSign(false);
                return(tmp);
            }

            //Значение переноса
            int k = 0;

            //Максимальная длина числа
            int n = Math.Max(arr.Count, value.arr.Count);

            //Результирующий массив
            List <int> ans = new List <int>();

            //Временное значение i-го разряда из первого и второго числа
            int tmp1, tmp2;

            for (int i = 0; i < n; i++)
            {
                tmp1 = (arr.Count > i) ? arr[i] : 0;
                tmp2 = (value.arr.Count > i) ? value.arr[i] : 0;

                ans.Add(tmp1 - tmp2 - k);

                if (ans[i] < 0)
                {
                    ans[i] += mybase;
                    k       = 1;
                }
                else
                {
                    k = 0;
                }
            }

            return(new BigInteger(Normalize(ans), true));
        }
Exemplo n.º 8
0
        /// <summary>
        /// Алгоритм Кнута деления длинных чисел
        /// </summary>
        /// <param name="q">Частное q[m]..q[0]</param>
        /// <param name="r">Остаток r[n - 1]..r[0]</param>
        /// <param name="u">u[m + n - 1]..u[0] — делимое по основанию b</param>
        /// <param name="v">v[n - 1]..v[0] — делитель по основанию b</param>
        public static int AbsDivide(out BigInteger q, out BigInteger r, BigInteger u, BigInteger v)
        {
            //Начальная инициализация
            int n = v.arr.Count;
            int m = u.arr.Count - v.arr.Count;

            int[] tempArray = new int[m + 1];
            tempArray[m] = 1;
            q            = new BigInteger(tempArray, true);

            /* 1. НОРМАЛИЗАЦИЯ
             * Нам необходимо преобразовать делимое и делитель,
             * умножив на коэффициент d. d = [b/(v[n-1]+1)] и умножаем.
             * Если d=1, то добавляем нулевой разряд u[m+n]=0 */
            int d = (mybase / (v.arr[n - 1] + 1));

            u = u.Multiply(d);
            v = v.Multiply(d);

            //Проверка на d==1
            if (u.arr.Count == n + m)
            {
                u.arr.Add(0);
            }

            //2. Начальная установка j. j = m
            int j = m;

            //Цикл по j
            while (j >= 0)
            {
                /*3. Вычислить временное q. tempq=[(u[j+n]*b+u[j+n-1])/v[n-1]],
                 * tempr — остаток от такого деления. Если tempq=b или q*v[n-2]>b*tempr + u[j+n-2],
                 * то tempq = tempq — 1 и tempr = tempr + v[n-1]. Необходимо повторять данную проверку
                 * пока temr < b*/
                long cur   = (long)(u.arr[j + n]) * (long)(mybase) + u.arr[j + n - 1];
                int  tempq = (int)(cur / v.arr[n - 1]);//нормализация помогает не выпрыгнуть за границу типа
                int  tempr = (int)(cur % v.arr[n - 1]);
                do
                {
                    if (tempq == mybase || (long)tempq * (long)v.arr[n - 2] > (long)mybase * (long)tempr + u.arr[j + n - 2])
                    {
                        tempq--;
                        tempr += v.arr[n - 1];
                    }
                    else
                    {
                        break;
                    }
                }while (tempr < mybase);

                /*4. Умножить и вычесть. u[j+n]..u[j] = u[j+n]..u[j] — tempq * v[n-1].. v[0]. Значение разрядов должно быть
                 * всегда положительным, поэтому если мы получаем отрицательный разряд, то должны
                 * прибавить b^(n+1). Причем следует запомнить заимствование слева из старшего разряда.*/
                BigInteger u2 = new BigInteger(u.arr.GetRange(j, n + 1), true);
                u2 = u2.Substract(v.Multiply(tempq));
                bool flag = false;
                if (!u2.sign) //если отрицательные
                {
                    flag = true;
                    List <int> bn = new List <int>();
                    for (int i = 0; i <= n; i++)
                    {
                        bn.Add(0);
                    }
                    bn.Add(1);
                    u2.ChangeSign(true);
                    u2 = new BigInteger(bn, true).Substract(u2);
                }

                /*5.Проверка остатка
                 * q[j] = tempq. Если результат 4 — го шага был отрицательным, то перейти к шагу 6, иначе к шагу 7.*/
                q.arr[j] = tempq;
                if (flag)
                { /*6.Компенсировать сложение. Вероятность данного шага очень мала, а именно r/b,
                   * т.е при большой базе вы очень редко будете попадать в отрицательные числа.
                   * q[j] = q[j] — 1. u[j+n]..u[j] = u[j+n]..u[j] + v[n-1]..v[0], при этом произойдет
                   * перенос в разряд слева от u[j+n], но им следует пренебречь, так как перенос погашается
                   * заимствованием из того же разряда произведенном на шаге 4.*/
                    q.arr[j]--;
                    u2 = u2.Add(v);
                    if (u2.arr.Count > n + j)
                    {
                        u2.arr.RemoveAt(n + j);
                    }
                }
                //меняем u, так как все вычисления происходят с его разрядами
                /*7.Цикл по j. j уменьшаем на 1. Если j>=0, то вернуться к шагу 3.*/
                for (int h = j; h < j + n; h++)
                {
                    if (h - j >= u2.arr.Count)
                    {
                        u.arr[h] = 0;
                    }
                    else
                    {
                        u.arr[h] = u2.arr[h - j];
                    }
                }
                j--;
            }
            Normalize(q.arr);
            //8.Денормализация
            /*q[m]..q[0] — искомое частное, а для получения искомого остатка достаточно u[n-1]..u[0]/d*/
            int unusedR = 0;

            r = new BigInteger(u.arr.GetRange(0, n), true).Divide(d, out unusedR);
            return(0);
        }