summaryrefslogtreecommitdiff
path: root/libguile/numbers.h
diff options
context:
space:
mode:
Diffstat (limited to 'libguile/numbers.h')
-rw-r--r--libguile/numbers.h40
1 files changed, 32 insertions, 8 deletions
diff --git a/libguile/numbers.h b/libguile/numbers.h
index 6e382ea35..bba336bd4 100644
--- a/libguile/numbers.h
+++ b/libguile/numbers.h
@@ -4,7 +4,7 @@
#define SCM_NUMBERS_H
/* Copyright (C) 1995,1996,1998,2000,2001,2002,2003,2004,2005, 2006,
- * 2008, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
+ * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -49,19 +49,43 @@ typedef scm_t_int32 scm_t_wchar;
#define SCM_MOST_POSITIVE_FIXNUM ((SCM_T_SIGNED_BITS_MAX-3)/4)
#define SCM_MOST_NEGATIVE_FIXNUM (-SCM_MOST_POSITIVE_FIXNUM-1)
-/* SCM_SRS is signed right shift */
-#if (-1 == (((-1) << 2) + 2) >> 2)
-# define SCM_SRS(x, y) ((x) >> (y))
+/* SCM_SRS (X, Y) is signed right shift, defined as floor (X / 2^Y),
+ where Y must be non-negative and less than the width in bits of X.
+ It's common for >> to do this, but the C standards do not specify
+ what happens when X is negative.
+
+ NOTE: X must not perform side effects. */
+#if (-1 >> 2 == -1) && (-4 >> 2 == -1) && (-5 >> 2 == -2) && (-8 >> 2 == -2)
+# define SCM_SRS(x, y) ((x) >> (y))
#else
-# define SCM_SRS(x, y) ((x) < 0 ? ~((~(x)) >> (y)) : ((x) >> (y)))
-#endif /* (-1 == (((-1) << 2) + 2) >> 2) */
+# define SCM_SRS(x, y) \
+ ((x) < 0 \
+ ? -1 - (scm_t_signed_bits) (~(scm_t_bits)(x) >> (y)) \
+ : ((x) >> (y)))
+#endif
+
+/* The first implementation of SCM_I_INUM below depends on behavior that
+ is specified by GNU C but not by C standards, namely that when
+ casting to a signed integer of width N, the value is reduced modulo
+ 2^N to be within range of the type. The second implementation below
+ should be portable to all conforming C implementations, but may be
+ less efficient if the compiler is not sufficiently clever.
+
+ NOTE: X must not perform side effects. */
+#ifdef __GNUC__
+# define SCM_I_INUM(x) (SCM_SRS ((scm_t_signed_bits) SCM_UNPACK (x), 2))
+#else
+# define SCM_I_INUM(x) \
+ (SCM_UNPACK (x) > LONG_MAX \
+ ? -1 - (scm_t_signed_bits) (~SCM_UNPACK (x) >> 2) \
+ : (scm_t_signed_bits) (SCM_UNPACK (x) >> 2))
+#endif
#define SCM_I_INUMP(x) (2 & SCM_UNPACK (x))
#define SCM_I_NINUMP(x) (!SCM_I_INUMP (x))
#define SCM_I_MAKINUM(x) \
- (SCM_PACK ((((scm_t_signed_bits) (x)) << 2) + scm_tc2_int))
-#define SCM_I_INUM(x) (SCM_SRS ((scm_t_signed_bits) SCM_UNPACK (x), 2))
+ (SCM_PACK ((((scm_t_bits) (x)) << 2) + scm_tc2_int))
/* SCM_FIXABLE is true if its long argument can be encoded in an SCM_INUM. */
#define SCM_POSFIXABLE(n) ((n) <= SCM_MOST_POSITIVE_FIXNUM)