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)); }
/** 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); }
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 (); }
/** 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 (); } } }
public static IntNum abs(IntNum x) { return x.isNegative () ? neg (x) : x; }
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); } } }
/** 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; }
/** 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); }
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); }
/** 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; }