infinities are no longer integers
[bpt/guile.git] / libguile / numbers.c
index 6583103..88b225c 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
  *
  * Portions Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories
  * and Bellcore.  See scm_divide.
@@ -60,6 +60,7 @@
 #include "libguile/root.h"
 #include "libguile/smob.h"
 #include "libguile/strings.h"
+#include "libguile/bdw-gc.h"
 
 #include "libguile/validate.h"
 #include "libguile/numbers.h"
@@ -67,8 +68,6 @@
 
 #include "libguile/eq.h"
 
-#include "libguile/discouraged.h"
-
 /* values per glibc, if not already defined */
 #ifndef M_LOG10E
 #define M_LOG10E   0.43429448190325182765
@@ -77,6 +76,9 @@
 #define M_PI       3.14159265358979323846
 #endif
 
+typedef scm_t_signed_bits scm_t_inum;
+#define scm_from_inum(x) (scm_from_signed_integer (x))
+
 \f
 
 /*
 /* the macro above will not work as is with fractions */
 
 
+static SCM flo0;
+
 #define SCM_SWAP(x, y) do { SCM __t = x; x = y; y = __t; } while (0)
 
 /* FLOBUFLEN is the maximum number of characters neccessary for the
  */
 #define FLOBUFLEN (40+2*(sizeof(double)/sizeof(char)*SCM_CHAR_BIT*3+9)/10)
 
-#if defined (SCO)
-#if ! defined (HAVE_ISNAN)
-#define HAVE_ISNAN
-static int
-isnan (double x)
-{
-  return (IsNANorINF (x) && NaN (x) && ! IsINF (x)) ? 1 : 0;
-}
-#endif
-#if ! defined (HAVE_ISINF)
-#define HAVE_ISINF
-static int
-isinf (double x)
-{
-  return (IsNANorINF (x) && IsINF (x)) ? 1 : 0;
-}
-
-#endif
-#endif
-
 
 #if !defined (HAVE_ASINH)
 static double asinh (double x) { return log (x + sqrt (x * x + 1)); }
@@ -141,35 +125,11 @@ static double atanh (double x) { return 0.5 * log ((1 + x) / (1 - x)); }
    mpz_cmp_d is supposed to do this itself.  */
 #if 1
 #define xmpz_cmp_d(z, d)                                \
-  (xisinf (d) ? (d < 0.0 ? 1 : -1) : mpz_cmp_d (z, d))
+  (isinf (d) ? (d < 0.0 ? 1 : -1) : mpz_cmp_d (z, d))
 #else
 #define xmpz_cmp_d(z, d)  mpz_cmp_d (z, d)
 #endif
 
-/* For reference, sparc solaris 7 has infinities (IEEE) but doesn't have
-   isinf.  It does have finite and isnan though, hence the use of those.
-   fpclass would be a possibility on that system too.  */
-static int
-xisinf (double x)
-{
-#if defined (HAVE_ISINF)
-  return isinf (x);
-#elif defined (HAVE_FINITE) && defined (HAVE_ISNAN)
-  return (! (finite (x) || isnan (x)));
-#else
-  return 0;
-#endif
-}
-
-static int
-xisnan (double x)
-{
-#if defined (HAVE_ISNAN)
-  return isnan (x);
-#else
-  return 0;
-#endif
-}
 
 #if defined (GUILE_I)
 #if HAVE_COMPLEX_DOUBLE
@@ -196,21 +156,66 @@ scm_from_complex_double (complex double z)
 static mpz_t z_negative_one;
 
 \f
+/* Clear the `mpz_t' embedded in bignum PTR.  */
+static void
+finalize_bignum (GC_PTR ptr, GC_PTR data)
+{
+  SCM bignum;
+
+  bignum = PTR2SCM (ptr);
+  mpz_clear (SCM_I_BIG_MPZ (bignum));
+}
+
+/* Return a new uninitialized bignum.  */
+static inline SCM
+make_bignum (void)
+{
+  scm_t_bits *p;
+  GC_finalization_proc prev_finalizer;
+  GC_PTR prev_finalizer_data;
+
+  /* Allocate one word for the type tag and enough room for an `mpz_t'.  */
+  p = scm_gc_malloc_pointerless (sizeof (scm_t_bits) + sizeof (mpz_t),
+                                "bignum");
+  p[0] = scm_tc16_big;
+
+  GC_REGISTER_FINALIZER_NO_ORDER (p, finalize_bignum, NULL,
+                                 &prev_finalizer,
+                                 &prev_finalizer_data);
+
+  return SCM_PACK (p);
+}
+
 
 SCM
 scm_i_mkbig ()
 {
   /* Return a newly created bignum. */
-  SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
+  SCM z = make_bignum ();
   mpz_init (SCM_I_BIG_MPZ (z));
   return z;
 }
 
+static SCM
+scm_i_inum2big (scm_t_inum x)
+{
+  /* Return a newly created bignum initialized to X. */
+  SCM z = make_bignum ();
+#if SIZEOF_VOID_P == SIZEOF_LONG
+  mpz_init_set_si (SCM_I_BIG_MPZ (z), x);
+#else
+  /* Note that in this case, you'll also have to check all mpz_*_ui and
+     mpz_*_si invocations in Guile. */
+#error creation of mpz not implemented for this inum size
+#endif
+  return z;
+}
+
 SCM
 scm_i_long2big (long x)
 {
   /* Return a newly created bignum initialized to X. */
-  SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
+  SCM z = make_bignum ();
   mpz_init_set_si (SCM_I_BIG_MPZ (z), x);
   return z;
 }
@@ -219,7 +224,7 @@ SCM
 scm_i_ulong2big (unsigned long x)
 {
   /* Return a newly created bignum initialized to X. */
-  SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
+  SCM z = make_bignum ();
   mpz_init_set_ui (SCM_I_BIG_MPZ (z), x);
   return z;
 }
@@ -228,7 +233,7 @@ SCM
 scm_i_clonebig (SCM src_big, int same_sign_p)
 {
   /* Copy src_big's value, negate it if same_sign_p is false, and return. */
-  SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
+  SCM z = make_bignum ();
   mpz_init_set (SCM_I_BIG_MPZ (z), SCM_I_BIG_MPZ (src_big));
   if (!same_sign_p)
     mpz_neg (SCM_I_BIG_MPZ (z), SCM_I_BIG_MPZ (z));
@@ -249,7 +254,7 @@ SCM
 scm_i_dbl2big (double d)
 {
   /* results are only defined if d is an integer */
-  SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
+  SCM z = make_bignum ();
   mpz_init_set_d (SCM_I_BIG_MPZ (z), d);
   return z;
 }
@@ -275,7 +280,7 @@ scm_i_dbl2num (double u)
 
   if (u < (double) (SCM_MOST_POSITIVE_FIXNUM+1)
       && u >= (double) SCM_MOST_NEGATIVE_FIXNUM)
-    return SCM_I_MAKINUM ((long) u);
+    return SCM_I_MAKINUM ((scm_t_inum) u);
   else
     return scm_i_dbl2big (u);
 }
@@ -360,7 +365,7 @@ scm_i_normbig (SCM b)
   /* presume b is a bignum */
   if (mpz_fits_slong_p (SCM_I_BIG_MPZ (b)))
     {
-      long val = mpz_get_si (SCM_I_BIG_MPZ (b));
+      scm_t_inum val = mpz_get_si (SCM_I_BIG_MPZ (b));
       if (SCM_FIXABLE (val))
         b = SCM_I_MAKINUM (val);
     }
@@ -373,13 +378,13 @@ scm_i_mpz2num (mpz_t b)
   /* convert a mpz number to a SCM number. */
   if (mpz_fits_slong_p (b))
     {
-      long val = mpz_get_si (b);
+      scm_t_inum val = mpz_get_si (b);
       if (SCM_FIXABLE (val))
         return SCM_I_MAKINUM (val);
     }
 
   {
-    SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
+    SCM z = make_bignum ();
     mpz_init_set (SCM_I_BIG_MPZ (z), b);
     return z;
   }
@@ -422,12 +427,12 @@ scm_i_make_ratio (SCM numerator, SCM denominator)
   */
   if (SCM_I_INUMP (numerator))
     {
-      long  x = SCM_I_INUM (numerator);
+      scm_t_inum x = SCM_I_INUM (numerator);
       if (scm_is_eq (numerator, SCM_INUM0))
        return SCM_INUM0;
       if (SCM_I_INUMP (denominator))
        {
-         long y;
+         scm_t_inum y;
          y = SCM_I_INUM (denominator);
          if (x == y)
            return SCM_I_MAKINUM(1);
@@ -450,7 +455,7 @@ scm_i_make_ratio (SCM numerator, SCM denominator)
     {
       if (SCM_I_INUMP (denominator))
        {
-         long yy = SCM_I_INUM (denominator);
+         scm_t_inum yy = SCM_I_INUM (denominator);
          if (mpz_divisible_ui_p (SCM_I_BIG_MPZ (numerator), yy))
            return scm_divide (numerator, denominator);
        }
@@ -515,7 +520,7 @@ SCM_DEFINE (scm_odd_p, "odd?", 1, 0, 0,
 {
   if (SCM_I_INUMP (n))
     {
-      long val = SCM_I_INUM (n);
+      scm_t_inum val = SCM_I_INUM (n);
       return scm_from_bool ((val & 1L) != 0);
     }
   else if (SCM_BIGP (n))
@@ -525,7 +530,7 @@ SCM_DEFINE (scm_odd_p, "odd?", 1, 0, 0,
       return scm_from_bool (odd_p);
     }
   else if (scm_is_true (scm_inf_p (n)))
-    return SCM_BOOL_T;
+    SCM_WRONG_TYPE_ARG (1, n);
   else if (SCM_REALP (n))
     {
       double rem = fabs (fmod (SCM_REAL_VALUE(n), 2.0));
@@ -550,7 +555,7 @@ SCM_DEFINE (scm_even_p, "even?", 1, 0, 0,
 {
   if (SCM_I_INUMP (n))
     {
-      long val = SCM_I_INUM (n);
+      scm_t_inum val = SCM_I_INUM (n);
       return scm_from_bool ((val & 1L) == 0);
     }
   else if (SCM_BIGP (n))
@@ -560,7 +565,7 @@ SCM_DEFINE (scm_even_p, "even?", 1, 0, 0,
       return scm_from_bool (even_p);
     }
   else if (scm_is_true (scm_inf_p (n)))
-    return SCM_BOOL_T;
+    SCM_WRONG_TYPE_ARG (1, n);
   else if (SCM_REALP (n))
     {
       double rem = fabs (fmod (SCM_REAL_VALUE(n), 2.0));
@@ -583,10 +588,10 @@ SCM_DEFINE (scm_inf_p, "inf?", 1, 0, 0,
 #define FUNC_NAME s_scm_inf_p
 {
   if (SCM_REALP (x))
-    return scm_from_bool (xisinf (SCM_REAL_VALUE (x)));
+    return scm_from_bool (isinf (SCM_REAL_VALUE (x)));
   else if (SCM_COMPLEXP (x))
-    return scm_from_bool (xisinf (SCM_COMPLEX_REAL (x))
-                         || xisinf (SCM_COMPLEX_IMAG (x)));
+    return scm_from_bool (isinf (SCM_COMPLEX_REAL (x))
+                         || isinf (SCM_COMPLEX_IMAG (x)));
   else
     return SCM_BOOL_F;
 }
@@ -599,10 +604,10 @@ SCM_DEFINE (scm_nan_p, "nan?", 1, 0, 0,
 #define FUNC_NAME s_scm_nan_p
 {
   if (SCM_REALP (n))
-    return scm_from_bool (xisnan (SCM_REAL_VALUE (n)));
+    return scm_from_bool (isnan (SCM_REAL_VALUE (n)));
   else if (SCM_COMPLEXP (n))
-    return scm_from_bool (xisnan (SCM_COMPLEX_REAL (n))
-                    || xisnan (SCM_COMPLEX_IMAG (n)));
+    return scm_from_bool (isnan (SCM_COMPLEX_REAL (n))
+                    || isnan (SCM_COMPLEX_IMAG (n)));
   else
     return SCM_BOOL_F;
 }
@@ -617,8 +622,6 @@ static double guile_NaN;
 static void
 guile_ieee_init (void)
 {
-#if defined (HAVE_ISINF) || defined (HAVE_FINITE)
-
 /* Some version of gcc on some old version of Linux used to crash when
    trying to make Inf and NaN.  */
 
@@ -645,10 +648,6 @@ guile_ieee_init (void)
     }
 #endif
 
-#endif
-
-#if defined (HAVE_ISNAN)
-
 #ifdef NAN
   /* C99 NAN, when available */
   guile_NaN = NAN;
@@ -661,8 +660,6 @@ guile_ieee_init (void)
 #else
   guile_NaN = guile_Inf / guile_Inf;
 #endif
-
-#endif
 }
 
 SCM_DEFINE (scm_inf, "inf", 0, 0, 0, 
@@ -703,13 +700,13 @@ SCM_PRIMITIVE_GENERIC (scm_abs, "abs", 1, 0, 0,
 {
   if (SCM_I_INUMP (x))
     {
-      long int xx = SCM_I_INUM (x);
+      scm_t_inum xx = SCM_I_INUM (x);
       if (xx >= 0)
        return x;
       else if (SCM_POSFIXABLE (-xx))
        return SCM_I_MAKINUM (-xx);
       else
-       return scm_i_long2big (-xx);
+       return scm_i_inum2big (-xx);
     }
   else if (SCM_BIGP (x))
     {
@@ -749,19 +746,19 @@ scm_quotient (SCM x, SCM y)
 {
   if (SCM_I_INUMP (x))
     {
-      long xx = SCM_I_INUM (x);
+      scm_t_inum xx = SCM_I_INUM (x);
       if (SCM_I_INUMP (y))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          if (yy == 0)
            scm_num_overflow (s_quotient);
          else
            {
-             long z = xx / yy;
+             scm_t_inum z = xx / yy;
              if (SCM_FIXABLE (z))
                return SCM_I_MAKINUM (z);
              else
-               return scm_i_long2big (z);
+               return scm_i_inum2big (z);
            }
        }
       else if (SCM_BIGP (y))
@@ -784,7 +781,7 @@ scm_quotient (SCM x, SCM y)
     {
       if (SCM_I_INUMP (y))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          if (yy == 0)
            scm_num_overflow (s_quotient);
          else if (yy == 1)
@@ -835,12 +832,12 @@ scm_remainder (SCM x, SCM y)
     {
       if (SCM_I_INUMP (y))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          if (yy == 0)
            scm_num_overflow (s_remainder);
          else
            {
-             long z = SCM_I_INUM (x) % yy;
+             scm_t_inum z = SCM_I_INUM (x) % yy;
              return SCM_I_MAKINUM (z);
            }
        }
@@ -864,7 +861,7 @@ scm_remainder (SCM x, SCM y)
     {
       if (SCM_I_INUMP (y))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          if (yy == 0)
            scm_num_overflow (s_remainder);
          else
@@ -906,10 +903,10 @@ scm_modulo (SCM x, SCM y)
 {
   if (SCM_I_INUMP (x))
     {
-      long xx = SCM_I_INUM (x);
+      scm_t_inum xx = SCM_I_INUM (x);
       if (SCM_I_INUMP (y))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          if (yy == 0)
            scm_num_overflow (s_modulo);
          else
@@ -917,8 +914,8 @@ scm_modulo (SCM x, SCM y)
              /* C99 specifies that "%" is the remainder corresponding to a
                  quotient rounded towards zero, and that's also traditional
                  for machine division, so z here should be well defined.  */
-             long z = xx % yy;
-             long result;
+             scm_t_inum z = xx % yy;
+             scm_t_inum result;
 
              if (yy < 0)
                {
@@ -983,7 +980,7 @@ scm_modulo (SCM x, SCM y)
     {
       if (SCM_I_INUMP (y))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          if (yy == 0)
            scm_num_overflow (s_modulo);
          else
@@ -1054,19 +1051,19 @@ scm_gcd (SCM x, SCM y)
     {
       if (SCM_I_INUMP (y))
         {
-          long xx = SCM_I_INUM (x);
-          long yy = SCM_I_INUM (y);
-          long u = xx < 0 ? -xx : xx;
-          long v = yy < 0 ? -yy : yy;
-          long result;
+          scm_t_inum xx = SCM_I_INUM (x);
+          scm_t_inum yy = SCM_I_INUM (y);
+          scm_t_inum u = xx < 0 ? -xx : xx;
+          scm_t_inum v = yy < 0 ? -yy : yy;
+          scm_t_inum result;
           if (xx == 0)
            result = v;
          else if (yy == 0)
            result = u;
          else
            {
-             long k = 1;
-             long t;
+             scm_t_inum k = 1;
+             scm_t_inum t;
              /* Determine a common factor 2^k */
              while (!(1 & (u | v)))
                {
@@ -1096,7 +1093,7 @@ scm_gcd (SCM x, SCM y)
            }
           return (SCM_POSFIXABLE (result)
                  ? SCM_I_MAKINUM (result)
-                 : scm_i_long2big (result));
+                 : scm_i_inum2big (result));
         }
       else if (SCM_BIGP (y))
         {
@@ -1110,8 +1107,8 @@ scm_gcd (SCM x, SCM y)
     {
       if (SCM_I_INUMP (y))
         {
-          unsigned long result;
-          long yy;
+          scm_t_bits result;
+          scm_t_inum yy;
         big_inum:
           yy = SCM_I_INUM (y);
           if (yy == 0)
@@ -1122,7 +1119,7 @@ scm_gcd (SCM x, SCM y)
           scm_remember_upto_here_1 (x);
           return (SCM_POSFIXABLE (result) 
                  ? SCM_I_MAKINUM (result)
-                 : scm_from_ulong (result));
+                 : scm_from_unsigned_integer (result));
         }
       else if (SCM_BIGP (y))
         {
@@ -1189,7 +1186,7 @@ scm_lcm (SCM n1, SCM n2)
         inumbig:
           {
             SCM result = scm_i_mkbig ();
-            long nn1 = SCM_I_INUM (n1);
+            scm_t_inum nn1 = SCM_I_INUM (n1);
             if (nn1 == 0) return SCM_INUM0;
             if (nn1 < 0) nn1 = - nn1;
             mpz_lcm_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n2), nn1);
@@ -1279,7 +1276,7 @@ SCM_DEFINE (scm_i_logand, "logand", 0, 2, 1,
 SCM scm_logand (SCM n1, SCM n2)
 #define FUNC_NAME s_scm_logand
 {
-  long int nn1;
+  scm_t_inum nn1;
 
   if (SCM_UNBNDP (n2))
     {
@@ -1298,7 +1295,7 @@ SCM scm_logand (SCM n1, SCM n2)
       nn1 = SCM_I_INUM (n1);
       if (SCM_I_INUMP (n2))
        {
-         long nn2 = SCM_I_INUM (n2);
+         scm_t_inum nn2 = SCM_I_INUM (n2);
          return SCM_I_MAKINUM (nn1 & nn2);
        }
       else if SCM_BIGP (n2)
@@ -1369,7 +1366,7 @@ SCM_DEFINE (scm_i_logior, "logior", 0, 2, 1,
 SCM scm_logior (SCM n1, SCM n2)
 #define FUNC_NAME s_scm_logior
 {
-  long int nn1;
+  scm_t_inum nn1;
 
   if (SCM_UNBNDP (n2))
     {
@@ -1459,7 +1456,7 @@ SCM_DEFINE (scm_i_logxor, "logxor", 0, 2, 1,
 SCM scm_logxor (SCM n1, SCM n2)
 #define FUNC_NAME s_scm_logxor
 {
-  long int nn1;
+  scm_t_inum nn1;
 
   if (SCM_UNBNDP (n2))
     {
@@ -1476,7 +1473,7 @@ SCM scm_logxor (SCM n1, SCM n2)
       nn1 = SCM_I_INUM (n1);
       if (SCM_I_INUMP (n2))
        {
-         long nn2 = SCM_I_INUM (n2);
+         scm_t_inum nn2 = SCM_I_INUM (n2);
          return SCM_I_MAKINUM (nn1 ^ nn2);
        }
       else if (SCM_BIGP (n2))
@@ -1534,14 +1531,14 @@ SCM_DEFINE (scm_logtest, "logtest", 2, 0, 0,
            "@end lisp")
 #define FUNC_NAME s_scm_logtest
 {
-  long int nj;
+  scm_t_inum nj;
 
   if (SCM_I_INUMP (j))
     {
       nj = SCM_I_INUM (j);
       if (SCM_I_INUMP (k))
        {
-         long nk = SCM_I_INUM (k);
+         scm_t_inum nk = SCM_I_INUM (k);
          return scm_from_bool (nj & nk);
        }
       else if (SCM_BIGP (k))
@@ -1795,14 +1792,26 @@ SCM_DEFINE (scm_integer_expt, "integer-expt", 2, 0, 0,
            "@end lisp")
 #define FUNC_NAME s_scm_integer_expt
 {
-  long i2 = 0;
+  scm_t_inum i2 = 0;
   SCM z_i2 = SCM_BOOL_F;
   int i2_is_big = 0;
   SCM acc = SCM_I_MAKINUM (1L);
 
-  /* 0^0 == 1 according to R5RS */
-  if (scm_is_eq (n, SCM_INUM0) || scm_is_eq (n, acc))
-    return scm_is_false (scm_zero_p(k)) ? n : acc;
+  SCM_VALIDATE_NUMBER (SCM_ARG1, n);
+  if (!SCM_I_INUMP (k) && !SCM_BIGP (k))
+    SCM_WRONG_TYPE_ARG (2, k);
+
+  if (scm_is_true (scm_zero_p (n)))
+    {
+      if (scm_is_true (scm_zero_p (k)))  /* 0^0 == 1 per R5RS */
+       return acc;        /* return exact 1, regardless of n */
+      else if (scm_is_true (scm_positive_p (k)))
+       return n;
+      else  /* return NaN for (0 ^ k) for negative k per R6RS */
+       return scm_nan ();
+    }
+  else if (scm_is_eq (n, acc))
+    return acc;
   else if (scm_is_eq (n, SCM_I_MAKINUM (-1L)))
     return scm_is_false (scm_even_p (k)) ? n : acc;
 
@@ -1890,7 +1899,7 @@ SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
 
   if (SCM_I_INUMP (n))
     {
-      long nn = SCM_I_INUM (n);
+      scm_t_inum nn = SCM_I_INUM (n);
 
       if (bits_to_shift > 0)
         {
@@ -1905,7 +1914,7 @@ SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
             return n;
 
           if (bits_to_shift < SCM_I_FIXNUM_BIT-1
-              && ((unsigned long)
+              && ((scm_t_bits)
                   (SCM_SRS (nn, (SCM_I_FIXNUM_BIT-1 - bits_to_shift)) + 1)
                   <= 1))
             {
@@ -1913,7 +1922,7 @@ SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
             }
           else
             {
-              SCM result = scm_i_long2big (nn);
+              SCM result = scm_i_inum2big (nn);
               mpz_mul_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result),
                             bits_to_shift);
               return result;
@@ -1986,7 +1995,7 @@ SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
 
   if (SCM_I_INUMP (n))
     {
-      long int in = SCM_I_INUM (n);
+      scm_t_inum in = SCM_I_INUM (n);
 
       /* When istart>=SCM_I_FIXNUM_BIT we can just limit the shift to
          SCM_I_FIXNUM_BIT-1 to get either 0 or -1 per the sign of "in". */
@@ -1998,7 +2007,7 @@ SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
           * special case requires us to produce a result that has
           * more bits than can be stored in a fixnum.
           */
-          SCM result = scm_i_long2big (in);
+          SCM result = scm_i_inum2big (in);
           mpz_fdiv_r_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result),
                            bits);
           return result;
@@ -2057,8 +2066,8 @@ SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
 {
   if (SCM_I_INUMP (n))
     {
-      unsigned long int c = 0;
-      long int nn = SCM_I_INUM (n);
+      unsigned long c = 0;
+      scm_t_inum nn = SCM_I_INUM (n);
       if (nn < 0)
         nn = -1 - nn;
       while (nn)
@@ -2105,9 +2114,9 @@ SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0,
 {
   if (SCM_I_INUMP (n))
     {
-      unsigned long int c = 0;
+      unsigned long c = 0;
       unsigned int l = 4;
-      long int nn = SCM_I_INUM (n);
+      scm_t_inum nn = SCM_I_INUM (n);
       if (nn < 0)
        nn = -1 - nn;
       while (nn)
@@ -2179,7 +2188,7 @@ void init_fx_radix(double *fx_list, int radix)
 }
 
 /* use this array as a way to generate a single digit */
-static const char*number_chars="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static const char number_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 
 static size_t
 idbl2str (double f, char *a, int radix)
@@ -2214,7 +2223,7 @@ idbl2str (double f, char *a, int radix)
       goto zero;       /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
     }
 
-  if (xisinf (f))
+  if (isinf (f))
     {
       if (f < 0)
        strcpy (a, "-inf.0");
@@ -2222,7 +2231,7 @@ idbl2str (double f, char *a, int radix)
        strcpy (a, "+inf.0");
       return ch+6;
     }
-  else if (xisnan (f))
+  else if (isnan (f))
     {
       strcpy (a, "+nan.0");
       return ch+6;
@@ -2374,7 +2383,7 @@ icmplx2str (double real, double imag, char *str, int radix)
     {
       /* Don't output a '+' for negative numbers or for Inf and
         NaN.  They will provide their own sign. */
-      if (0 <= imag && !xisinf (imag) && !xisnan (imag))
+      if (0 <= imag && !isinf (imag) && !isnan (imag))
        str[i++] = '+';
       i += idbl2str (imag, &str[i], radix);
       str[i++] = 'i';
@@ -2421,6 +2430,9 @@ scm_iuint2str (scm_t_uintmax num, int rad, char *p)
   size_t i;
   scm_t_uintmax n = num;
 
+  if (rad < 2 || rad > 36)
+    scm_out_of_range ("scm_iuint2str", scm_from_int (rad));
+
   for (n /= rad; n > 0; n /= rad)
     j++;
 
@@ -2431,7 +2443,7 @@ scm_iuint2str (scm_t_uintmax num, int rad, char *p)
       int d = n % rad;
 
       n /= rad;
-      p[i] = d + ((d < 10) ? '0' : 'a' - 10);
+      p[i] = number_chars[d];
     }
   return j;
 }
@@ -2564,11 +2576,26 @@ enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
 
 /* R5RS, section 7.1.1, lexical structure of numbers: <uinteger R>. */
 
-/* In non ASCII-style encodings the following macro might not work. */
-#define XDIGIT2UINT(d)                                                  \
-  (uc_is_property_decimal_digit ((int) (unsigned char) d)               \
-   ? (d) - '0'                                                          \
-   : uc_tolower ((int) (unsigned char) d) - 'a' + 10)
+/* Caller is responsible for checking that the return value is in range
+   for the given radix, which should be <= 36. */
+static unsigned int
+char_decimal_value (scm_t_uint32 c)
+{
+  /* uc_decimal_value returns -1 on error. When cast to an unsigned int,
+     that's certainly above any valid decimal, so we take advantage of
+     that to elide some tests. */
+  unsigned int d = (unsigned int) uc_decimal_value (c);
+
+  /* If that failed, try extended hexadecimals, then. Only accept ascii
+     hexadecimals. */
+  if (d >= 10U)
+    {
+      c = uc_tolower (c);
+      if (c >= (scm_t_uint32) 'a')
+        d = c - (scm_t_uint32)'a' + 10U;
+    }
+  return d;
+}
 
 static SCM
 mem2uinteger (SCM mem, unsigned int *p_idx,
@@ -2587,9 +2614,7 @@ mem2uinteger (SCM mem, unsigned int *p_idx,
     return SCM_BOOL_F;
 
   c = scm_i_string_ref (mem, idx);
-  if (!uc_is_property_ascii_hex_digit ((scm_t_uint32) c))
-    return SCM_BOOL_F;
-  digit_value = XDIGIT2UINT (c);
+  digit_value = char_decimal_value (c);
   if (digit_value >= radix)
     return SCM_BOOL_F;
 
@@ -2598,21 +2623,21 @@ mem2uinteger (SCM mem, unsigned int *p_idx,
   while (idx != len)
     {
       scm_t_wchar c = scm_i_string_ref (mem, idx);
-      if (uc_is_property_ascii_hex_digit ((scm_t_uint32) c))
-       {
-         if (hash_seen)
-           break;
-         digit_value = XDIGIT2UINT (c);
-         if (digit_value >= radix)
-           break;
-       }
-      else if (c == '#')
+      if (c == '#')
        {
          hash_seen = 1;
          digit_value = 0;
        }
+      else if (hash_seen)
+        break;
       else
-       break;
+        {
+          digit_value = char_decimal_value (c);
+          /* This check catches non-decimals in addition to out-of-range
+             decimals.  */
+          if (digit_value >= radix)
+           break;
+       }
 
       idx++;
       if (SCM_MOST_POSITIVE_FIXNUM / radix < shift)
@@ -3041,7 +3066,7 @@ mem2complex (SCM mem, unsigned int idx,
 
              if (scm_is_false (imag))
                imag = SCM_I_MAKINUM (sign);
-             else if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
+             else if (sign == -1 && scm_is_false (scm_nan_p (imag)))
                imag = scm_difference (imag, SCM_UNDEFINED);
 
              if (idx == len)
@@ -3308,7 +3333,8 @@ SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
   if (SCM_COMPLEXP (x))
     return SCM_BOOL_F;
   r = SCM_REAL_VALUE (x);
-  /* +/-inf passes r==floor(r), making those #t */
+  if (isinf (r))
+    return SCM_BOOL_F;
   if (r == floor (r))
     return SCM_BOOL_T;
   return SCM_BOOL_F;
@@ -3331,18 +3357,35 @@ SCM_DEFINE (scm_inexact_p, "inexact?", 1, 0, 0,
 #undef FUNC_NAME
 
 
-SCM_GPROC1 (s_eq_p, "=", scm_tc7_rpsubr, scm_num_eq_p, g_eq_p);
-/* "Return @code{#t} if all parameters are numerically equal."  */
+SCM scm_i_num_eq_p (SCM, SCM, SCM);
+SCM_PRIMITIVE_GENERIC (scm_i_num_eq_p, "=", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return @code{#t} if all parameters are numerically equal.")
+#define FUNC_NAME s_scm_i_num_eq_p
+{
+  if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
+    return SCM_BOOL_T;
+  while (!scm_is_null (rest))
+    {
+      if (scm_is_false (scm_num_eq_p (x, y)))
+        return SCM_BOOL_F;
+      x = y;
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_num_eq_p (x, y);
+}
+#undef FUNC_NAME
 SCM
 scm_num_eq_p (SCM x, SCM y)
 {
  again:
   if (SCM_I_INUMP (x))
     {
-      long xx = SCM_I_INUM (x);
+      scm_t_signed_bits xx = SCM_I_INUM (x);
       if (SCM_I_INUMP (y))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_signed_bits yy = SCM_I_INUM (y);
          return scm_from_bool (xx == yy);
        }
       else if (SCM_BIGP (y))
@@ -3361,13 +3404,13 @@ scm_num_eq_p (SCM x, SCM y)
              An alternative (for any size system actually) would be to check
              yy is an integer (with floor) and is in range of an inum
              (compare against appropriate powers of 2) then test
-             xx==(long)yy.  It's just a matter of which casts/comparisons
-             might be fastest or easiest for the cpu.  */
+             xx==(scm_t_signed_bits)yy.  It's just a matter of which
+             casts/comparisons might be fastest or easiest for the cpu.  */
 
           double yy = SCM_REAL_VALUE (y);
           return scm_from_bool ((double) xx == yy
                                && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
-                                   || xx == (long) yy));
+                                   || xx == (scm_t_signed_bits) yy));
         }
       else if (SCM_COMPLEXP (y))
        return scm_from_bool (((double) xx == SCM_COMPLEX_REAL (y))
@@ -3375,7 +3418,7 @@ scm_num_eq_p (SCM x, SCM y)
       else if (SCM_FRACTIONP (y))
        return SCM_BOOL_F;
       else
-       SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
+       SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
     }
   else if (SCM_BIGP (x))
     {
@@ -3390,7 +3433,7 @@ scm_num_eq_p (SCM x, SCM y)
       else if (SCM_REALP (y))
        {
          int cmp;
-         if (xisnan (SCM_REAL_VALUE (y)))
+         if (isnan (SCM_REAL_VALUE (y)))
            return SCM_BOOL_F;
          cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
          scm_remember_upto_here_1 (x);
@@ -3401,7 +3444,7 @@ scm_num_eq_p (SCM x, SCM y)
          int cmp;
          if (0.0 != SCM_COMPLEX_IMAG (y))
            return SCM_BOOL_F;
-         if (xisnan (SCM_COMPLEX_REAL (y)))
+         if (isnan (SCM_COMPLEX_REAL (y)))
            return SCM_BOOL_F;
          cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_COMPLEX_REAL (y));
          scm_remember_upto_here_1 (x);
@@ -3410,7 +3453,7 @@ scm_num_eq_p (SCM x, SCM y)
       else if (SCM_FRACTIONP (y))
        return SCM_BOOL_F;
       else
-       SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
+       SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
     }
   else if (SCM_REALP (x))
     {
@@ -3418,15 +3461,15 @@ scm_num_eq_p (SCM x, SCM y)
       if (SCM_I_INUMP (y))
         {
           /* see comments with inum/real above */
-          long yy = SCM_I_INUM (y);
+          scm_t_signed_bits yy = SCM_I_INUM (y);
           return scm_from_bool (xx == (double) yy
                                && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
-                                   || (long) xx == yy));
+                                   || (scm_t_signed_bits) xx == yy));
         }
       else if (SCM_BIGP (y))
        {
          int cmp;
-         if (xisnan (SCM_REAL_VALUE (x)))
+         if (isnan (SCM_REAL_VALUE (x)))
            return SCM_BOOL_F;
          cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
          scm_remember_upto_here_1 (y);
@@ -3440,15 +3483,15 @@ scm_num_eq_p (SCM x, SCM y)
       else if (SCM_FRACTIONP (y))
         {
           double  xx = SCM_REAL_VALUE (x);
-          if (xisnan (xx))
+          if (isnan (xx))
             return SCM_BOOL_F;
-          if (xisinf (xx))
+          if (isinf (xx))
             return scm_from_bool (xx < 0.0);
           x = scm_inexact_to_exact (x);  /* with x as frac or int */
           goto again;
         }
       else
-       SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
+       SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
     }
   else if (SCM_COMPLEXP (x))
     {
@@ -3460,7 +3503,7 @@ scm_num_eq_p (SCM x, SCM y)
          int cmp;
          if (0.0 != SCM_COMPLEX_IMAG (x))
            return SCM_BOOL_F;
-         if (xisnan (SCM_COMPLEX_REAL (x)))
+         if (isnan (SCM_COMPLEX_REAL (x)))
            return SCM_BOOL_F;
          cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_COMPLEX_REAL (x));
          scm_remember_upto_here_1 (y);
@@ -3478,15 +3521,15 @@ scm_num_eq_p (SCM x, SCM y)
           if (SCM_COMPLEX_IMAG (x) != 0.0)
             return SCM_BOOL_F;
           xx = SCM_COMPLEX_REAL (x);
-          if (xisnan (xx))
+          if (isnan (xx))
             return SCM_BOOL_F;
-          if (xisinf (xx))
+          if (isinf (xx))
             return scm_from_bool (xx < 0.0);
           x = scm_inexact_to_exact (x);  /* with x as frac or int */
           goto again;
         }
       else
-       SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
+       SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
     }
   else if (SCM_FRACTIONP (x))
     {
@@ -3497,9 +3540,9 @@ scm_num_eq_p (SCM x, SCM y)
       else if (SCM_REALP (y))
         {
           double yy = SCM_REAL_VALUE (y);
-          if (xisnan (yy))
+          if (isnan (yy))
             return SCM_BOOL_F;
-          if (xisinf (yy))
+          if (isinf (yy))
             return scm_from_bool (0.0 < yy);
           y = scm_inexact_to_exact (y);  /* with y as frac or int */
           goto again;
@@ -3510,9 +3553,9 @@ scm_num_eq_p (SCM x, SCM y)
           if (SCM_COMPLEX_IMAG (y) != 0.0)
             return SCM_BOOL_F;
           yy = SCM_COMPLEX_REAL (y);
-          if (xisnan (yy))
+          if (isnan (yy))
             return SCM_BOOL_F;
-          if (xisinf (yy))
+          if (isinf (yy))
             return scm_from_bool (0.0 < yy);
           y = scm_inexact_to_exact (y);  /* with y as frac or int */
           goto again;
@@ -3520,10 +3563,10 @@ scm_num_eq_p (SCM x, SCM y)
       else if (SCM_FRACTIONP (y))
        return scm_i_fraction_equalp (x, y);
       else
-       SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
+       SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
     }
   else
-    SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARG1, s_eq_p);
+    SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARG1, s_scm_i_num_eq_p);
 }
 
 
@@ -3533,20 +3576,36 @@ scm_num_eq_p (SCM x, SCM y)
    mpq_cmp.  flonum/frac compares likewise, but with the slight complication
    of the float exponent to take into account.  */
 
-SCM_GPROC1 (s_less_p, "<", scm_tc7_rpsubr, scm_less_p, g_less_p);
-/* "Return @code{#t} if the list of parameters is monotonically\n"
- * "increasing."
- */
+SCM_INTERNAL SCM scm_i_num_less_p (SCM, SCM, SCM);
+SCM_PRIMITIVE_GENERIC (scm_i_num_less_p, "<", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return @code{#t} if the list of parameters is monotonically\n"
+                       "increasing.")
+#define FUNC_NAME s_scm_i_num_less_p
+{
+  if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
+    return SCM_BOOL_T;
+  while (!scm_is_null (rest))
+    {
+      if (scm_is_false (scm_less_p (x, y)))
+        return SCM_BOOL_F;
+      x = y;
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_less_p (x, y);
+}
+#undef FUNC_NAME
 SCM
 scm_less_p (SCM x, SCM y)
 {
  again:
   if (SCM_I_INUMP (x))
     {
-      long xx = SCM_I_INUM (x);
+      scm_t_inum xx = SCM_I_INUM (x);
       if (SCM_I_INUMP (y))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          return scm_from_bool (xx < yy);
        }
       else if (SCM_BIGP (y))
@@ -3566,7 +3625,7 @@ scm_less_p (SCM x, SCM y)
           goto again;
         }
       else
-       SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
+       SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
     }
   else if (SCM_BIGP (x))
     {
@@ -3585,7 +3644,7 @@ scm_less_p (SCM x, SCM y)
       else if (SCM_REALP (y))
        {
          int cmp;
-         if (xisnan (SCM_REAL_VALUE (y)))
+         if (isnan (SCM_REAL_VALUE (y)))
            return SCM_BOOL_F;
          cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
          scm_remember_upto_here_1 (x);
@@ -3594,7 +3653,7 @@ scm_less_p (SCM x, SCM y)
       else if (SCM_FRACTIONP (y))
         goto int_frac;
       else
-       SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
+       SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
     }
   else if (SCM_REALP (x))
     {
@@ -3603,7 +3662,7 @@ scm_less_p (SCM x, SCM y)
       else if (SCM_BIGP (y))
        {
          int cmp;
-         if (xisnan (SCM_REAL_VALUE (x)))
+         if (isnan (SCM_REAL_VALUE (x)))
            return SCM_BOOL_F;
          cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
          scm_remember_upto_here_1 (y);
@@ -3614,15 +3673,15 @@ scm_less_p (SCM x, SCM y)
       else if (SCM_FRACTIONP (y))
         {
           double  xx = SCM_REAL_VALUE (x);
-         if (xisnan (xx))
+         if (isnan (xx))
            return SCM_BOOL_F;
-          if (xisinf (xx))
+          if (isinf (xx))
             return scm_from_bool (xx < 0.0);
           x = scm_inexact_to_exact (x);  /* with x as frac or int */
           goto again;
         }
       else
-       SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
+       SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
     }
   else if (SCM_FRACTIONP (x))
     {
@@ -3636,9 +3695,9 @@ scm_less_p (SCM x, SCM y)
       else if (SCM_REALP (y))
         {
           double yy = SCM_REAL_VALUE (y);
-          if (xisnan (yy))
+          if (isnan (yy))
             return SCM_BOOL_F;
-          if (xisinf (yy))
+          if (isinf (yy))
             return scm_from_bool (0.0 < yy);
           y = scm_inexact_to_exact (y);  /* with y as frac or int */
           goto again;
@@ -3655,43 +3714,75 @@ scm_less_p (SCM x, SCM y)
           goto again;
         }
       else
-       SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
+       SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
     }
   else
-    SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARG1, s_less_p);
+    SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARG1, s_scm_i_num_less_p);
 }
 
 
-SCM_GPROC1 (s_scm_gr_p, ">", scm_tc7_rpsubr, scm_gr_p, g_gr_p);
-/* "Return @code{#t} if the list of parameters is monotonically\n"
- * "decreasing."
- */
-#define FUNC_NAME s_scm_gr_p
+SCM scm_i_num_gr_p (SCM, SCM, SCM);
+SCM_PRIMITIVE_GENERIC (scm_i_num_gr_p, ">", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return @code{#t} if the list of parameters is monotonically\n"
+                       "decreasing.")
+#define FUNC_NAME s_scm_i_num_gr_p
+{
+  if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
+    return SCM_BOOL_T;
+  while (!scm_is_null (rest))
+    {
+      if (scm_is_false (scm_gr_p (x, y)))
+        return SCM_BOOL_F;
+      x = y;
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_gr_p (x, y);
+}
+#undef FUNC_NAME
+#define FUNC_NAME s_scm_i_num_gr_p
 SCM
 scm_gr_p (SCM x, SCM y)
 {
   if (!SCM_NUMBERP (x))
-    SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG1, FUNC_NAME);
+    SCM_WTA_DISPATCH_2 (g_scm_i_num_gr_p, x, y, SCM_ARG1, FUNC_NAME);
   else if (!SCM_NUMBERP (y))
-    SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG2, FUNC_NAME);
+    SCM_WTA_DISPATCH_2 (g_scm_i_num_gr_p, x, y, SCM_ARG2, FUNC_NAME);
   else
     return scm_less_p (y, x);
 }
 #undef FUNC_NAME
 
 
-SCM_GPROC1 (s_scm_leq_p, "<=", scm_tc7_rpsubr, scm_leq_p, g_leq_p);
-/* "Return @code{#t} if the list of parameters is monotonically\n"
- * "non-decreasing."
- */
-#define FUNC_NAME s_scm_leq_p
+SCM scm_i_num_leq_p (SCM, SCM, SCM);
+SCM_PRIMITIVE_GENERIC (scm_i_num_leq_p, "<=", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return @code{#t} if the list of parameters is monotonically\n"
+                       "non-decreasing.")
+#define FUNC_NAME s_scm_i_num_leq_p
+{
+  if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
+    return SCM_BOOL_T;
+  while (!scm_is_null (rest))
+    {
+      if (scm_is_false (scm_leq_p (x, y)))
+        return SCM_BOOL_F;
+      x = y;
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_leq_p (x, y);
+}
+#undef FUNC_NAME
+#define FUNC_NAME s_scm_i_num_leq_p
 SCM
 scm_leq_p (SCM x, SCM y)
 {
   if (!SCM_NUMBERP (x))
-    SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG1, FUNC_NAME);
+    SCM_WTA_DISPATCH_2 (g_scm_i_num_leq_p, x, y, SCM_ARG1, FUNC_NAME);
   else if (!SCM_NUMBERP (y))
-    SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG2, FUNC_NAME);
+    SCM_WTA_DISPATCH_2 (g_scm_i_num_leq_p, x, y, SCM_ARG2, FUNC_NAME);
   else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
     return SCM_BOOL_F;
   else
@@ -3700,18 +3791,34 @@ scm_leq_p (SCM x, SCM y)
 #undef FUNC_NAME
 
 
-SCM_GPROC1 (s_scm_geq_p, ">=", scm_tc7_rpsubr, scm_geq_p, g_geq_p);
-/* "Return @code{#t} if the list of parameters is monotonically\n"
- * "non-increasing."
- */
-#define FUNC_NAME s_scm_geq_p
+SCM scm_i_num_geq_p (SCM, SCM, SCM);
+SCM_PRIMITIVE_GENERIC (scm_i_num_geq_p, ">=", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return @code{#t} if the list of parameters is monotonically\n"
+                       "non-increasing.")
+#define FUNC_NAME s_scm_i_num_geq_p
+{
+  if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
+    return SCM_BOOL_T;
+  while (!scm_is_null (rest))
+    {
+      if (scm_is_false (scm_geq_p (x, y)))
+        return SCM_BOOL_F;
+      x = y;
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_geq_p (x, y);
+}
+#undef FUNC_NAME
+#define FUNC_NAME s_scm_i_num_geq_p
 SCM
 scm_geq_p (SCM x, SCM y)
 {
   if (!SCM_NUMBERP (x))
-    SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG1, FUNC_NAME);
+    SCM_WTA_DISPATCH_2 (g_scm_i_num_geq_p, x, y, SCM_ARG1, FUNC_NAME);
   else if (!SCM_NUMBERP (y))
-    SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG2, FUNC_NAME);
+    SCM_WTA_DISPATCH_2 (g_scm_i_num_geq_p, x, y, SCM_ARG2, FUNC_NAME);
   else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
     return SCM_BOOL_F;
   else
@@ -3829,10 +3936,10 @@ scm_max (SCM x, SCM y)
   
   if (SCM_I_INUMP (x))
     {
-      long xx = SCM_I_INUM (x);
+      scm_t_inum xx = SCM_I_INUM (x);
       if (SCM_I_INUMP (y))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          return (xx < yy) ? y : x;
        }
       else if (SCM_BIGP (y))
@@ -3905,7 +4012,7 @@ scm_max (SCM x, SCM y)
             calling isnan is unavoidable, since it's the only way to know
             which of x or y causes any compares to be false */
          double xx = SCM_REAL_VALUE (x);
-         return (xisnan (xx) || xx > SCM_REAL_VALUE (y)) ? x : y;
+         return (isnan (xx) || xx > SCM_REAL_VALUE (y)) ? x : y;
        }
       else if (SCM_FRACTIONP (y))
        {
@@ -3975,10 +4082,10 @@ scm_min (SCM x, SCM y)
   
   if (SCM_I_INUMP (x))
     {
-      long xx = SCM_I_INUM (x);
+      scm_t_inum xx = SCM_I_INUM (x);
       if (SCM_I_INUMP (y))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          return (xx < yy) ? x : y;
        }
       else if (SCM_BIGP (y))
@@ -4051,7 +4158,7 @@ scm_min (SCM x, SCM y)
             calling isnan is unavoidable, since it's the only way to know
             which of x or y causes any compares to be false */
          double xx = SCM_REAL_VALUE (x);
-         return (xisnan (xx) || xx < SCM_REAL_VALUE (y)) ? x : y;
+         return (isnan (xx) || xx < SCM_REAL_VALUE (y)) ? x : y;
        }
       else if (SCM_FRACTIONP (y))
        {
@@ -4121,10 +4228,10 @@ scm_sum (SCM x, SCM y)
     {
       if (SCM_LIKELY (SCM_I_INUMP (y)))
         {
-          long xx = SCM_I_INUM (x);
-          long yy = SCM_I_INUM (y);
-          long int z = xx + yy;
-          return SCM_FIXABLE (z) ? SCM_I_MAKINUM (z) : scm_i_long2big (z);
+          scm_t_inum xx = SCM_I_INUM (x);
+          scm_t_inum yy = SCM_I_INUM (y);
+          scm_t_inum z = xx + yy;
+          return SCM_FIXABLE (z) ? SCM_I_MAKINUM (z) : scm_i_inum2big (z);
         }
       else if (SCM_BIGP (y))
         {
@@ -4133,12 +4240,12 @@ scm_sum (SCM x, SCM y)
         }
       else if (SCM_REALP (y))
         {
-          long int xx = SCM_I_INUM (x);
+          scm_t_inum xx = SCM_I_INUM (x);
           return scm_from_double (xx + SCM_REAL_VALUE (y));
         }
       else if (SCM_COMPLEXP (y))
         {
-          long int xx = SCM_I_INUM (x);
+          scm_t_inum xx = SCM_I_INUM (x);
           return scm_c_make_rectangular (xx + SCM_COMPLEX_REAL (y),
                                    SCM_COMPLEX_IMAG (y));
         }
@@ -4152,7 +4259,7 @@ scm_sum (SCM x, SCM y)
       {
        if (SCM_I_INUMP (y))
          {
-           long int inum;
+           scm_t_inum inum;
            int bigsgn;
          add_big_inum:
            inum = SCM_I_INUM (y);      
@@ -4326,11 +4433,11 @@ scm_difference (SCM x, SCM y)
       else 
         if (SCM_I_INUMP (x))
           {
-            long xx = -SCM_I_INUM (x);
+            scm_t_inum xx = -SCM_I_INUM (x);
             if (SCM_FIXABLE (xx))
               return SCM_I_MAKINUM (xx);
             else
-              return scm_i_long2big (xx);
+              return scm_i_inum2big (xx);
           }
         else if (SCM_BIGP (x))
           /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
@@ -4352,18 +4459,18 @@ scm_difference (SCM x, SCM y)
     {
       if (SCM_LIKELY (SCM_I_INUMP (y)))
        {
-         long int xx = SCM_I_INUM (x);
-         long int yy = SCM_I_INUM (y);
-         long int z = xx - yy;
+         scm_t_inum xx = SCM_I_INUM (x);
+         scm_t_inum yy = SCM_I_INUM (y);
+         scm_t_inum z = xx - yy;
          if (SCM_FIXABLE (z))
            return SCM_I_MAKINUM (z);
          else
-           return scm_i_long2big (z);
+           return scm_i_inum2big (z);
        }
       else if (SCM_BIGP (y))
        {
          /* inum-x - big-y */
-         long xx = SCM_I_INUM (x);
+         scm_t_inum xx = SCM_I_INUM (x);
 
          if (xx == 0)
            return scm_i_clonebig (y, 0);
@@ -4391,12 +4498,12 @@ scm_difference (SCM x, SCM y)
        }
       else if (SCM_REALP (y))
        {
-         long int xx = SCM_I_INUM (x);
+         scm_t_inum xx = SCM_I_INUM (x);
          return scm_from_double (xx - SCM_REAL_VALUE (y));
        }
       else if (SCM_COMPLEXP (y))
        {
-         long int xx = SCM_I_INUM (x);
+         scm_t_inum xx = SCM_I_INUM (x);
          return scm_c_make_rectangular (xx - SCM_COMPLEX_REAL (y),
                                   - SCM_COMPLEX_IMAG (y));
        }
@@ -4413,13 +4520,13 @@ scm_difference (SCM x, SCM y)
       if (SCM_I_INUMP (y))
        {
          /* big-x - inum-y */
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
 
          scm_remember_upto_here_1 (x);
          if (sgn_x == 0)
            return (SCM_FIXABLE (-yy) ?
-                   SCM_I_MAKINUM (-yy) : scm_from_long (-yy));
+                   SCM_I_MAKINUM (-yy) : scm_from_inum (-yy));
          else
            {
              SCM result = scm_i_mkbig ();
@@ -4589,7 +4696,7 @@ scm_product (SCM x, SCM y)
   
   if (SCM_LIKELY (SCM_I_INUMP (x)))
     {
-      long xx;
+      scm_t_inum xx;
 
     intbig:
       xx = SCM_I_INUM (x);
@@ -4602,14 +4709,14 @@ scm_product (SCM x, SCM y)
 
       if (SCM_LIKELY (SCM_I_INUMP (y)))
        {
-         long yy = SCM_I_INUM (y);
-         long kk = xx * yy;
+         scm_t_inum yy = SCM_I_INUM (y);
+         scm_t_inum kk = xx * yy;
          SCM k = SCM_I_MAKINUM (kk);
          if ((kk == SCM_I_INUM (k)) && (kk / xx == yy))
            return k;
          else
            {
-             SCM result = scm_i_long2big (xx);
+             SCM result = scm_i_inum2big (xx);
              mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), yy);
              return scm_i_normbig (result);
            }
@@ -4821,7 +4928,7 @@ do_divide (SCM x, SCM y, int inexact)
        SCM_WTA_DISPATCH_0 (g_divide, s_divide);
       else if (SCM_I_INUMP (x))
        {
-         long xx = SCM_I_INUM (x);
+         scm_t_inum xx = SCM_I_INUM (x);
          if (xx == 1 || xx == -1)
            return x;
 #ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
@@ -4877,10 +4984,10 @@ do_divide (SCM x, SCM y, int inexact)
 
   if (SCM_LIKELY (SCM_I_INUMP (x)))
     {
-      long xx = SCM_I_INUM (x);
+      scm_t_inum xx = SCM_I_INUM (x);
       if (SCM_LIKELY (SCM_I_INUMP (y)))
        {
-         long yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          if (yy == 0)
            {
 #ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
@@ -4897,11 +5004,11 @@ do_divide (SCM x, SCM y, int inexact)
            }
          else
            {
-             long z = xx / yy;
+             scm_t_inum z = xx / yy;
              if (SCM_FIXABLE (z))
                return SCM_I_MAKINUM (z);
              else
-               return scm_i_long2big (z);
+               return scm_i_inum2big (z);
            }
        }
       else if (SCM_BIGP (y))
@@ -4952,7 +5059,7 @@ do_divide (SCM x, SCM y, int inexact)
     {
       if (SCM_I_INUMP (y))
        {
-         long int yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
          if (yy == 0)
            {
 #ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
@@ -4975,7 +5082,7 @@ do_divide (SCM x, SCM y, int inexact)
                 middle ground: test, then if divisible, use the faster div
                 func. */
 
-             long abs_yy = yy < 0 ? -yy : yy;
+             scm_t_inum abs_yy = yy < 0 ? -yy : yy;
              int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (x), abs_yy);
 
              if (divisible_p)
@@ -5066,7 +5173,7 @@ do_divide (SCM x, SCM y, int inexact)
       double rx = SCM_REAL_VALUE (x);
       if (SCM_I_INUMP (y))
        {
-         long int yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
 #ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
          if (yy == 0)
            scm_num_overflow (s_divide);
@@ -5106,7 +5213,7 @@ do_divide (SCM x, SCM y, int inexact)
       double ix = SCM_COMPLEX_IMAG (x);
       if (SCM_I_INUMP (y))
        {
-         long int yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
 #ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
          if (yy == 0)
            scm_num_overflow (s_divide);
@@ -5162,7 +5269,7 @@ do_divide (SCM x, SCM y, int inexact)
     {
       if (SCM_I_INUMP (y)) 
        {
-         long int yy = SCM_I_INUM (y);
+         scm_t_inum yy = SCM_I_INUM (y);
 #ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
          if (yy == 0)
            scm_num_overflow (s_divide);
@@ -5383,8 +5490,29 @@ SCM_DEFINE (scm_expt, "expt", 2, 0, 0,
            "Return @var{x} raised to the power of @var{y}.") 
 #define FUNC_NAME s_scm_expt
 {
-  if (!SCM_INEXACTP (y) && scm_is_integer (y))
-    return scm_integer_expt (x, y);
+  if (scm_is_integer (y))
+    {
+      if (scm_is_true (scm_exact_p (y)))
+       return scm_integer_expt (x, y);
+      else
+       {
+         /* Here we handle the case where the exponent is an inexact
+            integer.  We make the exponent exact in order to use
+            scm_integer_expt, and thus avoid the spurious imaginary
+            parts that may result from round-off errors in the general
+            e^(y log x) method below (for example when squaring a large
+            negative number).  In this case, we must return an inexact
+            result for correctness.  We also make the base inexact so
+            that scm_integer_expt will use fast inexact arithmetic
+            internally.  Note that making the base inexact is not
+            sufficient to guarantee an inexact result, because
+            scm_integer_expt will return an exact 1 when the exponent
+            is 0, even if the base is inexact. */
+         return scm_exact_to_inexact
+           (scm_integer_expt (scm_exact_to_inexact (x),
+                              scm_inexact_to_exact (y)));
+       }
+    }
   else if (scm_is_real (x) && scm_is_real (y) && scm_to_double (x) >= 0.0)
     {
       return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
@@ -5661,9 +5789,10 @@ scm_c_make_rectangular (double re, double im)
   else
     {
       SCM z;
-      SCM_NEWSMOB (z, scm_tc16_complex,
-                  scm_gc_malloc_pointerless (sizeof (scm_t_complex),
+
+      z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_complex),
                                              "complex"));
+      SCM_SET_CELL_TYPE (z, scm_tc16_complex);
       SCM_COMPLEX_REAL (z) = re;
       SCM_COMPLEX_IMAG (z) = im;
       return z;
@@ -5747,7 +5876,7 @@ scm_imag_part (SCM z)
   else if (SCM_BIGP (z))
     return SCM_INUM0;
   else if (SCM_REALP (z))
-    return scm_flo0;
+    return flo0;
   else if (SCM_COMPLEXP (z))
     return scm_from_double (SCM_COMPLEX_IMAG (z));
   else if (SCM_FRACTIONP (z))
@@ -5802,13 +5931,13 @@ scm_magnitude (SCM z)
 {
   if (SCM_I_INUMP (z))
     {
-      long int zz = SCM_I_INUM (z);
+      scm_t_inum zz = SCM_I_INUM (z);
       if (zz >= 0)
        return z;
       else if (SCM_POSFIXABLE (-zz))
        return SCM_I_MAKINUM (-zz);
       else
-       return scm_i_long2big (-zz);
+       return scm_i_inum2big (-zz);
     }
   else if (SCM_BIGP (z))
     {
@@ -5842,13 +5971,13 @@ SCM
 scm_angle (SCM z)
 {
   /* atan(0,-1) is pi and it'd be possible to have that as a constant like
-     scm_flo0 to save allocating a new flonum with scm_from_double each time.
+     flo0 to save allocating a new flonum with scm_from_double each time.
      But if atan2 follows the floating point rounding mode, then the value
      is not a constant.  Maybe it'd be close enough though.  */
   if (SCM_I_INUMP (z))
     {
       if (SCM_I_INUM (z) >= 0)
-        return scm_flo0;
+        return flo0;
       else
        return scm_from_double (atan2 (0.0, -1.0));
     }
@@ -5859,12 +5988,12 @@ scm_angle (SCM z)
       if (sgn < 0)
        return scm_from_double (atan2 (0.0, -1.0));
       else
-        return scm_flo0;
+        return flo0;
     }
   else if (SCM_REALP (z))
     {
       if (SCM_REAL_VALUE (z) >= 0)
-        return scm_flo0;
+        return flo0;
       else
         return scm_from_double (atan2 (0.0, -1.0));
     }
@@ -5873,7 +6002,7 @@ scm_angle (SCM z)
   else if (SCM_FRACTIONP (z))
     {
       if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
-       return scm_flo0;
+       return flo0;
       else return scm_from_double (atan2 (0.0, -1.0));
     }
   else
@@ -5911,7 +6040,7 @@ SCM_DEFINE (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
     return z;
   else if (SCM_REALP (z))
     {
-      if (xisinf (SCM_REAL_VALUE (z)) || xisnan (SCM_REAL_VALUE (z)))
+      if (isinf (SCM_REAL_VALUE (z)) || isnan (SCM_REAL_VALUE (z)))
        SCM_OUT_OF_RANGE (1, z);
       else
        {
@@ -6200,8 +6329,6 @@ scm_i_range_error (SCM bad_val, SCM min, SCM max)
 #define SCM_FROM_TYPE_PROTO(arg) scm_from_wchar (arg)
 #include "libguile/conv-integer.i.c"
 
-#if SCM_HAVE_T_INT64
-
 #define TYPE                     scm_t_int64
 #define TYPE_MIN                 SCM_T_INT64_MIN
 #define TYPE_MAX                 SCM_T_INT64_MAX
@@ -6218,8 +6345,6 @@ scm_i_range_error (SCM bad_val, SCM min, SCM max)
 #define SCM_FROM_TYPE_PROTO(arg) scm_from_uint64 (arg)
 #include "libguile/conv-uinteger.i.c"
 
-#endif
-
 void
 scm_to_mpz (SCM val, mpz_t rop)
 {
@@ -6267,20 +6392,28 @@ scm_to_double (SCM val)
 SCM
 scm_from_double (double val)
 {
-  SCM z = scm_double_cell (scm_tc16_real, 0, 0, 0);
+  SCM z;
+
+  z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_double), "real"));
+
+  SCM_SET_CELL_TYPE (z, scm_tc16_real);
   SCM_REAL_VALUE (z) = val;
+
   return z;
 }
 
-#if SCM_ENABLE_DISCOURAGED == 1
+#if SCM_ENABLE_DEPRECATED == 1
 
 float
-scm_num2float (SCM num, unsigned long int pos, const char *s_caller)
+scm_num2float (SCM num, unsigned long pos, const char *s_caller)
 {
+  scm_c_issue_deprecation_warning
+    ("`scm_num2float' is deprecated. Use scm_to_double instead.");
+
   if (SCM_BIGP (num))
     {
       float res = mpz_get_d (SCM_I_BIG_MPZ (num));
-      if (!xisinf (res))
+      if (!isinf (res))
        return res;
       else
        scm_out_of_range (NULL, num);
@@ -6290,12 +6423,15 @@ scm_num2float (SCM num, unsigned long int pos, const char *s_caller)
 }
 
 double
-scm_num2double (SCM num, unsigned long int pos, const char *s_caller)
+scm_num2double (SCM num, unsigned long pos, const char *s_caller)
 {
+  scm_c_issue_deprecation_warning
+    ("`scm_num2double' is deprecated. Use scm_to_double instead.");
+
   if (SCM_BIGP (num))
     {
       double res = mpz_get_d (SCM_I_BIG_MPZ (num));
-      if (!xisinf (res))
+      if (!isinf (res))
        return res;
       else
        scm_out_of_range (NULL, num);
@@ -6407,7 +6543,8 @@ SCM_DEFINE (scm_log10, "log10", 1, 0, 0,
       /* Mingw has clog() but not clog10().  (Maybe it'd be worth using
          clog() and a multiply by M_LOG10E, rather than the fallback
          log10+hypot+atan2.)  */
-#if HAVE_COMPLEX_DOUBLE && HAVE_CLOG10 && defined (SCM_COMPLEX_VALUE)
+#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CLOG10 \
+      && defined SCM_COMPLEX_VALUE
       return scm_from_complex_double (clog10 (SCM_COMPLEX_VALUE (z)));
 #else
       double re = SCM_COMPLEX_REAL (z);
@@ -6473,7 +6610,8 @@ SCM_DEFINE (scm_sqrt, "sqrt", 1, 0, 0,
 {
   if (SCM_COMPLEXP (x))
     {
-#if HAVE_COMPLEX_DOUBLE && HAVE_USABLE_CSQRT && defined (SCM_COMPLEX_VALUE)
+#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_USABLE_CSQRT   \
+      && defined SCM_COMPLEX_VALUE
       return scm_from_complex_double (csqrt (SCM_COMPLEX_VALUE (x)));
 #else
       double re = SCM_COMPLEX_REAL (x);
@@ -6513,7 +6651,7 @@ scm_init_numbers ()
 
   scm_add_feature ("complex");
   scm_add_feature ("inexact");
-  scm_flo0 = scm_from_double (0.0);
+  flo0 = scm_from_double (0.0);
 
   /* determine floating point precision */
   for (i=2; i <= SCM_MAX_DBL_RADIX; ++i)
@@ -6523,11 +6661,10 @@ scm_init_numbers ()
     }
 #ifdef DBL_DIG
   /* hard code precision for base 10 if the preprocessor tells us to... */
-      scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
+  scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
 #endif
 
-  exactly_one_half = scm_permanent_object (scm_divide (SCM_I_MAKINUM (1),
-                                                      SCM_I_MAKINUM (2)));
+  exactly_one_half = scm_divide (SCM_I_MAKINUM (1), SCM_I_MAKINUM (2));
 #include "libguile/numbers.x"
 }