/* arith06.c Copyright (C) 1990-2002 Codemist Ltd */ /* * Arithmetic functions... lots of Lisp entrypoints. * note that for CSL I want plus and times to be special forms. */ /* * 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: 1e60864f 10-Oct-2002 */ #include #include #include #include #include "machine.h" #include "tags.h" #include "cslerror.h" #include "externs.h" #include "arith.h" #include "entries.h" #ifdef TIMEOUT #include "timeout.h" #endif /*****************************************************************************/ /*** Lisp-callable versions of arithmetic functions ***/ /*****************************************************************************/ Lisp_Object Ladd1(Lisp_Object nil, Lisp_Object a) { if (is_fixnum(a)) { unsigned32 r = (unsigned32)a + 0x10; /* fixnums have data shifted left 4 bits */ if (r == ~0x7ffffffe) /* The ONLY possible overflow case here */ a = make_one_word_bignum(1 + int_of_fixnum(a)); else return onevalue((Lisp_Object)r); /* the cheap case */ } else a = plus2(a, fixnum_of_int(1)); errexit(); return onevalue(a); } Lisp_Object Lsub1(Lisp_Object nil, Lisp_Object a) { if (is_fixnum(a)) { if (a == ~0x7ffffffe) /* The ONLY possible overflow case here */ return make_one_word_bignum(int_of_fixnum(a) - 1); else return onevalue((Lisp_Object)(a - 0x10)); } else a = plus2(a, fixnum_of_int(-1)); errexit(); return onevalue(a); } #ifdef COMMON Lisp_Object Lfloat_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b) { CSL_IGNORE(nil); if (is_sfloat(b)) { double d = float_of_number(a); return onevalue(make_sfloat(d)); } else if (!is_bfloat(b)) return aerror1("bad arg for float", b); else { double d = float_of_number(a); return onevalue(make_boxfloat(d, type_of_header(flthdr(b)))); } } #endif Lisp_Object Lfloat(Lisp_Object nil, Lisp_Object a) { double d; CSL_IGNORE(nil); if (!is_number(a)) return aerror1("bad arg for float", a); d = float_of_number(a); #ifdef COMMON /* Do we REALLY want single precision by default here? */ return onevalue(make_boxfloat(d, TYPE_SINGLE_FLOAT)); #else return onevalue(make_boxfloat(d, TYPE_DOUBLE_FLOAT)); #endif } Lisp_Object Llognot(Lisp_Object nil, Lisp_Object a) { a = lognot(a); errexit(); return onevalue(a); } Lisp_Object Lash(Lisp_Object nil, Lisp_Object a, Lisp_Object b) { a = ash(a, b); errexit(); return onevalue(a); } Lisp_Object Lash1(Lisp_Object nil, Lisp_Object a, Lisp_Object b) /* * This function multiplies or divides by a power of two. Note that * this corresponds to natural shifts on a sign-and-magnitude machine, * but is not an "arithmetic" shift as that term is understood on * 2's complement machines. */ { CSLbool negative = NO; if (!is_fixnum(b)) return aerror("ash1"); if (minusp(a)) { negative = YES; a = negate(a); } errexit(); a = ash(a, b); errexit(); if (negative) { a = negate(a); errexit(); } return onevalue(a); } static int msd_table[256] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; Lisp_Object Lmsd(Lisp_Object nil, Lisp_Object a) { int32 top; int32 r = 0; CSL_IGNORE(nil); if (is_fixnum(a)) top = int_of_fixnum(a); else if (is_numbers(a)) { Header h = numhdr(a); if (!is_bignum_header(h)) return aerror1("bad arg for msd", a); r = (length_of_header(h)-CELL)/4 - 1; top = bignum_digits(a)[r]; r = 31*r; } else return aerror1("bad arg for msd", a); if (top < 0) return aerror1("negative arg for msd", a); /* -ve arg */ /* * Note that top may be zero here, but in that case the next word down of * the bignum involved MUST be fully normalised with its top bit set. * The effect of this code is that I return (msd 0) => 0. */ if (top >= 0x10000) r += 16, top >>= 16; if (top >= 0x100) r += 8, top >>= 8; return onevalue(fixnum_of_int(r + msd_table[top])); } static int lsd_table[256] = { 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; Lisp_Object Llsd(Lisp_Object nil, Lisp_Object a) { int32 top; int32 r = 0; CSL_IGNORE(nil); if (is_fixnum(a)) { top = int_of_fixnum(a); /* lsd(0) is taken to have the value 0 here - it is a bit of an odd case */ if (top == 0) return onevalue(a); } else if (is_numbers(a)) { Header h = numhdr(a); if (!is_bignum_header(h)) return aerror1("bad arg for lsd", a); while ((top = bignum_digits(a)[r]) == 0) r++; r = 31*r; } else return aerror1("bad arg for lsd", a); if (top < 0) return aerror1("negative arg for lsd", a); /* -ve arg */ /* top is non-zero here */ if ((top & 0xffffu) == 0) r += 16, top >>= 16; if ((top & 0xff) == 0) r += 8, top >>= 8; return onevalue(fixnum_of_int(r + lsd_table[top & 0xff])); } Lisp_Object Linorm(Lisp_Object nil, Lisp_Object a, Lisp_Object k) /* * This is a piece of magic especially designed to speed up the * REDUCE big-float code. It adjusts the integer a until it has * just k bits, and returns a correction to the associated exponent. * It combines aspects of msd, lsd, ash and a rounding operation. */ { int32 top, bottom, kk, bits; int32 rtop = 0, rbottom = 0; CSLbool was_fixnum = NO, was_negative = NO, round_up; if (is_fixnum(k) && (int32)k >= 0) kk = int_of_fixnum(k); else return aerror1("bad args for inorm", k); if (is_fixnum(a)) { top = int_of_fixnum(a); if (top == 0) return aerror1("zero arg for inorm", a); bottom = top; was_fixnum = YES; } else if (is_numbers(a)) { Header h = numhdr(a); if (!is_bignum_header(h)) return aerror1("bad arg for inorm", a); rtop = (length_of_header(h)-CELL)/4 - 1; top = bignum_digits(a)[rtop]; was_negative = (top < 0); rtop = 31*rtop; while ((bottom = bignum_digits(a)[rbottom]) == 0) rbottom++; rbottom = 31*rbottom; } else return aerror1("bad arg for inorm", a); if (top < 0) top = ~top; /* Now top is guaranteed positive */ if (top >= 0x10000) rtop += 16, top >>= 16; if (top >= 0x100) rtop += 8, top >>= 8; rtop = rtop + msd_table[top]; if ((bottom & 0xffffu) == 0) rbottom += 16, bottom >>= 16; if ((bottom & 0xff) == 0) rbottom += 8, bottom >>= 8; rbottom = rbottom + lsd_table[bottom & 0xff]; /* * The next line adjusts for the odd case where the input number is * minus an exact power of 2, in which case finding its most significant bit * involved just a little correction. */ round_up = was_negative; if (rtop == rbottom) rtop++; bits = rtop - rbottom; /* bits used in the number */ if (bits <= kk) kk = rbottom; /* no rounding wanted */ else if (was_fixnum) { int bit; /* * If the input was a fixnum and I need to decrease its precision * I will do it in-line here, mainly so that the bignum code that comes * later will not have to worry so much about the possibility of having * any fixnums around. */ kk = rtop - kk; bit = ((int32)1) << (kk - 1); top = int_of_fixnum(a); if (top < 0) { top = -top; /* * It is almost the case that for negative values I should round if the * bit I want to test is a zero (rather than a 1), but this is not true when * the bit involved is the least significant set bit in the word. So to * keep it simple I negate, test, adjust and negate back when working with * single precision numbers. I also do the shifting right on the positive * value to avoid problems with the bits that get shifted off, and with * computers where right shifts are logical rather than arithmetic. */ if ((top & bit) != 0) top += bit; top = top >> kk; top = -top; } else { if ((top & bit) != 0) top += bit; top = top >> kk; } /* * All the shifts I do here move only zero bits off the bottom of the * word, and so there are no issues about +ve vs -ve numbers to bother me. */ while ((top & 0xf) == 0) { top = top >> 4; #ifdef SIGNED_SHIFTS_ARE_LOGICAL if (top & 0x08000000) top |= ~0x0fffffff; #endif kk += 4; } while ((top & 0x1) == 0) { top = top >> 1; #ifdef SIGNED_SHIFTS_ARE_LOGICAL if (top & 0x40000000) top |= ~0x7fffffff; #endif kk += 1; } a = cons(fixnum_of_int(top), fixnum_of_int(kk)); errexit(); return onevalue(a); } else { int32 wk, bk; /* * Here my input was a bignum and I have established that I not only need * to shift it right but that I will need to lose some non-zero digits from * the right hand end. To cope with this I need to decide whether it will * round up or down, and then perform the appropriate shifts, including a * post-normalisation to ensure that the mantissa of the number as returned * is odd. */ kk = rtop - kk; if (rbottom == kk-1) round_up = YES; else { int32 wk1 = (kk-1) / 31, bk1 = (kk-1) % 31; int32 bit = ((int32)1) << bk1; round_up = ((bit & bignum_digits(a)[wk1]) != 0); if (was_negative) round_up = !round_up; } /* * Now I need to find out how much I will need to shift AFTER rounding * and truncation to leave me with a properly normalised value. */ wk = kk / 31, bk = kk % 31; /* * If I have a positive value that is not being rounded up I want to skip * over 0 bits until I find a 1. Similarly for a negative value that is * being rounded up. */ if (was_negative == round_up) { for (;;) { int32 bit = ((int32)1) << bk; if ((bignum_digits(a)[wk] & bit) != 0) break; kk++; bk++; if (bk == 31) bk = 0, wk++; } } else /* * A positive value that is being rounded up or a negative one that is not * should cause me to skip over 1 bits until I find a 0. The 0 I find * will be promoted into a 1 achieve the rounding I need. */ { for (;;) { int32 bit = ((int32)1) << bk; if ((bignum_digits(a)[wk] & bit) == 0) break; kk++; bk++; if (bk == 31) bk = 0, wk++; } } } if (kk != 0) { a = ash(a, fixnum_of_int(-kk)); errexit(); /* * All the adjustment I now need to allow for right-shifting negative * numbers and rounding off - at all reduces to just forcing the bottom bit * of the result I compute here to be a 1! */ if (is_fixnum(a)) a |= 0x10; else bignum_digits(a)[0] |= 1; } a = cons(a, fixnum_of_int(kk)); errexit(); return onevalue(a); } #ifdef COMMON /* * Implemented as a special form for Standard Lisp. Must be a regular * function in Common Lisp. */ static Lisp_Object MS_CDECL Lplus(Lisp_Object nil, int nargs, ...) /* * This adds up a whole bunch of numbers together. * (+ a1 a2 a3 a4 a5) is computed as * (+ a1 (+ a2 (* a3 (+ a4 a5)))) */ { va_list a; int i; Lisp_Object r; if (nargs == 0) return fixnum_of_int(0); va_start(a, nargs); push_args(a, nargs); /* * The actual args have been passed a C args - I can not afford to * risk garbage collection until they have all been moved somewhere safe, * and here that safe place is the Lisp stack. I have to delay checking for * overflow on same until all args have been pushed. */ stackcheck0(nargs); pop(r); nil = C_nil; for (i = 1; i) = nil. Note that this ensures * that minusp will not fail... so nil wil be intact on the way out. */ return onevalue(is_number(a) && minusp(a) ? lisp_true : nil); } Lisp_Object Lplusp(Lisp_Object nil, Lisp_Object a) { return onevalue(is_number(a) && plusp(a) ? lisp_true : nil); } /* * The next few functions take an arbitrary number of args in Common * Lisp mode but just 2 args in CSL. */ #ifdef COMMON Lisp_Object MS_CDECL Leqn_n(Lisp_Object nil, int nargs, ...) { va_list a; int i; Lisp_Object r; if (nargs < 2) return onevalue(lisp_true); if (nargs > ARG_CUT_OFF) return aerror("too many args for ="); va_start(a, nargs); push_args(a, nargs); stackcheck0(nargs); r = stack[1-nargs]; for (i = 1; i ARG_CUT_OFF) return aerror("too many args for <"); va_start(a, nargs); push_args(a, nargs); stackcheck0(nargs); r = stack[1-nargs]; for (i = 1; i ARG_CUT_OFF) return aerror("too many args for >"); va_start(a, nargs); push_args(a, nargs); stackcheck0(nargs); r = stack[1-nargs]; for (i = 1; i ARG_CUT_OFF) return aerror("too many args for /="); va_start(a, nargs); for (i=0; i ARG_CUT_OFF) return aerror("too many args for >="); va_start(a, nargs); push_args(a, nargs); stackcheck0(nargs); r = stack[1-nargs]; for (i = 1; i ARG_CUT_OFF) return aerror("too many args for <="); va_start(a, nargs); push_args(a, nargs); stackcheck0(nargs); r = stack[1-nargs]; for (i = 1; i(int32)b)); r = lessp2(b, a); errexit(); return onevalue(Lispify_predicate(r)); } Lisp_Object Lgeq(Lisp_Object nil, Lisp_Object a, Lisp_Object b) { CSLbool r; if (is_fixnum(a) && is_fixnum(b)) return onevalue(Lispify_predicate((int32)a>=(int32)b)); r = lessp2(a, b); errexit(); return onevalue(Lispify_predicate(!r)); } Lisp_Object Lleq(Lisp_Object nil, Lisp_Object a, Lisp_Object b) { CSLbool r; if (is_fixnum(a) && is_fixnum(b)) return onevalue(Lispify_predicate((int32)a<=(int32)b)); r = lessp2(b, a); errexit(); return onevalue(Lispify_predicate(!r)); } #endif /* COMMON */ Lisp_Object Lmax2(Lisp_Object nil, Lisp_Object a, Lisp_Object b) { CSLbool w; CSL_IGNORE(nil); push2(a, b); w = lessp2(a, b); pop2(b, a); errexit(); if (w) return onevalue(b); else return onevalue(a); } Lisp_Object Lmin2(Lisp_Object nil, Lisp_Object a, Lisp_Object b) { CSLbool w; CSL_IGNORE(nil); push2(a, b); w = lessp2(b, a); pop2(b, a); errexit(); if (w) return onevalue(b); else return onevalue(a); } Lisp_Object MS_CDECL Lmax(Lisp_Object nil, int nargs, ...) { va_list a; int i; Lisp_Object r; if (nargs < 1) return aerror("max"); if (nargs > ARG_CUT_OFF) return aerror("too many args for max"); va_start(a, nargs); push_args(a, nargs); stackcheck0(nargs); r = stack[1-nargs]; for (i = 1; i ARG_CUT_OFF) return aerror("too many args for min"); va_start(a, nargs); push_args(a, nargs); stackcheck0(nargs); r = stack[1-nargs]; for (i = 1; i> 1; } /* * If all the least significant bits were zero to start with they would * always stay that way, so I force one of them to be 1. */ random_number_seed[21] |= 1; } #ifdef COMMON Lisp_Object Lrandom_2(Lisp_Object nil, Lisp_Object a, Lisp_Object bb) { Lisp_Object b; /* * Common Lisp expects an optional second arg to be used for the random * state - at present I do not support that, but it will not be too hard * when I get around to it... */ b = bb; CSL_IGNORE(nil); if (is_fixnum(a)) { int32 v = int_of_fixnum(a), p, q; if (v <= 0) return aerror1("random", a); /* (random 1) always returns zero - a rather silly case! */ else if (v == 1) return onevalue(fixnum_of_int(0)); /* * I generate a value that is an exact multiple of my range (v) and * pick random bitpatterns until I find one less than that. On average * I will have only VERY slightly less than one draw needed, and doing things * this way ought to ensure that my pseudo random numbers are uniformly * distributed provided that the underlying generator is well behaved. */ p = v*(0x7fffffff/v); do q = ((unsigned32)Crand()) >> 1; while (q > p); return onevalue(fixnum_of_int(q % v)); } if (is_numbers(a)) { int32 len, len1, msd; unsigned32 w, w1; Lisp_Object r; if (!is_bignum(a)) return aerror1("random", a); len = bignum_length(a); push(a); r = getvector(TAG_NUMBERS, TYPE_BIGNUM, len); pop(a); errexit(); len1 = (len-CELL)/4-1; restart: len = len1; msd = bignum_digits(a)[len]; if (msd < 0) return aerror("negative arg for random"); /* -ve arg */ if (msd == 0) { bignum_digits(r)[len] = 0; len--; msd = bignum_digits(a)[len]; } for (;;) { w = (0xffffffffU/((unsigned32)msd+1U))*((unsigned32)msd+1U); do w1 = (unsigned32)Crand(); while (w1 >= w); w1 = w1%((unsigned32)msd+1U); bignum_digits(r)[len] = w1; if ((int32)w1 != msd) break; /* * The loop to restart on the next line is when the random value I * have built up word by word ends up being equal to the input number - I * will discard it and start again in that case. */ if (len == 0) goto restart; len--; msd = bignum_digits(a)[len]; } /* * having got some leading digits properly set up I can fill in the rest * as totally independent bit-patterns. */ for (len--;len>=0; len--) bignum_digits(r)[len] = ((unsigned32)Crand())>>1; return onevalue(shrink_bignum(r, len1)); } if (is_bfloat(a)) { Header h = flthdr(a); double d = float_of_number(a), v; /* * The calculation here turns 62 bits of integer data into a floating * point number in the range 0.0 (inclusive) to 1.0 (exclusive). Well, * to be more precise, rounding the value to the machine's floating point * format may round it up to be exactly 1.0, so I discard and cases where * that happens (once in several blue moons...). If I wrote code that * knew exactly how many bits my floating point format had I could avoid * the need for that extra test, but it does not seem very painful to me * and I prefer the more portable code. */ do { v = ((double)(int32)(Crand() & 0x7fffffff)) / TWO_31; v += (double)(int32)(Crand() & 0x7fffffff); v /= TWO_31; v *= d; } while (v == d); a = make_boxfloat(v, type_of_header(h)); errexit(); return onevalue(a); } if (is_sfloat(a)) { Float_union d; float v; d.i = a - TAG_SFLOAT; /* * similar idea to boxfloat case, but only 31 bits randomness used. * SOFTWARE_FLOATING_POINT conversion needed here, maybe */ do { v = (float)(int32)(Crand() & 0x7fffffff)/(float)TWO_31; v = v*d.f; } while (v == d.f); d.f = v; return onevalue((d.i & ~(int32)0xf) + TAG_SFLOAT); } return aerror1("random", a); } #endif Lisp_Object Lrandom(Lisp_Object nil, Lisp_Object a) { CSL_IGNORE(nil); if (is_fixnum(a)) { int32 v = int_of_fixnum(a), p, q; if (v <= 0) return aerror1("random", a); /* (random 1) always returns zero - a rather silly case! */ else if (v == 1) return onevalue(fixnum_of_int(0)); /* * I generate a value that is an exact multiple of my range (v) and * pick random bitpatterns until I find one less than that. On average * I will have only VERY slightly less than one draw needed, and doing things * this way ought to ensure that my pseudo random numbers are uniformly * distributed provided that the underlying generator is well behaved. */ p = v*(0x7fffffff/v); do q = ((unsigned32)Crand()) >> 1; while (q > p); return onevalue(fixnum_of_int(q % v)); } if (is_numbers(a)) { int32 len, len1, msd; unsigned32 w, w1; Lisp_Object r; if (!is_bignum(a)) return aerror1("random", a); len = bignum_length(a); push(a); r = getvector(TAG_NUMBERS, TYPE_BIGNUM, len); pop(a); errexit(); len1 = (len-CELL)/4-1; restart: len = len1; msd = bignum_digits(a)[len]; if (msd < 0) return aerror("negative arg for random"); /* -ve arg */ if (msd == 0) { bignum_digits(r)[len] = 0; len--; msd = bignum_digits(a)[len]; } for (;;) { w = (0xffffffffU/((unsigned32)msd+1U))*((unsigned32)msd+1U); do w1 = (unsigned32)Crand(); while (w1 >= w); w1 = w1%((unsigned32)msd+1U); bignum_digits(r)[len] = w1; if ((int32)w1 != msd) break; /* * The loop to restart on the next line is when the random value I * have built up word by word ends up being equal to the input number - I * will discard it and start again in that case. */ if (len == 0) goto restart; len--; msd = bignum_digits(a)[len]; } /* * having got some leading digits properly set up I can fill in the rest * as totally independent bit-patterns. */ for (len--;len>=0; len--) bignum_digits(r)[len] = ((unsigned32)Crand())>>1; return onevalue(shrink_bignum(r, len1)); } if (is_bfloat(a)) { Header h = flthdr(a); double d = float_of_number(a), v; /* * The calculation here turns 62 bits of integer data into a floating * point number in the range 0.0 (inclusive) to 1.0 (exclusive). Well, * to be more precise, rounding the value to the machine's floating point * format may round it up to be exactly 1.0, so I discard and cases where * that happens (once in several blue moons...). If I wrote code that * knew exactly how many bits my floating point format had I could avoid * the need for that extra test, but it does not seem very painful to me * and I prefer the more portable code. */ do { v = ((double)(int32)(Crand() & 0x7fffffff)) / TWO_31; v += (double)(int32)(Crand() & 0x7fffffff); v /= TWO_31; v *= d; } while (v == d); a = make_boxfloat(v, type_of_header(h)); errexit(); return onevalue(a); } #ifdef COMMON if (is_sfloat(a)) { Float_union d; float v; d.i = a - TAG_SFLOAT; /* * similar idea to boxfloat case, but only 31 bits randomness used. * SOFTWARE_FLOATING_POINT conversion needed here, maybe */ do { v = (float)(int32)(Crand() & 0x7fffffff)/(float)TWO_31; v = v*d.f; } while (v == d.f); d.f = v; return onevalue((d.i & ~(int32)0xf) + TAG_SFLOAT); } #endif return aerror1("random", a); } Lisp_Object MS_CDECL Lnext_random(Lisp_Object nil, int nargs, ...) /* * Returns a random positive fixnum. 27 bits in this Lisp! */ { int32 r; argcheck(nargs, 0, "next-random"); CSL_IGNORE(nil); r = Crand(); return onevalue((Lisp_Object)((r & 0x7ffffff0) + TAG_FIXNUM)); } Lisp_Object Lmake_random_state(Lisp_Object nil, Lisp_Object a, Lisp_Object b) { /* * Nasty temporary hack here to allow me to set the seed for the * random number generator in Standard Lisp mode. I need to re-think * this soon before it feels frozen in! Oops - too late!!! */ CSL_IGNORE(b); if (!is_fixnum(a)) return aerror1("make-random-state", a); Csrand(int_of_fixnum(a), is_fixnum(b) ? int_of_fixnum(b) : 0); return onevalue(nil); } Lisp_Object Lmake_random_state1(Lisp_Object nil, Lisp_Object a) { if (!is_fixnum(a)) return aerror1("make-random-state", a); Csrand(int_of_fixnum(a), 0); return onevalue(nil); } /* * The function md5() can be given a number or a string as an argument, * and it uses the md5 message digest algorithm to reduce it to a * numeric value in the range 0 to 2^128. * Well actually I will also allow an arbitrary expression, which I * will treat as if it has to be printed... */ Lisp_Object Lmd5(Lisp_Object env, Lisp_Object a) { Lisp_Object nil = C_nil; Lisp_Object r; unsigned char md[16]; unsigned32 v0, v1, v2, v3, v4; int32 len, i; CSL_IGNORE(env); if (is_fixnum(a)) { sprintf((char *)md, "%.8lx", (unsigned long)a); MD5_Init(); MD5_Update(md, 8); } else if (is_numbers(a) && is_bignum_header(numhdr(a))) { len = length_of_header(numhdr(a)); MD5_Init(); for (i=CELL; i> 28; v3 = ((v3 << 3) | (v2 >> 29)) & 0x7fffffff; v2 = ((v2 << 2) | (v1 >> 30)) & 0x7fffffff; v1 = ((v1 << 1) | (v0 >> 31)) & 0x7fffffff; v0 &= 0x7fffffff; /* * Note the funny tests. This is because in my representation the * top word of a bignum is a 2s complement signed value and to keep clear * of overflow that means I use an extra digit slightly before one might * imagine it is necessary! */ if (v4 != 0 || (v3 & 0x40000000) != 0) len = CELL+20; else if (v3 != 0 || (v2 & 0x40000000) != 0) len = CELL+16; else if (v2 != 0 || (v1 & 0x40000000) != 0) len = CELL+12; else if (v1 != 0 || (v0 & 0x40000000) != 0) len = CELL+8; else if ((v0 & fix_mask) != 0) len = CELL+4; else return onevalue(fixnum_of_int(v0)); r = getvector(TAG_NUMBERS, TYPE_BIGNUM, len); errexit(); #ifdef ADDRESS_64 switch (len) { case CELL+20: bignum_digits(r)[5] = 0; /* zeros out padding word as necessary */ bignum_digits(r)[4] = v4; case CELL+16: case CELL+12: bignum_digits(r)[3] = v3; bignum_digits(r)[2] = v2; case CELL+8: case CELL+4: bignum_digits(r)[1] = v1; bignum_digits(r)[0] = v0; break; } #else switch (len) { case CELL+20: case CELL+16: bignum_digits(r)[4] = v4; /* zeros out padding word as necessary */ bignum_digits(r)[3] = v3; case CELL+12: case CELL+8: bignum_digits(r)[2] = v2; bignum_digits(r)[1] = v1; case CELL+4: bignum_digits(r)[0] = v0; break; } #endif /* validate_number("MD5", r, r, r); */ return onevalue(r); } /* * md60 is a function that uses MD5 but then returns just about 60 bits * of number not 128. It is for use when the full 128 bits of checksum * would be clumsy overkill. */ Lisp_Object Lmd60(Lisp_Object env, Lisp_Object a) { Lisp_Object nil = C_nil; Lisp_Object r; unsigned char md[16]; unsigned32 v0, v1; int32 len, i; CSL_IGNORE(env); if (is_fixnum(a)) { sprintf((char *)md, "%.8lx", (unsigned long)a); MD5_Init(); MD5_Update(md, 8); } else if (is_numbers(a) && is_bignum_header(numhdr(a))) { len = length_of_header(numhdr(a)); MD5_Init(); for (i=CELL; i> 31)) & 0x3fffffff; v0 &= 0x7fffffff; if (v1 != 0 || (v0 & 0x40000000) != 0) len = CELL+8; else if ((v0 & fix_mask) != 0) len = CELL+4; else return onevalue(fixnum_of_int(v0)); r = getvector(TAG_NUMBERS, TYPE_BIGNUM, len); errexit(); #ifdef ADDRESS_64 bignum_digits(r)[1] = v1; bignum_digits(r)[0] = v0; #else switch (len) { case CELL+8: bignum_digits(r)[2] = 0; bignum_digits(r)[1] = v1; case CELL+4: bignum_digits(r)[0] = v0; break; } #endif /* validate_number("MD60", r, r, r); */ return onevalue(r); } static Lisp_Object Llogand2(Lisp_Object env, Lisp_Object a1, Lisp_Object a2) { return Lboolfn(env, 2, a1, a2); } static Lisp_Object Llogeqv2(Lisp_Object env, Lisp_Object a1, Lisp_Object a2) { return Lboolfn(env, 2, a1, a2); } static Lisp_Object Llogxor2(Lisp_Object env, Lisp_Object a1, Lisp_Object a2) { return Lboolfn(env, 2, a1, a2); } static Lisp_Object Llogor2(Lisp_Object env, Lisp_Object a1, Lisp_Object a2) { return Lboolfn(env, 2, a1, a2); } static Lisp_Object MS_CDECL Ldemo_mode(Lisp_Object nil, int nargs, ...) { argcheck(nargs, 0, "demo-mode"); #ifdef DEMO_BUILD /* if (qfn1(compiler_symbol) == undefined1) */ { Csrand(demo_key1, demo_key2); return onevalue(lisp_true); } #endif return onevalue(nil); } setup_type const arith06_setup[] = { {"ash", too_few_2, Lash, wrong_no_2}, {"ash1", too_few_2, Lash1, wrong_no_2}, {"divide", too_few_2, Ldivide, wrong_no_2}, {"evenp", Levenp, too_many_1, wrong_no_1}, {"inorm", too_few_2, Linorm, wrong_no_2}, {"logand", Lidentity, Llogand2, Lboolfn}, {"logeqv", Lidentity, Llogeqv2, Lboolfn}, {"lognot", Llognot, too_many_1, wrong_no_1}, {"logxor", Lidentity, Llogxor2, Lboolfn}, {"lsd", Llsd, too_many_1, wrong_no_1}, {"make-random-state", Lmake_random_state1, Lmake_random_state, wrong_no_2}, {"max", Lidentity, Lmax2, Lmax}, {"max2", too_few_2, Lmax2, wrong_no_2}, {"min", Lidentity, Lmin2, Lmin}, {"min2", too_few_2, Lmin2, wrong_no_2}, {"minus", Lminus, too_many_1, wrong_no_1}, {"minusp", Lminusp, too_many_1, wrong_no_1}, {"mod", too_few_2, Lmod, wrong_no_2}, {"msd", Lmsd, too_many_1, wrong_no_1}, {"oddp", Loddp, too_many_1, wrong_no_1}, {"onep", Lonep, too_many_1, wrong_no_1}, {"plus2", too_few_2, Lplus2, wrong_no_2}, {"plusp", Lplusp, too_many_1, wrong_no_1}, {"rational", Lrational, too_many_1, wrong_no_1}, {"times2", too_few_2, Ltimes2, wrong_no_2}, {"zerop", Lzerop, too_many_1, wrong_no_1}, {"md5", Lmd5, too_many_1, wrong_no_1}, {"md60", Lmd60, too_many_1, wrong_no_1}, {"demo-mode", wrong_no_0a, wrong_no_0b, Ldemo_mode}, #ifdef COMMON {"*", Lidentity, Ltimes2, Ltimes}, {"+", Lidentity, Lplus2, Lplus}, {"-", Lminus, Ldifference2, Ldifference}, {"/", Lquotient_1, Lquotient, Lquotient_n}, {"/=", Lneq_1, Lneq_2, Lneqn}, {"1+", Ladd1, too_many_1, wrong_no_1}, {"1-", Lsub1, too_many_1, wrong_no_1}, {"<", Llessp_1, Llessp, Llessp_n}, {"<=", Lleq_1, Lleq, Lleq_n}, {"=", Leqn_1, Leqn, Leqn_n}, {">", Lgreaterp_1, Lgreaterp, Lgreaterp_n}, {">=", Lgeq_1, Lgeq, Lgeq_n}, {"float", Lfloat, Lfloat_2, wrong_no_1}, {"logior", Lidentity, Llogor2, Lboolfn}, {"random", Lrandom, Lrandom_2, wrong_no_1}, {"rationalize", Lrationalize, too_many_1, wrong_no_1}, {"manexp", Lmanexp, too_many_1, wrong_no_1}, {"rem", too_few_2, Lrem, wrong_no_2}, /* * I also provide the old style names to make porting code easier for me */ {"times", Lidentity, Ltimes2, Ltimes}, {"plus", Lidentity, Lplus2, Lplus}, {"times2", too_few_2, Ltimes2, wrong_no_2}, {"plus2", too_few_2, Lplus2, wrong_no_2}, {"minus", Lminus, too_many_1, wrong_no_1}, {"difference", too_few_2, Ldifference2, Ldifference}, /* I leave QUOTIENT as the integer-truncating form, while "/" gives ratios */ {"quotient", too_few_2, LSLquotient, wrong_no_2}, {"remainder", too_few_2, Lrem, wrong_no_2}, {"add1", Ladd1, too_many_1, wrong_no_1}, {"sub1", Lsub1, too_many_1, wrong_no_1}, {"lessp", Llessp_1, Llessp, Llessp_n}, {"leq", Lleq_1, Lleq, Lleq_n}, {"eqn", Leqn_1, Leqn, Leqn_n}, {"greaterp", Lgreaterp_1, Lgreaterp, Lgreaterp_n}, {"geq", Lgeq_1, Lgeq, Lgeq_n}, {"next-random-number", wrong_no_0a, wrong_no_0b, Lnext_random}, {"logor", Lidentity, Llogor2, Lboolfn}, #else {"add1", Ladd1, too_many_1, wrong_no_1}, {"difference", too_few_2, Ldifference2, wrong_no_2}, {"eqn", too_few_2, Leqn, wrong_no_2}, {"float", Lfloat, too_many_1, wrong_no_1}, {"geq", too_few_2, Lgeq, wrong_no_2}, {"greaterp", too_few_2, Lgreaterp, wrong_no_2}, {"leq", too_few_2, Lleq, wrong_no_2}, {"lessp", too_few_2, Llessp, wrong_no_2}, {"logor", Lidentity, Llogor2, Lboolfn}, {"quotient", too_few_2, Lquotient, wrong_no_2}, /* * I used to call these just random and next-random-number, but REDUCE * wants its own versions of those (for cross-Lisp consistency) so I use * alternative names here. */ {"random-number", Lrandom, too_many_1, wrong_no_1}, {"random-fixnum", wrong_no_0a, wrong_no_0b, Lnext_random}, {"remainder", too_few_2, Lrem, wrong_no_2}, {"sub1", Lsub1, too_many_1, wrong_no_1}, #endif {NULL, 0, 0, 0} }; /* end of arith06.c */