1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228 |
- /* arith01.c Copyright (C) 1990 Codemist Ltd */
- /*
- * Arithmetic functions.
- * Addition of generic numbers
- * and in particular a lot of bignum support.
- *
- * Version 1.4 November 1990.
- *
- */
- /* Signature: 07d5049f 23-Jan-1999 */
- #include <stdarg.h>
- #include <string.h>
- #include <ctype.h>
- #include <math.h>
- #include "machine.h"
- #include "tags.h"
- #include "cslerror.h"
- #include "externs.h"
- #include "arith.h"
- #ifdef TIMEOUT
- #include "timeout.h"
- #endif
- /*
- * I start off with a collection of utility functions that create
- * Lisp structures to represent various sorts of numbers
- * and which extract values from same.
- * The typedefs that explain the layout of these structures are in "tags.h"
- */
- Lisp_Object make_one_word_bignum(int32 n)
- /*
- * n is an integer - create a bignum representation of it. This is
- * done when n is outside the range 0xf8000000 to 0x07ffffff.
- */
- { Lisp_Object w = getvector(TAG_NUMBERS, TYPE_BIGNUM, 8);
- Lisp_Object nil;
- errexit();
- bignum_digits(w)[0] = n;
- return w;
- }
- Lisp_Object make_two_word_bignum(int32 a1, unsigned32 a0)
- /*
- * This make a 2-word bignum from the 2-word value (a1,a0), where it
- * must have been arranged already that a1 and a0 are correctly
- * normalized to put in the two words as indicated.
- */
- {
- Lisp_Object w = getvector(TAG_NUMBERS, TYPE_BIGNUM, 12);
- Lisp_Object nil;
- errexit();
- bignum_digits(w)[0] = a0;
- bignum_digits(w)[1] = a1;
- bignum_digits(w)[2] = 0;
- return w;
- }
- #ifdef COMMON
- Lisp_Object make_sfloat(double d)
- /*
- * Turn a regular floating point value into a Lisp "short float", which
- * is an immediate object obtained by using the bottom 4 bits of a 32-bit
- * word as tag, and the rest as just whatever would stand for a regular
- * single precision value. In doing the conversion here I ignore
- * rounding etc - short floats are to save heap turn-over, but will
- * not give robust numeric results.
- */
- {
- Float_union w;
- w.f = (float)d;
- return (w.i & ~(int32)0xf) + TAG_SFLOAT;
- }
- #endif
- Lisp_Object make_boxfloat(double a, int32 type)
- /*
- * Make a boxed float (single, double or long according to the type specifier)
- * if type==0 this makes a short float
- */
- {
- Lisp_Object r, nil;
- #ifndef COMMON
- CSL_IGNORE(type);
- #endif
- #ifdef COMMON
- switch (type)
- {
- case 0:
- { Float_union aa;
- aa.f = (float)a;
- return (aa.i & ~(int32)0xf) + TAG_SFLOAT;
- }
- case TYPE_SINGLE_FLOAT:
- r = getvector(TAG_BOXFLOAT, TYPE_SINGLE_FLOAT, sizeof(Single_Float));
- errexit();
- single_float_val(r) = (float)a;
- return r;
- default: /* TYPE_DOUBLE_FLOAT I hope */
- #endif
- r = getvector(TAG_BOXFLOAT, TYPE_DOUBLE_FLOAT, sizeof(Double_Float));
- errexit();
- double_float_val(r) = a;
- return r;
- #ifdef COMMON
- case TYPE_LONG_FLOAT:
- r = getvector(TAG_BOXFLOAT, TYPE_LONG_FLOAT, sizeof(Long_Float));
- errexit();
- long_float_val(r) = a;
- return r;
- }
- #endif
- }
- static double bignum_to_float(Lisp_Object v, int32 h, int *xp)
- /*
- * Convert a Lisp bignum to get a floating point value. This uses at most the
- * top 3 digits of the bignum's representation since that is enough to achieve
- * full double precision accuracy.
- * This can not overflow, because it leaves an exponent-adjustment value
- * in *xp. You need ldexp(r, *xp) afterwards.
- */
- {
- int32 n = (h>>2) - 2; /* Last index into the data */
- int x = 31*(int)n;
- int32 msd = (int32)bignum_digits(v)[n];
- /* NB signed conversion on next line */
- double r = (double)msd;
- switch (n)
- {
- default: /* for very big numbers combine in 3 digits */
- r = TWO_31*r + (double)bignum_digits(v)[--n];
- x -= 31;
- /* drop through */
- case 1: r = TWO_31*r + (double)bignum_digits(v)[--n];
- x -= 31;
- /* drop through */
- case 0: break; /* do no more */
- }
- *xp = x;
- return r;
- }
- double float_of_number(Lisp_Object a)
- /*
- * Return a (double precision) floating point value for the given Lisp
- * number, or 0.0 in case of trouble. This is often called in circumstances
- * where I already know the type of its argument and so its type-dispatch
- * is unnecessary - in doing so I am trading off performance against
- * code repetition.
- */
- {
- if (is_fixnum(a)) return (double)int_of_fixnum(a);
- #ifdef COMMON
- else if (is_sfloat(a))
- { Float_union w;
- w.i = a - TAG_SFLOAT;
- return (double)w.f;
- }
- #endif
- else if (is_bfloat(a))
- { int32 h = type_of_header(flthdr(a));
- switch (h)
- {
- #ifdef COMMON
- case TYPE_SINGLE_FLOAT:
- return (double)single_float_val(a);
- #endif
- case TYPE_DOUBLE_FLOAT:
- return double_float_val(a);
- #ifdef COMMON
- case TYPE_LONG_FLOAT:
- return (double)long_float_val(a);
- #endif
- default:
- return 0.0;
- }
- }
- else
- { Header h = numhdr(a);
- int x1;
- double r1;
- switch (type_of_header(h))
- {
- case TYPE_BIGNUM:
- r1 = bignum_to_float(a, length_of_header(h), &x1);
- return ldexp(r1, x1);
- #ifdef COMMON
- case TYPE_RATNUM:
- { int x2;
- Lisp_Object na = numerator(a);
- a = denominator(a);
- if (is_fixnum(na)) r1 = float_of_number(na), x1 = 0;
- else r1 = bignum_to_float(na,
- length_of_header(numhdr(na)), &x1);
- if (is_fixnum(a)) r1 = r1 / float_of_number(a), x2 = 0;
- else r1 = r1 / bignum_to_float(a,
- length_of_header(numhdr(a)), &x2);
- /* Floating point overflow can only arise in this ldexp() */
- return ldexp(r1, x1 - x2);
- }
- #endif
- default:
- /*
- * If the value was non-numeric or a complex number I hand back 0.0,
- * and since I am supposed to have checked the object type already
- * this OUGHT not to arrive - bit raising an exception seems over-keen.
- */
- return 0.0;
- }
- }
- }
- int32 thirty_two_bits(Lisp_Object a)
- /*
- * return a 32 bit integer value for the Lisp integer (fixnum or bignum)
- * passed down - ignore any higher order bits and return 0 if the arg was
- * floating, rational etc or not a number at all. Only really wanted where
- * links between C-specific code (that might really want 32-bit values)
- * and Lisp are being coded.
- */
- {
- switch ((int)a & TAG_BITS)
- {
- case TAG_FIXNUM:
- return int_of_fixnum(a);
- case TAG_NUMBERS:
- if (is_bignum(a))
- { int len = bignum_length(a);
- /*
- * Note that I keep 31 bits per word and use a 2s complement representation.
- * thus if I have a one-word bignum I just want its contents but in all
- * other cases I need just one bit from the next word up.
- */
- if (len == 8) return bignum_digits(a)[0]; /* One word bignum */
- return bignum_digits(a)[0] | (bignum_digits(a)[1] << 31);
- }
- /* else drop through */
- case TAG_BOXFLOAT:
- default:
- /*
- * return 0 for all non-fixnums
- */
- return 0;
- }
- }
- #ifdef COMMON
- Lisp_Object make_complex(Lisp_Object r, Lisp_Object i)
- {
- Lisp_Object v, nil = C_nil;
- /*
- * Here r and i are expected to be either both rational (which in this
- * context includes the case of integer values) or both of the same
- * floating point type. It is assumed that this has already been
- * arranged by here.
- */
- if (i == fixnum_of_int(0)) return r;
- stackcheck2(0, r, i);
- push2(r, i);
- v = getvector(TAG_NUMBERS, TYPE_COMPLEX_NUM, sizeof(Complex_Number));
- /*
- * The vector r has uninitialized contents here - dodgy. If the call
- * to getvector succeeded then I fill it in, otherwise I will not
- * refer to it again, and I think that unreferenced vectors containing junk
- * are OK.
- */
- pop2(i, r);
- errexit();
- real_part(v) = r;
- imag_part(v) = i;
- return v;
- }
- Lisp_Object make_ratio(Lisp_Object p, Lisp_Object q)
- /*
- * By the time this is called (p/q) must be in its lowest terms, q>0
- */
- {
- Lisp_Object v, nil = C_nil;
- if (q == fixnum_of_int(1)) return p;
- stackcheck2(0, p, q);
- push2(p, q);
- v = getvector(TAG_NUMBERS, TYPE_RATNUM, sizeof(Rational_Number));
- pop2(q, p);
- errexit();
- numerator(v) = p;
- denominator(v) = q;
- return v;
- }
- #endif
- /*
- * The next bit of code seems pretty dreadful, but I think that is just
- * what generic arithmetic is all about. The code for plus2 is written
- * as a dispatch function into over 30 separate possible type-specific
- * versions of the code. In a very few simple (and performance-critical)
- * cases the code is written in-line in plus2 - in particular arithmetic
- * on fixnums is done that way. Similarly for other cases.
- * I Use one-character suffices to remind me about types:
- * i fixnum
- * b bignum
- * r ratio
- * s short float
- * f boxed float (single/double/long)
- * c complex
- *
- * Throughout this code I am going to IGNORE floating point exceptions,
- * at least for a first attempt. Decent detection of and recovery after
- * floating point overflow seems an extra unpleasant distraction! Note
- * that C allows me to trap the SIGFPE exception, but returning from
- * the exception handler gives undefined behaviour - one is expected
- * to longjmp out, which means accepting the cost of using setjmp.
- *
- * It would perhaps be reasonable to write the dispatch code as a big
- * macro so that the versions for plus, times etc could all be kept
- * in step - I have not done that (a) because the macro would have been
- * bigger than I like macros to be (b) it would have involved token-
- * splicing (or VERY many parameters) to generate the names of the
- * separate type-specific procedures and (c) doing it by hand allows me
- * total flexibility about coding various cases in-line.
- */
- #ifdef COMMON
- static Lisp_Object plusis(Lisp_Object a, Lisp_Object b)
- {
- Float_union bb;
- bb.i = b - TAG_SFLOAT;
- bb.f = (float)((float)int_of_fixnum(a) + bb.f);
- return (bb.i & ~(int32)0xf) + TAG_SFLOAT;
- }
- #endif
- /*
- * Bignums are represented as vectors where the most significant 32-bit
- * digit is treated as signed, and the remaining ones are unsigned.
- */
- static Lisp_Object plusib(Lisp_Object a, Lisp_Object b)
- /*
- * Add a fixnum to a bignum, returning a result as a fixnum or bignum
- * depending on its size. This seems much nastier than one would have
- * hoped.
- */
- {
- int32 len = bignum_length(b), i, sign = int_of_fixnum(a), s;
- Lisp_Object c, nil;
- len = (len >> 2) - 1;
- if (len == 1)
- { int32 t;
- /*
- * Partly because it will be a common case and partly because it has
- * various special cases I have special purpose code to cope with
- * adding a fixnum to a one-word bignum.
- */
- s = (int32)bignum_digits(b)[0] + sign;
- t = s + s;
- if (top_bit_set(s ^ t)) /* needs to turn into two-word bignum */
- { c = getvector(TAG_NUMBERS, TYPE_BIGNUM, 12);
- errexit();
- if (top_bit_set(s))
- { bignum_digits(c)[0] = clear_top_bit(s);
- bignum_digits(c)[1] = (unsigned32)(-1);
- }
- else
- { bignum_digits(c)[0] = s;
- bignum_digits(c)[1] = 0;
- }
- bignum_digits(c)[2] = 0; /* set padding word to zero to be tidy */
- return c;
- }
- t = s & fix_mask; /* Will it fit as a fixnum? */
- if (t == 0 || t == fix_mask) return fixnum_of_int(s);
- /* here the result is a one-word bignum */
- c = getvector(TAG_NUMBERS, TYPE_BIGNUM, 8);
- errexit();
- bignum_digits(c)[0] = s;
- return c;
- }
- /*
- * Now, after all the silly cases have been handled, I have a calculation
- * which seems set to give a multi-word result. The result here can at
- * least never shrink to a fixnum since subtracting a fixnum can at
- * most shrink the length of a number by one word. I omit the stack-
- * check here in the hope that code here never nests enough for trouble.
- */
- push(b);
- c = getvector(TAG_NUMBERS, TYPE_BIGNUM, 4+(len<<2));
- pop(b);
- errexit();
- s = bignum_digits(b)[0] + clear_top_bit(sign);
- bignum_digits(c)[0] = clear_top_bit(s);
- if (sign >= 0) sign = 0; else sign = 0x7fffffff; /* extend the sign */
- len--;
- for (i=1; i<len; i++)
- { s = bignum_digits(b)[i] + sign + top_bit(s);
- bignum_digits(c)[i] = clear_top_bit(s);
- }
- /* Now just the most significant digit remains to be processed */
- if (sign != 0) sign = -1;
- { s = bignum_digits(b)[i] + sign + top_bit(s);
- if (!signed_overflow(s)) /* did it overflow? */
- {
- /*
- * Here the most significant digit did not produce an overflow, but maybe
- * what we actually had was some cancellation and the MSD is now zero
- * or -1, so that the number should shrink...
- */
- if ((s == 0 && (bignum_digits(c)[i-1] & 0x40000000) == 0) ||
- (s == -1 && (bignum_digits(c)[i-1] & 0x40000000) != 0))
- { /* shrink the number */
- numhdr(c) -= pack_hdrlength(1L);
- if (s == -1) bignum_digits(c)[i-1] |= ~0x7fffffff;
- /*
- * Now sometimes the shrinkage will leave a padding word, sometimes it
- * will really allow me to save space.
- */
- if ((i & 1) == 0)
- { bignum_digits(c)[i] = 0; /* leave the unused word tidy */
- return c;
- }
- /*
- * Having shrunk the number I am leaving a doubleword of unallocated space
- * in the heap. Dump a header word into it to make it look like an
- * 8-byte bignum since that will allow the garbage collector to handle it.
- * It I left it containing arbitrary junk I could wreck myself.
- */
- bignum_digits(c)[i] = make_bighdr(2L);
- return c;
- }
- bignum_digits(c)[i] = s; /* length unchanged */
- return c;
- }
- /*
- * Here the result is one word longer than the input-bignum.
- * Once again SOMTIMES this will not involve allocating more store,
- * but just encroaching into the previously unused word that was padding
- * things out to a multiple of 8 bytes.
- */
- if ((i & 1) == 1)
- { bignum_digits(c)[i++] = clear_top_bit(s);
- bignum_digits(c)[i] = top_bit_set(s) ? -1 : 0;
- numhdr(c) += pack_hdrlength(1L);
- return c;
- }
- push(c);
- b = getvector(TAG_NUMBERS, TYPE_BIGNUM, 12+(len<<2));
- pop(c);
- errexit();
- for (i=0; i<=len; i++)
- bignum_digits(b)[i] = bignum_digits(c)[i];
- bignum_digits(b)[i++] = clear_top_bit(s);
- bignum_digits(b)[i] = top_bit_set(s) ? -1 : 0;
- return b;
- }
- }
- #ifdef COMMON
- 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));
- }
- static Lisp_Object plusic(Lisp_Object a, Lisp_Object b)
- /*
- * real of any sort plus complex.
- */
- {
- Lisp_Object nil;
- push(b);
- a = plus2(a, real_part(b));
- pop(b);
- errexit();
- /*
- * make_complex() takes responsibility for mapping #C(n 0) onto n
- */
- return make_complex(a, imag_part(b));
- }
- #endif
- static Lisp_Object plusif(Lisp_Object a, Lisp_Object b)
- /*
- * Fixnum plus boxed-float.
- */
- {
- double d = (double)int_of_fixnum(a) + float_of_number(b);
- return make_boxfloat(d, type_of_header(flthdr(b)));
- }
- #ifdef COMMON
- #define plussi(a, b) plusis(b, a)
- #define plussb(a, b) plusbs(b, a)
- #define plussr(a, b) plusrs(b, a)
- #define plussc(a, b) plusic(a, b)
- #endif
- static Lisp_Object plussf(Lisp_Object a, Lisp_Object b)
- /*
- * This can be used for any rational value plus a boxed-float. plusif()
- * is separated just for (minor) efficiency reasons.
- */
- {
- double d = float_of_number(a) + float_of_number(b);
- return make_boxfloat(d, type_of_header(flthdr(b)));
- }
- #define plusbi(a, b) plusib(b, a)
- #ifdef COMMON
- static Lisp_Object plusbs(Lisp_Object a, Lisp_Object b)
- {
- double d = float_of_number(a) + float_of_number(b);
- return make_sfloat(d);
- }
- #endif
- Lisp_Object lengthen_by_one_bit(Lisp_Object a, int32 msd)
- /*
- * (a) is a bignum, and arithmetic on it has (just) caused overflow
- * in its top word - I just need to stick on another word. (msd) is the
- * current top word, and its sign will be used to decide on the value
- * that must be appended.
- */
- {
- int32 len = bignum_length(a);
- /*
- * Sometimes I need to allocate a new vector and copy data across into it
- */
- if ((len & 4) == 0)
- { Lisp_Object b, nil;
- int32 i;
- push(a);
- b = getvector(TAG_NUMBERS, TYPE_BIGNUM, len+4);
- pop(a);
- errexit();
- len = (len >> 2) - 1;
- for (i=0; i<len; i++)
- bignum_digits(b)[i] = clear_top_bit(bignum_digits(a)[i]);
- bignum_digits(b)[i] = top_bit_set(msd) ? -1 : 0;
- bignum_digits(b)[i+1] = 0;
- return b;
- }
- else
- /*
- * .. whereas sometimes I have a spare word already available.
- */
- { numhdr(a) += pack_hdrlength(1L);
- len = (len >> 2) - 1;
- bignum_digits(a)[len-1] = clear_top_bit(bignum_digits(a)[len-1]);
- bignum_digits(a)[len] = top_bit_set(msd) ? -1 : 0;
- return a;
- }
- }
- static Lisp_Object plusbb(Lisp_Object a, Lisp_Object b)
- /*
- * add two bignums.
- */
- {
- int32 la = bignum_length(a),
- lb = bignum_length(b),
- i, s, carry;
- Lisp_Object c, nil;
- if (la < lb) /* maybe swap order of args */
- { Lisp_Object t = a;
- int32 t1;
- a = b; b = t;
- t1 = la; la = lb; lb = t1;
- }
- /*
- * now (a) is AT LEAST as long as b. I have special case code for
- * when both args are single-word bignums, since I expect that to be
- * an especially common case.
- */
- if (la == 8) /* and hence b also has only 1 digit */
- { int32 va = bignum_digits(a)[0],
- vb = bignum_digits(b)[0],
- vc = va + vb;
- if (signed_overflow(vc)) /* we have a 2-word bignum result */
- { Lisp_Object w = getvector(TAG_NUMBERS, TYPE_BIGNUM, 12);
- errexit();
- bignum_digits(w)[0] = clear_top_bit(vc);
- bignum_digits(w)[1] = top_bit_set(vc) ? -1 : 0;
- bignum_digits(w)[2] = 0;
- return w;
- }
- /*
- * here the result fits into one word - maybe it will squash down into
- * a fixnum?
- */
- else
- { vb = vc & fix_mask;
- if (vb == 0 || vb == fix_mask) return fixnum_of_int(vc);
- else return make_one_word_bignum(vc);
- }
- }
- push2(a, b);
- c = getvector(TAG_NUMBERS, TYPE_BIGNUM, la);
- pop2(b, a);
- errexit();
- la = (la >> 2) - 2;
- lb = (lb >> 2) - 2;
- carry = 0;
- /*
- * Add all but the top digit of b
- */
- for (i=0; i<lb; i++)
- { carry = bignum_digits(a)[i] + bignum_digits(b)[i] + top_bit(carry);
- bignum_digits(c)[i] = clear_top_bit(carry);
- }
- if (la == lb) s = bignum_digits(b)[i];
- else
- /*
- * If a is strictly longer than b I sign extend b here and add in as many
- * copies of 0 or -1 as needbe to get up to the length of a.
- */
- { s = bignum_digits(b)[i];
- carry = bignum_digits(a)[i] + clear_top_bit(s) + top_bit(carry);
- bignum_digits(c)[i] = clear_top_bit(carry);
- if (s < 0) s = -1; else s = 0;
- for (i++; i<la; i++)
- { carry = bignum_digits(a)[i] + clear_top_bit(s) + top_bit(carry);
- bignum_digits(c)[i] = clear_top_bit(carry);
- }
- }
- /*
- * the most significant digit is added using signed arithmetic so that I
- * can tell if it overflowed.
- */
- carry = bignum_digits(a)[i] + s + top_bit(carry);
- if (!signed_overflow(carry))
- {
- /*
- * Here the number has not expanded - but it may be shrinking, and it can
- * shrink by any number of words, all the way down to a fixnum maybe. Note
- * that I started with at least a 2-word bignum here.
- */
- int32 msd;
- bignum_digits(c)[i] = carry;
- if (carry == 0)
- { int32 j = i-1;
- while ((msd = bignum_digits(c)[j]) == 0 && j > 0) j--;
- /*
- * ... but I may need a zero word on the front if the next word down
- * has its top bit set... (top of 31 bits, that is)
- */
- if ((msd & 0x40000000) != 0)
- { j++;
- if (i == j) return c;
- }
- if (j == 0)
- { int32 s = bignum_digits(c)[0];
- if ((s & fix_mask) == 0) return fixnum_of_int(s);
- }
- /*
- * If I am shrinking by one word and had an even length to start with
- * I do not have to mess about so much.
- */
- if (j == i-1 && (i & 1) == 0)
- { numhdr(c) -= pack_hdrlength(1L);
- return c;
- }
- numhdr(c) -= pack_hdrlength(i - j);
- i = (i+1) | 1;
- j = (j+1) | 1; /* Round up to odd index */
- /*
- * I forge a header word to allow the garbage collector to skip over
- * (and in due course reclaim) the space that turned out not to be needed.
- */
- bignum_digits(c)[j] = make_bighdr(i - j);
- return c;
- }
- /*
- * Now do all the same sorts of things but this time for negative numbers.
- */
- else if (carry == -1)
- { int32 j = i-1;
- msd = carry; /* in case j = 0 */
- while ((msd = bignum_digits(c)[j]) == 0x7fffffff && j > 0) j--;
- if ((msd & 0x40000000) == 0)
- { j++;
- if (i == j) return c;
- }
- if (j == 0)
- { int32 s = bignum_digits(c)[0] | ~0x7fffffff;
- if ((s & fix_mask) == fix_mask) return fixnum_of_int(s);
- }
- if (j == i-1 && (i & 1) == 0)
- { bignum_digits(c)[i] = 0;
- bignum_digits(c)[i-1] |= ~0x7fffffff;
- numhdr(c) -= pack_hdrlength(1);
- return c;
- }
- numhdr(c) -= pack_hdrlength(i - j);
- bignum_digits(c)[j+1] = 0;
- bignum_digits(c)[j] |= ~0x7fffffff;
- i = (i+1) | 1;
- j = (j+1) | 1; /* Round up to odd index */
- bignum_digits(c)[j] = make_bighdr(i - j);
- return c;
- }
- return c;
- }
- else
- { bignum_digits(c)[i] = carry;
- return lengthen_by_one_bit(c, carry);
- }
- }
- #ifdef COMMON
- #define plusbr(a, b) plusir(a, b)
- #define plusbc(a, b) plusic(a, b)
- #endif
- #define plusbf(a, b) plussf(a, b)
- #ifdef COMMON
- #define plusri(a, b) plusir(b, a)
- #define plusrs(a, b) plusbs(a, b)
- #define plusrb(a, b) plusri(a, b)
- 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
- }
- #define plusrc(a, b) plusic(a, b)
- #define plusrf(a, b) plussf(a, b)
- #define plusci(a, b) plusic(b, a)
- #define pluscs(a, b) plussc(b, a)
- #define pluscb(a, b) plusbc(b, a)
- #define pluscr(a, b) plusrc(b, a)
- static Lisp_Object pluscc(Lisp_Object a, Lisp_Object b)
- /*
- * Add complex values.
- */
- {
- Lisp_Object c, nil;
- push2(a, b);
- c = plus2(imag_part(a), imag_part(b));
- pop2(b, a);
- errexit();
- a = plus2(real_part(a), real_part(b));
- errexit();
- return make_complex(a, c);
- }
- #define pluscf(a, b) plusfc(b, a)
- #endif
- #define plusfi(a, b) plusif(b, a)
- #ifdef COMMON
- #define plusfs(a, b) plussf(b, a)
- #endif
- #define plusfb(a, b) plusbf(b, a)
- #ifdef COMMON
- #define plusfr(a, b) plusrf(b, a)
- #define plusfc(a, b) plusic(a, b)
- #endif
- static Lisp_Object plusff(Lisp_Object a, Lisp_Object b)
- /*
- * Add two boxed floats - the type of the result must match the
- * longer of the types of the arguments, hence the extra
- * messing about.
- */
- {
- #ifdef COMMON
- int32 ha = type_of_header(flthdr(a)), hb = type_of_header(flthdr(b));
- #endif
- double d;
- /*
- * This is written as a declaration followed by a separate assignment to
- * d because I hit a compiler bug on a VAX once otherwise.
- */
- d = float_of_number(a) + float_of_number(b);
- #ifdef COMMON
- if (ha == TYPE_LONG_FLOAT || hb == TYPE_LONG_FLOAT)
- ha = TYPE_LONG_FLOAT;
- else if (ha == TYPE_DOUBLE_FLOAT || hb == TYPE_DOUBLE_FLOAT)
- ha = TYPE_DOUBLE_FLOAT;
- else ha = TYPE_SINGLE_FLOAT;
- return make_boxfloat(d, ha);
- #else
- return make_boxfloat(d, TYPE_DOUBLE_FLOAT);
- #endif
- }
- /*
- * and now for the dispatch code...
- */
- /*
- * The following verifies that a number is properly formatted - a
- * fixnum if small enough or a decently normalised bignum. For use when
- * there is suspicion of a bug wrt such matters. Call is
- * validate_number("msg", numberToCheck, nX, nY)
- * where nX and nY must be numbers and are shown in any
- * diagnostic.
- */
- void validate_number(char *s, Lisp_Object a, Lisp_Object b, Lisp_Object c)
- {
- int32 la, w, msd;
- if (!is_numbers(a)) return;
- la = (length_of_header(numhdr(a))>>2)-2;
- if (la < 0)
- { trace_printf("%s: number with no digits (%.8x)\n", s, numhdr(a));
- if (is_number(b)) prin_to_trace(b), trace_printf("\n");
- if (is_number(c)) prin_to_trace(c), trace_printf("\n");
- my_exit(EXIT_FAILURE);
- }
- if (la == 0)
- { msd = bignum_digits(a)[0];
- w = msd & fix_mask;
- if (w == 0 || w == fix_mask)
- { trace_printf("%s: %.8x should be fixnum\n", s, msd);
- if (is_number(b)) prin_to_trace(b), trace_printf("\n");
- if (is_number(c)) prin_to_trace(c), trace_printf("\n");
- my_exit(EXIT_FAILURE);
- }
- if (signed_overflow(msd))
- { trace_printf("%s: %.8x should be two-word\n", s, msd);
- if (is_number(b)) prin_to_trace(b), trace_printf("\n");
- if (is_number(c)) prin_to_trace(c), trace_printf("\n");
- my_exit(EXIT_FAILURE);
- }
- return;
- }
- msd = bignum_digits(a)[la];
- if (signed_overflow(msd))
- { trace_printf("%s: %.8x should be longer\n", s, msd);
- if (is_number(b)) prin_to_trace(b), trace_printf("\n");
- if (is_number(c)) prin_to_trace(c), trace_printf("\n");
- my_exit(EXIT_FAILURE);
- }
- if (msd == 0 && ((msd = bignum_digits(a)[la-1]) & 0x40000000) == 0)
- { trace_printf("%s: 0: %.8x should be shorter\n", s, msd);
- if (is_number(b)) prin_to_trace(b), trace_printf("\n");
- if (is_number(c)) prin_to_trace(c), trace_printf("\n");
- my_exit(EXIT_FAILURE);
- }
- if (msd == -1 && ((msd = bignum_digits(a)[la-1]) & 0x40000000) != 0)
- { trace_printf("%s: -1: %.8x should be shorter\n", s, msd);
- if (is_number(b)) prin_to_trace(b), trace_printf("\n");
- if (is_number(c)) prin_to_trace(c), trace_printf("\n");
- my_exit(EXIT_FAILURE);
- }
- }
- Lisp_Object plus2(Lisp_Object a, Lisp_Object b)
- /*
- * I probably want to change the specification of plus2 so that the fixnum +
- * fixnum case is always expected to be done before the main body of the code
- * is entered. Well maybe even if I do that it then costs very little to
- * include the fixnum code here as well, so I will not delete it.
- */
- {
- switch ((int)a & TAG_BITS)
- {
- case TAG_FIXNUM:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- /*
- * This is where fixnum + fixnum arithmetic happens - the case I most want to
- * make efficient.
- */
- { int32 r = int_of_fixnum(a) + int_of_fixnum(b);
- int32 t = r & fix_mask;
- if (t == 0 || t == fix_mask) return fixnum_of_int(r);
- else return make_one_word_bignum(r);
- }
- #ifdef COMMON
- case TAG_SFLOAT:
- return plusis(a, b);
- #endif
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return plusib(a, b);
- #ifdef COMMON
- case TYPE_RATNUM:
- return plusir(a, b);
- case TYPE_COMPLEX_NUM:
- return plusic(a, b);
- #endif
- default:
- return aerror1("bad arg for plus", b);
- }
- }
- case TAG_BOXFLOAT:
- return plusif(a, b);
- default:
- return aerror1("bad arg for plus", b);
- }
- #ifdef COMMON
- case TAG_SFLOAT:
- switch (b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return plussi(a, b);
- case TAG_SFLOAT:
- { Float_union aa, bb;
- aa.i = a - TAG_SFLOAT;
- bb.i = b - TAG_SFLOAT;
- aa.f = (float)(aa.f + bb.f);
- return (aa.i & ~(int32)0xf) + TAG_SFLOAT;
- }
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return plussb(a, b);
- case TYPE_RATNUM:
- return plussr(a, b);
- case TYPE_COMPLEX_NUM:
- return plussc(a, b);
- default:
- return aerror1("bad arg for plus", b);
- }
- }
- case TAG_BOXFLOAT:
- return plussf(a, b);
- default:
- return aerror1("bad arg for plus", b);
- }
- #endif
- case TAG_NUMBERS:
- { int32 ha = type_of_header(numhdr(a));
- switch (ha)
- {
- case TYPE_BIGNUM:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return plusbi(a, b);
- #ifdef COMMON
- case TAG_SFLOAT:
- return plusbs(a, b);
- #endif
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return plusbb(a, b);
- #ifdef COMMON
- case TYPE_RATNUM:
- return plusbr(a, b);
- case TYPE_COMPLEX_NUM:
- return plusbc(a, b);
- #endif
- default:
- return aerror1("bad arg for plus", b);
- }
- }
- case TAG_BOXFLOAT:
- return plusbf(a, b);
- default:
- return aerror1("bad arg for plus", b);
- }
- #ifdef COMMON
- case TYPE_RATNUM:
- switch (b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return plusri(a, b);
- case TAG_SFLOAT:
- return plusrs(a, b);
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return plusrb(a, b);
- case TYPE_RATNUM:
- return plusrr(a, b);
- case TYPE_COMPLEX_NUM:
- return plusrc(a, b);
- default:
- return aerror1("bad arg for plus", b);
- }
- }
- case TAG_BOXFLOAT:
- return plusrf(a, b);
- default:
- return aerror1("bad arg for plus", b);
- }
- case TYPE_COMPLEX_NUM:
- switch (b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return plusci(a, b);
- case TAG_SFLOAT:
- return pluscs(a, b);
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return pluscb(a, b);
- case TYPE_RATNUM:
- return pluscr(a, b);
- case TYPE_COMPLEX_NUM:
- return pluscc(a, b);
- default:
- return aerror1("bad arg for plus", b);
- }
- }
- case TAG_BOXFLOAT:
- return pluscf(a, b);
- default:
- return aerror1("bad arg for plus", b);
- }
- #endif
- default: return aerror1("bad arg for plus", a);
- }
- }
- case TAG_BOXFLOAT:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return plusfi(a, b);
- #ifdef COMMON
- case TAG_SFLOAT:
- return plusfs(a, b);
- #endif
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return plusfb(a, b);
- #ifdef COMMON
- case TYPE_RATNUM:
- return plusfr(a, b);
- case TYPE_COMPLEX_NUM:
- return plusfc(a, b);
- #endif
- default:
- return aerror1("bad arg for plus", b);
- }
- }
- case TAG_BOXFLOAT:
- return plusff(a, b);
- default:
- return aerror1("bad arg for plus", b);
- }
- default:
- return aerror1("bad arg for plus", a);
- }
- }
- Lisp_Object difference2(Lisp_Object a, Lisp_Object b)
- {
- Lisp_Object nil;
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- if (is_fixnum(a))
- {
- int32 r = int_of_fixnum(a) - int_of_fixnum(b);
- int32 t = r & fix_mask;
- if (t == 0 || t == fix_mask) return fixnum_of_int(r);
- else return make_one_word_bignum(r);
- }
- else if (b != ~0x7ffffffe) return plus2(a, 2*TAG_FIXNUM-b);
- else
- { push(a);
- b = make_one_word_bignum(-int_of_fixnum(b));
- break;
- }
- case TAG_NUMBERS:
- push(a);
- if (type_of_header(numhdr(b)) == TYPE_BIGNUM) b = negateb(b);
- else b = negate(b);
- break;
- case TAG_BOXFLOAT:
- default:
- push(a);
- b = negate(b);
- break;
- }
- pop(a);
- errexit();
- return plus2(a, b);
- }
- Lisp_Object add1(Lisp_Object p)
- /*
- * Increment a number. Short cut when the number is a fixnum, otherwise
- * just hand over to the general addition code.
- */
- {
- if (is_fixnum(p))
- { unsigned32 r = (int32)p + 0x10;
- /* fixnums have data shifted left 4 bits */
- if (r == ~0x7ffffffe) /* The ONLY possible overflow case here */
- return make_one_word_bignum(1 + int_of_fixnum(p));
- else return (Lisp_Object)r;
- }
- else return plus2(p, fixnum_of_int(1));
- }
- Lisp_Object sub1(Lisp_Object p)
- /*
- * Decrement a number. Short cut when the number is a fixnum, otherwise
- * just hand over to the general addition code.
- */
- {
- if (is_fixnum(p))
- { if (p == ~0x7ffffffe) /* The ONLY possible overflow case here */
- return make_one_word_bignum(int_of_fixnum(p) - 1);
- else return (Lisp_Object)(p - 0x10);
- }
- else return plus2(p, fixnum_of_int(-1));
- }
- /* end of arith01.c */
|