1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318 |
- /* arith11.c Copyright (C) 1990-2002 Codemist Ltd */
- /*
- * Arithmetic functions.
- * remainder, =,
- * minusp, plusp
- *
- */
- /*
- * This code may be used and modified, and redistributed in binary
- * or source form, subject to the "CCL Public License", which should
- * accompany it. This license is a variant on the BSD license, and thus
- * permits use of code derived from this in either open and commercial
- * projects: but it does require that updates to this code be made
- * available back to the originators of the package.
- * Before merging other code in with this or linking this code
- * with other packages or libraries please check that the license terms
- * of the other material are compatible with those of this.
- */
- /* Signature: 4439bf35 08-Apr-2002 */
- #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
- Lisp_Object rembi(Lisp_Object a, Lisp_Object b)
- {
- Lisp_Object nil;
- if (b == fixnum_of_int(0)) return aerror2("bad arg for remainder", a, b);
- else if (b == fixnum_of_int(1) ||
- b == fixnum_of_int(-1)) return fixnum_of_int(0);
- quotbn1(a, int_of_fixnum(b));
- /*
- * If the divisor was a fixnum then the remainder will be a fixnum too.
- */
- errexit();
- return fixnum_of_int(nwork);
- }
- Lisp_Object rembb(Lisp_Object a, Lisp_Object b)
- {
- Lisp_Object nil;
- quotbb(a, b);
- errexit();
- return mv_2;
- }
- #ifdef COMMON
- static Lisp_Object remis(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remir(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remif(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remsi(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remsb(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remsr(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remsf(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object rembs(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object rembr(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object rembf(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remri(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remrs(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remrb(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remrr(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remrf(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remfi(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remfs(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remfb(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remfr(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- static Lisp_Object remff(Lisp_Object a, Lisp_Object b)
- {
- return aerror2("bad arg for remainder", a, b);
- }
- #endif /* COMMON */
- Lisp_Object Cremainder(Lisp_Object a, Lisp_Object b)
- {
- int32 c;
- 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.
- */
- if (b == fixnum_of_int(0))
- return aerror2("bad arg for remainder", a, b);
- /* No overflow is possible in a remaindering operation */
- { int32 aa = int_of_fixnum(a);
- int32 bb = int_of_fixnum(b);
- c = aa % bb;
- /*
- * C does not specify just what happens when % is used with negative
- * operands (except maybe if the division went exactly), so here I do
- * some adjusting, assuming that the quotient returned was one of the
- * integral values surrounding the exact result.
- */
- if (aa < 0)
- { if (c > 0) c -= bb;
- }
- else if (c < 0) c += bb;
- return fixnum_of_int(c);
- }
- #ifdef COMMON
- /*
- * Common Lisp defines a meaning for the remainder function when applied
- * to floating point values - so there is a whole pile of mess here to
- * support that. Standard Lisp is only concerned with fixnums and
- * bignums.
- */
- case TAG_SFLOAT:
- return remis(a, b);
- #endif
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- /*
- * When I divide a fixnum a by a bignum b the remainder is a except in
- * the case that a = 0xf8000000 and b = 0x08000000 in which case the
- * answer is zero.
- */
- if (int_of_fixnum(a) == fix_mask &&
- bignum_length(b) == 8 &&
- bignum_digits(b)[0] == 0x08000000)
- return fixnum_of_int(0);
- else return a;
- #ifdef COMMON
- case TYPE_RATNUM:
- return remir(a, b);
- #endif
- default:
- return aerror1("Bad arg for remainder", b);
- }
- }
- #ifdef COMMON
- case TAG_BOXFLOAT:
- return remif(a, b);
- #else
- case TAG_BOXFLOAT:
- { double v = (double) int_of_fixnum(a);
- double u = float_of_number(b);
- v = v - (v/u)*u;
- return make_boxfloat(v, TYPE_DOUBLE_FLOAT);
- }
- #endif
- default:
- return aerror1("Bad arg for remainder", b);
- }
- #ifdef COMMON
- case TAG_SFLOAT:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return remsi(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 remsb(a, b);
- case TYPE_RATNUM:
- return remsr(a, b);
- default:
- return aerror1("Bad arg for remainder", b);
- }
- }
- case TAG_BOXFLOAT:
- return remsf(a, b);
- default:
- return aerror1("Bad arg for remainder", 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 rembi(a, b);
- #ifdef COMMON
- case TAG_SFLOAT:
- return rembs(a, b);
- #endif
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return rembb(a, b);
- #ifdef COMMON
- case TYPE_RATNUM:
- return rembr(a, b);
- #endif
- default:
- return aerror1("Bad arg for remainder", b);
- }
- }
- #ifdef COMMON
- case TAG_BOXFLOAT:
- return rembf(a, b);
- #endif
- default:
- return aerror1("Bad arg for remainder", b);
- }
- #ifdef COMMON
- case TYPE_RATNUM:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return remri(a, b);
- case TAG_SFLOAT:
- return remrs(a, b);
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return remrb(a, b);
- case TYPE_RATNUM:
- return remrr(a, b);
- default:
- return aerror1("Bad arg for remainder", b);
- }
- }
- case TAG_BOXFLOAT:
- return remrf(a, b);
- default:
- return aerror1("Bad arg for remainder", b);
- }
- #endif
- default: return aerror1("Bad arg for remainder", a);
- }
- }
- case TAG_BOXFLOAT:
- switch ((int)b & TAG_BITS)
- {
- #ifndef COMMON
- case TAG_FIXNUM:
- { double u = (double) int_of_fixnum(b);
- double v = float_of_number(a);
- v = v - (v/u)*u;
- return make_boxfloat(v, TYPE_DOUBLE_FLOAT);
- }
- case TAG_BOXFLOAT:
- { double u = float_of_number(b);
- double v = float_of_number(a);
- v = v - (v/u)*u;
- return make_boxfloat(v, TYPE_DOUBLE_FLOAT);
- }
- default:
- return aerror1("Bad arg for remainder", b);
- #else
- case TAG_FIXNUM:
- return remfi(a, b);
- case TAG_SFLOAT:
- return remfs(a, b);
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return remfb(a, b);
- case TYPE_RATNUM:
- return remfr(a, b);
- default:
- return aerror1("Bad arg for remainder", b);
- }
- }
- case TAG_BOXFLOAT:
- return remff(a, b);
- default:
- return aerror1("Bad arg for remainder", b);
- #endif
- }
- default:
- return aerror1("Bad arg for remainder", a);
- }
- }
- /*
- * In the cases that I expect to be most speed-critical I will
- * implement "mod" directly. But in a load of other cases I will just
- * activate the existing "remainder" code and then make a few final
- * adjustments. This MAY lead to error messages (on modulus by zero)
- * mentioning remainder rather than mod....
- * I will leave in the whole structure of separate functions for each
- * case since that will be useful if I ever need to come back here and
- * fine-tune more of the type-combinations. As a first pass I give
- * special treatment to (fixnum,fixnum) and (bignum,fixnum)
- */
- static Lisp_Object mod_by_rem(Lisp_Object a, Lisp_Object b)
- {
- Lisp_Object nil;
- CSLbool sb = minusp(b);
- errexit();
- a = Cremainder(a, b); /* Repeats dispatch on argument type. Sorry */
- errexit();
- if (sb)
- { if (plusp(a))
- { errexit();
- a = plus2(a, b);
- }
- }
- else if (minusp(a))
- { errexit();
- a = plus2(a, b);
- }
- return a;
- }
- static Lisp_Object modib(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modbi(Lisp_Object a, Lisp_Object b)
- {
- Lisp_Object nil = C_nil;
- int32 bb = int_of_fixnum(b);
- if (b == fixnum_of_int(0)) return aerror2("bad arg for mod", a, b);
- if (bb == 1 || bb == -1) nwork = 0;
- else quotbn1(a, bb);
- /*
- * If the divisor was a fixnum then the remainder will be a fixnum too.
- */
- errexit();
- if (bb < 0)
- { if (nwork > 0) nwork += bb;
- }
- else if (nwork < 0) nwork += bb;
- return fixnum_of_int(nwork);
- }
- static Lisp_Object modbb(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- #ifdef COMMON
- static Lisp_Object modis(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modir(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modif(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modsi(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modsb(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modsr(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modsf(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modbs(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modbr(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modbf(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modri(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modrs(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modrb(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modrr(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modrf(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modfi(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modfs(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modfb(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object modfr(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- static Lisp_Object ccl_modff(Lisp_Object a, Lisp_Object b)
- {
- return mod_by_rem(a, b);
- }
- #endif /* COMMON */
- Lisp_Object modulus(Lisp_Object a, Lisp_Object b)
- {
- 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 p = int_of_fixnum(a);
- int32 q = int_of_fixnum(b);
- if (q == 0) return aerror2("bad arg for mod", a, b);
- p = p % q;
- if (q < 0)
- { if (p > 0) p += q;
- }
- else if (p < 0) p += q;
- /* No overflow is possible in a modulus operation */
- return fixnum_of_int(p);
- }
- #ifdef COMMON
- /*
- * Common Lisp defines a meaning for the modulus function when applied
- * to floating point values - so there is a whole pile of mess here to
- * support that. Standard Lisp is only concerned with fixnums and
- * bignums.
- */
- case TAG_SFLOAT:
- return modis(a, b);
- #endif
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return modib(a, b);
- #ifdef COMMON
- case TYPE_RATNUM:
- return modir(a, b);
- #endif
- default:
- return aerror1("Bad arg for mod", b);
- }
- }
- #ifdef COMMON
- case TAG_BOXFLOAT:
- return modif(a, b);
- #endif
- default:
- return aerror1("Bad arg for mod", b);
- }
- #ifdef COMMON
- case TAG_SFLOAT:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return modsi(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 modsb(a, b);
- case TYPE_RATNUM:
- return modsr(a, b);
- default:
- return aerror1("Bad arg for mod", b);
- }
- }
- case TAG_BOXFLOAT:
- return modsf(a, b);
- default:
- return aerror1("Bad arg for mod", 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 modbi(a, b);
- #ifdef COMMON
- case TAG_SFLOAT:
- return modbs(a, b);
- #endif
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return modbb(a, b);
- #ifdef COMMON
- case TYPE_RATNUM:
- return modbr(a, b);
- #endif
- default:
- return aerror1("Bad arg for mod", b);
- }
- }
- #ifdef COMMON
- case TAG_BOXFLOAT:
- return modbf(a, b);
- #endif
- default:
- return aerror1("Bad arg for mod", b);
- }
- #ifdef COMMON
- case TYPE_RATNUM:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return modri(a, b);
- case TAG_SFLOAT:
- return modrs(a, b);
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return modrb(a, b);
- case TYPE_RATNUM:
- return modrr(a, b);
- default:
- return aerror1("Bad arg for mod", b);
- }
- }
- case TAG_BOXFLOAT:
- return modrf(a, b);
- default:
- return aerror1("Bad arg for mod", b);
- }
- #endif
- default: return aerror1("Bad arg for mod", a);
- }
- }
- #ifdef COMMON
- case TAG_BOXFLOAT:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return modfi(a, b);
- case TAG_SFLOAT:
- return modfs(a, b);
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return modfb(a, b);
- case TYPE_RATNUM:
- return modfr(a, b);
- default:
- return aerror1("Bad arg for mod", b);
- }
- }
- case TAG_BOXFLOAT:
- return ccl_modff(a, b);
- default:
- return aerror1("Bad arg for mod", b);
- }
- #endif
- default:
- return aerror1("Bad arg for mod", a);
- }
- }
- CSLbool zerop(Lisp_Object a)
- {
- switch ((int)a & TAG_BITS)
- {
- case TAG_FIXNUM:
- return (a == fixnum_of_int(0));
- #ifdef COMMON
- case TAG_NUMBERS:
- /* #C(r i) must satisfy zerop is r and i both do */
- if (is_complex(a) && zerop(real_part(a)))
- return zerop(imag_part(a));
- else return NO;
- case TAG_SFLOAT:
- /*
- * The code here assumes that the the floating point number zero
- * is represented by a zero bit-pattern... see onep() for a more
- * cautious way of coding things.
- */
- return ((a & 0x7ffffff8) == 0); /* Strip sign bit as well as tags */
- #endif
- case TAG_BOXFLOAT:
- return (float_of_number(a) == 0.0);
- default:
- return NO;
- }
- }
- CSLbool onep(Lisp_Object a)
- {
- switch ((int)a & TAG_BITS)
- {
- case TAG_FIXNUM:
- return (a == fixnum_of_int(1));
- #ifdef COMMON
- case TAG_NUMBERS:
- /* #C(r i) must satisfy onep(r) and zerop(i) */
- if (is_complex(a) && onep(real_part(a)))
- return zerop(imag_part(a));
- else return NO;
- case TAG_SFLOAT:
- { Float_union w;
- w.f = (float)1.0;
- return (a == (w.i & ~(int32)0xf) + TAG_SFLOAT);
- }
- #endif
- case TAG_BOXFLOAT:
- return (float_of_number(a) == 1.0);
- default:
- return NO;
- }
- }
- /*
- * sign testing
- */
- CSLbool minusp(Lisp_Object a)
- {
- switch ((int)a & TAG_BITS)
- {
- case TAG_FIXNUM:
- return ((int32)a < 0);
- #ifdef COMMON
- case TAG_SFLOAT:
- { Float_union aa;
- aa.i = a - TAG_SFLOAT;
- return (aa.f < 0.0);
- }
- #endif
- case TAG_NUMBERS:
- { int32 ha = type_of_header(numhdr(a));
- switch (ha)
- {
- case TYPE_BIGNUM:
- { int32 l = (bignum_length(a)-CELL-4)/4;
- return ((int32)bignum_digits(a)[l] < (int32)0);
- }
- #ifdef COMMON
- case TYPE_RATNUM:
- return minusp(numerator(a));
- #endif
- default:
- aerror1("Bad arg for minusp", a);
- return 0;
- }
- }
- case TAG_BOXFLOAT:
- { double d = float_of_number(a);
- return (d < 0.0);
- }
- default:
- aerror1("Bad arg for minusp", a);
- return 0;
- }
- }
- CSLbool plusp(Lisp_Object a)
- {
- switch ((int)a & TAG_BITS)
- {
- case TAG_FIXNUM:
- return (a > fixnum_of_int(0));
- #ifdef COMMON
- case TAG_SFLOAT:
- { Float_union aa;
- aa.i = a - TAG_SFLOAT;
- return (aa.f > 0.0);
- }
- #endif
- case TAG_NUMBERS:
- { int32 ha = type_of_header(numhdr(a));
- switch (ha)
- {
- case TYPE_BIGNUM:
- { int32 l = (bignum_length(a)-CELL-4)/4;
- /* This is OK because a bignum can never have the value zero */
- return ((int32)bignum_digits(a)[l] >= (int32)0);
- }
- #ifdef COMMON
- case TYPE_RATNUM:
- return plusp(numerator(a));
- #endif
- default:
- aerror1("Bad arg for plusp", a);
- return 0;
- }
- }
- case TAG_BOXFLOAT:
- { double d = float_of_number(a);
- return (d > 0.0);
- }
- default:
- aerror1("Bad arg for plusp", a);
- return 0;
- }
- }
- /*
- * Numeric equality - note that comparisons involving non-numbers
- * are errors here (unlike the position in eql, equal, equalp). Also
- * this must be coded so that it never provokes garbage collection.
- */
- #ifdef COMMON
- static CSLbool numeqis(Lisp_Object a, Lisp_Object b)
- {
- Float_union bb;
- bb.i = b - TAG_SFLOAT;
- return ((double)int_of_fixnum(a) == (double)bb.f);
- }
- static CSLbool numeqic(Lisp_Object a, Lisp_Object b)
- {
- if (!zerop(imag_part(b))) return NO;
- else return numeq2(a, real_part(b));
- }
- #endif
- #define numeqif(a,b) ((double)int_of_fixnum(a) == float_of_number(b))
- #ifdef COMMON
- #define numeqsi(a, b) numeqis(b, a)
- #endif
- static CSLbool numeqsb(Lisp_Object a, Lisp_Object b)
- /*
- * This is coded to allow comparison of any floating type
- * with a bignum
- */
- {
- double d = float_of_number(a), d1;
- int x;
- int32 w, len;
- unsigned32 u;
- if (-1.0e8 < d && d < 1.0e8) return NO; /* fixnum range (approx) */
- len = (bignum_length(b)-CELL-4)/4;
- if (len == 0) /* One word bignums can be treated specially */
- { int32 v = bignum_digits(b)[0];
- return (d == (double)v);
- }
- d1 = frexp(d, &x); /* separate exponent from mantissa */
- if (d1 == 1.0) d1 = 0.5, x++; /* For Zortech */
- /* The exponent x must be positive here, hence the % operation is defined */
- d1 = ldexp(d1, x % 31);
- /*
- * At most 3 words in the bignum may contain nonzero data - I subtract
- * the (double) value of those bits off and check that (a) the floating
- * result left is zero and (b) there are no more bits left.
- */
- x = x / 31;
- if (x != len) return NO;
- w = bignum_digits(b)[len];
- d1 = (d1 - (double)w) * TWO_31;
- u = bignum_digits(b)[--len];
- d1 = (d1 - (double)u) * TWO_31;
- if (len > 0)
- { u = bignum_digits(b)[--len];
- d1 = d1 - (double)u;
- }
- if (d1 != 0.0) return NO;
- while (--len >= 0)
- if (bignum_digits(b)[len] != 0) return NO;
- return YES;
- }
- #ifdef COMMON
- static CSLbool numeqsr(Lisp_Object a, Lisp_Object b)
- /*
- * Here I will rely somewhat on the use of IEEE floating point values
- * (an in particular the weaker supposition that I have floating point
- * with a binary radix). Then for equality the denominator of b must
- * be a power of 2, which I can test for and then account for.
- */
- {
- Lisp_Object nb = numerator(b), db = denominator(b);
- double d = float_of_number(a), d1;
- int x;
- int32 dx, w, len;
- unsigned32 u, bit;
- /*
- * first I will check that db (which will be positive) is a power of 2,
- * and set dx to indicate what power of two it is.
- * Note that db != 0 and that one of the top two words of a bignum
- * must be nonzero (for normalisation) so I end up with a nonzero
- * value in the variable 'bit'
- */
- if (is_fixnum(db))
- { bit = int_of_fixnum(db);
- w = bit;
- if (w != (w & (-w))) return NO; /* not a power of 2 */
- dx = 0;
- }
- else if (is_numbers(db) && is_bignum(db))
- { int32 lenb = (bignum_length(db)-CELL-4)/4;
- bit = bignum_digits(db)[lenb];
- /*
- * I need to cope with bignums where the leading digits is zero because
- * the 0x80000000 bit of the next word down is 1. To do this I treat
- * the number as having one fewer digits.
- */
- if (bit == 0) bit = bignum_digits(db)[--lenb];
- w = bit;
- if (w != (w & (-w))) return NO; /* not a power of 2 */
- dx = 31*lenb;
- while (--lenb >= 0) /* check that the rest of db is zero */
- if (bignum_digits(db)[lenb] != 0) return NO;
- }
- else return NO; /* Odd - what type IS db here? Maybe error. */
- if ((bit & 0xffffU) == 0) dx += 16, bit = bit >> 16;
- if ((bit & 0xff) == 0) dx += 8, bit = bit >> 8;
- if ((bit & 0xf) == 0) dx += 4, bit = bit >> 4;
- if ((bit & 0x3) == 0) dx += 2, bit = bit >> 2;
- if ((bit & 0x1) == 0) dx += 1;
- if (is_fixnum(nb))
- { double d1 = (double)int_of_fixnum(nb);
- /*
- * The ldexp on the next line could potentially underflow. In that case C
- * defines that the result 0.0 be returned. To avoid trouble I put in a
- * special test the relies on that fact that a value represented as a rational
- * would not have been zero.
- */
- if (dx > 10000) return NO; /* Avoid gross underflow */
- d1 = ldexp(d1, (int)-dx);
- return (d == d1 && d != 0.0);
- }
- len = (bignum_length(nb)-CELL-4)/4;
- if (len == 0) /* One word bignums can be treated specially */
- { int32 v = bignum_digits(nb)[0];
- double d1;
- if (dx > 10000) return NO; /* Avoid gross underflow */
- d1 = ldexp((double)v, (int)-dx);
- return (d == d1 && d != 0.0);
- }
- d1 = frexp(d, &x); /* separate exponent from mantissa */
- if (d1 == 1.0) d1 = 0.5, x++; /* For Zortech */
- dx += x; /* adjust to allow for the denominator */
- d1 = ldexp(d1, (int)(dx % 31));
- /* can neither underflow nor overflow here */
- /*
- * At most 3 words in the bignum may contain nonzero data - I subtract
- * the (double) value of those bits off and check that (a) the floating
- * result left is zero and (b) there are no more bits left.
- */
- dx = dx / 31;
- if (dx != len) return NO;
- w = bignum_digits(nb)[len];
- d1 = (d1 - (double)w) * TWO_31;
- u = bignum_digits(nb)[--len];
- d1 = (d1 - (double)u) * TWO_31;
- if (len > 0)
- { u = bignum_digits(nb)[--len];
- d1 = d1 - (double)u;
- }
- if (d1 != 0.0) return NO;
- while (--len >= 0)
- if (bignum_digits(nb)[len] != 0) return NO;
- return YES;
- }
- #define numeqsc(a, b) numeqic(a, b)
- static CSLbool numeqsf(Lisp_Object a, Lisp_Object b)
- {
- Float_union aa;
- aa.i = a - TAG_SFLOAT;
- return ((double)aa.f == float_of_number(b));
- }
- #define numeqbs(a, b) numeqsb(b, a)
- #endif
- static CSLbool numeqbb(Lisp_Object a, Lisp_Object b)
- {
- int32 la = bignum_length(a);
- if (la != (int32)bignum_length(b)) return NO;
- la = (la-CELL-4)/4;
- while (la >= 0)
- { if (bignum_digits(a)[la] != bignum_digits(b)[la]) return NO;
- else la--;
- }
- return YES;
- }
- #ifdef COMMON
- #define numeqbc(a, b) numeqic(a, b)
- #endif
- #define numeqbf(a, b) numeqsb(b, a)
- #ifdef COMMON
- #define numeqrs(a, b) numeqsr(b, a)
- static CSLbool numeqrr(Lisp_Object a, Lisp_Object b)
- {
- return numeq2(numerator(a), numerator(b)) &&
- numeq2(denominator(a), denominator(b));
- }
- #define numeqrc(a, b) numeqic(a, b)
- #define numeqrf(a, b) numeqsr(b, a)
- #define numeqci(a, b) numeqic(b, a)
- #define numeqcs(a, b) numeqic(b, a)
- #define numeqcb(a, b) numeqic(b, a)
- #define numeqcr(a, b) numeqic(b, a)
- static CSLbool numeqcc(Lisp_Object a, Lisp_Object b)
- {
- return numeq2(real_part(a), real_part(b)) &&
- numeq2(imag_part(a), imag_part(b));
- }
- #define numeqcf(a, b) numeqic(b, a)
- #endif
- #define numeqfi(a, b) numeqif(b, a)
- #ifdef COMMON
- #define numeqfs(a, b) numeqsf(b, a)
- #endif
- #define numeqfb(a, b) numeqbf(b, a)
- #ifdef COMMON
- #define numeqfr(a, b) numeqrf(b, a)
- #define numeqfc(a, b) numeqic(a, b)
- #endif
- static CSLbool numeqff(Lisp_Object a, Lisp_Object b)
- {
- return (float_of_number(a) == float_of_number(b));
- }
- /*
- * This comparison must signal an error on non-numeric operands in
- * Common Lisp mode, but behave as EQ in CSL mode.
- */
- #ifdef COMMON
- # define differenta aerror1("Bad arg for =", a); return 0
- # define differentb aerror1("Bad arg for =", b); return 0
- #else
- # define differenta return NO
- # define differentb return NO
- #endif
- CSLbool numeq2(Lisp_Object a, Lisp_Object b)
- {
- #ifndef COMMON
- if (a == b) return YES;
- #endif
- switch ((int)a & TAG_BITS)
- {
- case TAG_FIXNUM:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- #ifdef COMMON
- return (a == b);
- #else
- return NO;
- #endif
- #ifdef COMMON
- case TAG_SFLOAT:
- return numeqis(a, b);
- #endif
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return 0;
- #ifdef COMMON
- case TYPE_RATNUM:
- return 0;
- case TYPE_COMPLEX_NUM:
- return numeqic(a, b); /* (= 2 #C(2.0 0.0))? Yuk */
- #endif
- default:
- differentb;
- }
- }
- case TAG_BOXFLOAT:
- return numeqif(a, b);
- default:
- differentb;
- }
- #ifdef COMMON
- case TAG_SFLOAT:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return numeqsi(a, b);
- case TAG_SFLOAT:
- return (a == b) ||
- (a == TAG_SFLOAT && b == TAG_SFLOAT|0x80000000) ||
- (a == TAG_SFLOAT|0x80000000 && b == TAG_SFLOAT); /* !!! */
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return numeqsb(a, b);
- case TYPE_RATNUM:
- return numeqsr(a, b);
- case TYPE_COMPLEX_NUM:
- return numeqsc(a, b);
- default:
- differentb;
- }
- }
- case TAG_BOXFLOAT:
- return numeqsf(a, b);
- default:
- differentb;
- }
- #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 0;
- #ifdef COMMON
- case TAG_SFLOAT:
- return numeqbs(a, b);
- #endif
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return numeqbb(a, b);
- #ifdef COMMON
- case TYPE_RATNUM:
- return 0;
- case TYPE_COMPLEX_NUM:
- return numeqbc(a, b);
- #endif
- default:
- differentb;
- }
- }
- case TAG_BOXFLOAT:
- return numeqbf(a, b);
- default:
- differentb;
- }
- #ifdef COMMON
- case TYPE_RATNUM:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return 0;
- case TAG_SFLOAT:
- return numeqrs(a, b);
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return 0;
- case TYPE_RATNUM:
- return numeqrr(a, b);
- case TYPE_COMPLEX_NUM:
- return numeqrc(a, b);
- default:
- differentb;
- }
- }
- case TAG_BOXFLOAT:
- return numeqrf(a, b);
- default:
- differentb;
- }
- case TYPE_COMPLEX_NUM:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return numeqci(a, b);
- case TAG_SFLOAT:
- return numeqcs(a, b);
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return numeqcb(a, b);
- case TYPE_RATNUM:
- return numeqcr(a, b);
- case TYPE_COMPLEX_NUM:
- return numeqcc(a, b);
- default:
- differentb;
- }
- }
- case TAG_BOXFLOAT:
- return numeqcf(a, b);
- default:
- differentb;
- }
- #endif
- default: differenta;
- }
- }
- case TAG_BOXFLOAT:
- switch ((int)b & TAG_BITS)
- {
- case TAG_FIXNUM:
- return numeqfi(a, b);
- #ifdef COMMON
- case TAG_SFLOAT:
- return numeqfs(a, b);
- #endif
- case TAG_NUMBERS:
- { int32 hb = type_of_header(numhdr(b));
- switch (hb)
- {
- case TYPE_BIGNUM:
- return numeqfb(a, b);
- #ifdef COMMON
- case TYPE_RATNUM:
- return numeqfr(a, b);
- case TYPE_COMPLEX_NUM:
- return numeqfc(a, b);
- #endif
- default:
- differentb;
- }
- }
- case TAG_BOXFLOAT:
- return numeqff(a, b);
- default:
- differentb;
- }
- default:
- differenta;
- }
- }
- /* end of arith11.c */
|