Esempio n. 1
0
File: IntNum.cs Progetto: vic/ioke
 /** Add an IntNum and an int, yielding a new IntNum. */
 public static IntNum add(IntNum x, int y)
 {
     if (x.words == null)
         return IntNum.add (x.ival, y);
     IntNum result = new IntNum (0);
     result.setAdd (x, y);
     return result.canonicalize ();
 }
Esempio n. 2
0
File: IntNum.cs Progetto: vic/ioke
        /** Divide two integers, yielding quotient and remainder.
         * @param x the numerator in the division
         * @param y the denominator in the division
         * @param quotient is set to the quotient of the result (iff quotient!=null)
         * @param remainder is set to the remainder of the result
         *  (iff remainder!=null)
         * @param rounding_mode one of FLOOR, CEILING, TRUNCATE, or ROUND.
         */
        public static void divide(IntNum x, IntNum y,
                                   IntNum quotient, IntNum remainder,
                                   int rounding_mode)
        {
            if ((x.words == null || x.ival <= 2)
                && (y.words == null || y.ival <= 2))
                {
                    long x_l = x.longValue ();
                    long y_l = y.longValue ();
                    if (x_l != long.MinValue && y_l != long.MinValue)
                        {
                            divide (x_l, y_l, quotient, remainder, rounding_mode);
                            return;
                        }
                }

            bool xNegative = x.isNegative ();
            bool yNegative = y.isNegative ();
            bool qNegative = xNegative ^ yNegative;

            int ylen = y.words == null ? 1 : y.ival;
            int[] ywords = new int[ylen];
            y.getAbsolute (ywords);
            while (ylen > 1 && ywords[ylen-1] == 0)  ylen--;

            int xlen = x.words == null ? 1 : x.ival;
            int[] xwords = new int[xlen+2];
            x.getAbsolute (xwords);
            while (xlen > 1 && xwords[xlen-1] == 0)  xlen--;

            int qlen, rlen;

            int cmpval = MPN.cmp (xwords, xlen, ywords, ylen);
            if (cmpval < 0)  // abs(x) < abs(y)
                { // quotient = 0;  remainder = num.
                    int[] rwords = xwords;  xwords = ywords;  ywords = rwords;
                    rlen = xlen;  qlen = 1;  xwords[0] = 0;
                }
            else if (cmpval == 0)  // abs(x) == abs(y)
                {
                    xwords[0] = 1;  qlen = 1;  // quotient = 1
                    ywords[0] = 0;  rlen = 1;  // remainder = 0;
                }
            else if (ylen == 1)
                {
                    qlen = xlen;
                    rlen = 1;
                    ywords[0] = MPN.divmod_1 (xwords, xwords, xlen, ywords[0]);
                }
            else  // abs(x) > abs(y)
                {
                    // Normalize the denominator, i.e. make its most significant bit set by
                    // shifting it normalization_steps bits to the left.  Also shift the
                    // numerator the same number of steps (to keep the quotient the same!).

                    int nshift = MPN.count_leading_zeros (ywords[ylen-1]);
                    if (nshift != 0)
                        {
                            // Shift up the denominator setting the most significant bit of
                            // the most significant word.
                            MPN.lshift (ywords, 0, ywords, ylen, nshift);

                            // Shift up the numerator, possibly introducing a new most
                            // significant word.
                            int x_high = MPN.lshift (xwords, 0, xwords, xlen, nshift);
                            xwords[xlen++] = x_high;
                        }

                    if (xlen == ylen)
                        xwords[xlen++] = 0;
                    MPN.divide (xwords, xlen, ywords, ylen);
                    rlen = ylen;
                    MPN.rshift0 (ywords, xwords, 0, rlen, nshift);

                    qlen = xlen + 1 - ylen;
                    if (quotient != null)
                        {
                            for (int i = 0;  i < qlen;  i++)
                                xwords[i] = xwords[i+ylen];
                        }
                }

            while (rlen > 1 && ywords[rlen-1] == 0)
                rlen--;
            if (ywords[rlen-1] < 0)
                {
                    ywords[rlen] = 0;
                    rlen++;
                }

            // Now the quotient is in xwords, and the remainder is in ywords.

            bool add_one = false;
            if (rlen > 1 || ywords[0] != 0)
                { // Non-zero remainder i.e. in-exact quotient.
                    switch (rounding_mode)
                        {
                        case TRUNCATE:
                            break;
                        case CEILING:
                            if (qNegative == (rounding_mode == FLOOR))
                                add_one = true;
                            break;
                        case FLOOR:
                            if (qNegative == (rounding_mode == FLOOR))
                                add_one = true;
                            break;
                        case ROUND:
                            // int cmp = compare (remainder<<1, abs(y));
                            IntNum tmp = remainder == null ? new IntNum() : remainder;
                            tmp.set (ywords, rlen);
                            tmp = shift (tmp, 1);
                            if (yNegative)
                                tmp.setNegative();
                            int cmp = compare (tmp, y);
                            // Now cmp == compare(sign(y)*(remainder<<1), y)
                            if (yNegative)
                                cmp = -cmp;
                            add_one = (cmp == 1) || (cmp == 0 && (xwords[0]&1) != 0);
                            break;
                        }
                }
            if (quotient != null)
                {
                    if (xwords[qlen-1] < 0)
                        {
                            xwords[qlen] = 0;
                            qlen++;
                        }
                    quotient.set (xwords, qlen);
                    if (qNegative)
                        {
                            if (add_one)  // -(quotient + 1) == ~(quotient)
                                quotient.setInvert ();
                            else
                                quotient.setNegative ();
                        }
                    else if (add_one)
                        quotient.setAdd (1);
                }
            if (remainder != null)
                {
                    // The remainder is by definition: X-Q*Y
                    remainder.set (ywords, rlen);
                    if (add_one)
                        {
                            // Subtract the remainder from Y:
                            // abs(R) = abs(Y) - abs(orig_rem) = -(abs(orig_rem) - abs(Y)).
                            IntNum tmp;
                            if (y.words == null)
                                {
                                    tmp = remainder;
                                    tmp.set(yNegative ? ywords[0] + y.ival : ywords[0] - y.ival);
                                }
                            else
                                tmp = IntNum.add(remainder, y, yNegative ? 1 : -1);
                            // Now tmp <= 0.
                            // In this case, abs(Q) = 1 + floor(abs(X)/abs(Y)).
                            // Hence, abs(Q*Y) > abs(X).
                            // So sign(remainder) = -sign(X).
                            if (xNegative)
                                remainder.setNegative(tmp);
                            else
                                remainder.set(tmp);
                        }
                    else
                        {
                            // If !add_one, then: abs(Q*Y) <= abs(X).
                            // So sign(remainder) = sign(X).
                            if (xNegative)
                                remainder.setNegative ();
                        }
                }
        }