Beispiel #1
0
 public static RatNum make(IntNum num, IntNum den)
 {
     IntNum g = IntNum.gcd (num, den);
     if (den.isNegative ())
         g = IntNum.neg (g);
     if (! g.isOne ())
         {
             num = IntNum.quotient (num, g);
             den = IntNum.quotient (den, g);
         }
     return den.isOne () ? (RatNum)num : (RatNum)(new IntFraction (num, den));
 }
Beispiel #2
0
 /** Calculate the integral power of an IntNum.
  * @param x the value (base) to exponentiate
  * @param y the exponent (must be non-negative)
  */
 public static IntNum power(IntNum x, int y)
 {
     if (y <= 0)
         {
             if (y == 0)
                 return one ();
             else
                 throw new Exception ("negative exponent");
         }
     if (x.isZero ())
         return x;
     int plen = x.words == null ? 1 : x.ival;  // Length of pow2.
     int blen = ((x.intLength () * y) >> 5) + 2 * plen;
     bool negative = x.isNegative () && (y & 1) != 0;
     int[] pow2 = new int [blen];
     int[] rwords = new int [blen];
     int[] work = new int [blen];
     x.getAbsolute (pow2);	// pow2 = abs(x);
     int rlen = 1;
     rwords[0] = 1; // rwords = 1;
     for (;;)  // for (i = 0;  ; i++)
         {
             // pow2 == x**(2**i)
             // prod = x**(sum(j=0..i-1, (y>>j)&1))
             if ((y & 1) != 0)
                 { // r *= pow2
                     MPN.mul (work, pow2, plen, rwords, rlen);
                     int[] tempx = work;  work = rwords;  rwords = tempx;
                     rlen += plen;
                     while (rwords[rlen-1] == 0)  rlen--;
                 }
             y >>= 1;
             if (y == 0)
                 break;
             // pow2 *= pow2;
             MPN.mul (work, pow2, plen, pow2, plen);
             int[] temp = work;  work = pow2;  pow2 = temp;  // swap to avoid a copy
             plen *= 2;
             while (pow2[plen-1] == 0)  plen--;
         }
     if (rwords[rlen-1] < 0)
         rlen++;
     if (negative)
         negate (rwords, rwords, rlen);
     return IntNum.make (rwords, rlen);
 }
Beispiel #3
0
 public static IntNum times(IntNum x, IntNum y)
 {
     if (y.words == null)
         return times(x, y.ival);
     if (x.words == null)
         return times(y, x.ival);
     bool negative = false;
     int[] xwords;
     int[] ywords;
     int xlen = x.ival;
     int ylen = y.ival;
     if (x.isNegative ())
         {
             negative = true;
             xwords = new int[xlen];
             negate(xwords, x.words, xlen);
         }
     else
         {
             negative = false;
             xwords = x.words;
         }
     if (y.isNegative ())
         {
             negative = !negative;
             ywords = new int[ylen];
             negate(ywords, y.words, ylen);
         }
     else
         ywords = y.words;
     // Swap if x is shorter then y.
     if (xlen < ylen)
         {
             int[] twords = xwords;  xwords = ywords;  ywords = twords;
             int tlen = xlen;  xlen = ylen;  ylen = tlen;
         }
     IntNum result = IntNum.alloc (xlen+ylen);
     MPN.mul (result.words, xwords, xlen, ywords, ylen);
     result.ival = xlen+ylen;
     if (negative)
         result.setNegative ();
     return result.canonicalize ();
 }
Beispiel #4
0
        /** 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 ();
                        }
                }
        }
Beispiel #5
0
 public static IntNum abs(IntNum x)
 {
     return x.isNegative () ? neg (x) : x;
 }
Beispiel #6
0
 void setShiftRight(IntNum x, int count)
 {
     if (x.words == null)
         set (count < 32 ? x.ival >> count : x.ival < 0 ? -1 : 0);
     else if (count == 0)
         set (x);
     else
         {
             bool neg = x.isNegative ();
             int word_count = count >> 5;
             count &= 31;
             int d_len = x.ival - word_count;
             if (d_len <= 0)
                 set (neg ? -1 : 0);
             else
                 {
                     if (words == null || words.Length < d_len)
                         realloc (d_len);
                     MPN.rshift0 (words, x.words, word_count, d_len, count);
                     ival = d_len;
                     if (neg)
                         words[d_len-1] |= -2 << (31 - count);
                 }
         }
 }
Beispiel #7
0
 /** Return -1, 0, or 1, depending on which value is greater. */
 public static int compare(IntNum x, long y)
 {
     long x_word;
     if (x.words == null)
         x_word = x.ival;
     else
         {
             bool x_negative = x.isNegative ();
             bool y_negative = y < 0;
             if (x_negative != y_negative)
                 return x_negative ? -1 : 1;
             int x_len = x.words == null ? 1 : x.ival;
             if (x_len == 1)
                 x_word = x.words[0];
             else if (x_len == 2)
                 x_word = x.longValue();
             else // We assume x is canonicalized.
                 return x_negative ? -1 : 1;
         }
     return x_word < y ? -1 : x_word > y ? 1 : 0;
 }
Beispiel #8
0
 /** Return -1, 0, or 1, depending on which value is greater. */
 public static int compare(IntNum x, IntNum y)
 {
     if (x.words == null && y.words == null)
         return x.ival < y.ival ? -1 : x.ival > y.ival ? 1 : 0;
     bool x_negative = x.isNegative ();
     bool y_negative = y.isNegative ();
     if (x_negative != y_negative)
         return x_negative ? -1 : 1;
     int x_len = x.words == null ? 1 : x.ival;
     int y_len = y.words == null ? 1 : y.ival;
     if (x_len != y_len) // We assume x and y are canonicalized.
         return (x_len > y_len)!=x_negative ? 1 : -1;
     return MPN.cmp (x.words, y.words, x_len);
 }
Beispiel #9
0
 public override Numeric power(IntNum y)
 {
     if (isOne())
         return this;
     if (isMinusOne())
         return y.isOdd () ? this : IntNum.one ();
     if (y.words == null && y.ival >= 0)
         return power (this, y.ival);
     if (isZero())
         return y.isNegative () ? RatNum.infinity(-1) : (RatNum) this;
     return base.power (y);
 }
Beispiel #10
0
 /** Return this raised to an integer power.
  * Implemented by repeated squaring and multiplication.
  * If y < 0, returns div_inv of the result. */
 public virtual Numeric power(IntNum y)
 {
     if (y.isNegative ())
         return power(IntNum.neg(y)).div_inv();
     Numeric pow2 = this;
     Numeric r = null;
     for (;;)  // for (i = 0;  ; i++)
         {
             // pow2 == x**(2**i)
             // prod = x**(sum(j=0..i-1, (y>>j)&1))
             if (y.isOdd())
                 r = r == null ? pow2 : r.mul (pow2);  // r *= pow2
             y = IntNum.shift (y, -1);
             if (y.isZero())
                 break;
             // pow2 *= pow2;
             pow2 = pow2.mul (pow2);
         }
     return r == null ? mul_ident() : r;
 }