/* arith08.c Copyright (C) 1990-2002 Codemist Ltd */
/*
* Arithmetic functions.
*/
/*
* 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: 2f37a658 08-Apr-2002 */
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <float.h>
#include "machine.h"
#include "tags.h"
#include "cslerror.h"
#include "externs.h"
#include "arith.h"
#include "entries.h"
#ifdef TIMEOUT
#include "timeout.h"
#endif
#ifdef COMMON
static Lisp_Object MS_CDECL Lboole(Lisp_Object nil, int nargs, ...)
{
Lisp_Object r, op, a, b;
va_list aa;
argcheck(nargs, 3, "boole");
va_start(aa, nargs);
op = va_arg(aa, Lisp_Object);
a = va_arg(aa, Lisp_Object);
b = va_arg(aa, Lisp_Object);
va_end(aa);
switch (op)
{
case fixnum_of_int(boole_clr):
return onevalue(fixnum_of_int(0));
case fixnum_of_int(boole_and):
r = logand2(a, b);
break;
case fixnum_of_int(boole_andc2):
push(a);
b = lognot(b);
pop(a);
errexit();
r = logand2(a, b);
break;
case fixnum_of_int(boole_1):
return onevalue(a);
case fixnum_of_int(boole_andc1):
push(b);
a = lognot(a);
pop(b);
errexit();
r = logand2(a, b);
break;
case fixnum_of_int(boole_2):
return onevalue(b);
case fixnum_of_int(boole_xor):
r = logxor2(a, b);
break;
case fixnum_of_int(boole_ior):
r = logior2(a, b);
break;
case fixnum_of_int(boole_nor):
a = logior2(a, b);
errexit();
r = lognot(a);
break;
case fixnum_of_int(boole_eqv):
r = logeqv2(a, b);
break;
case fixnum_of_int(boole_c2):
r = lognot(b);
break;
case fixnum_of_int(boole_orc2):
b = lognot(b);
errexit();
r = logior2(a, b);
break;
case fixnum_of_int(boole_c1):
r = lognot(a);
break;
case fixnum_of_int(boole_orc1):
push(b);
a = lognot(a);
pop(b);
errexit();
r = logior2(a, b);
break;
case fixnum_of_int(boole_nand):
a = logand2(a, b);
errexit();
r = lognot(a);
break;
case fixnum_of_int(boole_set):
return onevalue(fixnum_of_int(-1));
default:
return aerror1("bad arg for boole", op);
}
errexit();
return onevalue(r);
}
static Lisp_Object Lbyte(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
a = cons(a, b);
errexit();
return onevalue(a);
}
static Lisp_Object Lbyte_position(Lisp_Object nil, Lisp_Object a)
{
if (!consp(a)) return aerror1("byte-position", a);
else return onevalue(qcdr(a));
}
static Lisp_Object Lbyte_size(Lisp_Object nil, Lisp_Object a)
{
if (!consp(a)) return aerror1("byte-size", a);
else return onevalue(qcar(a));
}
static Lisp_Object Lcomplex_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
/* /* Need to coerce a and b to the same type here... */
a = make_complex(a, b);
errexit();
return onevalue(a);
}
static Lisp_Object Lcomplex_1(Lisp_Object nil, Lisp_Object a)
{
/* /* Need to make zero of same type as a */
a = make_complex(a, fixnum_of_int(0));
errexit();
return onevalue(a);
}
static Lisp_Object Lconjugate(Lisp_Object nil, Lisp_Object a)
{
if (!is_number(a)) return aerror1("conjugate", a);
if (is_numbers(a) && is_complex(a))
{ Lisp_Object r = real_part(a),
i = imag_part(a);
push(r);
i = negate(i);
pop(r);
errexit();
a = make_complex(r, i);
errexit();
return onevalue(a);
}
else return onevalue(a);
}
static Lisp_Object Ldecode_float(Lisp_Object nil, Lisp_Object a)
{
double d = float_of_number(a), neg = 1.0;
int x;
Lisp_Object sign;
if (!is_float(a)) return aerror("decode-float");
if (d < 0.0) d = -d, neg = -1.0;
if (d == 0.0) x = 0;
else
{ d = frexp(d, &x);
if (d == 1.0) d = 0.5, x++;
}
if (is_sfloat(a)) sign = make_sfloat(neg);
else sign = make_boxfloat(neg, type_of_header(flthdr(a)));
errexit();
push(sign);
if (is_sfloat(a)) a = make_sfloat(d);
else a = make_boxfloat(d, type_of_header(flthdr(a)));
pop(sign);
errexit();
mv_2 = fixnum_of_int(x);
mv_3 = sign;
return nvalues(a, 3);
}
/*
* The next two functions depend on IEEE-format floating point numbers.
* They are (thus?) potentially a portability trap, but may suffice for
* MOST systems. I need to test the handling of double precision values
* on computers that store the two words of a double in each of the
* possible orders. If the exponent field in floats was not stored in the
* position that would be 0x7f800000 in an integer my treatment of short
* floats would fail, so I have already assumed that that is so. I think.
*/
static Lisp_Object Lfloat_denormalized_p(Lisp_Object nil, Lisp_Object a)
{
int x = 0;
switch ((int)a & TAG_BITS)
{
#ifdef COMMON
case TAG_SFLOAT:
if ((a & 0x7fffffff) == TAG_SFLOAT) return onevalue(nil); /* 0.0 */
x = (int32)a & 0x7f800000;
return onevalue(x == 0 ? lisp_true : nil);
#endif
case TAG_BOXFLOAT:
switch (type_of_header(flthdr(a)))
{
#ifdef COMMON
case TYPE_SINGLE_FLOAT:
if (single_float_val(a) == 0.0) return onevalue(nil);
x = ((Single_Float *)((char *)a-TAG_BOXFLOAT))->f.i & 0x7f800000;
return onevalue(x == 0 ? lisp_true : nil);
case TYPE_LONG_FLOAT:
if (long_float_val(a) == 0.0) return onevalue(nil);
x = ((Long_Float *)((char *)a-TAG_BOXFLOAT)
)->f.i[current_fp_rep&FP_WORD_ORDER ? 0 : 1] & 0x7ff00000;
return onevalue(x == 0 ? lisp_true : nil);
#endif
case TYPE_DOUBLE_FLOAT:
if (double_float_val(a) == 0.0) return onevalue(nil);
x = ((Double_Float *)((char *)a-TAG_BOXFLOAT)
)->f.i[current_fp_rep&FP_WORD_ORDER ? 0 : 1] & 0x7ff00000;
return onevalue(x == 0 ? lisp_true : nil);
}
default:
break;
}
return onevalue(nil);
}
static Lisp_Object Lfloat_infinity_p(Lisp_Object nil, Lisp_Object a)
{
/*
* The issue of NaN values is one I do not want to worry about at present.
* I deem anything with the largest possibl exponent value to be infinite.
*/
int x = 0;
switch ((int)a & TAG_BITS)
{
#ifdef COMMON
case TAG_SFLOAT:
x = (int32)a & 0x7f800000;
return onevalue(x == 0x7f800000 ? lisp_true : nil);
#endif
case TAG_BOXFLOAT:
switch (type_of_header(flthdr(a)))
{
#ifdef COMMON
case TYPE_SINGLE_FLOAT:
if (single_float_val(a) == 0.0) return onevalue(nil);
x = ((Single_Float *)((char *)a-TAG_BOXFLOAT))->f.i & 0x7f800000;
return onevalue(x == 0x7f800000 ? lisp_true : nil);
case TYPE_LONG_FLOAT:
if (long_float_val(a) == 0.0) return onevalue(nil);
x = ((Long_Float *)((char *)a-TAG_BOXFLOAT)
)->f.i[current_fp_rep&FP_WORD_ORDER ? 0 : 1] & 0x7ff00000;
return onevalue(x == 0x7ff00000 ? lisp_true : nil);
#endif
case TYPE_DOUBLE_FLOAT:
if (double_float_val(a) == 0.0) return onevalue(nil);
x = ((Double_Float *)((char *)a-TAG_BOXFLOAT)
)->f.i[current_fp_rep&FP_WORD_ORDER ? 0 : 1] & 0x7ff00000;
return onevalue(x == 0x7ff00000 ? lisp_true : nil);
}
default:
break;
}
return onevalue(nil);
}
static Lisp_Object Ldenominator(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
if (!is_number(a)) return aerror1("denominator", a);
if (is_numbers(a) && is_ratio(a))
return onevalue(denominator(a));
else return onevalue(fixnum_of_int(1));
}
static Lisp_Object MS_CDECL Ldeposit_field(Lisp_Object nil, int nargs, ...)
{
va_list aa;
Lisp_Object a, b, c;
CSL_IGNORE(nil);
CSL_IGNORE(nargs);
va_start(aa, nargs);
a = va_arg(aa, Lisp_Object);
b = va_arg(aa, Lisp_Object);
c = va_arg(aa, Lisp_Object);
va_end(aa);
return aerror("deposit-field");
}
static Lisp_Object MS_CDECL Ldpb(Lisp_Object nil, int nargs, ...)
{
va_list aa;
Lisp_Object a, b, c;
CSL_IGNORE(nil);
CSL_IGNORE(nargs);
va_start(aa, nargs);
a = va_arg(aa, Lisp_Object);
b = va_arg(aa, Lisp_Object);
c = va_arg(aa, Lisp_Object);
va_end(aa);
return aerror("dpb");
}
static Lisp_Object Lffloor(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
CSL_IGNORE(a);
CSL_IGNORE(b);
return aerror("ffloor");
}
/*
* The functions such as float-digits, float-precision, float-radix are
* coded here assuming that IEEE-style arithmetic is being used. If this is
* not so then all the code in this file needs review. Furthermore I will
* be lazy about NaNs and denormalised numbers for now and come back to
* worry about them later on if I am really forced to.
*/
static Lisp_Object Lfloat_digits(Lisp_Object nil, Lisp_Object a)
{
int tag = (int)a & TAG_BITS;
CSL_IGNORE(nil);
switch (tag)
{
#ifdef COMMON
case TAG_SFLOAT:
return onevalue(fixnum_of_int(20));
#endif
case TAG_BOXFLOAT:
switch (type_of_header(flthdr(a)))
{
#ifdef COMMON
case TYPE_SINGLE_FLOAT:
return onevalue(fixnum_of_int(24));
#endif
default:
return onevalue(fixnum_of_int(53));
}
default:
return aerror("float-digits");
}
}
static Lisp_Object Lfloat_precision(Lisp_Object nil, Lisp_Object a)
{
int tag = (int)a & TAG_BITS;
double d = float_of_number(a);
CSL_IGNORE(nil);
if (d == 0.0) return onevalue(fixnum_of_int(0));
/* /* I do not cope with de-normalised numbers here */
switch (tag)
{
#ifdef COMMON
case TAG_SFLOAT:
return onevalue(fixnum_of_int(20));
#endif
case TAG_BOXFLOAT:
switch (type_of_header(flthdr(a)))
{
#ifdef COMMON
case TYPE_SINGLE_FLOAT:
return onevalue(fixnum_of_int(24));
#endif
default:
return onevalue(fixnum_of_int(53));
}
default:
return aerror("float-precision");
}
}
static Lisp_Object Lfloat_radix(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
CSL_IGNORE(a);
return onevalue(fixnum_of_int(FLT_RADIX));
}
static Lisp_Object Lfloat_sign2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
double d = float_of_number(b);
CSL_IGNORE(nil);
if (float_of_number(a) < 0.0) d = -d;
if (is_sfloat(b)) return onevalue(make_sfloat(d));
else if (!is_bfloat(b)) return aerror1("bad arg for float-sign", b);
else return onevalue(make_boxfloat(d, type_of_header(flthdr(b))));
}
static Lisp_Object Lfloat_sign1(Lisp_Object nil, Lisp_Object a)
{
double d = float_of_number(a);
CSL_IGNORE(nil);
if (d < 0.0) d = -1.0; else d = 1.0;
if (is_sfloat(a)) return onevalue(make_sfloat(d));
else if (!is_bfloat(a)) return aerror1("bad arg for float-sign", a);
else return onevalue(make_boxfloat(d, type_of_header(flthdr(a))));
}
static Lisp_Object Lfround(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
CSL_IGNORE(a);
CSL_IGNORE(b);
return aerror("fround");
}
static Lisp_Object Lftruncate(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
CSL_IGNORE(a);
CSL_IGNORE(b);
return aerror("ftruncate");
}
Lisp_Object MS_CDECL Lgcd_n(Lisp_Object nil, int nargs, ...)
{
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);
for (i = 1; i<nargs; i++)
{ Lisp_Object w;
if (r == fixnum_of_int(1))
{ popv(nargs-i);
break;
}
pop(w);
r = gcd(r, w);
errexitn(nargs-i-1);
}
return onevalue(r);
}
Lisp_Object Lgcd(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
a = gcd(a, b);
errexit();
return onevalue(a);
}
Lisp_Object Lgcd_1(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
return onevalue(a);
}
static Lisp_Object Limagpart(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
if (!is_number(a)) return aerror1("imagpart", a);
if (is_numbers(a) && is_complex(a))
return onevalue(imag_part(a));
/* /* the 0.0 returned here ought to be the same type as a has */
else return onevalue(fixnum_of_int(0));
}
static Lisp_Object Linteger_decode_float(Lisp_Object nil, Lisp_Object a)
{
double d = float_of_number(a);
int tag = (int)a & TAG_BITS, x, neg = 0;
int32 a1, a2;
CSL_IGNORE(nil);
if (!is_float(a)) return aerror("integer-decode-float");
if (d == 0.0)
#ifdef COMMON
{ mv_2 = fixnum_of_int(0);
mv_3 = fixnum_of_int(1);
nvalues(a, 3);
}
#else
return list3(a, fixnum_of_int(0), fixnum_of_int(1));
#endif
if (d < 0.0) d = -d, neg = 1;
d = frexp(d, &x);
if (d == 1.0) d = 0.5, x++;
#ifdef COMMON
if (tag == TAG_SFLOAT)
{ d *= TWO_20;
x -= 20;
a1 = (int32)d;
a = fixnum_of_int(a1);
}
else if (tag == TAG_BOXFLOAT &&
type_of_header(flthdr(a)) == TYPE_SINGLE_FLOAT)
{ d *= TWO_24;
x -= 24;
a1 = (int32)d;
a = fixnum_of_int(a1);
}
else
#endif
{ d *= TWO_22;
a1 = (int32)d;
d -= (double)a1;
a2 = (int32)(d*TWO_31); /* This conversion should be exact */
x -= 53;
a = make_two_word_bignum(a1, a2);
errexit();
}
#ifdef COMMON
{ mv_2 = fixnum_of_int(x);
mv_3 = neg ? fixnum_of_int(-1) : fixnum_of_int(1);
return nvalues(a, 3);
}
#else
return list3(a, fixnum_of_int(x),
neg ? fixnum_of_int(-1) : fixnum_of_int(1));
#endif
}
static Lisp_Object Linteger_length(Lisp_Object nil, Lisp_Object a)
{
a = Labsval(nil, a);
errexit();
return Lmsd(nil, a);
}
static Lisp_Object Lldb(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
CSL_IGNORE(a);
CSL_IGNORE(b);
return aerror("ldb");
}
Lisp_Object MS_CDECL Llcm_n(Lisp_Object nil, int nargs, ...)
{
va_list a;
int i;
Lisp_Object r;
if (nargs == 0) return onevalue(fixnum_of_int(1));
va_start(a, nargs);
push_args(a, nargs);
stackcheck0(nargs);
pop(r);
for (i = 1; i<nargs; i++)
{ Lisp_Object w;
pop(w);
r = lcm(r, w);
errexitn(nargs-i-1);
}
return onevalue(r);
}
Lisp_Object Llcm(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
a = lcm(a, b);
errexit();
return onevalue(a);
}
Lisp_Object Llcm_1(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
return onevalue(a);
}
static Lisp_Object Lldb_test(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
CSL_IGNORE(a);
CSL_IGNORE(b);
return aerror("ldb-test");
}
static Lisp_Object Llogbitp(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
CSL_IGNORE(a);
CSL_IGNORE(b);
return aerror("logbitp");
}
static Lisp_Object Llogcount(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
CSL_IGNORE(a);
return aerror("logcount");
}
static Lisp_Object Llogtest(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
CSL_IGNORE(a);
CSL_IGNORE(b);
return aerror("logtest");
}
static Lisp_Object Lmask_field(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
CSL_IGNORE(a);
CSL_IGNORE(b);
return aerror("mask-field");
}
static Lisp_Object Lnumerator(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
if (!is_number(a)) return aerror1("numerator", a);
if (is_numbers(a) && is_ratio(a))
return onevalue(numerator(a));
else return onevalue(a);
}
static Lisp_Object Lrealpart(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
if (!is_number(a)) return aerror1("realpart", a);
if (is_numbers(a) && is_complex(a))
return onevalue(real_part(a));
else return onevalue(a);
}
static Lisp_Object Lscale_float(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
double d = float_of_number(a);
CSL_IGNORE(nil);
if (!is_fixnum(b)) return aerror("scale-float");
d = ldexp(d, int_of_fixnum(b));
if (is_sfloat(a)) return onevalue(make_sfloat(d));
else if (!is_bfloat(a)) return aerror1("bad arg for scale-float", a);
else return onevalue(make_boxfloat(d, type_of_header(flthdr(a))));
}
#else /* COMMON */
Lisp_Object Lgcd(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
a = gcd(a, b);
errexit();
return onevalue(a);
}
Lisp_Object Llcm(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
Lisp_Object g;
push2(b, a);
g = gcd(a, b);
errexitn(2);
pop(a);
a = quot2(a, g);
pop(b);
errexit();
a = times2(a, b);
errexit();
return onevalue(a);
}
#endif /* COMMON */
#define FIX_TRUNCATE 0
#define FIX_ROUND 1
#define FIX_FLOOR 2
#define FIX_CEILING 3
static Lisp_Object lisp_fix_sub(Lisp_Object a, int roundmode)
/*
* This converts from a double to a Lisp integer, which will
* quite often have to be a bignum. No overflow is permitted - the
* result can always be accurate.
*/
{
int32 a0, a1, a2, a3;
int x, x1;
CSLbool negative;
double d = float_of_number(a);
if (M2_31_1 < d && d < TWO_31)
{ int32 a = (int32)d;
/*
* If my floating point value is in the range -(2^31+1) to +2^31 (exclusive)
* then when C truncates it I will get an integer in the inclusive range
* from -2^31 to 2^31-1, i.e. the whole range of C 32-bit integers.
* If I then apply a rounding mode other than truncation I may just have
* overflow, which I have to detect specially.
*/
int32 w;
double f;
switch (roundmode)
{
case FIX_TRUNCATE:
break; /* C casts truncate, so this is OK */
case FIX_ROUND:
f = d - (double)a;
if (f > 0.5)
{ if (a == 0x7fffffff) return make_two_word_bignum(1, 0);
else a++;
}
else if (f < -0.5)
{ if (a == ~0x7fffffff)
return make_two_word_bignum(-2, 0x7fffffff);
else a--;
}
/* The rounding rule on the next lines show what I do in 1/2ulp cases */
else if (f == 0.5) a = (a+1) & ~1;
else if (f == -0.5)
{ if (a == ~0x7fffffff)
return make_two_word_bignum(-2, 0x7fffffff);
else a = a & ~1;
}
break;
case FIX_FLOOR:
f = d - (double)a;
if (f < 0.0)
{ if (a == ~0x7fffffff)
return make_two_word_bignum(-2, 0x7fffffff);
else a--;
}
break;
case FIX_CEILING:
f = d - (double)a;
if (f > 0.0)
{ if (a == 0x7fffffff) return make_two_word_bignum(1, 0);
else a++;
}
break;
}
w = a & fix_mask;
if (w == 0 || w == fix_mask) return fixnum_of_int(a);
else if (!signed_overflow(a)) return make_one_word_bignum(a);
else if (a > 0) return make_two_word_bignum(0, a);
else return make_two_word_bignum(-1, clear_top_bit(a));
}
if (d < 0.0) d = -d, negative = YES;
else negative = NO;
d = frexp(d, &x); /* 0.5 <= abs(d) < 1.0, x = the (binary) exponent */
if (d == 1.0) d = 0.5, x++;
d *= TWO_31;
a1 = (int32)d; /* 2^31 > d >= 2^30 */
d -= (double)a1;
a2 = (unsigned32)(d*TWO_31); /* This conversion should be exact */
if (negative)
{ if (a2 == 0) a1 = -a1;
else a2 = clear_top_bit(-a2), a1 = ~a1;
}
x -= 62;
if (x < 0) /* Need to shift right x places */
{ x = -x; /* The shift amount here can be 31 at most... */
a3 = a2 << (32 - x);
a2 = clear_top_bit((a2 >> x) | (a1 << (31 - x)));
#ifdef SIGNED_SHIFTS_ARE_LOGICAL
if (a1 < 0) a1 = (a1 >> x) | (((int32)-1) << (31 - x));
else a1 = a1 >> x;
#else
a1 = a1 >> x;
#endif
switch (roundmode)
{
case FIX_TRUNCATE:
if (a1 < 0 && a3 != 0) /* proper rounding on -ve values */
{ a2++;
if (a2 < 0) /* carry */
{ a2 = 0;
a1++;
}
}
break;
case FIX_ROUND:
if ((a3 & 0x80000000U) != 0 &&
(a3 != ~0x7fffffff || (a2 & 1) != 0))
{ a2++;
if (a2 < 0) /* carry */
{ a2 = 0;
a1++;
}
}
break;
case FIX_FLOOR: /* Comes out in wash of 2's complement */
break;
case FIX_CEILING:
if (a3 != 0)
{ a2++;
if (a2 < 0) /* carry */
{ a2 = 0;
a1++;
}
}
break;
}
return make_two_word_bignum(a1, a2);
}
/* Now the double-length value (a1,a2) is correct and exact, and it
* needs shifting left by x bits. This will give a 3 or more word bignum.
* Note that no rounding etc is needed at all here since there are no
* fractional bits in the representation.
*/
if (a1 < 0)
{ a0 = -1;
a1 = clear_top_bit(a1);
}
else a0 = 0;
x1 = x / 31;
x = x % 31;
a0 = (a0 << x) | (a1 >> (31-x));
a1 = clear_top_bit(a1 << x) | (a2 >> (31-x));
a2 = clear_top_bit(a2 << x);
return make_n_word_bignum(a0, a1, a2, x1);
}
#ifdef COMMON
static Lisp_Object lisp_fix_ratio(Lisp_Object a, int roundmode)
/*
* This converts from a ratio to a Lisp integer. It has to apply
* the specified rounding regime.
*/
{
Lisp_Object p, q, r, nil = C_nil;;
p = numerator(a);
q = denominator(a);
push2(q, p);
r = quot2(p, q);
errexitn(2);
p = stack[0];
stack[0] = r;
p = Cremainder(p, stack[-1]);
pop2(r, q);
errexit();
switch (roundmode)
{
case FIX_TRUNCATE:
break;
case FIX_ROUND:
/* /* This case unfinished at present */
break;
case FIX_FLOOR:
if (minusp(p))
{ push(r);
p = plus2(p, q);
pop(r);
errexit();
r = sub1(r);
errexit();
}
break;
case FIX_CEILING:
if (plusp(p))
{ push(r);
p = difference2(p, q);
pop(r);
errexit();
r = add1(r);
errexit();
}
break;
}
mv_2 = p;
return nvalues(r, 2);
}
#endif
static Lisp_Object lisp_fix(Lisp_Object a, int roundmode)
{
Lisp_Object r, nil;
push(a);
r = lisp_fix_sub(a, roundmode);
errexitn(1);
a = stack[0];
stack[0] = r;
a = difference2(a, r);
pop(r);
errexit();
mv_2 = a;
return nvalues(r, 2);
}
static Lisp_Object lisp_ifix(Lisp_Object a, Lisp_Object b, int roundmode)
{
Lisp_Object q, r, nil;
if (is_float(a) || is_float(b))
{ double p = float_of_number(a), q = float_of_number(b), d = p/q;
a = make_boxfloat(d, TYPE_DOUBLE_FLOAT);
errexit();
r = lisp_fix(a, roundmode);
errexit();
push(r);
a = make_boxfloat(float_of_number(mv_2)*q, TYPE_DOUBLE_FLOAT);
pop(r);
errexit();
mv_2 = a;
return nvalues(r, 2);
}
push2(a, b);
q = quot2(a, b);
errexitn(2);
a = stack[-1];
b = stack[0];
push(q);
r = Cremainder(a, b);
errexitn(3);
switch (roundmode)
{
case FIX_TRUNCATE:
break;
case FIX_ROUND:
popv(3); return aerror("two-arg ROUND");
case FIX_FLOOR:
if (!minusp(r)) break;
r = plus2(r, stack[-1]);
errexitn(3);
q = stack[0];
push(r);
q = sub1(q);
pop(r);
errexitn(3);
stack[0] = q;
break;
case FIX_CEILING:
if (!plusp(r)) break;
r = difference2(r, stack[-1]);
errexitn(3);
q = stack[0];
push(r);
q = add1(q);
pop(r);
errexitn(3);
stack[0] = q;
break;
}
pop3(q, b, a);
mv_2 = r;
return nvalues(q, 2);
}
/*
* So far I have not implemented support for rational numbers in the 2-arg
* versions of these functions. /*
*/
static Lisp_Object Lceiling_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
if (!is_number(a) || !is_number(b)) return aerror1("ceiling", a);
return lisp_ifix(a, b, FIX_CEILING);
}
static Lisp_Object Lfloor_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
if (!is_number(a) || !is_number(b)) return aerror1("floor", a);
return lisp_ifix(a, b, FIX_FLOOR);
}
static Lisp_Object Lround_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
if (!is_number(a) || !is_number(b)) return aerror1("round", a);
return lisp_ifix(a, b, FIX_ROUND);
}
Lisp_Object Ltruncate_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
CSL_IGNORE(nil);
if (!is_number(a) || !is_number(b)) return aerror1("truncate", a);
return lisp_ifix(a, b, FIX_TRUNCATE);
}
static Lisp_Object Lceiling(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
if (!is_number(a)) return aerror1("ceiling", a);
#ifdef COMMON
if (is_numbers(a) && is_ratio(a)) return lisp_fix_ratio(a, FIX_CEILING);
#endif
if (!is_float(a)) { mv_2 = fixnum_of_int(0); return nvalues(a, 2); }
return lisp_fix(a, FIX_CEILING);
}
static Lisp_Object Lfloor(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
if (!is_number(a)) return aerror1("floor", a);
#ifdef COMMON
if (is_numbers(a) && is_ratio(a)) return lisp_fix_ratio(a, FIX_FLOOR);
#endif
if (!is_float(a)) { mv_2 = fixnum_of_int(0); return nvalues(a, 2); }
return lisp_fix(a, FIX_FLOOR);
}
static Lisp_Object Lround(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
if (!is_number(a)) return aerror1("round", a);
#ifdef COMMON
if (is_numbers(a) && is_ratio(a)) return lisp_fix_ratio(a, FIX_ROUND);
#endif
if (!is_float(a)) { mv_2 = fixnum_of_int(0); return nvalues(a, 2); }
return lisp_fix(a, FIX_ROUND);
}
Lisp_Object Ltruncate(Lisp_Object nil, Lisp_Object a)
{
CSL_IGNORE(nil);
if (!is_number(a)) return aerror1("fix", a);
#ifdef COMMON
if (is_numbers(a) && is_ratio(a)) return lisp_fix_ratio(a, FIX_TRUNCATE);
#endif
if (!is_float(a)) { mv_2 = fixnum_of_int(0); return nvalues(a, 2); }
return lisp_fix(a, FIX_TRUNCATE);
}
/*
* The following macro is expected to select out the 32-bit word within a
* floating point number that has the exponent field packed within it.
* On IEEE-format machines I expect to find the exponent in the
* 0x7ff00000 bits within this word.
*/
#define top_half(d) ((int32 *)&(d))[(~current_fp_rep) & FP_WORD_ORDER]
/*
* symbolic procedure safe!-fp!-plus(x,y);
* if zerop x then y else if zerop y then x else
* begin scalar u;
* if x>0.0 and y>0.0 then
* if x<!!plumax and y<!!plumax then go to ret else return nil;
* if x<0.0 and y<0.0 then
* if -x<!!plumax and -y<!!plumax then go to ret else return nil;
* if abs x<!!plumin and abs y<!!plumin then return nil;
* ret: return
* if (u := plus2(x,y))=0.0
* or x>0.0 and y>0.0 or x<0.0 and y<0.0 then u
* else if abs u<(abs x)*!!fleps1 then 0.0 else u end;
*/
static Lisp_Object Lsafe_fp_plus(Lisp_Object env, Lisp_Object a, Lisp_Object b)
/*
* safe!-fp!-plus must always be given floating point arguments. In
* most reasonable cases it just returns the floating point sum. If
* there was some chance that the sum might either overflow or underflow
* then the value NIL is returned instead. The exact place where this
* function starts to report overflow is not precisely defined - all that
* is guaranteed is that if a result is returned then it will be of full
* precision.
*/
{
Lisp_Object nil = C_nil;
double aa, bb, cc;
int32 ah, bh;
if (!is_float(a) || !is_float(b)) return aerror2("safe-fp-plus", a, b);
/*
* I accept here that adding 0.0 to anything is always possible without
* problem.
*/
if ((aa = double_float_val(a)) == 0.0) return onevalue(b);
if ((bb = double_float_val(b)) == 0.0) return onevalue(a);
if (current_fp_rep & (FP_VAXREP|FP_IBMREP))
return aerror("VAX or 370 FP rep");
ah = top_half(aa);
bh = top_half(bb);
/*
* Here I am going to assume IEEE-format numbers. I hope that I have
* picked out the word containing the exponent and that it is positioned in
* the word where I expect.
*/
/*
* I deem overflow POSSIBLE if both numbers have the same sign and if at
* least one of them has an exponent 0x7fe (i.e. the highest exponent that
* a non-infinite number can have).
*/
if (ah >= 0)
{ if (bh >= 0)
{ if (ah >= 0x7fe00000 || bh >= 0x7fe00000) return onevalue(nil);
cc = aa + bb;
}
else
/*
* I deem underflow POSSIBLE if the numbers have opposite signs and BOTH
* of them have exponents less than 0x035 (which is 53 in decimal, and
* IEEE-format numbers have 53-bit mantissas. The critical case would
* be the subtraction
* (53) 1 00000000000000000000 00000000000000000000000000000001
* - (53) 1 00000000000000000000 00000000000000000000000000000000
* where you see the LSB (which is all that is left after the subtraction)
* has to be shifted left 52 bits to get to the position of the implied
* leading 1 bit in the mantissa. As that happens 52 gets subtracted
* from the exponent, leaving it as 1, the smallest exponent for a normalised
* non-zero value.
*/
{ double eps, ra;
bh &= 0x7fffffff;
if (ah < 0x03500000 && bh < 0x03500000) return onevalue(nil);
/*
* The next few lines check to see if addition has led to cancellation of
* leading digits to an extent greater than !!fleps1. The environent cell
* of safe!-fp!-plus must be set to !!fleps, and then the value cell of
* this symbol is accessed to obtain the limit.
*/
eps = 0.0;
if (is_symbol(env))
{ Lisp_Object ve = qvalue(env);
if (is_float(ve)) eps = double_float_val(ve);
}
cc = aa + bb;
ra = cc/aa;
if (ra < 0.0) ra = -ra;
if (ra < eps) cc = 0.0; /* Force to zero if too small */
}
}
else
{ if (bh >= 0)
{ double eps, ra;
ah &= 0x7fffffff;
if (ah < 0x03500000 && bh < 0x03500000) return onevalue(nil);
eps = 0.0;
if (is_symbol(env))
{ Lisp_Object ve = qvalue(env);
if (is_float(ve)) eps = double_float_val(ve);
}
cc = aa + bb;
ra = cc/aa;
if (ra < 0.0) ra = -ra;
if (ra < eps) cc = 0.0;
}
else
{ ah &= 0x7fffffff;
bh &= 0x7fffffff;
if (ah >= 0x7fe00000 || bh >= 0x7fe00000) return onevalue(nil);
cc = aa + bb;
}
}
a = make_boxfloat(cc, TYPE_DOUBLE_FLOAT);
errexit();
return onevalue(a);
}
/*
* symbolic procedure safe!-fp!-times(x,y);
* if zerop x or zerop y then 0.0
* else if x=1.0 then y else if y=1.0 then x else
* begin scalar u,v; u := abs x; v := abs y;
* if u>=1.0 and u<=!!timmax then
* if v<=!!timmax then go to ret else return nil;
* if u>!!timmax then if v<=1.0 then go to ret else return nil;
* if u<1.0 and u>=!!timmin then
* if v>=!!timmin then go to ret else return nil;
* if u<!!timmin and v<1.0 then return nil;
* ret: return times2(x,y) end;
*/
static Lisp_Object Lsafe_fp_times(Lisp_Object nil,
Lisp_Object a, Lisp_Object b)
/*
* safe!-fp!-times must always be given floating point arguments. In
* most reasonable cases it just returns the floating point product. If
* there was some chance that the product might either overflow or underflow
* then the value NIL is returned instead. REDUCE requires that if this
* function returns a non-overflow result than two such returned values
* can be added witjout fear of overflow, as in a*b+c*d. Hence I ought to
* report trouble slightly earlier than I might otherwise. - but REDUCE is
* being changed to remove this oddity, and it seems it could only cause
* trouble in (1.0,max)*(max, 1.0) complex multiplication, so I am not
* going to worry...
*/
{
double aa, bb, cc;
int32 ah, bh;
if (!is_float(a) || !is_float(b)) return aerror2("safe-fp-times", a, b);
/*
* Multiplication by zero is handled as a special case here - doing so
* means that I do not have to worry about the special case of zero
* exponents later on, and it also avoids allocating fresh space to hold
* a new floating point zero value.
*/
if ((aa = double_float_val(a)) == 0.0) return onevalue(a);
if ((bb = double_float_val(b)) == 0.0) return onevalue(b);
if (current_fp_rep & (FP_VAXREP|FP_IBMREP))
return aerror("VAX or 370 FP rep");
ah = top_half(aa);
bh = top_half(bb);
/*
* Here I am going to assume IEEE-format numbers. I hope that I have
* picked out the word containing the exponent and that it is positioned in
* the word where I expect.
*/
ah = (ah >> 20) & 0x7ff;
bh = (bh >> 20) & 0x7ff;
ah = ah + bh;
/*
* I can estimate the value of the product by adding the exponents of the
* two operands.
*/
if (ah < 0x400 || ah >= 0xbfd) return onevalue(nil);
cc = aa * bb;
a = make_boxfloat(cc, TYPE_DOUBLE_FLOAT);
errexit();
return onevalue(a);
}
/*
* symbolic procedure safe!-fp!-quot(x,y);
* if zerop y then rdqoterr()
* else if zerop x then 0.0 else if y=1.0 then x else
* begin scalar u,v; u := abs x; v := abs y;
* if u>=1.0 and u<=!!timmax then
* if v>=!!timmin then go to ret else return nil;
* if u>!!timmax then if v>=1.0 then go to ret else return nil;
* if u<1.0 and u>=!!timmin then
* if v<=!!timmax then go to ret else return nil;
* if u<!!timmin and v>1.0 then return nil;
* ret: return quotient(x,y) end;
*/
static Lisp_Object Lsafe_fp_quot(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
double aa, bb, cc;
int32 ah, bh;
if (!is_float(a) || !is_float(b)) return aerror2("safe-fp-quot", a, b);
if ((aa = double_float_val(a)) == 0.0) return onevalue(a);
/*
* I pass division by zero back to the general case here.
*/
if ((bb = double_float_val(b)) == 0.0) return onevalue(nil);
if (current_fp_rep & (FP_VAXREP|FP_IBMREP))
return aerror("VAX or 370 FP rep");
ah = top_half(aa);
bh = top_half(bb);
ah = (ah >> 20) & 0x7ff;
bh = (bh >> 20) & 0x7ff;
ah = ah - bh;
if (ah <= -0x3fe || ah >= 0x3fe) return onevalue(nil);
cc = aa / bb;
a = make_boxfloat(cc, TYPE_DOUBLE_FLOAT);
errexit();
return onevalue(a);
}
/*
* symbolic procedure safe!-fp!-pl(x,y);
* % floating plus protect from under- and over-flows but no zero
* % result check.
* if zerop x then y else if zerop y then x
* else if x>0 and y>0 then
* if x<!!plumax and y<!!plumax then plus2(x,y) else nil
* else if x<0 and y<0 then
* if (-x<!!plumax and -y<!!plumax) then plus2(x,y) else nil
* else if abs x<!!plumin or abs y<!!plumin then nil else plus2(x,y);
*/
static Lisp_Object Lsafe_fp_pl(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
{
double aa, bb, cc;
int32 ah, bh;
if (!is_float(a) || !is_float(b)) return aerror2("safe-fp-pl", a, b);
if ((aa = double_float_val(a)) == 0.0) return onevalue(b);
if ((bb = double_float_val(b)) == 0.0) return onevalue(a);
if (current_fp_rep & (FP_VAXREP|FP_IBMREP))
return aerror("VAX or 370 FP rep");
ah = top_half(aa);
bh = top_half(bb);
if (ah >= 0)
{ if (bh >= 0)
{ if (ah >= 0x7fe00000 || bh >= 0x7fe00000) return onevalue(nil);
}
else
{ bh &= 0x7fffffff;
if (ah < 0x03500000 && bh < 0x03500000) return onevalue(nil);
}
}
else
{ if (bh >= 0)
{ ah &= 0x7fffffff;
if (ah < 0x03500000 && bh < 0x03500000) return onevalue(nil);
}
else
{ ah &= 0x7fffffff;
bh &= 0x7fffffff;
if (ah >= 0x7fe00000 || bh >= 0x7fe00000) return onevalue(nil);
}
}
cc = aa + bb;
a = make_boxfloat(cc, TYPE_DOUBLE_FLOAT);
errexit();
return onevalue(a);
}
/*
* symbolic procedure safe!-fp!-pl0(x,y);
* % protects floating plus against under-flow only.
* if zerop x then y else if zerop y then x
* else if abs x<!!plumin and abs y<!!plumin then nil else plus2(x,y);
*
* implement as safe!-fp!-pl without MUCH loss of speed.
*/
static Lisp_Object Llose_precision(Lisp_Object nil,
Lisp_Object a, Lisp_Object n)
{
double aa;
char buffer[64];
int32 nn;
if (!is_float(a) || !is_fixnum(n)) return aerror2("lose_precision", a, n);
nn = int_of_fixnum(n);
if (nn <= 0 || nn >= 20) return onevalue(a);
sprintf(buffer, "%.*g", (int)nn, double_float_val(a));
if (sscanf(buffer, "%lg", &aa) != 1) return aerror("lose-precision");
a = make_boxfloat(aa, TYPE_DOUBLE_FLOAT);
errexit();
return onevalue(a);
}
setup_type const arith08_setup[] =
{
/*
* The next few are JUST for REDUCE, but they are expected to speed up
* rounded-mode arithmetic rather a lot.
*/
{"lose-precision", too_few_2, Llose_precision, wrong_no_2},
{"safe-fp-plus", too_few_2, Lsafe_fp_plus, wrong_no_2},
{"safe-fp-times", too_few_2, Lsafe_fp_times, wrong_no_2},
{"safe-fp-quot", too_few_2, Lsafe_fp_quot, wrong_no_2},
{"safe-fp-pl", too_few_2, Lsafe_fp_pl, wrong_no_2},
{"safe-fp-pl0", too_few_2, Lsafe_fp_pl, wrong_no_2},
/* End of REDUCE specialities */
{"ceiling", Lceiling, Lceiling_2, wrong_no_1},
{"floor", Lfloor, Lfloor_2, wrong_no_1},
{"round", Lround, Lround_2, wrong_no_1},
{"truncate", Ltruncate, Ltruncate_2, wrong_no_1},
#ifdef COMMON
{"boole", wrong_no_na, wrong_no_nb, Lboole},
{"byte", too_few_2, Lbyte, wrong_no_2},
{"byte-position", Lbyte_position, too_many_1, wrong_no_1},
{"byte-size", Lbyte_size, too_many_1, wrong_no_1},
{"complex", Lcomplex_1, Lcomplex_2, wrong_no_2},
{"conjugate", Lconjugate, too_many_1, wrong_no_1},
{"decode-float", Ldecode_float, too_many_1, wrong_no_1},
{"float-denormalized-p", Lfloat_denormalized_p, too_many_1, wrong_no_1},
{"float-infinity-p", Lfloat_infinity_p, too_many_1, wrong_no_1},
{"denominator", Ldenominator, too_many_1, wrong_no_1},
{"deposit-field", wrong_no_na, wrong_no_nb, Ldeposit_field},
{"dpb", wrong_no_na, wrong_no_nb, Ldpb},
{"ffloor", too_few_2, Lffloor, wrong_no_2},
{"float-digits", Lfloat_digits, too_many_1, wrong_no_1},
{"float-precision", Lfloat_precision, too_many_1, wrong_no_1},
{"float-radix", Lfloat_radix, too_many_1, wrong_no_1},
{"float-sign", Lfloat_sign1, Lfloat_sign2, wrong_no_2},
{"fround", too_few_2, Lfround, wrong_no_2},
{"ftruncate", too_few_2, Lftruncate, wrong_no_2},
{"gcd", Lgcd_1, Lgcd, Lgcd_n},
{"imagpart", Limagpart, too_many_1, wrong_no_1},
{"integer-decode-float", Linteger_decode_float, too_many_1, wrong_no_1},
{"integer-length", Linteger_length, too_many_1, wrong_no_1},
{"ldb", too_few_2, Lldb, wrong_no_2},
{"ldb-test", too_few_2, Lldb_test, wrong_no_2},
{"lcm", Llcm_1, Llcm, Llcm_n},
{"logbitp", too_few_2, Llogbitp, wrong_no_2},
{"logcount", Llogcount, too_many_1, wrong_no_1},
{"logtest", too_few_2, Llogtest, wrong_no_2},
{"mask-field", too_few_2, Lmask_field, wrong_no_2},
{"numerator", Lnumerator, too_many_1, wrong_no_1},
{"realpart", Lrealpart, too_many_1, wrong_no_1},
{"scale-float", too_few_2, Lscale_float, wrong_no_2},
#else
{"fix", Ltruncate, too_many_1, wrong_no_1},
{"gcdn", too_few_2, Lgcd, wrong_no_2},
{"lcmn", too_few_2, Llcm, wrong_no_2},
#endif
{NULL, 0,0,0}
};
/* end of arith08.c */