fix a number of assuptions that a long could hold an inum
[bpt/guile.git] / libguile / numbers.c
index 7006ccc..d5ebf9c 100644 (file)
@@ -1,22 +1,23 @@
-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
  *
  * Portions Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories
  * and Bellcore.  See scm_divide.
  *
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
  *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
  */
 
 \f
@@ -45,8 +46,9 @@
 #endif
 
 #include <math.h>
-#include <ctype.h>
 #include <string.h>
+#include <unicase.h>
+#include <unictype.h>
 
 #if HAVE_COMPLEX_H
 #include <complex.h>
@@ -58,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"
@@ -65,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
@@ -75,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;
-}
 
+#if !defined (HAVE_ASINH)
+static double asinh (double x) { return log (x + sqrt (x * x + 1)); }
 #endif
+#if !defined (HAVE_ACOSH)
+static double acosh (double x) { return log (x + sqrt (x * x - 1)); }
+#endif
+#if !defined (HAVE_ATANH)
+static double atanh (double x) { return 0.5 * log ((1 + x) / (1 - x)); }
 #endif
-
 
 /* mpz_cmp_d in gmp 4.1.3 doesn't recognise infinities, so xmpz_cmp_d uses
    an explicit check.  In some future gmp (don't know what version number),
    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
@@ -184,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;
 }
@@ -207,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;
 }
@@ -216,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));
@@ -237,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;
 }
@@ -263,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);
 }
@@ -348,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);
     }
@@ -361,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;
   }
@@ -410,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);
@@ -438,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);
        }
@@ -503,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))
@@ -538,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))
@@ -571,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;
 }
@@ -587,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;
 }
@@ -605,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.  */
 
@@ -617,7 +632,7 @@ guile_ieee_init (void)
      before trying to use it.  (But in practice we believe this is not a
      problem on any system guile is likely to target.)  */
   guile_Inf = INFINITY;
-#elif HAVE_DINFINITY
+#elif defined HAVE_DINFINITY
   /* OSF */
   extern unsigned int DINFINITY[2];
   guile_Inf = (*((double *) (DINFINITY)));
@@ -633,14 +648,10 @@ guile_ieee_init (void)
     }
 #endif
 
-#endif
-
-#if defined (HAVE_ISNAN)
-
 #ifdef NAN
   /* C99 NAN, when available */
   guile_NaN = NAN;
-#elif HAVE_DQNAN
+#elif defined HAVE_DQNAN
   {
     /* OSF */
     extern unsigned int DQNAN[2];
@@ -649,8 +660,6 @@ guile_ieee_init (void)
 #else
   guile_NaN = guile_Inf / guile_Inf;
 #endif
-
-#endif
 }
 
 SCM_DEFINE (scm_inf, "inf", 0, 0, 0, 
@@ -691,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))
     {
@@ -737,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))
@@ -772,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)
@@ -823,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);
            }
        }
@@ -852,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
@@ -894,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
@@ -905,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)
                {
@@ -971,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
@@ -1014,10 +1023,24 @@ scm_modulo (SCM x, SCM y)
     SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG1, s_modulo);
 }
 
-SCM_GPROC1 (s_gcd, "gcd", scm_tc7_asubr, scm_gcd, g_gcd);
-/* "Return the greatest common divisor of all arguments.\n"
- * "If called without arguments, 0 is returned."
- */
+SCM_PRIMITIVE_GENERIC (scm_i_gcd, "gcd", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return the greatest common divisor of all parameter values.\n"
+                       "If called without arguments, 0 is returned.")
+#define FUNC_NAME s_scm_i_gcd
+{
+  while (!scm_is_null (rest))
+    { x = scm_gcd (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_gcd (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_gcd s_scm_i_gcd
+#define g_gcd g_scm_i_gcd
+
 SCM
 scm_gcd (SCM x, SCM y)
 {
@@ -1028,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)))
                {
@@ -1070,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))
         {
@@ -1084,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)
@@ -1096,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))
         {
@@ -1114,10 +1137,24 @@ scm_gcd (SCM x, SCM y)
     SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG1, s_gcd);
 }
 
-SCM_GPROC1 (s_lcm, "lcm", scm_tc7_asubr, scm_lcm, g_lcm);
-/* "Return the least common multiple of the arguments.\n"
- * "If called without arguments, 1 is returned."
- */
+SCM_PRIMITIVE_GENERIC (scm_i_lcm, "lcm", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return the least common multiple of the arguments.\n"
+                       "If called without arguments, 1 is returned.")
+#define FUNC_NAME s_scm_i_lcm
+{
+  while (!scm_is_null (rest))
+    { x = scm_lcm (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_lcm (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_lcm s_scm_i_lcm
+#define g_lcm g_scm_i_lcm
+
 SCM
 scm_lcm (SCM n1, SCM n2)
 {
@@ -1149,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);
@@ -1215,17 +1252,31 @@ scm_lcm (SCM n1, SCM n2)
 
 */
 
-SCM_DEFINE1 (scm_logand, "logand", scm_tc7_asubr,
-             (SCM n1, SCM n2),
-            "Return the bitwise AND of the integer arguments.\n\n"
-            "@lisp\n"
-            "(logand) @result{} -1\n"
-            "(logand 7) @result{} 7\n"
-            "(logand #b111 #b011 #b001) @result{} 1\n"
-            "@end lisp")
+SCM_DEFINE (scm_i_logand, "logand", 0, 2, 1,
+            (SCM x, SCM y, SCM rest),
+            "Return the bitwise AND of the integer arguments.\n\n"
+            "@lisp\n"
+            "(logand) @result{} -1\n"
+            "(logand 7) @result{} 7\n"
+            "(logand #b111 #b011 #b001) @result{} 1\n"
+            "@end lisp")
+#define FUNC_NAME s_scm_i_logand
+{
+  while (!scm_is_null (rest))
+    { x = scm_logand (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_logand (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_scm_logand s_scm_i_logand
+
+SCM scm_logand (SCM n1, SCM n2)
 #define FUNC_NAME s_scm_logand
 {
-  long int nn1;
+  scm_t_inum nn1;
 
   if (SCM_UNBNDP (n2))
     {
@@ -1244,7 +1295,7 @@ SCM_DEFINE1 (scm_logand, "logand", scm_tc7_asubr,
       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)
@@ -1291,17 +1342,31 @@ SCM_DEFINE1 (scm_logand, "logand", scm_tc7_asubr,
 #undef FUNC_NAME
 
 
-SCM_DEFINE1 (scm_logior, "logior", scm_tc7_asubr,
-             (SCM n1, SCM n2),
-            "Return the bitwise OR of the integer arguments.\n\n"
-            "@lisp\n"
-            "(logior) @result{} 0\n"
-            "(logior 7) @result{} 7\n"
-            "(logior #b000 #b001 #b011) @result{} 3\n"
-           "@end lisp")
+SCM_DEFINE (scm_i_logior, "logior", 0, 2, 1,
+            (SCM x, SCM y, SCM rest),
+            "Return the bitwise OR of the integer arguments.\n\n"
+            "@lisp\n"
+            "(logior) @result{} 0\n"
+            "(logior 7) @result{} 7\n"
+            "(logior #b000 #b001 #b011) @result{} 3\n"
+            "@end lisp")
+#define FUNC_NAME s_scm_i_logior
+{
+  while (!scm_is_null (rest))
+    { x = scm_logior (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_logior (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_scm_logior s_scm_i_logior
+
+SCM scm_logior (SCM n1, SCM n2)
 #define FUNC_NAME s_scm_logior
 {
-  long int nn1;
+  scm_t_inum nn1;
 
   if (SCM_UNBNDP (n2))
     {
@@ -1365,8 +1430,8 @@ SCM_DEFINE1 (scm_logior, "logior", scm_tc7_asubr,
 #undef FUNC_NAME
 
 
-SCM_DEFINE1 (scm_logxor, "logxor", scm_tc7_asubr,
-             (SCM n1, SCM n2),
+SCM_DEFINE (scm_i_logxor, "logxor", 0, 2, 1,
+            (SCM x, SCM y, SCM rest),
             "Return the bitwise XOR of the integer arguments.  A bit is\n"
             "set in the result if it is set in an odd number of arguments.\n"
             "@lisp\n"
@@ -1375,9 +1440,23 @@ SCM_DEFINE1 (scm_logxor, "logxor", scm_tc7_asubr,
             "(logxor #b000 #b001 #b011) @result{} 2\n"
             "(logxor #b000 #b001 #b011 #b011) @result{} 1\n"
            "@end lisp")
+#define FUNC_NAME s_scm_i_logxor
+{
+  while (!scm_is_null (rest))
+    { x = scm_logxor (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_logxor (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_scm_logxor s_scm_i_logxor
+
+SCM scm_logxor (SCM n1, SCM n2)
 #define FUNC_NAME s_scm_logxor
 {
-  long int nn1;
+  scm_t_inum nn1;
 
   if (SCM_UNBNDP (n2))
     {
@@ -1394,7 +1473,7 @@ SCM_DEFINE1 (scm_logxor, "logxor", scm_tc7_asubr,
       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))
@@ -1452,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))
@@ -1713,11 +1792,13 @@ 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);
 
+  SCM_VALIDATE_NUMBER (SCM_ARG1, n);
+
   /* 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;
@@ -1808,7 +1889,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)
         {
@@ -1823,7 +1904,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))
             {
@@ -1831,7 +1912,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;
@@ -1904,7 +1985,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". */
@@ -1916,7 +1997,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;
@@ -1975,8 +2056,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)
@@ -2023,9 +2104,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)
@@ -2097,7 +2178,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)
@@ -2132,7 +2213,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");
@@ -2140,7 +2221,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;
@@ -2292,7 +2373,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';
@@ -2339,6 +2420,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++;
 
@@ -2349,7 +2433,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;
 }
@@ -2436,7 +2520,7 @@ scm_i_print_fraction (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
 {
   SCM str;
   str = scm_number_to_string (sexp, SCM_UNDEFINED);
-  scm_lfwrite (scm_i_string_chars (str), scm_i_string_length (str), port);
+  scm_lfwrite_str (str, port);
   scm_remember_upto_here_1 (str);
   return !0;
 }
@@ -2482,14 +2566,29 @@ 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)                                  \
-  (isdigit ((int) (unsigned char) d)                    \
-   ? (d) - '0'                                          \
-   : 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 (const char* mem, size_t len, unsigned int *p_idx,
+mem2uinteger (SCM mem, unsigned int *p_idx,
              unsigned int radix, enum t_exactness *p_exactness)
 {
   unsigned int idx = *p_idx;
@@ -2499,14 +2598,13 @@ mem2uinteger (const char* mem, size_t len, unsigned int *p_idx,
   unsigned int digit_value;
   SCM result;
   char c;
+  size_t len = scm_i_string_length (mem);
 
   if (idx == len)
     return SCM_BOOL_F;
 
-  c = mem[idx];
-  if (!isxdigit ((int) (unsigned char) c))
-    return SCM_BOOL_F;
-  digit_value = XDIGIT2UINT (c);
+  c = scm_i_string_ref (mem, idx);
+  digit_value = char_decimal_value (c);
   if (digit_value >= radix)
     return SCM_BOOL_F;
 
@@ -2514,22 +2612,22 @@ mem2uinteger (const char* mem, size_t len, unsigned int *p_idx,
   result = SCM_I_MAKINUM (digit_value);
   while (idx != len)
     {
-      char c = mem[idx];
-      if (isxdigit ((int) (unsigned char) c))
-       {
-         if (hash_seen)
-           break;
-         digit_value = XDIGIT2UINT (c);
-         if (digit_value >= radix)
-           break;
-       }
-      else if (c == '#')
+      scm_t_wchar c = scm_i_string_ref (mem, idx);
+      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)
@@ -2568,20 +2666,20 @@ mem2uinteger (const char* mem, size_t len, unsigned int *p_idx,
  * has already been seen in the digits before the point.
  */
 
-/* In non ASCII-style encodings the following macro might not work. */
-#define DIGIT2UINT(d) ((d) - '0')
+#define DIGIT2UINT(d) (uc_numeric_value(d).numerator)
 
 static SCM
-mem2decimal_from_point (SCM result, const char* mem, size_t len
+mem2decimal_from_point (SCM result, SCM mem
                        unsigned int *p_idx, enum t_exactness *p_exactness)
 {
   unsigned int idx = *p_idx;
   enum t_exactness x = *p_exactness;
+  size_t len = scm_i_string_length (mem);
 
   if (idx == len)
     return result;
 
-  if (mem[idx] == '.')
+  if (scm_i_string_ref (mem, idx) == '.')
     {
       scm_t_bits shift = 1;
       scm_t_bits add = 0;
@@ -2591,8 +2689,8 @@ mem2decimal_from_point (SCM result, const char* mem, size_t len,
       idx++;
       while (idx != len)
        {
-         char c = mem[idx];
-         if (isdigit ((int) (unsigned char) c))
+         scm_t_wchar c = scm_i_string_ref (mem, idx);
+         if (uc_is_property_decimal_digit ((scm_t_uint32) c))
            {
              if (x == INEXACT)
                return SCM_BOOL_F;
@@ -2642,13 +2740,13 @@ mem2decimal_from_point (SCM result, const char* mem, size_t len,
     {
       int sign = 1;
       unsigned int start;
-      char c;
+      scm_t_wchar c;
       int exponent;
       SCM e;
 
       /* R5RS, section 7.1.1, lexical structure of numbers: <suffix> */
 
-      switch (mem[idx])
+      switch (scm_i_string_ref (mem, idx))
        {
        case 'd': case 'D':
        case 'e': case 'E':
@@ -2656,32 +2754,41 @@ mem2decimal_from_point (SCM result, const char* mem, size_t len,
        case 'l': case 'L':
        case 's': case 'S':
          idx++;
+          if (idx == len)
+            return SCM_BOOL_F;
+
          start = idx;
-         c = mem[idx];
+         c = scm_i_string_ref (mem, idx);
          if (c == '-')
            {
              idx++;
+              if (idx == len)
+                return SCM_BOOL_F;
+
              sign = -1;
-             c = mem[idx];
+             c = scm_i_string_ref (mem, idx);
            }
          else if (c == '+')
            {
              idx++;
+              if (idx == len)
+                return SCM_BOOL_F;
+
              sign = 1;
-             c = mem[idx];
+             c = scm_i_string_ref (mem, idx);
            }
          else
            sign = 1;
 
-         if (!isdigit ((int) (unsigned char) c))
+         if (!uc_is_property_decimal_digit ((scm_t_uint32) c))
            return SCM_BOOL_F;
 
          idx++;
          exponent = DIGIT2UINT (c);
          while (idx != len)
            {
-             char c = mem[idx];
-             if (isdigit ((int) (unsigned char) c))
+             scm_t_wchar c = scm_i_string_ref (mem, idx);
+             if (uc_is_property_decimal_digit ((scm_t_uint32) c))
                {
                  idx++;
                  if (exponent <= SCM_MAXEXP)
@@ -2694,7 +2801,7 @@ mem2decimal_from_point (SCM result, const char* mem, size_t len,
          if (exponent > SCM_MAXEXP)
            {
              size_t exp_len = idx - start;
-             SCM exp_string = scm_from_locale_stringn (&mem[start], exp_len);
+             SCM exp_string = scm_i_substring_copy (mem, start, start + exp_len);
              SCM exp_num = scm_string_to_number (exp_string, SCM_UNDEFINED);
              scm_out_of_range ("string->number", exp_num);
            }
@@ -2726,63 +2833,67 @@ mem2decimal_from_point (SCM result, const char* mem, size_t len,
 /* R5RS, section 7.1.1, lexical structure of numbers: <ureal R> */
 
 static SCM
-mem2ureal (const char* mem, size_t len, unsigned int *p_idx,
+mem2ureal (SCM mem, unsigned int *p_idx,
           unsigned int radix, enum t_exactness *p_exactness)
 {
   unsigned int idx = *p_idx;
   SCM result;
+  size_t len = scm_i_string_length (mem);
+
+  /* Start off believing that the number will be exact.  This changes
+     to INEXACT if we see a decimal point or a hash. */
+  enum t_exactness x = EXACT;
 
   if (idx == len)
     return SCM_BOOL_F;
 
-  if (idx+5 <= len && !strncmp (mem+idx, "inf.0", 5))
+  if (idx+5 <= len && !scm_i_string_strcmp (mem, idx, "inf.0"))
     {
       *p_idx = idx+5;
       return scm_inf ();
     }
 
-  if (idx+4 < len && !strncmp (mem+idx, "nan.", 4))
+  if (idx+4 < len && !scm_i_string_strcmp (mem, idx, "nan."))
     {
-      enum t_exactness x = EXACT;
-
       /* Cobble up the fractional part.  We might want to set the
         NaN's mantissa from it. */
       idx += 4;
-      mem2uinteger (mem, len, &idx, 10, &x);
+      mem2uinteger (mem, &idx, 10, &x);
       *p_idx = idx;
       return scm_nan ();
     }
 
-  if (mem[idx] == '.')
+  if (scm_i_string_ref (mem, idx) == '.')
     {
       if (radix != 10)
        return SCM_BOOL_F;
       else if (idx + 1 == len)
        return SCM_BOOL_F;
-      else if (!isdigit ((int) (unsigned char) mem[idx + 1]))
+      else if (!uc_is_property_decimal_digit ((scm_t_uint32) scm_i_string_ref (mem, idx+1)))
        return SCM_BOOL_F;
       else
-       result = mem2decimal_from_point (SCM_I_MAKINUM (0), mem, len,
-                                        p_idx, p_exactness);
+       result = mem2decimal_from_point (SCM_I_MAKINUM (0), mem,
+                                        p_idx, &x);
     }
   else
     {
-      enum t_exactness x = EXACT;
       SCM uinteger;
 
-      uinteger = mem2uinteger (mem, len, &idx, radix, &x);
+      uinteger = mem2uinteger (mem, &idx, radix, &x);
       if (scm_is_false (uinteger))
        return SCM_BOOL_F;
 
       if (idx == len)
        result = uinteger;
-      else if (mem[idx] == '/')
+      else if (scm_i_string_ref (mem, idx) == '/')
        {
          SCM divisor;
 
          idx++;
+          if (idx == len)
+            return SCM_BOOL_F;
 
-         divisor = mem2uinteger (mem, len, &idx, radix, &x);
+         divisor = mem2uinteger (mem, &idx, radix, &x);
          if (scm_is_false (divisor))
            return SCM_BOOL_F;
 
@@ -2791,7 +2902,7 @@ mem2ureal (const char* mem, size_t len, unsigned int *p_idx,
        }
       else if (radix == 10)
        {
-         result = mem2decimal_from_point (uinteger, mem, len, &idx, &x);
+         result = mem2decimal_from_point (uinteger, mem, &idx, &x);
          if (scm_is_false (result))
            return SCM_BOOL_F;
        }
@@ -2799,10 +2910,16 @@ mem2ureal (const char* mem, size_t len, unsigned int *p_idx,
        result = uinteger;
 
       *p_idx = idx;
-      if (x == INEXACT)
-       *p_exactness = x;
     }
 
+  /* Update *p_exactness if the number just read was inexact.  This is
+     important for complex numbers, so that a complex number is
+     treated as inexact overall if either its real or imaginary part
+     is inexact.
+  */
+  if (x == INEXACT)
+    *p_exactness = x;
+
   /* When returning an inexact zero, make sure it is represented as a
      floating point value so that we can change its sign. 
   */
@@ -2816,17 +2933,18 @@ mem2ureal (const char* mem, size_t len, unsigned int *p_idx,
 /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
 
 static SCM
-mem2complex (const char* mem, size_t len, unsigned int idx,
+mem2complex (SCM mem, unsigned int idx,
             unsigned int radix, enum t_exactness *p_exactness)
 {
-  char c;
+  scm_t_wchar c;
   int sign = 0;
   SCM ureal;
+  size_t len = scm_i_string_length (mem);
 
   if (idx == len)
     return SCM_BOOL_F;
 
-  c = mem[idx];
+  c = scm_i_string_ref (mem, idx);
   if (c == '+')
     {
       idx++;
@@ -2841,7 +2959,7 @@ mem2complex (const char* mem, size_t len, unsigned int idx,
   if (idx == len)
     return SCM_BOOL_F;
 
-  ureal = mem2ureal (mem, len, &idx, radix, p_exactness);
+  ureal = mem2ureal (mem, &idx, radix, p_exactness);
   if (scm_is_false (ureal))
     {
       /* input must be either +i or -i */
@@ -2849,7 +2967,8 @@ mem2complex (const char* mem, size_t len, unsigned int idx,
       if (sign == 0)
        return SCM_BOOL_F;
 
-      if (mem[idx] == 'i' || mem[idx] == 'I')
+      if (scm_i_string_ref (mem, idx) == 'i'
+         || scm_i_string_ref (mem, idx) == 'I')
        {
          idx++;
          if (idx != len)
@@ -2868,7 +2987,7 @@ mem2complex (const char* mem, size_t len, unsigned int idx,
       if (idx == len)
        return ureal;
 
-      c = mem[idx];
+      c = scm_i_string_ref (mem, idx);
       switch (c)
        {
        case 'i': case 'I':
@@ -2893,21 +3012,25 @@ mem2complex (const char* mem, size_t len, unsigned int idx,
              SCM angle;
              SCM result;
 
-             c = mem[idx];
+             c = scm_i_string_ref (mem, idx);
              if (c == '+')
                {
                  idx++;
+                  if (idx == len)
+                    return SCM_BOOL_F;
                  sign = 1;
                }
              else if (c == '-')
                {
                  idx++;
+                  if (idx == len)
+                    return SCM_BOOL_F;
                  sign = -1;
                }
              else
                sign = 1;
 
-             angle = mem2ureal (mem, len, &idx, radix, p_exactness);
+             angle = mem2ureal (mem, &idx, radix, p_exactness);
              if (scm_is_false (angle))
                return SCM_BOOL_F;
              if (idx != len)
@@ -2929,16 +3052,17 @@ mem2complex (const char* mem, size_t len, unsigned int idx,
          else
            {
              int sign = (c == '+') ? 1 : -1;
-             SCM imag = mem2ureal (mem, len, &idx, radix, p_exactness);
+             SCM imag = mem2ureal (mem, &idx, radix, p_exactness);
 
              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)
                return SCM_BOOL_F;
-             if (mem[idx] != 'i' && mem[idx] != 'I')
+             if (scm_i_string_ref (mem, idx) != 'i'
+                 && scm_i_string_ref (mem, idx) != 'I')
                return SCM_BOOL_F;
 
              idx++;
@@ -2959,19 +3083,19 @@ mem2complex (const char* mem, size_t len, unsigned int idx,
 enum t_radix {NO_RADIX=0, DUAL=2, OCT=8, DEC=10, HEX=16};
 
 SCM
-scm_c_locale_stringn_to_number (const char* mem, size_t len,
-                               unsigned int default_radix)
+scm_i_string_to_number (SCM mem, unsigned int default_radix)
 {
   unsigned int idx = 0;
   unsigned int radix = NO_RADIX;
   enum t_exactness forced_x = NO_EXACTNESS;
   enum t_exactness implicit_x = EXACT;
   SCM result;
+  size_t len = scm_i_string_length (mem);
 
   /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
-  while (idx + 2 < len && mem[idx] == '#')
+  while (idx + 2 < len && scm_i_string_ref (mem, idx) == '#')
     {
-      switch (mem[idx + 1])
+      switch (scm_i_string_ref (mem, idx + 1))
        {
        case 'b': case 'B':
          if (radix != NO_RADIX)
@@ -3011,9 +3135,9 @@ scm_c_locale_stringn_to_number (const char* mem, size_t len,
 
   /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
   if (radix == NO_RADIX)
-    result = mem2complex (mem, len, idx, default_radix, &implicit_x);
+    result = mem2complex (mem, idx, default_radix, &implicit_x);
   else
-    result = mem2complex (mem, len, idx, (unsigned int) radix, &implicit_x);
+    result = mem2complex (mem, idx, (unsigned int) radix, &implicit_x);
 
   if (scm_is_false (result))
     return SCM_BOOL_F;
@@ -3044,6 +3168,15 @@ scm_c_locale_stringn_to_number (const char* mem, size_t len,
     }
 }
 
+SCM
+scm_c_locale_stringn_to_number (const char* mem, size_t len,
+                               unsigned int default_radix)
+{
+  SCM str = scm_from_locale_stringn (mem, len);
+
+  return scm_i_string_to_number (str, default_radix);
+}
+
 
 SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
             (SCM string, SCM radix),
@@ -3066,9 +3199,7 @@ SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
   else
     base = scm_to_unsigned_integer (radix, 2, INT_MAX);
 
-  answer = scm_c_locale_stringn_to_number (scm_i_string_chars (string),
-                                          scm_i_string_length (string),
-                                          base);
+  answer = scm_i_string_to_number (string, base);
   scm_remember_upto_here_1 (string);
   return answer;
 }
@@ -3215,18 +3346,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))
@@ -3245,13 +3393,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))
@@ -3259,7 +3407,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))
     {
@@ -3274,7 +3422,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);
@@ -3285,7 +3433,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);
@@ -3294,7 +3442,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))
     {
@@ -3302,15 +3450,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);
@@ -3324,15 +3472,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))
     {
@@ -3344,7 +3492,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);
@@ -3362,15 +3510,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))
     {
@@ -3381,9 +3529,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;
@@ -3394,9 +3542,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;
@@ -3404,10 +3552,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);
 }
 
 
@@ -3417,20 +3565,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))
@@ -3450,7 +3614,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))
     {
@@ -3469,7 +3633,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);
@@ -3478,7 +3642,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))
     {
@@ -3487,7 +3651,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);
@@ -3498,15 +3662,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))
     {
@@ -3520,9 +3684,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;
@@ -3539,43 +3703,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
@@ -3584,18 +3780,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
@@ -3681,9 +3893,23 @@ scm_negative_p (SCM x)
    unlike scm_less_p above which takes some trouble to preserve all bits in
    its test, such trouble is not required for min and max.  */
 
-SCM_GPROC1 (s_max, "max", scm_tc7_asubr, scm_max, g_max);
-/* "Return the maximum of all parameter values."
- */
+SCM_PRIMITIVE_GENERIC (scm_i_max, "max", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return the maximum of all parameter values.")
+#define FUNC_NAME s_scm_i_max
+{
+  while (!scm_is_null (rest))
+    { x = scm_max (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_max (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_max s_scm_i_max
+#define g_max g_scm_i_max
+
 SCM
 scm_max (SCM x, SCM y)
 {
@@ -3699,10 +3925,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))
@@ -3775,7 +4001,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))
        {
@@ -3813,9 +4039,23 @@ scm_max (SCM x, SCM y)
 }
 
 
-SCM_GPROC1 (s_min, "min", scm_tc7_asubr, scm_min, g_min);
-/* "Return the minium of all parameter values."
- */
+SCM_PRIMITIVE_GENERIC (scm_i_min, "min", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return the minimum of all parameter values.")
+#define FUNC_NAME s_scm_i_min
+{
+  while (!scm_is_null (rest))
+    { x = scm_min (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_min (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_min s_scm_i_min
+#define g_min g_scm_i_min
+
 SCM
 scm_min (SCM x, SCM y)
 {
@@ -3831,10 +4071,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))
@@ -3907,7 +4147,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))
        {
@@ -3938,17 +4178,31 @@ scm_min (SCM x, SCM y)
           goto use_less;
        }
       else
-       SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
+       SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
     }
   else
     SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
 }
 
 
-SCM_GPROC1 (s_sum, "+", scm_tc7_asubr, scm_sum, g_sum);
-/* "Return the sum of all parameter values.  Return 0 if called without\n"
- * "any parameters." 
- */
+SCM_PRIMITIVE_GENERIC (scm_i_sum, "+", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return the sum of all parameter values.  Return 0 if called without\n"
+                       "any parameters." )
+#define FUNC_NAME s_scm_i_sum
+{
+  while (!scm_is_null (rest))
+    { x = scm_sum (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_sum (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_sum s_scm_i_sum
+#define g_sum g_scm_i_sum
+
 SCM
 scm_sum (SCM x, SCM y)
 {
@@ -3963,10 +4217,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))
         {
@@ -3975,12 +4229,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));
         }
@@ -3994,7 +4248,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);      
@@ -4138,13 +4392,28 @@ SCM_DEFINE (scm_oneplus, "1+", 1, 0, 0,
 #undef FUNC_NAME
 
 
-SCM_GPROC1 (s_difference, "-", scm_tc7_asubr, scm_difference, g_difference);
-/* If called with one argument @var{z1}, -@var{z1} returned. Otherwise
- * the sum of all but the first argument are subtracted from the first
- * argument.  */
-#define FUNC_NAME s_difference
+SCM_PRIMITIVE_GENERIC (scm_i_difference, "-", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "If called with one argument @var{z1}, -@var{z1} returned. Otherwise\n"
+                       "the sum of all but the first argument are subtracted from the first\n"
+                       "argument.")
+#define FUNC_NAME s_scm_i_difference
+{
+  while (!scm_is_null (rest))
+    { x = scm_difference (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_difference (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_difference s_scm_i_difference
+#define g_difference g_scm_i_difference
+
 SCM
 scm_difference (SCM x, SCM y)
+#define FUNC_NAME s_difference
 {
   if (SCM_UNLIKELY (SCM_UNBNDP (y)))
     {
@@ -4153,11 +4422,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
@@ -4179,18 +4448,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);
@@ -4218,12 +4487,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));
        }
@@ -4240,13 +4509,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 ();
@@ -4383,10 +4652,24 @@ SCM_DEFINE (scm_oneminus, "1-", 1, 0, 0,
 #undef FUNC_NAME
 
 
-SCM_GPROC1 (s_product, "*", scm_tc7_asubr, scm_product, g_product);
-/* "Return the product of all arguments.  If called without arguments,\n"
- * "1 is returned."
- */
+SCM_PRIMITIVE_GENERIC (scm_i_product, "*", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Return the product of all arguments.  If called without arguments,\n"
+                       "1 is returned.")
+#define FUNC_NAME s_scm_i_product
+{
+  while (!scm_is_null (rest))
+    { x = scm_product (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_product (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_product s_scm_i_product
+#define g_product g_scm_i_product
+
 SCM
 scm_product (SCM x, SCM y)
 {
@@ -4402,7 +4685,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);
@@ -4415,14 +4698,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);
            }
@@ -4603,13 +4886,28 @@ arising out of or in connection with the use or performance of
 this software.
 ****************************************************************/
 
-SCM_GPROC1 (s_divide, "/", scm_tc7_asubr, scm_divide, g_divide);
-/* Divide the first argument by the product of the remaining
-   arguments.  If called with one argument @var{z1}, 1/@var{z1} is
-   returned.  */
-#define FUNC_NAME s_divide
+SCM_PRIMITIVE_GENERIC (scm_i_divide, "/", 0, 2, 1,
+                       (SCM x, SCM y, SCM rest),
+                       "Divide the first argument by the product of the remaining\n"
+                       "arguments.  If called with one argument @var{z1}, 1/@var{z1} is\n"
+                       "returned.")
+#define FUNC_NAME s_scm_i_divide
+{
+  while (!scm_is_null (rest))
+    { x = scm_divide (x, y);
+      y = scm_car (rest);
+      rest = scm_cdr (rest);
+    }
+  return scm_divide (x, y);
+}
+#undef FUNC_NAME
+                       
+#define s_divide s_scm_i_divide
+#define g_divide g_scm_i_divide
+
 static SCM
-scm_i_divide (SCM x, SCM y, int inexact)
+do_divide (SCM x, SCM y, int inexact)
+#define FUNC_NAME s_divide
 {
   double a;
 
@@ -4619,7 +4917,7 @@ scm_i_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
@@ -4675,10 +4973,10 @@ scm_i_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
@@ -4695,11 +4993,11 @@ scm_i_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))
@@ -4750,7 +5048,7 @@ scm_i_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
@@ -4773,7 +5071,7 @@ scm_i_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)
@@ -4864,7 +5162,7 @@ scm_i_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);
@@ -4904,7 +5202,7 @@ scm_i_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);
@@ -4960,7 +5258,7 @@ scm_i_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);
@@ -5002,61 +5300,16 @@ scm_i_divide (SCM x, SCM y, int inexact)
 SCM
 scm_divide (SCM x, SCM y)
 {
-  return scm_i_divide (x, y, 0);
+  return do_divide (x, y, 0);
 }
 
 static SCM scm_divide2real (SCM x, SCM y)
 {
-  return scm_i_divide (x, y, 1);
+  return do_divide (x, y, 1);
 }
 #undef FUNC_NAME
 
 
-double
-scm_asinh (double x)
-{
-#if HAVE_ASINH
-  return asinh (x);
-#else
-#define asinh scm_asinh
-  return log (x + sqrt (x * x + 1));
-#endif
-}
-SCM_GPROC1 (s_asinh, "$asinh", scm_tc7_dsubr, (SCM (*)()) asinh, g_asinh);
-/* "Return the inverse hyperbolic sine of @var{x}."
- */
-
-
-double
-scm_acosh (double x)
-{
-#if HAVE_ACOSH
-  return acosh (x);
-#else
-#define acosh scm_acosh
-  return log (x + sqrt (x * x - 1));
-#endif
-}
-SCM_GPROC1 (s_acosh, "$acosh", scm_tc7_dsubr, (SCM (*)()) acosh, g_acosh);
-/* "Return the inverse hyperbolic cosine of @var{x}."
- */
-
-
-double
-scm_atanh (double x)
-{
-#if HAVE_ATANH
-  return atanh (x);
-#else
-#define atanh scm_atanh
-  return 0.5 * log ((1 + x) / (1 - x));
-#endif
-}
-SCM_GPROC1 (s_atanh, "$atanh", scm_tc7_dsubr, (SCM (*)()) atanh, g_atanh);
-/* "Return the inverse hyperbolic tangent of @var{x}."
- */
-
-
 double
 scm_c_truncate (double x)
 {
@@ -5215,108 +5468,284 @@ SCM_PRIMITIVE_GENERIC (scm_ceiling, "ceiling", 1, 0, 0,
 }
 #undef FUNC_NAME
 
-SCM_GPROC1 (s_i_sqrt, "$sqrt", scm_tc7_dsubr, (SCM (*)()) sqrt, g_i_sqrt);
-/* "Return the square root of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_abs, "$abs", scm_tc7_dsubr, (SCM (*)()) fabs, g_i_abs);
-/* "Return the absolute value of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_exp, "$exp", scm_tc7_dsubr, (SCM (*)()) exp, g_i_exp);
-/* "Return the @var{x}th power of e."
- */
-SCM_GPROC1 (s_i_log, "$log", scm_tc7_dsubr, (SCM (*)()) log, g_i_log);
-/* "Return the natural logarithm of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_sin, "$sin", scm_tc7_dsubr, (SCM (*)()) sin, g_i_sin);
-/* "Return the sine of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_cos, "$cos", scm_tc7_dsubr, (SCM (*)()) cos, g_i_cos);
-/* "Return the cosine of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_tan, "$tan", scm_tc7_dsubr, (SCM (*)()) tan, g_i_tan);
-/* "Return the tangent of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_asin, "$asin", scm_tc7_dsubr, (SCM (*)()) asin, g_i_asin);
-/* "Return the arc sine of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_acos, "$acos", scm_tc7_dsubr, (SCM (*)()) acos, g_i_acos);
-/* "Return the arc cosine of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_atan, "$atan", scm_tc7_dsubr, (SCM (*)()) atan, g_i_atan);
-/* "Return the arc tangent of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_sinh, "$sinh", scm_tc7_dsubr, (SCM (*)()) sinh, g_i_sinh);
-/* "Return the hyperbolic sine of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_cosh, "$cosh", scm_tc7_dsubr, (SCM (*)()) cosh, g_i_cosh);
-/* "Return the hyperbolic cosine of the real number @var{x}."
- */
-SCM_GPROC1 (s_i_tanh, "$tanh", scm_tc7_dsubr, (SCM (*)()) tanh, g_i_tanh);
-/* "Return the hyperbolic tangent of the real number @var{x}."
- */
+/* sin/cos/tan/asin/acos/atan
+   sinh/cosh/tanh/asinh/acosh/atanh
+   Derived from "Transcen.scm", Complex trancendental functions for SCM.
+   Written by Jerry D. Hedden, (C) FSF.
+   See the file `COPYING' for terms applying to this program. */
 
-struct dpair
+SCM_DEFINE (scm_expt, "expt", 2, 0, 0,
+            (SCM x, SCM y),
+           "Return @var{x} raised to the power of @var{y}.") 
+#define FUNC_NAME s_scm_expt
 {
-  double x, y;
-};
+  if (scm_is_true (scm_exact_p (x)) && scm_is_integer (y))
+    return scm_integer_expt (x, 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)));
+    }
+  else
+    return scm_exp (scm_product (scm_log (x), y));
+}
+#undef FUNC_NAME
 
-static void scm_two_doubles (SCM x,
-                            SCM y,
-                            const char *sstring,
-                            struct dpair * xy);
+SCM_PRIMITIVE_GENERIC (scm_sin, "sin", 1, 0, 0,
+                       (SCM z),
+                       "Compute the sine of @var{z}.")
+#define FUNC_NAME s_scm_sin
+{
+  if (scm_is_real (z))
+    return scm_from_double (sin (scm_to_double (z)));
+  else if (SCM_COMPLEXP (z))
+    { double x, y;
+      x = SCM_COMPLEX_REAL (z);
+      y = SCM_COMPLEX_IMAG (z);
+      return scm_c_make_rectangular (sin (x) * cosh (y),
+                                     cos (x) * sinh (y));
+    }
+  else
+    SCM_WTA_DISPATCH_1 (g_scm_sin, z, 1, s_scm_sin);
+}
+#undef FUNC_NAME
 
-static void
-scm_two_doubles (SCM x, SCM y, const char *sstring, struct dpair *xy)
+SCM_PRIMITIVE_GENERIC (scm_cos, "cos", 1, 0, 0,
+                       (SCM z),
+                       "Compute the cosine of @var{z}.")
+#define FUNC_NAME s_scm_cos
 {
-  if (SCM_I_INUMP (x))
-    xy->x = SCM_I_INUM (x);
-  else if (SCM_BIGP (x))
-    xy->x = scm_i_big2dbl (x);
-  else if (SCM_REALP (x))
-    xy->x = SCM_REAL_VALUE (x);
-  else if (SCM_FRACTIONP (x))
-    xy->x = scm_i_fraction2double (x);
+  if (scm_is_real (z))
+    return scm_from_double (cos (scm_to_double (z)));
+  else if (SCM_COMPLEXP (z))
+    { double x, y;
+      x = SCM_COMPLEX_REAL (z);
+      y = SCM_COMPLEX_IMAG (z);
+      return scm_c_make_rectangular (cos (x) * cosh (y),
+                                     -sin (x) * sinh (y));
+    }
   else
-    scm_wrong_type_arg (sstring, SCM_ARG1, x);
-
-  if (SCM_I_INUMP (y))
-    xy->y = SCM_I_INUM (y);
-  else if (SCM_BIGP (y))
-    xy->y = scm_i_big2dbl (y);
-  else if (SCM_REALP (y))
-    xy->y = SCM_REAL_VALUE (y);
-  else if (SCM_FRACTIONP (y))
-    xy->y = scm_i_fraction2double (y);
+    SCM_WTA_DISPATCH_1 (g_scm_cos, z, 1, s_scm_cos);
+}
+#undef FUNC_NAME
+
+SCM_PRIMITIVE_GENERIC (scm_tan, "tan", 1, 0, 0,
+                       (SCM z),
+                       "Compute the tangent of @var{z}.")
+#define FUNC_NAME s_scm_tan
+{
+  if (scm_is_real (z))
+    return scm_from_double (tan (scm_to_double (z)));
+  else if (SCM_COMPLEXP (z))
+    { double x, y, w;
+      x = 2.0 * SCM_COMPLEX_REAL (z);
+      y = 2.0 * SCM_COMPLEX_IMAG (z);
+      w = cos (x) + cosh (y);
+#ifndef ALLOW_DIVIDE_BY_ZERO
+      if (w == 0.0)
+        scm_num_overflow (s_scm_tan);
+#endif
+      return scm_c_make_rectangular (sin (x) / w, sinh (y) / w);
+    }
   else
-    scm_wrong_type_arg (sstring, SCM_ARG2, y);
+    SCM_WTA_DISPATCH_1 (g_scm_tan, z, 1, s_scm_tan);
 }
+#undef FUNC_NAME
 
+SCM_PRIMITIVE_GENERIC (scm_sinh, "sinh", 1, 0, 0,
+                       (SCM z),
+                       "Compute the hyperbolic sine of @var{z}.")
+#define FUNC_NAME s_scm_sinh
+{
+  if (scm_is_real (z))
+    return scm_from_double (sinh (scm_to_double (z)));
+  else if (SCM_COMPLEXP (z))
+    { double x, y;
+      x = SCM_COMPLEX_REAL (z);
+      y = SCM_COMPLEX_IMAG (z);
+      return scm_c_make_rectangular (sinh (x) * cos (y),
+                                     cosh (x) * sin (y));
+    }
+  else
+    SCM_WTA_DISPATCH_1 (g_scm_sinh, z, 1, s_scm_sinh);
+}
+#undef FUNC_NAME
 
-SCM_DEFINE (scm_sys_expt, "$expt", 2, 0, 0,
-            (SCM x, SCM y),
-           "Return @var{x} raised to the power of @var{y}. This\n"
-           "procedure does not accept complex arguments.") 
-#define FUNC_NAME s_scm_sys_expt
+SCM_PRIMITIVE_GENERIC (scm_cosh, "cosh", 1, 0, 0,
+                       (SCM z),
+                       "Compute the hyperbolic cosine of @var{z}.")
+#define FUNC_NAME s_scm_cosh
 {
-  struct dpair xy;
-  scm_two_doubles (x, y, FUNC_NAME, &xy);
-  return scm_from_double (pow (xy.x, xy.y));
+  if (scm_is_real (z))
+    return scm_from_double (cosh (scm_to_double (z)));
+  else if (SCM_COMPLEXP (z))
+    { double x, y;
+      x = SCM_COMPLEX_REAL (z);
+      y = SCM_COMPLEX_IMAG (z);
+      return scm_c_make_rectangular (cosh (x) * cos (y),
+                                     sinh (x) * sin (y));
+    }
+  else
+    SCM_WTA_DISPATCH_1 (g_scm_cosh, z, 1, s_scm_cosh);
 }
 #undef FUNC_NAME
 
+SCM_PRIMITIVE_GENERIC (scm_tanh, "tanh", 1, 0, 0,
+                       (SCM z),
+                       "Compute the hyperbolic tangent of @var{z}.")
+#define FUNC_NAME s_scm_tanh
+{
+  if (scm_is_real (z))
+    return scm_from_double (tanh (scm_to_double (z)));
+  else if (SCM_COMPLEXP (z))
+    { double x, y, w;
+      x = 2.0 * SCM_COMPLEX_REAL (z);
+      y = 2.0 * SCM_COMPLEX_IMAG (z);
+      w = cosh (x) + cos (y);
+#ifndef ALLOW_DIVIDE_BY_ZERO
+      if (w == 0.0)
+        scm_num_overflow (s_scm_tanh);
+#endif
+      return scm_c_make_rectangular (sinh (x) / w, sin (y) / w);
+    }
+  else
+    SCM_WTA_DISPATCH_1 (g_scm_tanh, z, 1, s_scm_tanh);
+}
+#undef FUNC_NAME
 
-SCM_DEFINE (scm_sys_atan2, "$atan2", 2, 0, 0,
-            (SCM x, SCM y),
-           "Return the arc tangent of the two arguments @var{x} and\n"
-           "@var{y}. This is similar to calculating the arc tangent of\n"
-           "@var{x} / @var{y}, except that the signs of both arguments\n"
-           "are used to determine the quadrant of the result. This\n"
-           "procedure does not accept complex arguments.")
-#define FUNC_NAME s_scm_sys_atan2
+SCM_PRIMITIVE_GENERIC (scm_asin, "asin", 1, 0, 0,
+                       (SCM z),
+                       "Compute the arc sine of @var{z}.")
+#define FUNC_NAME s_scm_asin
+{
+  if (scm_is_real (z))
+    {
+      double w = scm_to_double (z);
+      if (w >= -1.0 && w <= 1.0)
+        return scm_from_double (asin (w));
+      else
+        return scm_product (scm_c_make_rectangular (0, -1),
+                            scm_sys_asinh (scm_c_make_rectangular (0, w)));
+    }
+  else if (SCM_COMPLEXP (z))
+    { double x, y;
+      x = SCM_COMPLEX_REAL (z);
+      y = SCM_COMPLEX_IMAG (z);
+      return scm_product (scm_c_make_rectangular (0, -1),
+                          scm_sys_asinh (scm_c_make_rectangular (-y, x)));
+    }
+  else
+    SCM_WTA_DISPATCH_1 (g_scm_asin, z, 1, s_scm_asin);
+}
+#undef FUNC_NAME
+
+SCM_PRIMITIVE_GENERIC (scm_acos, "acos", 1, 0, 0,
+                       (SCM z),
+                       "Compute the arc cosine of @var{z}.")
+#define FUNC_NAME s_scm_acos
+{
+  if (scm_is_real (z))
+    {
+      double w = scm_to_double (z);
+      if (w >= -1.0 && w <= 1.0)
+        return scm_from_double (acos (w));
+      else
+        return scm_sum (scm_from_double (acos (0.0)),
+                        scm_product (scm_c_make_rectangular (0, 1),
+                                     scm_sys_asinh (scm_c_make_rectangular (0, w))));
+    }
+  else if (SCM_COMPLEXP (z))
+    { double x, y;
+      x = SCM_COMPLEX_REAL (z);
+      y = SCM_COMPLEX_IMAG (z);
+      return scm_sum (scm_from_double (acos (0.0)),
+                      scm_product (scm_c_make_rectangular (0, 1),
+                                   scm_sys_asinh (scm_c_make_rectangular (-y, x))));
+    }
+  else
+    SCM_WTA_DISPATCH_1 (g_scm_acos, z, 1, s_scm_acos);
+}
+#undef FUNC_NAME
+
+SCM_PRIMITIVE_GENERIC (scm_atan, "atan", 1, 1, 0,
+                       (SCM z, SCM y),
+                       "With one argument, compute the arc tangent of @var{z}.\n"
+                       "If @var{y} is present, compute the arc tangent of @var{z}/@var{y},\n"
+                       "using the sign of @var{z} and @var{y} to determine the quadrant.")
+#define FUNC_NAME s_scm_atan
 {
-  struct dpair xy;
-  scm_two_doubles (x, y, FUNC_NAME, &xy);
-  return scm_from_double (atan2 (xy.x, xy.y));
+  if (SCM_UNBNDP (y))
+    {
+      if (scm_is_real (z))
+        return scm_from_double (atan (scm_to_double (z)));
+      else if (SCM_COMPLEXP (z))
+        {
+          double v, w;
+          v = SCM_COMPLEX_REAL (z);
+          w = SCM_COMPLEX_IMAG (z);
+          return scm_divide (scm_log (scm_divide (scm_c_make_rectangular (v, w - 1.0),
+                                                  scm_c_make_rectangular (v, w + 1.0))),
+                             scm_c_make_rectangular (0, 2));
+        }
+      else
+        SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
+    }
+  else if (scm_is_real (z))
+    {
+      if (scm_is_real (y))
+        return scm_from_double (atan2 (scm_to_double (z), scm_to_double (y)));
+      else
+        SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG2, s_scm_atan);
+    }
+  else
+    SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
+}
+#undef FUNC_NAME
+
+SCM_PRIMITIVE_GENERIC (scm_sys_asinh, "asinh", 1, 0, 0,
+                       (SCM z),
+                       "Compute the inverse hyperbolic sine of @var{z}.")
+#define FUNC_NAME s_scm_sys_asinh
+{
+  if (scm_is_real (z))
+    return scm_from_double (asinh (scm_to_double (z)));
+  else if (scm_is_number (z))
+    return scm_log (scm_sum (z,
+                             scm_sqrt (scm_sum (scm_product (z, z),
+                                                SCM_I_MAKINUM (1)))));
+  else
+    SCM_WTA_DISPATCH_1 (g_scm_sys_asinh, z, 1, s_scm_sys_asinh);
+}
+#undef FUNC_NAME
+
+SCM_PRIMITIVE_GENERIC (scm_sys_acosh, "acosh", 1, 0, 0,
+                       (SCM z),
+                       "Compute the inverse hyperbolic cosine of @var{z}.")
+#define FUNC_NAME s_scm_sys_acosh
+{
+  if (scm_is_real (z) && scm_to_double (z) >= 1.0)
+    return scm_from_double (acosh (scm_to_double (z)));
+  else if (scm_is_number (z))
+    return scm_log (scm_sum (z,
+                             scm_sqrt (scm_difference (scm_product (z, z),
+                                                       SCM_I_MAKINUM (1)))));
+  else
+    SCM_WTA_DISPATCH_1 (g_scm_sys_acosh, z, 1, s_scm_sys_acosh);
+}
+#undef FUNC_NAME
+
+SCM_PRIMITIVE_GENERIC (scm_sys_atanh, "atanh", 1, 0, 0,
+                       (SCM z),
+                       "Compute the inverse hyperbolic tangent of @var{z}.")
+#define FUNC_NAME s_scm_sys_atanh
+{
+  if (scm_is_real (z) && scm_to_double (z) >= -1.0 && scm_to_double (z) <= 1.0)
+    return scm_from_double (atanh (scm_to_double (z)));
+  else if (scm_is_number (z))
+    return scm_divide (scm_log (scm_divide (scm_sum (SCM_I_MAKINUM (1), z),
+                                            scm_difference (SCM_I_MAKINUM (1), z))),
+                       SCM_I_MAKINUM (2));
+  else
+    SCM_WTA_DISPATCH_1 (g_scm_sys_atanh, z, 1, s_scm_sys_atanh);
 }
 #undef FUNC_NAME
 
@@ -5328,9 +5757,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;
@@ -5343,9 +5773,12 @@ SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
            "and @var{imaginary-part} parts.")
 #define FUNC_NAME s_scm_make_rectangular
 {
-  struct dpair xy;
-  scm_two_doubles (real_part, imaginary_part, FUNC_NAME, &xy);
-  return scm_c_make_rectangular (xy.x, xy.y);
+  SCM_ASSERT_TYPE (scm_is_real (real_part), real_part,
+                   SCM_ARG1, FUNC_NAME, "real");
+  SCM_ASSERT_TYPE (scm_is_real (imaginary_part), imaginary_part,
+                   SCM_ARG2, FUNC_NAME, "real");
+  return scm_c_make_rectangular (scm_to_double (real_part),
+                                 scm_to_double (imaginary_part));
 }
 #undef FUNC_NAME
 
@@ -5353,7 +5786,12 @@ SCM
 scm_c_make_polar (double mag, double ang)
 {
   double s, c;
-#if HAVE_SINCOS
+
+  /* The sincos(3) function is undocumented an broken on Tru64.  Thus we only
+     use it on Glibc-based systems that have it (it's a GNU extension).  See
+     http://lists.gnu.org/archive/html/guile-user/2009-04/msg00033.html for
+     details.  */
+#if (defined HAVE_SINCOS) && (defined __GLIBC__) && (defined _GNU_SOURCE)
   sincos (ang, &s, &c);
 #else
   s = sin (ang);
@@ -5367,9 +5805,9 @@ SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
            "Return the complex number @var{x} * e^(i * @var{y}).")
 #define FUNC_NAME s_scm_make_polar
 {
-  struct dpair xy;
-  scm_two_doubles (x, y, FUNC_NAME, &xy);
-  return scm_c_make_polar (xy.x, xy.y);
+  SCM_ASSERT_TYPE (scm_is_real (x), x, SCM_ARG1, FUNC_NAME, "real");
+  SCM_ASSERT_TYPE (scm_is_real (y), y, SCM_ARG2, FUNC_NAME, "real");
+  return scm_c_make_polar (scm_to_double (x), scm_to_double (y));
 }
 #undef FUNC_NAME
 
@@ -5406,7 +5844,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))
@@ -5461,13 +5899,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))
     {
@@ -5501,13 +5939,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));
     }
@@ -5518,12 +5956,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));
     }
@@ -5532,7 +5970,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
@@ -5570,7 +6008,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
        {
@@ -5851,7 +6289,13 @@ scm_i_range_error (SCM bad_val, SCM min, SCM max)
 #define SCM_FROM_TYPE_PROTO(arg) scm_from_uint32 (arg)
 #include "libguile/conv-uinteger.i.c"
 
-#if SCM_HAVE_T_INT64
+#define TYPE                     scm_t_wchar
+#define TYPE_MIN                 (scm_t_int32)-1
+#define TYPE_MAX                 (scm_t_int32)0x10ffff
+#define SIZEOF_TYPE              4
+#define SCM_TO_TYPE_PROTO(arg)   scm_to_wchar (arg)
+#define SCM_FROM_TYPE_PROTO(arg) scm_from_wchar (arg)
+#include "libguile/conv-integer.i.c"
 
 #define TYPE                     scm_t_int64
 #define TYPE_MIN                 SCM_T_INT64_MIN
@@ -5869,8 +6313,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)
 {
@@ -5918,20 +6360,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);
@@ -5941,12 +6391,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);
@@ -6058,7 +6511,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);
@@ -6124,7 +6578,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);
@@ -6164,7 +6619,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)
@@ -6174,11 +6629,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"
 }