/* Division */ Rational bignum_div(Bignum _n, Bignum _m) { mpz_t n, m, tmp; *n = *theBIGNUM(_n); *m = *theBIGNUM(_m); mpz_init(tmp); mpz_mod(tmp, n, m); /* Divided evenly */ if (mpz_sgn(tmp) == 0) { mpz_cdiv_q(tmp, n, m); return make_bignum(tmp); } else { mpz_t q; ratio_t r; mpz_gcd(tmp, n, m); r = malloc(sizeof(struct ratio_t)); mpz_cdiv_q(q, n, tmp); r->numerator = make_bignum(q); mpz_cdiv_q(q, m, tmp); r->denominator = make_bignum(q); return make_ratio(r); } }
static Lisp_Object plusir(Lisp_Object a, Lisp_Object b) /* * fixnum and ratio, but also valid for bignum and ratio. * Note that if the inputs were in lowest terms there is no need for * and GCD calculations here. */ { Lisp_Object nil; push(b); a = times2(a, denominator(b)); nil = C_nil; if (!exception_pending()) a = plus2(a, numerator(stack[0])); pop(b); errexit(); return make_ratio(a, denominator(b)); }
Ratio parse_ratio(char *token) { int i; ratio_t ratio; for (i = 0; token[i] != '\0'; i++) { if ('/' == token[i]) { token[i] = '\0'; break; } } ratio = malloc(sizeof(ratio_t)); ratio->numerator = parse_input(token); ratio->denominator = parse_input(token + i + 1); free(token); return make_ratio(ratio); }
Lisp_Object negate(Lisp_Object a) { #ifdef COMMON Lisp_Object nil; /* needed for errexit() */ #endif switch ((int)a & TAG_BITS) { case TAG_FIXNUM: { int32_t aa = -int_of_fixnum(a); /* * negating the number -#x8000000 (which is a fixnum) yields a value * which just fails to be a fixnum. */ if (aa != 0x08000000) return fixnum_of_int(aa); else return make_one_word_bignum(aa); } #ifdef COMMON case TAG_SFLOAT: { Float_union aa; aa.i = a - TAG_SFLOAT; aa.f = (float) (-aa.f); return (aa.i & ~(int32_t)0xf) + TAG_SFLOAT; } #endif case TAG_NUMBERS: { int32_t ha = type_of_header(numhdr(a)); switch (ha) { case TYPE_BIGNUM: return negateb(a); #ifdef COMMON case TYPE_RATNUM: { Lisp_Object n = numerator(a), d = denominator(a); push(d); n = negate(n); pop(d); errexit(); return make_ratio(n, d); } case TYPE_COMPLEX_NUM: { Lisp_Object r = real_part(a), i = imag_part(a); push(i); r = negate(r); pop(i); errexit(); push(r); i = negate(i); pop(r); errexit(); return make_complex(r, i); } #endif default: return aerror1("bad arg for minus", a); } } case TAG_BOXFLOAT: { double d = float_of_number(a); return make_boxfloat(-d, type_of_header(flthdr(a))); } default: return aerror1("bad arg for minus", a); } }
static Lisp_Object plusrr(Lisp_Object a, Lisp_Object b) /* * Adding two ratios involves some effort to keep the result in * lowest terms. */ { Lisp_Object nil = C_nil; Lisp_Object na = numerator(a), nb = numerator(b); Lisp_Object da = denominator(a), db = denominator(b); Lisp_Object w = nil; push5(na, nb, da, db, nil); #define g stack[0] #define db stack[-1] #define da stack[-2] #define nb stack[-3] #define na stack[-4] g = gcd(da, db); nil = C_nil; if (exception_pending()) goto fail; /* * all the calls to quot2() in this procedure are expected - nay required - * to give exact integer quotients. */ db = quot2(db, g); nil = C_nil; if (exception_pending()) goto fail; g = quot2(da, g); nil = C_nil; if (exception_pending()) goto fail; na = times2(na, db); nil = C_nil; if (exception_pending()) goto fail; nb = times2(nb, g); nil = C_nil; if (exception_pending()) goto fail; na = plus2(na, nb); nil = C_nil; if (exception_pending()) goto fail; da = times2(da, db); nil = C_nil; if (exception_pending()) goto fail; g = gcd(na, da); nil = C_nil; if (exception_pending()) goto fail; na = quot2(na, g); nil = C_nil; if (exception_pending()) goto fail; da = quot2(da, g); nil = C_nil; if (exception_pending()) goto fail; w = make_ratio(na, da); /* * All the goto statements and the label seem a fair way of expressing * the common action that has to be taken if an error or interrupt is * detected during any of the intermediate steps here. Anyone who * objects can change it if they really want... */ fail: popv(5); return w; #undef na #undef nb #undef da #undef db #undef g }