prefer compilers earlier in list
[bpt/guile.git] / libguile / numbers.c
index 3cdc7fd..14d98ff 100644 (file)
@@ -1,6 +1,6 @@
 /* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
  *   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
- *   2013 Free Software Foundation, Inc.
+ *   2013, 2014 Free Software Foundation, Inc.
  *
  * Portions Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories
  * and Bellcore.  See scm_divide.
@@ -48,6 +48,7 @@
 #endif
 
 #include <verify.h>
+#include <assert.h>
 
 #include <math.h>
 #include <string.h>
@@ -4678,9 +4679,15 @@ SCM_DEFINE (scm_logbit_p, "logbit?", 2, 0, 0,
 
   if (SCM_I_INUMP (j))
     {
-      /* bits above what's in an inum follow the sign bit */
-      iindex = min (iindex, SCM_LONG_BIT - 1);
-      return scm_from_bool ((1L << iindex) & SCM_I_INUM (j));
+      if (iindex < SCM_LONG_BIT - 1)
+        /* Arrange for the number to be converted to unsigned before
+           checking the bit, to ensure that we're testing the bit in a
+           two's complement representation (regardless of the native
+           representation.  */
+        return scm_from_bool ((1UL << iindex) & SCM_I_INUM (j));
+      else
+        /* Portably check the sign.  */
+        return scm_from_bool (SCM_I_INUM (j) < 0);
     }
   else if (SCM_BIGP (j))
     {
@@ -4976,24 +4983,27 @@ left_shift_exact_integer (SCM n, long count)
     {
       scm_t_inum nn = SCM_I_INUM (n);
 
-      /* Left shift of count >= SCM_I_FIXNUM_BIT-1 will always
+      /* Left shift of count >= SCM_I_FIXNUM_BIT-1 will almost[*] always
          overflow a non-zero fixnum.  For smaller shifts we check the
          bits going into positions above SCM_I_FIXNUM_BIT-1.  If they're
          all 0s for nn>=0, or all 1s for nn<0 then there's no overflow.
-         Those bits are "nn >> (SCM_I_FIXNUM_BIT-1 - count)".  */
+         Those bits are "nn >> (SCM_I_FIXNUM_BIT-1 - count)".
+
+         [*] There's one exception:
+             (-1) << SCM_I_FIXNUM_BIT-1 == SCM_MOST_NEGATIVE_FIXNUM  */
 
       if (nn == 0)
         return n;
       else if (count < SCM_I_FIXNUM_BIT-1 &&
                ((scm_t_bits) (SCM_SRS (nn, (SCM_I_FIXNUM_BIT-1 - count)) + 1)
                 <= 1))
-        return SCM_I_MAKINUM (nn << count);
+        return SCM_I_MAKINUM (nn < 0 ? -(-nn << count) : (nn << count));
       else
         {
           SCM result = scm_i_inum2big (nn);
           mpz_mul_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result),
                         count);
-          return result;
+          return scm_i_normbig (result);
         }
     }
   else if (SCM_BIGP (n))
@@ -5004,7 +5014,7 @@ left_shift_exact_integer (SCM n, long count)
       return result;
     }
   else
-    scm_syserror ("left_shift_exact_integer");
+    assert (0);
 }
 
 /* Efficiently compute floor (N / 2^COUNT),
@@ -5030,7 +5040,7 @@ floor_right_shift_exact_integer (SCM n, long count)
       return scm_i_normbig (result);
     }
   else
-    scm_syserror ("floor_right_shift_exact_integer");
+    assert (0);
 }
 
 /* Efficiently compute round (N / 2^COUNT),
@@ -5068,7 +5078,7 @@ round_right_shift_exact_integer (SCM n, long count)
       return scm_i_normbig (q);
     }
   else
-    scm_syserror ("round_right_shift_exact_integer");
+    assert (0);
 }
 
 SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
@@ -5797,20 +5807,25 @@ enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
 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)
+  if (c >= (scm_t_uint32) '0' && c <= (scm_t_uint32) '9')
+    return c - (scm_t_uint32) '0';
+  else
     {
-      c = uc_tolower (c);
-      if (c >= (scm_t_uint32) 'a')
-        d = c - (scm_t_uint32)'a' + 10U;
+      /* 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;
     }
-  return d;
 }
 
 /* Parse the substring of MEM starting at *P_IDX for an unsigned integer
@@ -6199,7 +6214,7 @@ mem2ureal (SCM mem, unsigned int *p_idx,
     }
 
   /* We should never get here */
-  scm_syserror ("mem2ureal");
+  assert (0);
 }
 
 
@@ -6510,8 +6525,8 @@ SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0,
 
 SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0, 
             (SCM x),
-           "Return @code{#t} if @var{x} is an integer number, @code{#f}\n"
-           "else.")
+           "Return @code{#t} if @var{x} is an integer number,\n"
+           "else return @code{#f}.")
 #define FUNC_NAME s_scm_integer_p
 {
   if (SCM_I_INUMP (x) || SCM_BIGP (x))
@@ -6526,6 +6541,19 @@ SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
 }
 #undef FUNC_NAME
 
+SCM_DEFINE (scm_exact_integer_p, "exact-integer?", 1, 0, 0,
+            (SCM x),
+           "Return @code{#t} if @var{x} is an exact integer number,\n"
+           "else return @code{#f}.")
+#define FUNC_NAME s_scm_exact_integer_p
+{
+  if (SCM_I_INUMP (x) || SCM_BIGP (x))
+    return SCM_BOOL_T;
+  else
+    return SCM_BOOL_F;
+}
+#undef FUNC_NAME
+
 
 SCM scm_i_num_eq_p (SCM, SCM, SCM);
 SCM_PRIMITIVE_GENERIC (scm_i_num_eq_p, "=", 0, 2, 1,
@@ -9194,7 +9222,15 @@ SCM_PRIMITIVE_GENERIC (scm_numerator, "numerator", 1, 0, 0,
   else if (SCM_FRACTIONP (z))
     return SCM_FRACTION_NUMERATOR (z);
   else if (SCM_REALP (z))
-    return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
+    {
+      double zz = SCM_REAL_VALUE (z);
+      if (zz == floor (zz))
+        /* Handle -0.0 and infinities in accordance with R6RS
+           flnumerator, and optimize handling of integers. */
+        return z;
+      else
+        return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
+    }
   else
     return scm_wta_dispatch_1 (g_scm_numerator, z, SCM_ARG1, s_scm_numerator);
 }
@@ -9211,7 +9247,15 @@ SCM_PRIMITIVE_GENERIC (scm_denominator, "denominator", 1, 0, 0,
   else if (SCM_FRACTIONP (z))
     return SCM_FRACTION_DENOMINATOR (z);
   else if (SCM_REALP (z))
-    return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
+    {
+      double zz = SCM_REAL_VALUE (z);
+      if (zz == floor (zz))
+        /* Handle infinities in accordance with R6RS fldenominator, and
+           optimize handling of integers. */
+        return scm_i_from_double (1.0);
+      else
+        return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
+    }
   else
     return scm_wta_dispatch_1 (g_scm_denominator, z, SCM_ARG1,
                                s_scm_denominator);
@@ -9598,6 +9642,12 @@ scm_is_integer (SCM val)
   return scm_is_true (scm_integer_p (val));
 }
 
+int
+scm_is_exact_integer (SCM val)
+{
+  return scm_is_true (scm_exact_integer_p (val));
+}
+
 int
 scm_is_signed_integer (SCM val, scm_t_intmax min, scm_t_intmax max)
 {