changeset 8169:66bc6f9b4f72

rewrite integer arithmetics and conversions
author Jaroslav Hajek <highegg@gmail.com>
date Wed, 01 Oct 2008 11:05:13 -0400
parents dadf478ddc42
children 1651939a394b
files ChangeLog aclocal.m4 configure.in liboctave/ChangeLog liboctave/oct-inttypes.cc liboctave/oct-inttypes.h
diffstat 6 files changed, 997 insertions(+), 1061 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Sep 30 09:19:43 2008 +0200
+++ b/ChangeLog	Wed Oct 01 11:05:13 2008 -0400
@@ -1,3 +1,8 @@
+2008-09-30  Jaroslav Hajek <highegg@gmail.com>
+
+	* aclocal.m4 (OCTAVE_FAST_INT_OPS): New macro.
+	* configure.in: Call OCTAVE_FAST_INT_OPS
+
 2008-09-08  John W. Eaton  <jwe@octave.org>
 
 	* mkoctfile.cc.in, octave-bug.cc.in, octave-config.cc.in: Style fixes.
--- a/aclocal.m4	Tue Sep 30 09:19:43 2008 +0200
+++ b/aclocal.m4	Wed Oct 01 11:05:13 2008 -0400
@@ -1206,3 +1206,68 @@
    AC_SUBST([FT2_CFLAGS])
    AC_SUBST([FT2_LIBS])])
 dnl end of freetype2.m4
+
+dnl Check whether fast signed integer arithmetics using bit tricks
+dnl can be used in oct-inttypes.h. Defines HAVE_FAST_INT_OPS if
+dnl the following conditions hold:
+dnl 1. Signed numbers are represented by twos complement
+dnl    (see <http://en.wikipedia.org/wiki/Two%27s_complement>)
+dnl 2. static_cast to unsigned int counterpart works like interpreting
+dnl    the signed bit pattern as unsigned (and is thus zero-cost).
+dnl 3. Signed addition and subtraction yield the same bit results as unsigned.
+dnl    (We use casts to prevent optimization interference, so there is no
+dnl     need for things like -ftrapv).
+dnl 4. Bit operations on signed integers work like on unsigned integers,
+dnl    except for the shifts. Shifts are arithmetic.
+dnl
+AC_DEFUN([OCTAVE_FAST_INT_OPS],[
+AC_MSG_CHECKING([whether fast integer arithmetics is usable])
+AC_LANG_PUSH(C++)
+AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <limits>
+template<class UT, class ST>
+static bool 
+do_test (UT, ST)
+{
+  volatile ST s = std::numeric_limits<ST>::min () / 3;
+  volatile UT u = static_cast<UT> (s);
+  if (*(reinterpret_cast<volatile ST *> (&u)) != s) return true;
+  
+  u = 0; u = ~u;
+  if (*(reinterpret_cast<volatile ST *> (&u)) != -1) return true;
+  
+  ST sx, sy;
+  sx = std::numeric_limits<ST>::max () / 2 + 1;
+  sy = std::numeric_limits<ST>::max () / 2 + 2;
+  if (static_cast<ST> (static_cast<UT> (sx) + static_cast<UT> (sy))
+      != std::numeric_limits<ST>::min () + 1) return true;
+  if (static_cast<ST> (static_cast<UT> (sx) - static_cast<UT> (sy))
+      != -1) return true;
+  
+  if ((sx & sy) != (static_cast<UT> (sx) & static_cast<UT> (sy)))
+    return true;
+  if ((sx | sy) != (static_cast<UT> (sx) | static_cast<UT> (sy)))
+    return true;
+  if ((sx ^ sy) != (static_cast<UT> (sx) ^ static_cast<UT> (sy)))
+    return true;
+  if ((-1 >> 1) != -1) return true;
+  return false;
+}
+
+#define DO_TEST(T) \
+if (do_test (static_cast<unsigned T> (0), static_cast<signed T> (0))) \
+  return sizeof (T);
+]],[[
+  DO_TEST(char)
+  DO_TEST(short)
+  DO_TEST(int)
+  DO_TEST(long)
+#if (defined(HAVE_LONG_LONG_INT) && defined(HAVE_UNSIGNED_LONG_LONG_INT))
+  DO_TEST(long long)
+#endif
+]])],
+[AC_MSG_RESULT([yes])
+ AC_DEFINE(HAVE_FAST_INT_OPS,1,[Define if signed integers use two's complement])],
+[AC_MSG_RESULT([no])])
+AC_LANG_POP(C++)])
+
--- a/configure.in	Tue Sep 30 09:19:43 2008 +0200
+++ b/configure.in	Wed Oct 01 11:05:13 2008 -0400
@@ -1374,6 +1374,10 @@
 
 OCTAVE_DYNAMIC_AUTO_ARRAYS
 
+### See if we can use fast integer arithmetics
+
+OCTAVE_FAST_INT_OPS
+
 ### Checks for header files.
 
 AC_HEADER_STDC
--- a/liboctave/ChangeLog	Tue Sep 30 09:19:43 2008 +0200
+++ b/liboctave/ChangeLog	Wed Oct 01 11:05:13 2008 -0400
@@ -1,3 +1,8 @@
+2008-09-30  Jaroslav Hajek <highegg@gmail.com>
+
+	* oct-inttypes.h: Mostly rewrite. 
+	* oct-inttypes.cc: Modstly rewrite.
+
 2008-09-29  Jaroslav Hajek  <highegg@gmail.com>
 
 	* Array.cc (Array<T>::maybe_delete_elements_2(idx_vector&)): Return on
--- a/liboctave/oct-inttypes.cc	Tue Sep 30 09:19:43 2008 +0200
+++ b/liboctave/oct-inttypes.cc	Wed Oct 01 11:05:13 2008 -0400
@@ -24,71 +24,164 @@
 #include <config.h>
 #endif
 
+#include "lo-error.h"
+
 #include "oct-inttypes.h"
 
-#define INSTANTIATE_INT_DOUBLE_BIN_OP(T, OP) \
-  template OCTAVE_API octave_int<T> operator OP (const octave_int<T>&, double)
+// define type names. 
+#define DECLARE_OCTAVE_INT_TYPENAME(TYPE, TYPENAME) \
+  template <> \
+  const char * \
+  octave_int<TYPE>::type_name () { return TYPENAME; }
 
-#define INSTANTIATE_INT_DOUBLE_BIN_OPS(T) \
-  INSTANTIATE_INT_DOUBLE_BIN_OP (T, +); \
-  INSTANTIATE_INT_DOUBLE_BIN_OP (T, -); \
-  INSTANTIATE_INT_DOUBLE_BIN_OP (T, *); \
-  INSTANTIATE_INT_DOUBLE_BIN_OP (T, /)
+DECLARE_OCTAVE_INT_TYPENAME (int8_t, "int8")
+DECLARE_OCTAVE_INT_TYPENAME (int16_t, "int16")
+DECLARE_OCTAVE_INT_TYPENAME (int32_t, "int32")
+DECLARE_OCTAVE_INT_TYPENAME (int64_t, "int64")
+DECLARE_OCTAVE_INT_TYPENAME (uint8_t, "uint8")
+DECLARE_OCTAVE_INT_TYPENAME (uint16_t, "uint16")
+DECLARE_OCTAVE_INT_TYPENAME (uint32_t, "uint32")
+DECLARE_OCTAVE_INT_TYPENAME (uint64_t, "uint64")
+
+static void
+gripe_64bit_mul()
+{
+  (*current_liboctave_error_handler) 
+    ("64-bit integer multiplication is not implemented");
+}
 
-#define INSTANTIATE_DOUBLE_INT_BIN_OP(T, OP) \
-  template OCTAVE_API octave_int<T> operator OP (double, const octave_int<T>&)
+template <>
+uint64_t 
+octave_int_arith_base<uint64_t, false>::mul (uint64_t, uint64_t)
+{ 
+  gripe_64bit_mul (); 
+  return static_cast<uint64_t> (0);
+}
+template <>
+int64_t 
+octave_int_arith_base<int64_t, true>::mul (int64_t, int64_t)
+{ 
+  gripe_64bit_mul (); 
+  return static_cast<int64_t> (0);
+}
+
+static void
+gripe_64bit_mixed()
+{
+  (*current_liboctave_error_handler) 
+    ("mixed double - 64-bit integer operations are not implemented");
+}
 
-#define INSTANTIATE_DOUBLE_INT_BIN_OPS(T) \
-  INSTANTIATE_DOUBLE_INT_BIN_OP (T, +); \
-  INSTANTIATE_DOUBLE_INT_BIN_OP (T, -); \
-  INSTANTIATE_DOUBLE_INT_BIN_OP (T, *); \
-  INSTANTIATE_DOUBLE_INT_BIN_OP (T, /)
+#define DEFINE_DOUBLE_INT64_OP0(OP,ARGT,RETT) \
+  template <> \
+  OCTAVE_API RETT \
+  operator OP (const double&, const ARGT&) \
+  { gripe_64bit_mixed (); return 0.0; } \
+  template <> \
+  OCTAVE_API RETT \
+  operator OP (const ARGT&, const double&) \
+  { gripe_64bit_mixed (); return 0.0; } \
 
-#define INSTANTIATE_INT_DOUBLE_CMP_OP(T, OP) \
-  template OCTAVE_API bool operator OP (const octave_int<T>&, const double&)
+#define DEFINE_DOUBLE_INT64_BIN_OP(OP) \
+  DEFINE_DOUBLE_INT64_OP0(OP,octave_int64,octave_int64) \
+  DEFINE_DOUBLE_INT64_OP0(OP,octave_uint64,octave_uint64) 
+
+DEFINE_DOUBLE_INT64_BIN_OP(+)
+DEFINE_DOUBLE_INT64_BIN_OP(-)
+DEFINE_DOUBLE_INT64_BIN_OP(*)
+DEFINE_DOUBLE_INT64_BIN_OP(/)
+
+#define DEFINE_DOUBLE_INT64_CMP_OP(OP) \
+  DEFINE_DOUBLE_INT64_OP0(OP,octave_int64,bool) \
+  DEFINE_DOUBLE_INT64_OP0(OP,octave_uint64,bool) 
 
-#define INSTANTIATE_INT_DOUBLE_CMP_OPS(T) \
-  INSTANTIATE_INT_DOUBLE_CMP_OP (T, <); \
-  INSTANTIATE_INT_DOUBLE_CMP_OP (T, <=); \
-  INSTANTIATE_INT_DOUBLE_CMP_OP (T, >=); \
-  INSTANTIATE_INT_DOUBLE_CMP_OP (T, >); \
-  INSTANTIATE_INT_DOUBLE_CMP_OP (T, ==); \
-  INSTANTIATE_INT_DOUBLE_CMP_OP (T, !=)
+DEFINE_DOUBLE_INT64_CMP_OP(<)
+DEFINE_DOUBLE_INT64_CMP_OP(<=)
+DEFINE_DOUBLE_INT64_CMP_OP(>)
+DEFINE_DOUBLE_INT64_CMP_OP(>=)
+DEFINE_DOUBLE_INT64_CMP_OP(==)
+DEFINE_DOUBLE_INT64_CMP_OP(!=)
+
+//template <class T>
+//bool
+//xisnan (const octave_int<T>&)
+//{
+//  return false;
+//}
 
-#define INSTANTIATE_DOUBLE_INT_CMP_OP(T, OP) \
-  template OCTAVE_API bool operator OP (const double&, const octave_int<T>&)
+template <class T>
+octave_int<T>
+pow (const octave_int<T>& a, const octave_int<T>& b)
+{
+  octave_int<T> retval;
+
+  octave_int<T> zero = octave_int<T> (0);
+  octave_int<T> one = octave_int<T> (1);
+
+  if (b == zero || a == one)
+    retval = one;
+  else if (b < zero)
+    {
+      if (std::numeric_limits<T>::is_signed && a.value () == -1)
+        retval = (b.value () % 2) ? a : one;
+      else
+        retval = zero;
+    }
+  else
+    {
+      octave_int<T> a_val = a;
+      T b_val = b; // no need to do saturation on b
 
-#define INSTANTIATE_DOUBLE_INT_CMP_OPS(T) \
-  INSTANTIATE_DOUBLE_INT_CMP_OP (T, <); \
-  INSTANTIATE_DOUBLE_INT_CMP_OP (T, <=); \
-  INSTANTIATE_DOUBLE_INT_CMP_OP (T, >=); \
-  INSTANTIATE_DOUBLE_INT_CMP_OP (T, >); \
-  INSTANTIATE_DOUBLE_INT_CMP_OP (T, ==); \
-  INSTANTIATE_DOUBLE_INT_CMP_OP (T, !=)
+      retval = a;
+
+      b_val -= 1;
+
+      while (b_val != 0)
+	{
+	  if (b_val & 1)
+	    retval = retval * a_val;
+
+	  b_val = b_val >> 1;
+
+	  if (b_val)
+	    a_val = a_val * a_val;
+	}
+    }
+
+  return retval;
+}
 
-#define INSTANTIATE_INT_BITCMP_OP(T, OP) \
-  template OCTAVE_API octave_int<T> \
-  operator OP (const octave_int<T>&, const octave_int<T>&)
+template <class T>
+octave_int<T>
+pow (const double& a, const octave_int<T>& b)
+{ return octave_int<T> (pow (a, b.double_value ())); }
+
+template <class T>
+octave_int<T>
+pow (const octave_int<T>& a, const double& b)
+{ return octave_int<T> (pow (a.double_value (), b)); }
 
-#define INSTANTIATE_INT_BITCMP_OPS(T) \
-  INSTANTIATE_INT_BITCMP_OP (T, &); \
-  INSTANTIATE_INT_BITCMP_OP (T, |); \
-  INSTANTIATE_INT_BITCMP_OP (T, ^)
+template <class T>
+octave_int<T>
+powf (const float& a, const octave_int<T>& b)
+{ return octave_int<T> (pow (a, b.float_value ())); }
+
+template <class T>
+octave_int<T>
+powf (const octave_int<T>& a, const float& b)
+{ return octave_int<T> (pow (a.float_value (), b)); }
 
 #define INSTANTIATE_INTTYPE(T) \
   template class OCTAVE_API octave_int<T>; \
   template OCTAVE_API octave_int<T> pow (const octave_int<T>&, const octave_int<T>&); \
-  template OCTAVE_API octave_int<T> pow (double, const octave_int<T>&); \
-  template OCTAVE_API octave_int<T> pow (const octave_int<T>&, double b); \
+  template OCTAVE_API octave_int<T> pow (const double&, const octave_int<T>&); \
+  template OCTAVE_API octave_int<T> pow (const octave_int<T>&, const double&); \
+  template OCTAVE_API octave_int<T> powf (const float&, const octave_int<T>&); \
+  template OCTAVE_API octave_int<T> powf (const octave_int<T>&, const float&); \
   template OCTAVE_API std::ostream& operator << (std::ostream&, const octave_int<T>&); \
   template OCTAVE_API std::istream& operator >> (std::istream&, octave_int<T>&); \
   template OCTAVE_API octave_int<T> \
   bitshift (const octave_int<T>&, int, const octave_int<T>&); \
-  INSTANTIATE_INT_DOUBLE_BIN_OPS (T); \
-  INSTANTIATE_DOUBLE_INT_BIN_OPS (T); \
-  INSTANTIATE_INT_DOUBLE_CMP_OPS (T); \
-  INSTANTIATE_DOUBLE_INT_CMP_OPS (T); \
-  INSTANTIATE_INT_BITCMP_OPS (T)
 
 INSTANTIATE_INTTYPE (int8_t);
 INSTANTIATE_INTTYPE (int16_t);
@@ -100,283 +193,6 @@
 INSTANTIATE_INTTYPE (uint32_t);
 INSTANTIATE_INTTYPE (uint64_t);
 
-#define INSTANTIATE_INTTYPE_BIN_OP(T1, T2, OP) \
-  template OCTAVE_API octave_int<octave_int_binop_traits<T1, T2>::TR> \
-  operator OP<T1, T2> (const octave_int<T1>&, const octave_int<T2>&)
-
-#define INSTANTIATE_INTTYPE_BIN_OPS(T1, T2) \
-  INSTANTIATE_INTTYPE_BIN_OP (T1, T2, +); \
-  INSTANTIATE_INTTYPE_BIN_OP (T1, T2, -); \
-  INSTANTIATE_INTTYPE_BIN_OP (T1, T2, *); \
-  INSTANTIATE_INTTYPE_BIN_OP (T1, T2, /)
-
-INSTANTIATE_INTTYPE_BIN_OPS (int8_t, int8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int8_t, int16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int8_t, int32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int8_t, int64_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int8_t, uint8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int8_t, uint16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int8_t, uint32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int8_t, uint64_t);
-
-INSTANTIATE_INTTYPE_BIN_OPS (int16_t, int8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int16_t, int16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int16_t, int32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int16_t, int64_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int16_t, uint8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int16_t, uint16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int16_t, uint32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int16_t, uint64_t);
-
-INSTANTIATE_INTTYPE_BIN_OPS (int32_t, int8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int32_t, int16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int32_t, int32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int32_t, int64_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int32_t, uint8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int32_t, uint16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int32_t, uint32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int32_t, uint64_t);
-
-INSTANTIATE_INTTYPE_BIN_OPS (int64_t, int8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int64_t, int16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int64_t, int32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int64_t, int64_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int64_t, uint8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int64_t, uint16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int64_t, uint32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (int64_t, uint64_t);
-
-INSTANTIATE_INTTYPE_BIN_OPS (uint8_t, int8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint8_t, int16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint8_t, int32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint8_t, int64_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint8_t, uint8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint8_t, uint16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint8_t, uint32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint8_t, uint64_t);
-
-INSTANTIATE_INTTYPE_BIN_OPS (uint16_t, int8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint16_t, int16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint16_t, int32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint16_t, int64_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint16_t, uint8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint16_t, uint16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint16_t, uint32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint16_t, uint64_t);
-
-INSTANTIATE_INTTYPE_BIN_OPS (uint32_t, int8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint32_t, int16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint32_t, int32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint32_t, int64_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint32_t, uint8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint32_t, uint16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint32_t, uint32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint32_t, uint64_t);
-
-INSTANTIATE_INTTYPE_BIN_OPS (uint64_t, int8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint64_t, int16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint64_t, int32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint64_t, int64_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint64_t, uint8_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint64_t, uint16_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint64_t, uint32_t);
-INSTANTIATE_INTTYPE_BIN_OPS (uint64_t, uint64_t);
-
-#define INSTANTIATE_INTTYPE_SHIFT_OP(T, OP) \
-  template OCTAVE_API octave_int<T> operator OP (const octave_int<T>&, const int&)
-
-#define INSTANTIATE_INTTYPE_SHIFT_OPS(T) \
-  INSTANTIATE_INTTYPE_SHIFT_OP (T, <<); \
-  INSTANTIATE_INTTYPE_SHIFT_OP (T, >>)
-
-INSTANTIATE_INTTYPE_SHIFT_OPS (int8_t);
-INSTANTIATE_INTTYPE_SHIFT_OPS (int16_t);
-INSTANTIATE_INTTYPE_SHIFT_OPS (int32_t);
-INSTANTIATE_INTTYPE_SHIFT_OPS (int64_t);
-INSTANTIATE_INTTYPE_SHIFT_OPS (uint8_t);
-INSTANTIATE_INTTYPE_SHIFT_OPS (uint16_t);
-INSTANTIATE_INTTYPE_SHIFT_OPS (uint32_t);
-INSTANTIATE_INTTYPE_SHIFT_OPS (uint64_t);
-
-#define INSTANTIATE_OCTAVE_INT_CMP_OP(OP, T1, T2) \
-  template OCTAVE_API bool operator OP (const octave_int<T1>&, const octave_int<T2>&)
-
-#define INSTANTIATE_OCTAVE_INT_CMP_OPS(T1, T2) \
-  INSTANTIATE_OCTAVE_INT_CMP_OP (<, T1, T2); \
-  INSTANTIATE_OCTAVE_INT_CMP_OP (<=, T1, T2); \
-  INSTANTIATE_OCTAVE_INT_CMP_OP (>=, T1, T2); \
-  INSTANTIATE_OCTAVE_INT_CMP_OP (>, T1, T2); \
-  INSTANTIATE_OCTAVE_INT_CMP_OP (==, T1, T2); \
-  INSTANTIATE_OCTAVE_INT_CMP_OP (!=, T1, T2)
-
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int8_t, int8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int8_t, int16_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int8_t, int32_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int8_t, int64_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int8_t, uint8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int8_t, uint16_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (int8_t, uint32_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (int8_t, uint64_t);
-
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int16_t, int8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int16_t, int16_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int16_t, int32_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int16_t, int64_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int16_t, uint8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int16_t, uint16_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (int16_t, uint32_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (int16_t, uint64_t);
-
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int32_t, int8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int32_t, int16_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int32_t, int32_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int32_t, int64_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int32_t, uint8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int32_t, uint16_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (int32_t, uint32_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (int32_t, uint64_t);
-
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int64_t, int8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int64_t, int16_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int64_t, int32_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int64_t, int64_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int64_t, uint8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (int64_t, uint16_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (int64_t, uint32_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (int64_t, uint64_t);
-
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint8_t, int8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint8_t, int16_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint8_t, int32_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint8_t, int64_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint8_t, uint8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint8_t, uint16_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint8_t, uint32_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint8_t, uint64_t);
-
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint16_t, int8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint16_t, int16_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint16_t, int32_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint16_t, int64_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint16_t, uint8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint16_t, uint16_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint16_t, uint32_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint16_t, uint64_t);
-
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (uint32_t, int8_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (uint32_t, int16_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (uint32_t, int32_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (uint32_t, int64_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint32_t, uint8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint32_t, uint16_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint32_t, uint32_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint32_t, uint64_t);
-
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (uint64_t, int8_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (uint64_t, int16_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (uint64_t, int32_t);
-// INSTANTIATE_OCTAVE_INT_CMP_OPS (uint64_t, int64_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint64_t, uint8_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint64_t, uint16_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint64_t, uint32_t);
-INSTANTIATE_OCTAVE_INT_CMP_OPS (uint64_t, uint64_t);
-
-// The following apply if the unsigned type is at least as wide as the
-// signed type (then we can cast postive signed values to the unsigned
-// type and compare).
-
-#define OCTAVE_US_TYPE1_CMP_OP(OP, LTZ_VAL, UT, ST) \
-  template <> \
-  bool \
-  operator OP (const octave_int<UT>& lhs, const octave_int<ST>& rhs) \
-  { \
-    return rhs.value () < 0 ? LTZ_VAL \
-      : lhs.value () OP static_cast<UT> (rhs.value ()); \
-  }
-
-#define OCTAVE_US_TYPE1_CMP_OPS(UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP (<, false, UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP (<=, false, UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP (>=, true, UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP (>, true, UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP (==, false, UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP (!=, true, UT, ST)
-
-#define OCTAVE_SU_TYPE1_CMP_OP(OP, LTZ_VAL, ST, UT) \
-  template <> \
-  bool \
-  operator OP (const octave_int<ST>& lhs, const octave_int<UT>& rhs) \
-  { \
-    return lhs.value () < 0 ? LTZ_VAL \
-      : static_cast<UT> (lhs.value ()) OP rhs.value (); \
-  }
-
-#define OCTAVE_SU_TYPE1_CMP_OPS(ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP (<, true, ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP (<=, true, ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP (>=, false, ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP (>, false, ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP (==, false, ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP (!=, true, ST, UT)
-
-#define OCTAVE_TYPE1_CMP_OPS(UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OPS (UT, ST) \
-  OCTAVE_SU_TYPE1_CMP_OPS (ST, UT)
-
-OCTAVE_TYPE1_CMP_OPS (uint32_t, int8_t)
-OCTAVE_TYPE1_CMP_OPS (uint32_t, int16_t)
-OCTAVE_TYPE1_CMP_OPS (uint32_t, int32_t)
-
-OCTAVE_TYPE1_CMP_OPS (uint64_t, int8_t)
-OCTAVE_TYPE1_CMP_OPS (uint64_t, int16_t)
-OCTAVE_TYPE1_CMP_OPS (uint64_t, int32_t)
-OCTAVE_TYPE1_CMP_OPS (uint64_t, int64_t)
-
-// The following apply if the signed type is wider than the unsigned
-// type (then we can cast unsigned values to the signed type and
-// compare if the signed value is positive).
-
-#define OCTAVE_US_TYPE2_CMP_OP(OP, LTZ_VAL, UT, ST) \
-  template <> \
-  bool \
-  operator OP (const octave_int<UT>& lhs, const octave_int<ST>& rhs) \
-  { \
-    return rhs.value () < 0 ? LTZ_VAL \
-      : static_cast<ST> (lhs.value ()) OP rhs.value (); \
-  }
-
-#define OCTAVE_US_TYPE2_CMP_OPS(ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP (<, false, ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP (<=, false, ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP (>=, true, ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP (>, true, ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP (==, false, ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP (!=, true, ST, UT)
-
-#define OCTAVE_SU_TYPE2_CMP_OP(OP, LTZ_VAL, ST, UT) \
-  template <> \
-  bool \
-  operator OP (const octave_int<ST>& lhs, const octave_int<UT>& rhs) \
-  { \
-    return lhs.value () < 0 ? LTZ_VAL \
-      : lhs.value () OP static_cast<ST> (rhs.value ()); \
-  }
-
-#define OCTAVE_SU_TYPE2_CMP_OPS(ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP (<, true, ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP (<=, true, ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP (>=, false, ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP (>, false, ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP (==, false, ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP (!=, true, ST, UT)
-
-#define OCTAVE_TYPE2_CMP_OPS(UT, ST) \
-  OCTAVE_US_TYPE2_CMP_OPS (UT, ST) \
-  OCTAVE_SU_TYPE2_CMP_OPS (ST, UT)
-
-OCTAVE_TYPE2_CMP_OPS (uint32_t, int64_t)
-
-
 
 /*
 ;;; Local Variables: ***
--- a/liboctave/oct-inttypes.h	Tue Sep 30 09:19:43 2008 +0200
+++ b/liboctave/oct-inttypes.h	Wed Oct 01 11:05:13 2008 -0400
@@ -25,6 +25,7 @@
 #define octave_inttypes_h 1
 
 #include <climits>
+#include <cstdlib>
 
 #include <limits>
 #include <iostream>
@@ -33,296 +34,661 @@
 #include "lo-ieee.h"
 #include "lo-mappers.h"
 
-template <class T1, class T2>
-class
-octave_int_binop_traits
+// Query for an integer type of certain sizeof, and signedness.
+template<int qsize, bool qsigned>
+struct query_integer_type
 {
 public:
-  // The return type for a T1 by T2 binary operation.
-  typedef T1 TR;
+  static const bool registered = false;
+  typedef void type; // Void shall result in a compile-time error if we 
+                     // attempt to use it in computations.
 };
 
-#define OCTAVE_INT_BINOP_TRAIT(T1, T2, T3) \
-  template <> \
-  class octave_int_binop_traits <T1, T2> \
-  { \
-  public: \
-    typedef T3 TR; \
-  }
-
-OCTAVE_INT_BINOP_TRAIT (int8_t, int8_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (int8_t, int16_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (int8_t, int32_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (int8_t, int64_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (int8_t, uint8_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (int8_t, uint16_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (int8_t, uint32_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (int8_t, uint64_t, int8_t);
-
-OCTAVE_INT_BINOP_TRAIT (int16_t, int8_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (int16_t, int16_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (int16_t, int32_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (int16_t, int64_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (int16_t, uint8_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (int16_t, uint16_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (int16_t, uint32_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (int16_t, uint64_t, int16_t);
-
-OCTAVE_INT_BINOP_TRAIT (int32_t, int8_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (int32_t, int16_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (int32_t, int32_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (int32_t, int64_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (int32_t, uint8_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (int32_t, uint16_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (int32_t, uint32_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (int32_t, uint64_t, int32_t);
-
-OCTAVE_INT_BINOP_TRAIT (int64_t, int8_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (int64_t, int16_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (int64_t, int32_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (int64_t, int64_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (int64_t, uint8_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (int64_t, uint16_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (int64_t, uint32_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (int64_t, uint64_t, int64_t);
-
-OCTAVE_INT_BINOP_TRAIT (uint8_t, int8_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (uint8_t, int16_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (uint8_t, int32_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (uint8_t, int64_t, int8_t);
-OCTAVE_INT_BINOP_TRAIT (uint8_t, uint8_t, uint8_t);
-OCTAVE_INT_BINOP_TRAIT (uint8_t, uint16_t, uint8_t);
-OCTAVE_INT_BINOP_TRAIT (uint8_t, uint32_t, uint8_t);
-OCTAVE_INT_BINOP_TRAIT (uint8_t, uint64_t, uint8_t);
-
-OCTAVE_INT_BINOP_TRAIT (uint16_t, int8_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (uint16_t, int16_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (uint16_t, int32_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (uint16_t, int64_t, int16_t);
-OCTAVE_INT_BINOP_TRAIT (uint16_t, uint8_t, uint16_t);
-OCTAVE_INT_BINOP_TRAIT (uint16_t, uint16_t, uint16_t);
-OCTAVE_INT_BINOP_TRAIT (uint16_t, uint32_t, uint16_t);
-OCTAVE_INT_BINOP_TRAIT (uint16_t, uint64_t, uint16_t);
-
-OCTAVE_INT_BINOP_TRAIT (uint32_t, int8_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (uint32_t, int16_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (uint32_t, int32_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (uint32_t, int64_t, int32_t);
-OCTAVE_INT_BINOP_TRAIT (uint32_t, uint8_t, uint32_t);
-OCTAVE_INT_BINOP_TRAIT (uint32_t, uint16_t, uint32_t);
-OCTAVE_INT_BINOP_TRAIT (uint32_t, uint32_t, uint32_t);
-OCTAVE_INT_BINOP_TRAIT (uint32_t, uint64_t, uint32_t);
-
-OCTAVE_INT_BINOP_TRAIT (uint64_t, int8_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (uint64_t, int16_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (uint64_t, int32_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (uint64_t, int64_t, int64_t);
-OCTAVE_INT_BINOP_TRAIT (uint64_t, uint8_t, uint64_t);
-OCTAVE_INT_BINOP_TRAIT (uint64_t, uint16_t, uint64_t);
-OCTAVE_INT_BINOP_TRAIT (uint64_t, uint32_t, uint64_t);
-OCTAVE_INT_BINOP_TRAIT (uint64_t, uint64_t, uint64_t);
-
-template <class T1, class T2>
-inline T2
-octave_int_fit_to_range (const T1& x, const T2& mn, const T2& mx,
-			 int& conv_flag, int math_truncate)
-{
-  bool out_of_range_max = x > mx;
-  bool out_of_range_min = x < mn;
-  conv_flag |= (out_of_range_max || out_of_range_min ? math_truncate : 0);
-  return (out_of_range_max ? mx : (out_of_range_min ? mn : T2 (x)));
-}
-
-template <typename T>
-inline T
-octave_int_fit_to_range (const double& x, const T& mn, const T& mx,
-			 int& conv_flag, int math_truncate)
-{
-  bool out_of_range_max = x > mx;
-  bool out_of_range_min = x < mn;
-  conv_flag |= (out_of_range_max || out_of_range_min ? math_truncate : 0);
-  return (__lo_ieee_isnan (x)
-	  ? 0 : (out_of_range_max
-		 ? mx : (out_of_range_min ? mn : static_cast<T> (x))));
+#define REGISTER_INT_TYPE(TYPE) \
+template <> \
+class query_integer_type<sizeof (TYPE), std::numeric_limits<TYPE>::is_signed> \
+{ \
+public: \
+  static const bool registered = true; \
+  typedef TYPE type; \
 }
 
-// If X is unsigned and the new type is signed, then we only have to
-// check the upper limit, but we should cast the maximum value of the
-// new type to an unsigned type before performing the comparison.
-// This should always be OK because the maximum value should always be
-// positive.
+// No two registered integers can share sizeof and signedness.
+REGISTER_INT_TYPE (int8_t);
+REGISTER_INT_TYPE (uint8_t);
+REGISTER_INT_TYPE (int16_t);
+REGISTER_INT_TYPE (uint16_t);
+REGISTER_INT_TYPE (int32_t);
+REGISTER_INT_TYPE (uint32_t);
+REGISTER_INT_TYPE (int64_t);
+REGISTER_INT_TYPE (uint64_t);
+
+// Selects one of two types, according to a static bool.  May be useful in
+// general.
+
+template<bool cond, class TT, class FT>
+class if_else_type
+{
+public:
+  typedef FT type;
+};
 
-#define OCTAVE_US_S_FTR(T1, T2, TC) \
-  template <> \
-  inline T2 \
-  octave_int_fit_to_range<T1, T2> (const T1& x, const T2&, const T2& mx, \
-				   int& conv_flag, int math_truncate) \
-  { \
-    bool out_of_range = x > static_cast<TC> (mx); \
-    conv_flag |= (out_of_range ? math_truncate : 0); \
-    return out_of_range ? mx : x; \
-  }
+template<class TT, class FT>
+class if_else_type<true, TT, FT>
+{
+public:
+  typedef TT type;
+};
+
+// Rationale: Comparators have a single static method, rel(), that returns the
+// result of the binary relation. They also have two static boolean fields:
+// ltval, gtval determine the value of x OP y if x < y, x > y, respectively. 
+#define REGISTER_OCTAVE_CMP_OP(NM,OP) \
+  class NM \
+    { \
+    public: \
+      static const bool ltval = (0 OP 1), gtval = (1 OP 0); \
+      template <class T> \
+      static bool op (T x, T y) { return x OP y; } \
+    }
+
+// We also provide two special relations: ct, yielding always true, and cf,
+// yielding always false.
+#define REGISTER_OCTAVE_CONST_OP(NM,value) \
+  class NM \
+    { \
+    public: \
+      static const bool ltval = value, gtval = value; \
+      template <class T> \
+      static bool op (T, T) { return value; } \
+    }
 
-#define OCTAVE_US_S_FTR_FCNS(T) \
-  OCTAVE_US_S_FTR (T, char, unsigned char) \
-  OCTAVE_US_S_FTR (T, signed char, unsigned char) \
-  OCTAVE_US_S_FTR (T, short, unsigned short) \
-  OCTAVE_US_S_FTR (T, int, unsigned int) \
-  OCTAVE_US_S_FTR (T, long, unsigned long) \
-  OCTAVE_US_S_FTR (T, long long, unsigned long long)
-
-OCTAVE_US_S_FTR_FCNS (unsigned char)
-OCTAVE_US_S_FTR_FCNS (unsigned short)
-OCTAVE_US_S_FTR_FCNS (unsigned int)
-OCTAVE_US_S_FTR_FCNS (unsigned long)
-OCTAVE_US_S_FTR_FCNS (unsigned long long)
+// Handles non-homogeneous integer comparisons. Avoids doing useless tests.
+class octave_int_cmp_op
+{
+  // This determines a suitable promotion type for T1 when meeting T2 in a
+  // binary relation. If promotion to int or T2 is safe, it is used. Otherwise,
+  // the signedness of T1 is preserved and it is widened if T2 is wider.
+  // Notice that if this is applied to both types, they must end up with equal
+  // size.
+  template <class T1, class T2>
+  class prom
+    {
+      // Promote to int?
+      static const bool pint = (sizeof (T1) < sizeof (int) 
+                                && sizeof (T2) < sizeof (int));
+      static const bool t1sig = std::numeric_limits<T1>::is_signed;
+      static const bool t2sig = std::numeric_limits<T2>::is_signed;
+      static const bool psig = 
+        (pint || (sizeof (T2) > sizeof (T1) && t2sig) || t1sig);
+      static const int psize =
+        (pint ? sizeof (int) : (sizeof (T2) > sizeof (T1) 
+                                ? sizeof (T2) : sizeof (T1)));
+    public:
+      typedef typename query_integer_type<psize, psig>::type type;
+    };
 
-// If X is signed and the new type is unsigned, then we only have to
-// check the lower limit (which will always be 0 for an unsigned
-// type).  The upper limit will be enforced correctly by converting to
-// the new type, even if the type of X is wider than the new type.
+  // Implements comparisons between two types of equal size but
+  // possibly different signedness.
+  template<class xop, int size>
+  class uiop
+    {
+      typedef typename query_integer_type<size, false>::type utype;
+      typedef typename query_integer_type<size, true>::type stype;
+    public:
+      static bool op (utype x, utype y) 
+        { return xop::op (x, y); }
+      static bool op (stype x, stype y) 
+        { return xop::op (x, y); }
+      static bool op (stype x, utype y) 
+        { return (x < 0) ? xop::ltval : xop::op (static_cast<utype> (x), y); }
+      static bool op (utype x, stype y) 
+        { return (y < 0) ? xop::gtval : xop::op (x, static_cast<utype> (y)); }
+    };
 
-#define OCTAVE_S_US_FTR(T1, T2) \
-  template <> \
-  inline T2 \
-  octave_int_fit_to_range<T1, T2> (const T1& x, const T2&, const T2&, \
-				   int& conv_flag, int math_truncate) \
-  { \
-    bool out_of_range = x < 0; \
-    conv_flag |= (out_of_range ? math_truncate : 0); \
-    return x <= 0 ? 0 : x; \
-   }
+public:
+  REGISTER_OCTAVE_CMP_OP (lt, <);
+  REGISTER_OCTAVE_CMP_OP (le, <=);
+  REGISTER_OCTAVE_CMP_OP (gt, >);
+  REGISTER_OCTAVE_CMP_OP (ge, >=);
+  REGISTER_OCTAVE_CMP_OP (eq, ==);
+  REGISTER_OCTAVE_CMP_OP (ne, !=);
+  REGISTER_OCTAVE_CONST_OP (ct, true);
+  REGISTER_OCTAVE_CONST_OP (cf, false);
+
+  // Universal comparison operation.
+  template<class xop, class T1, class T2>
+  static bool
+  op (T1 x, T2 y)
+    {
+      typedef typename prom<T1, T2>::type PT1;
+      typedef typename prom<T2, T1>::type PT2;
+      return uiop<xop, sizeof (PT1)>::op (static_cast<PT1> (x), 
+                                          static_cast<PT2> (y));
+    }
+};
+
+// Base integer class. No data, just conversion methods and exception flags.
+template <class T> 
+class octave_int_base
+{
+protected:
+
+  static T min_val () { return std::numeric_limits<T>:: min (); }
+  static T max_val () { return std::numeric_limits<T>:: max (); }
 
-#define OCTAVE_S_US_FTR_FCNS(T) \
-  OCTAVE_S_US_FTR (T, unsigned char) \
-  OCTAVE_S_US_FTR (T, unsigned short) \
-  OCTAVE_S_US_FTR (T, unsigned int) \
-  OCTAVE_S_US_FTR (T, unsigned long) \
-  OCTAVE_S_US_FTR (T, unsigned long long)
+public:
+
+  // Convert integer value.
+  template <class S>
+  static T 
+  truncate_int (const S& value)
+    { 
+      // An exhaustive test whether the max and/or min check can be omitted.
+      static const bool t_is_signed = std::numeric_limits<T>::is_signed;
+      static const bool s_is_signed = std::numeric_limits<S>::is_signed;
+      static const int t_size = sizeof (T), s_size = sizeof (S);
+      static const bool omit_chk_min = 
+        (! s_is_signed || (t_is_signed && t_size >= s_size));
+      static const bool omit_chk_max = 
+        (t_size > s_size || (t_size == s_size 
+         && (! t_is_signed || s_is_signed)));
+      // If the check can be omitted, substitute constant false relation.
+      typedef octave_int_cmp_op::cf cf;
+      typedef octave_int_cmp_op::lt lt;
+      typedef octave_int_cmp_op::gt gt;
+      typedef typename if_else_type<omit_chk_min, cf, lt>::type chk_min;
+      typedef typename if_else_type<omit_chk_max, cf, gt>::type chk_max;
 
-OCTAVE_S_US_FTR_FCNS (char)
-OCTAVE_S_US_FTR_FCNS (signed char)
-OCTAVE_S_US_FTR_FCNS (short)
-OCTAVE_S_US_FTR_FCNS (int)
-OCTAVE_S_US_FTR_FCNS (long)
-OCTAVE_S_US_FTR_FCNS (long long)
+      // Efficiency of the following depends on inlining and dead code
+      // elimination, but that should be a piece of cake for most compilers.
+      if (chk_min::op (value, static_cast<S> (min_val ())))
+        {
+          ftrunc = true;
+          return min_val ();
+        }
+      else if (chk_max::op (value, static_cast<S> (max_val ())))
+        {
+          ftrunc = true;
+          return max_val ();
+        }
+      else
+        return static_cast<T> (value);
+    }
 
-#define OCTAVE_INT_CONV_FIT_TO_RANGE(r, T) \
-  octave_int_fit_to_range (r, \
-                           std::numeric_limits<T>::min (), \
-                           std::numeric_limits<T>::max (), \
-			   octave_int<T>::conv_flag, \
-			   octave_int<T>::int_truncate)
+  // This does not check for NaN and non-int. It can be useful when using real
+  // types for integer arithmetics, e.g., 64-bit multiply via long double.
+  template <class S>
+  static T
+  truncate_real (const S& value)
+    {
+      if (value < min_val ())
+        {
+          ftrunc = true;
+          return min_val ();
+        }
+      else if (value > max_val ())
+        {
+          ftrunc = true;
+          return max_val ();
+        }
+      else
+        return static_cast<T> (value);
+    }
 
-#define OCTAVE_INT_FIT_TO_RANGE(r, T) \
-  octave_int_fit_to_range (r, \
-                           std::numeric_limits<T>::min (), \
-                           std::numeric_limits<T>::max (), \
-			   octave_int<T>::conv_flag, \
-			   octave_int<T>::math_truncate)
-
-#define OCTAVE_INT_MIN_VAL2(T1, T2) \
-  std::numeric_limits<typename octave_int_binop_traits<T1, T2>::TR>::min ()
-
-#define OCTAVE_INT_MAX_VAL2(T1, T2) \
-  std::numeric_limits<typename octave_int_binop_traits<T1, T2>::TR>::max ()
+  // Convert a real number (check NaN and non-int).
+  template <class S>
+  static T 
+  convert_real (const S& value)
+    {
+      if (lo_ieee_isnan (value))
+        {
+          fnan = true;
+          return static_cast<T> (0);
+        }
+      else if (value < min_val ())
+        {
+          octave_int_base<T>::ftrunc = true;
+          return min_val ();
+        }
+      else if (value > max_val ())
+        {
+          ftrunc = true;
+          return max_val ();
+        }
+      else
+        {
+          S rvalue = xround (value);
+          if (rvalue != value) fnon_int = true;
+          return static_cast<T> (rvalue);
+        }
+    }
 
-#define OCTAVE_INT_FIT_TO_RANGE2(r, T1, T2) \
-  octave_int_fit_to_range (r, \
-                           OCTAVE_INT_MIN_VAL2 (T1, T2), \
-                           OCTAVE_INT_MAX_VAL2 (T1, T2), \
-			   octave_int<typename octave_int_binop_traits<T1, T2>::TR>::conv_flag, \
-			   octave_int<typename octave_int_binop_traits<T1, T2>::TR>::math_truncate)
+  // Exception flags rationale:
+  // There is little reason to distinguish math and conversion exceptions at
+  // octave_int level. Doing this would require special constructors for
+  // intermediate int results in math computations.
+  // 
+  // Boolean flags are used rather than a single flag, because raising a boolean
+  // flag is faster than masking an int flag (single mov versus mov, or, mov).
+  // Also, it is atomic, and thus thread-safe (but there is *one* flag for all
+  // threads).
 
-// We have all the machinery below (octave_int_helper) to avoid a few
-// warnings from GCC about comparisons always false due to limited
-// range of data types.  Ugh.  The cure may be worse than the disease.
+  static bool get_trunc_flag () { return ftrunc; }
+  static bool get_nan_flag () { return fnan; }
+  static bool get_non_int_flag () { return fnon_int; }
+  static void clear_conv_flags () 
+    { 
+      ftrunc = false;
+      fnan = false;
+      fnon_int = false;
+    }
+  // For compatibility.
+  static bool get_math_trunc_flag () { return ftrunc || fnan; }
+  static void clear_conv_flag () { clear_conv_flags (); }
+
+protected:
 
-// FIXME -- it would be nice to nest the helper class inside the
-// octave_int class, but I don't see the magic for that at the moment.
+  // Conversion flags.
+  static bool ftrunc;
+  static bool fnon_int;
+  static bool fnan;
+};
 
-template <class T> class octave_int;
+template<class T> bool octave_int_base<T>::ftrunc = false;
+template<class T> bool octave_int_base<T>::fnon_int = false;
+template<class T> bool octave_int_base<T>::fnan = false;
+
+// Saturated (homogeneous) integer arithmetics. The signed and unsigned
+// implementations are significantly different, so we implement another layer
+// and completely specialize. Arithmetics inherits from octave_int_base so that
+// it can use its exceptions and truncation functions.
 
 template <class T, bool is_signed>
-class octave_int_helper
-{
-public:
-  static octave_int<T> abs (const T& x);
+class octave_int_arith_base
+{ };
 
-  static octave_int<T> signum (const T& x);
-
-  template <class T2> static void rshift_eq (T& ival, const T2& x);
-};
-
+// Unsigned arithmetics. C++ standard requires it to be modular, so the
+// overflows can be handled efficiently and reliably.
 template <class T>
-class octave_int_helper<T, false>
+class octave_int_arith_base<T, false> : octave_int_base<T>
 {
 public:
-  static octave_int<T>
-  abs (const T& x) { return x; }
+
+  static T
+  abs (T x) { return x; }
+
+  static T
+  signum (T x) { return x ? static_cast<T> (1) : static_cast<T> (0); }
+
+  // Shifts do not overflow.
+  static T
+  rshift (T x, int n) { return x >> n; }
+
+  static T
+  lshift (T x, int n) { return x << n; }
+
+  static T
+  minus (T x)
+    {
+      if (x != 0) octave_int_base<T>::ftrunc = true;
+      return static_cast<T> (0);
+    }
+
+  // the overflow behaviour for unsigned integers is guaranteed by C/C++,
+  // so the following should always work.
+  static T 
+  add (T x, T y)
+    {
+      T u = x + y;
+      if (u < x)
+        {
+          u = octave_int_base<T>::max_val ();
+          octave_int_base<T>::ftrunc = true; 
+        }
+      return u;
+    }
+
+  static T 
+  sub (T x, T y)
+    {
+      T u = x - y;
+      if (u > x)
+        {
+          u = 0;
+          octave_int_base<T>::ftrunc = true; 
+        }
+      return u;
+    }
 
-  static octave_int<T>
-  signum (const T& x) { return x > 0 ? 1 : 0; }
+  // Multiplication is done using promotion to wider type.  If there is no
+  // suitable promotion type, this operation *MUST* be specialized. But note
+  // that a real type can be used as the promotion type (e.g., long double for
+  // int64_t).
+  static T 
+  mul (T x, T y)
+    {
+      // Promotion type for multiplication (if exists).
+      typedef typename query_integer_type<2*sizeof (T), false>::type mptype;
+      return truncate_int (static_cast<mptype> (x) 
+                           * static_cast<mptype> (y));
+    }
 
-  template <class T2>
-  static void
-  rshift_eq (T& ival, const T2& x) { ival = ival >> x; }
+  // Division with rounding to nearest. Note that / and % are probably
+  // computed by a single instruction.
+  static T 
+  div (T x, T y)
+    {
+      if (y != 0)
+        {
+          T z = x / y, w = x % y;
+          if (w >= y-w) z += 1;
+          return z;
+        }
+      else
+        {
+          octave_int_base<T>::ftrunc = true; 
+          return x ? octave_int_base<T>::max_val () : 0;
+        }
+    }
 };
 
+// Special handler for 64-bit integer multiply.
+template <>
+OCTAVE_API uint64_t 
+octave_int_arith_base<uint64_t, false>::mul (uint64_t, uint64_t);
+
+// Signed integer arithmetics.
+// Rationale: If HAVE_FAST_INT_OPS is defined, the following conditions
+// should hold:
+// 1. Signed numbers are represented by twos complement
+//    (see <http://en.wikipedia.org/wiki/Two%27s_complement>)
+// 2. static_cast to unsigned int counterpart works like interpreting
+//    the signed bit pattern as unsigned (and is thus zero-cost).
+// 3. Signed addition and subtraction yield the same bit results as unsigned.
+//    (We use casts to prevent optimization interference, so there is no
+//     need for things like -ftrapv).
+// 4. Bit operations on signed integers work like on unsigned integers,
+//    except for the shifts. Shifts are arithmetic.
+//
+// The above conditions are satisfied by most modern platforms. If
+// HAVE_FAST_INT_OPS is defined, bit tricks and wraparound arithmetics are used
+// to avoid conditional jumps as much as possible, thus being friendly to modern
+// pipeline processor architectures.
+// Otherwise, we fall back to a bullet-proof code that only uses assumptions 
+// guaranteed by the standard.
+
 template <class T>
-class octave_int_helper<T, true>
+class octave_int_arith_base<T, true> : octave_int_base<T>
 {
+  // The corresponding unsigned type.
+  typedef typename query_integer_type<sizeof (T), false>::type UT;
 public:
-  static octave_int<T>
-  abs (const T& x) { return x < 0 ? -x : x; }
+
+  // Returns 1 for negative number, 0 otherwise.
+  static T
+  signbit (T x) 
+    { 
+#ifdef HAVE_FAST_INT_OPS
+      return static_cast<UT> (x) >> std::numeric_limits<T>::digits;
+#else
+      return (x < 0) ? 1 : 0; 
+#endif
+    }
 
-  static octave_int<T>
-  signum (const T& x) { return x < 0 ? -1 : (x > 0 ? 1 : 0); }
+  static T
+  abs (T x)
+    {
+#ifdef HAVE_FAST_INT_OPS
+      // This is close to how GCC does std::abs, but we can't just use std::abs,
+      // because its behaviour for INT_MIN is undefined and the compiler could
+      // discard the following test.
+      T m = x >> std::numeric_limits<T>::digits;
+      T y = (x ^ m) - m;
+      if (y < 0) 
+        {
+          y = octave_int_base<T>::max_val ();
+          octave_int_base<T>::ftrunc = true;
+        }
+      return y;
+#else
+      // -INT_MAX is safe because C++ actually allows only three implementations
+      // of integers: sign & magnitude, ones complement and twos complement.
+      // The first test will, with modest optimizations, evaluate at compile
+      // time, and maybe eliminate the branch completely.
+      T y;
+      if (octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
+          && x == octave_int_base<T>::min_val ())
+        {
+          y = octave_int_base<T>::max_val ();
+          octave_int_base<T>::ftrunc = true;
+        }
+      else
+        y = (x < 0) ? -x : x;
+      return y;
+#endif
+    }
+
+  static T
+  signum (T x) 
+    { 
+      // With modest optimizations, this will compile without a jump.
+      return ((x > 0) ? 1 : 0) - signbit (x); 
+    }
+
+  // TODO: We do not have an authority what signed shifts should exactly do, so
+  // we define them the easy way. Note that Matlab does not define signed
+  // shifts.
+
+  static T
+  rshift (T x, int n) { return x >> n; }
+
+  static T
+  lshift (T x, int n) { return x << n; }
+
+  // Minus has problems similar to abs.
+  static T
+  minus (T x)
+    {
+#ifdef HAVE_FAST_INT_OPS
+      T y = -x;
+      if (y == octave_int_base<T>::min_val ())
+        {
+          --y;
+          octave_int_base<T>::ftrunc = false;
+        }
+      return y;
+#else
+      T y;
+      if (octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
+          && x == octave_int_base<T>::min_val ())
+        {
+          y = octave_int_base<T>::max_val ();
+          octave_int_base<T>::ftrunc = true;
+        }
+      else
+        y = -x;
+      return y;
+#endif
+    }
 
-  template <class T2>
-  static void
-  rshift_eq (T& ival, const T2& x)
-  {
-    if (ival < 0)
-      ival = - (((-ival) >> x) & std::numeric_limits<T>::max());
-    else
-      ival = ival >> x;
-  }
+  static T 
+  add (T x, T y)
+    {
+#ifdef HAVE_FAST_INT_OPS
+    // The typecasts do nothing, but they are here to prevent an optimizing
+    // compiler from interfering. Also, the signed operations on small types
+    // actually return int.
+      T u = static_cast<UT> (x) + static_cast<UT> (y);
+      T ux = u ^ x, uy = u ^ y; 
+      if ((ux & uy) < 0) 
+        {
+          u = octave_int_base<T>::max_val () + signbit (~u);
+          octave_int_base<T>::ftrunc = true;
+        }
+      return u;
+#else
+      // We shall carefully avoid anything that may overflow.
+      T u;
+      if (y < 0)
+        {
+          if (x < octave_int_base<T>::min_val () - y)
+            {
+              u = octave_int_base<T>::min_val ();
+              octave_int_base<T>::ftrunc = true;
+            }
+          else
+            u = x + y;
+        }
+      else
+        {
+          if (x > octave_int_base<T>::max_val () - y)
+            {
+              u = octave_int_base<T>::max_val ();
+              octave_int_base<T>::ftrunc = true;
+            }
+          else
+            u = x + y;
+        }
+
+      return u;
+#endif
+    }
+
+  // This is very similar to addition.
+  static T 
+  sub (T x, T y)
+    {
+#ifdef HAVE_FAST_INT_OPS
+    // The typecasts do nothing, but they are here to prevent an optimizing
+    // compiler from interfering. Also, the signed operations on small types
+    // actually return int.
+      T u = static_cast<UT> (x) - static_cast<UT> (y);
+      T ux = u ^ x, uy = u ^ ~y; 
+      if ((ux & uy) < 0) 
+        {
+          u = octave_int_base<T>::max_val () + signbit (~u);
+          octave_int_base<T>::ftrunc = true;
+        }
+      return u;
+#else
+      // We shall carefully avoid anything that may overflow.
+      T u;
+      if (y < 0)
+        {
+          if (x > octave_int_base<T>::max_val () + y)
+            {
+              u = octave_int_base<T>::max_val ();
+              octave_int_base<T>::ftrunc = true;
+            }
+          else
+            u = x - y;
+        }
+      else
+        {
+          if (x < octave_int_base<T>::min_val () + y)
+            {
+              u = octave_int_base<T>::min_val ();
+              octave_int_base<T>::ftrunc = true;
+            }
+          else
+            u = x - y;
+        }
+
+      return u;
+#endif
+    }
+
+  // Multiplication is done using promotion to wider type.  If there is no
+  // suitable promotion type, this operation *MUST* be specialized. But note
+  // that a real type can be used as the promotion type (e.g., long double for
+  // int64_t).
+  static T 
+  mul (T x, T y)
+    {
+      // Promotion type for multiplication (if exists).
+      typedef typename query_integer_type<2*sizeof (T), true>::type mptype;
+      return truncate_int (static_cast<mptype> (x) 
+                           * static_cast<mptype> (y));
+    }
+
+  // Division.
+  static T 
+  div (T x, T y)
+    {
+      T z;
+      if (y == 0)
+        {
+          octave_int_base<T>::ftrunc = true;
+          if (x < 0)
+            z = octave_int_base<T>::min_val ();
+          else if (x != 0)
+            z = octave_int_base<T>::max_val ();
+          else
+            z = 0;
+        }
+      else if (y < 0)
+        {
+          // This is a special case that overflows as well.
+          if (y == -1 && x == octave_int_base<T>::min_val ())
+            {
+              octave_int_base<T>::ftrunc = true;
+              z = octave_int_base<T>::max_val ();
+            }
+          else
+            {
+              z = x / y;
+              T w = -std::abs (x % y); // Can't overflow, but std::abs (x) can!
+              if (w <= y - w) 
+                z -= 1 - (signbit (x) << 1);
+            }
+        }
+      else
+        {
+          z = x / y;
+          T w = std::abs (x % y); // Can't overflow, but std::abs (x) can!
+          if (w >= y - w) 
+            z += 1 - (signbit (x) << 1);
+        }
+      return z;
+    }
+
 };
 
+// Special handler for 64-bit integer multiply.
+template <>
+OCTAVE_API int64_t 
+octave_int_arith_base<int64_t, true>::mul (int64_t, int64_t);
+
+// This class simply selects the proper arithmetics.
+template<class T>
+class octave_int_arith 
+ : public octave_int_arith_base<T, std::numeric_limits<T>::is_signed>
+{};
+
 template <class T>
 class
-octave_int
+octave_int : public octave_int_base<T>
 {
 public:
-  enum conv_error_type
-    {
-      int_truncate = 1,
-      conv_nan = 2,
-      conv_non_int = 4,
-      math_truncate = 8
-    };
-
   typedef T val_type;
 
   octave_int (void) : ival () { }
 
-  template <class U>
-  octave_int (U i) : ival (OCTAVE_INT_CONV_FIT_TO_RANGE (i, T)) { }
+  octave_int (T i) : ival (i) { }
 
-  octave_int (double d) : ival (OCTAVE_INT_CONV_FIT_TO_RANGE (xround (d), T)) 
-    { 
-      if (xisnan (d))
-	conv_flag |= conv_nan;
-      else
-	conv_flag |= (d != xround (d) ? conv_non_int : 0);
-    }
+  octave_int (double d) : ival (octave_int_base<T>::convert_real (d)) { } 
+
+  octave_int (float d) : ival (octave_int_base<T>::convert_real (d)) { } 
 
   octave_int (bool b) : ival (b) { }
 
   template <class U>
+  octave_int (const U& i) : ival(octave_int_base<T>::truncate_int (i)) { }
+
+  template <class U>
   octave_int (const octave_int<U>& i)
-    : ival (OCTAVE_INT_CONV_FIT_TO_RANGE (i.value (), T)) { }
+    : ival (octave_int_base<T>::truncate_int (i.value ())) { }
 
   octave_int (const octave_int<T>& i) : ival (i.ival) { }
 
@@ -332,8 +698,6 @@
     return *this;
   }
 
-  ~octave_int (void) { }
-  
   T value (void) const { return ival; }
 
   const unsigned char * iptr (void) const
@@ -341,23 +705,6 @@
 
   bool operator ! (void) const { return ! ival; }
 
-  octave_int<T> operator + (void) const { return *this; }
-
-  octave_int<T> operator - (void) const
-  {
-    // Can't just return -ival because signed types are not
-    // symmetric, which causes things like -intmin("int32") to be the
-    // same as intmin("int32") instead of intmax("int32") (which is
-    // what we should get with saturation semantics).
-    if (std::numeric_limits<T>::is_signed)
-      return OCTAVE_INT_FIT_TO_RANGE (- static_cast<double> (ival), T);
-    else
-      {
-	conv_flag |= math_truncate;
-	return 0;
-      }
-  }
-
   bool bool_value (void) const { return static_cast<bool> (value ()); }
 
   char char_value (void) const { return static_cast<char> (value ()); }
@@ -374,188 +721,110 @@
 
   operator float (void) const { return float_value (); }
 
-  octave_int<T>& operator += (const octave_int<T>& x)
-  {
-    double t = static_cast<double> (value ());
-    double tx = static_cast<double> (x.value ());
-    ival = OCTAVE_INT_FIT_TO_RANGE (t + tx, T);
-    return *this;
-  }
+  octave_int<T>
+  operator + () const
+    { return *this; }
+
+  // unary operators & mappers
+#define OCTAVE_INT_UN_OP(OPNAME,NAME) \
+  inline octave_int<T> \
+  OPNAME () const \
+  { return octave_int_arith<T>::NAME (ival); }
 
-  octave_int<T>& operator -= (const octave_int<T>& x)
-  {
-    double t = static_cast<double> (value ());
-    double tx = static_cast<double> (x.value ());
-    ival = OCTAVE_INT_FIT_TO_RANGE (t - tx, T);
-    return *this;
-  }
+  OCTAVE_INT_UN_OP(operator -, minus)
+  OCTAVE_INT_UN_OP(abs, abs)
+  OCTAVE_INT_UN_OP(signum, signum)
+
+# undef OCTAVE_INT_UN_OP
 
-  octave_int<T>& operator *= (const octave_int<T>& x)
-  {
-    double t = static_cast<double> (value ());
-    double tx = static_cast<double> (x.value ());
-    ival = OCTAVE_INT_FIT_TO_RANGE (t * tx, T);
-    return *this;
+// Homogeneous binary integer operations.
+#define OCTAVE_INT_BIN_OP(OP, NAME, ARGT) \
+  inline octave_int<T> \
+  operator OP (const ARGT& y) const \
+  { return octave_int_arith<T>::NAME (ival, y); } \
+  inline octave_int<T>& \
+  operator OP##= (const ARGT& y) \
+  { \
+    ival = octave_int_arith<T>::NAME (ival, y); \
+    return *this; \
   }
 
-  octave_int<T>& operator /= (const octave_int<T>& x)
-  {
-    double t = static_cast<double> (value ());
-    double tx = static_cast<double> (x.value ());
-    double r = (t == 0 && tx == 0) ? 0 : xround (t / tx);
-    ival = OCTAVE_INT_FIT_TO_RANGE (r, T);
-    return *this;
-  }
-
-  template <class T2>
-  octave_int<T>& operator <<= (const T2& x)
-  {
-    ival = ival << x;
-    return *this;
-  }
+  OCTAVE_INT_BIN_OP(+, add, octave_int<T>)
+  OCTAVE_INT_BIN_OP(-, sub, octave_int<T>)
+  OCTAVE_INT_BIN_OP(*, mul, octave_int<T>)
+  OCTAVE_INT_BIN_OP(/, div, octave_int<T>)
+  OCTAVE_INT_BIN_OP(<<, lshift, int)
+  OCTAVE_INT_BIN_OP(>>, rshift, int)
 
-  // Use helper functions in the operator >>=, abs, and signum
-  // functions to avoid "comparison of unsigned expression < 0 is
-  // always false" warnings from GCC when instantiating these funtions
-  // for unsigned types.
-
-  template <class T2>
-  octave_int<T>& operator >>= (const T2& x)
-  {
-    octave_int_helper<T, std::numeric_limits<T>::is_signed>::rshift_eq (ival, x);
-    return *this;
-  }
-
-  octave_int<T> abs (void) const
-  {
-    return octave_int_helper<T, std::numeric_limits<T>::is_signed>::abs (value ());
-  }
-
-  octave_int<T> signum (void) const 
-  { 
-    return octave_int_helper<T, std::numeric_limits<T>::is_signed>::signum (value ());
-  }
+# undef OCTAVE_INT_BIN_OP
 
   octave_int<T> min (void) const { return std::numeric_limits<T>::min (); }
   octave_int<T> max (void) const { return std::numeric_limits<T>::max (); }
 
-  static int nbits (void) { return sizeof (T) * CHAR_BIT; }
+  static int nbits (void) { return std::numeric_limits<T>::digits; }
 
   static int byte_size (void) { return sizeof(T); }
 
-  static int get_conv_flag () { return conv_flag; }
-  static bool get_trunc_flag () { return (conv_flag & int_truncate); }
-  static bool get_nan_flag () { return (conv_flag & conv_nan); }
-  static bool get_non_int_flag () { return (conv_flag & conv_non_int); }
-  static bool get_math_trunc_flag () { return (conv_flag & math_truncate); }
-  static void clear_conv_flag () { conv_flag = 0; }
-
-  static const char *type_name () { return "unknown type"; }
+  static const char *type_name ();
 
   // Unsafe.  This function exists to support the MEX interface.
   // You should not use it anywhere else.
   void *mex_get_data (void) const { return const_cast<T *> (&ival); }
 
-  static int conv_flag;
-
 private:
 
   T ival;
 };
 
-template<class T> int octave_int<T>::conv_flag = 0;
+// No mixed integer binary operations!
+
+template <class T>
+inline bool
+xisnan (const octave_int<T>&)
+{ return false; }
+
+// TODO: Can/should any of these be inline?
 
 template <class T>
-bool
-xisnan (const octave_int<T>&)
-{
-  return false;
-}
+extern OCTAVE_API octave_int<T>
+pow (const octave_int<T>&, const octave_int<T>&);
+
+template <class T>
+extern OCTAVE_API octave_int<T>
+pow (const double& a, const octave_int<T>& b);
+
+template <class T>
+extern OCTAVE_API octave_int<T>
+pow (const octave_int<T>& a, const double& b);
 
 template <class T>
-octave_int<T>
-pow (const octave_int<T>& a, const octave_int<T>& b)
-{
-  octave_int<T> retval;
-
-  octave_int<T> zero = octave_int<T> (0);
-  octave_int<T> one = octave_int<T> (1);
-
-  if (b == zero || a == one)
-    retval = one;
-  else if (b < zero)
-    {
-      if (std::numeric_limits<T>::is_signed && a.value () == -1)
-        retval = (b.value () % 2) ? a : one;
-      else
-        retval = zero;
-    }
-  else
-    {
-      octave_int<T> a_val = a;
-      octave_int<T> b_val = b;
-
-      retval = a;
-
-      b_val -= 1;
-
-      while (b_val != zero)
-	{
-	  if ((b_val & one) != zero)
-	    retval = retval * a_val;
-
-	  b_val = b_val >> 1;
-
-	  if (b_val > zero)
-	    a_val = a_val * a_val;
-	}
-    }
-
-  return retval;
-}
+extern OCTAVE_API octave_int<T>
+powf (const float& a, const octave_int<T>& b);
 
 template <class T>
-octave_int<T>
-pow (double a, const octave_int<T>& b)
-{
-  double tb = static_cast<double> (b.value ());
-  double r = pow (a, tb);
-  r = __lo_ieee_isnan (r) ? 0 : xround (r);
-  return OCTAVE_INT_FIT_TO_RANGE (r, T);
-}
+extern OCTAVE_API octave_int<T>
+powf (const octave_int<T>& a, const float& b);
+
+// Binary relations
 
-template <class T>
-octave_int<T>
-pow (const octave_int<T>& a, double b)
-{
-  double ta = static_cast<double> (a.value ());
-  double r = pow (ta, b);
-  r = __lo_ieee_isnan (r) ? 0 : xround (r);
-  return OCTAVE_INT_FIT_TO_RANGE (r, T);
-}
+#define OCTAVE_INT_CMP_OP(OP, NAME) \
+  template<class T1, class T2> \
+  inline bool \
+  operator OP (const octave_int<T1>& x, const octave_int<T2>& y) \
+  { return octave_int_cmp_op::op<octave_int_cmp_op::NAME, T1, T2> \
+    (x.value (), y.value ()); }
+
+OCTAVE_INT_CMP_OP (<, lt)
+OCTAVE_INT_CMP_OP (<=, le)
+OCTAVE_INT_CMP_OP (>, gt)
+OCTAVE_INT_CMP_OP (>=, ge)
+OCTAVE_INT_CMP_OP (==, eq)
+OCTAVE_INT_CMP_OP (!=, ne)
+
+# undef OCTAVE_INT_CMP_OP
 
 template <class T>
-octave_int<T>
-powf (float a, const octave_int<T>& b)
-{
-  float tb = static_cast<float> (b.value ());
-  float r = powf (a, tb);
-  r = __lo_ieee_float_isnan (r) ? 0 : xround (r);
-  return OCTAVE_INT_FIT_TO_RANGE (r, T);
-}
-
-template <class T>
-octave_int<T>
-powf (const octave_int<T>& a, float b)
-{
-  float ta = static_cast<float> (a.value ());
-  float r = pow (ta, b);
-  r = __lo_ieee_float_isnan (r) ? 0 : xround (r);
-  return OCTAVE_INT_FIT_TO_RANGE (r, T);
-}
-
-template <class T>
-std::ostream&
+inline std::ostream&
 operator << (std::ostream& os, const octave_int<T>& ival)
 {
   os << ival.value ();
@@ -563,7 +832,7 @@
 }
 
 template <class T>
-std::istream&
+inline std::istream&
 operator >> (std::istream& is, octave_int<T>& ival)
 {
   T tmp = 0;
@@ -572,237 +841,21 @@
   return is;
 }
 
-// specialize the widening conversions to make them faster
-// gosh. the syntax is tricky!
-
-#define SPECIALIZE_WIDENING_CONVERSION(T1, T2) \
-  template <> template <> \
-  inline octave_int<T2>::octave_int (T1 i) \
-    : ival (i) { } \
- \
-  template <> template <> \
-  inline octave_int<T2>::octave_int (const octave_int<T1>& i) \
-    : ival (i.value ()) { }
-
-SPECIALIZE_WIDENING_CONVERSION (int8_t, int16_t)
-SPECIALIZE_WIDENING_CONVERSION (int8_t, int32_t)
-SPECIALIZE_WIDENING_CONVERSION (int8_t, int64_t)
-SPECIALIZE_WIDENING_CONVERSION (int16_t, int32_t)
-SPECIALIZE_WIDENING_CONVERSION (int16_t, int64_t)
-SPECIALIZE_WIDENING_CONVERSION (int32_t, int64_t)
-SPECIALIZE_WIDENING_CONVERSION (uint8_t, uint16_t)
-SPECIALIZE_WIDENING_CONVERSION (uint8_t, uint32_t)
-SPECIALIZE_WIDENING_CONVERSION (uint8_t, uint64_t)
-SPECIALIZE_WIDENING_CONVERSION (uint16_t, uint32_t)
-SPECIALIZE_WIDENING_CONVERSION (uint16_t, uint64_t)
-SPECIALIZE_WIDENING_CONVERSION (uint32_t, uint64_t)
-
-// declare type names
-#define DECLARE_OCTAVE_INT_TYPENAME(TYPE, TYPENAME) \
-  template <> \
-  inline const char * \
-  octave_int<TYPE>::type_name () { return TYPENAME; }
-
-DECLARE_OCTAVE_INT_TYPENAME (int8_t, "int8")
-DECLARE_OCTAVE_INT_TYPENAME (int16_t, "int16")
-DECLARE_OCTAVE_INT_TYPENAME (int32_t, "int32")
-DECLARE_OCTAVE_INT_TYPENAME (int64_t, "int64")
-DECLARE_OCTAVE_INT_TYPENAME (uint8_t, "uint8")
-DECLARE_OCTAVE_INT_TYPENAME (uint16_t, "uint16")
-DECLARE_OCTAVE_INT_TYPENAME (uint32_t, "uint32")
-DECLARE_OCTAVE_INT_TYPENAME (uint64_t, "uint64")
-
-typedef octave_int<int8_t> octave_int8;
-typedef octave_int<int16_t> octave_int16;
-typedef octave_int<int32_t> octave_int32;
-typedef octave_int<int64_t> octave_int64;
-
-typedef octave_int<uint8_t> octave_uint8;
-typedef octave_int<uint16_t> octave_uint16;
-typedef octave_int<uint32_t> octave_uint32;
-typedef octave_int<uint64_t> octave_uint64;
-
-#define OCTAVE_INT_BIN_OP(OP) \
-  template <class T1, class T2> \
-  octave_int<typename octave_int_binop_traits<T1, T2>::TR> \
-  operator OP (const octave_int<T1>& x, const octave_int<T2>& y) \
-  { \
-    double tx = static_cast<double> (x.value ()); \
-    double ty = static_cast<double> (y.value ()); \
-    double r = tx OP ty; \
-    return OCTAVE_INT_FIT_TO_RANGE2 (r, T1, T2); \
-  }
-
-OCTAVE_INT_BIN_OP (+)
-OCTAVE_INT_BIN_OP (-)
-OCTAVE_INT_BIN_OP (*)
-
-template <class T1, class T2>
-octave_int<typename octave_int_binop_traits<T1, T2>::TR>
-operator / (const octave_int<T1>& x, const octave_int<T2>& y)
-{
-  double tx = static_cast<double> (x.value ());
-  double ty = static_cast<double> (y.value ());
-  double r = (tx == 0 && ty == 0) ? 0 : xround (tx / ty);
-  return OCTAVE_INT_FIT_TO_RANGE2 (r, T1, T2);
-}
-
-#define OCTAVE_INT_DOUBLE_BIN_OP(OP) \
-  template <class T> \
-  octave_int<T> \
-  operator OP (const octave_int<T>& x, double y) \
-  { \
-    double tx = static_cast<double> (x.value ()); \
-    double r = xround (tx OP y); \
-    r = __lo_ieee_isnan (r) ? 0 : xround (r); \
-    return OCTAVE_INT_FIT_TO_RANGE (r, T); \
-  }
-
-OCTAVE_INT_DOUBLE_BIN_OP (+)
-OCTAVE_INT_DOUBLE_BIN_OP (-)
-OCTAVE_INT_DOUBLE_BIN_OP (*)
-OCTAVE_INT_DOUBLE_BIN_OP (/)
-
-#define OCTAVE_DOUBLE_INT_BIN_OP(OP) \
-  template <class T> \
-  octave_int<T> \
-  operator OP (double x, const octave_int<T>& y) \
-  { \
-    double ty = static_cast<double> (y.value ()); \
-    double r = x OP ty; \
-    r = __lo_ieee_isnan (r) ? 0 : xround (r); \
-    return OCTAVE_INT_FIT_TO_RANGE (r, T); \
-  }
-
-OCTAVE_DOUBLE_INT_BIN_OP (+)
-OCTAVE_DOUBLE_INT_BIN_OP (-)
-OCTAVE_DOUBLE_INT_BIN_OP (*)
-OCTAVE_DOUBLE_INT_BIN_OP (/)
-
-#define OCTAVE_INT_DOUBLE_CMP_OP(OP) \
-  template <class T> \
-  bool \
-  operator OP (const octave_int<T>& x, const double& y) \
-  { \
-    double tx = static_cast<double> (x.value ()); \
-    return tx OP y; \
-  }
-
-OCTAVE_INT_DOUBLE_CMP_OP (<)
-OCTAVE_INT_DOUBLE_CMP_OP (<=)
-OCTAVE_INT_DOUBLE_CMP_OP (>=)
-OCTAVE_INT_DOUBLE_CMP_OP (>)
-OCTAVE_INT_DOUBLE_CMP_OP (==)
-OCTAVE_INT_DOUBLE_CMP_OP (!=)
-
-#define OCTAVE_DOUBLE_INT_CMP_OP(OP) \
-  template <class T> \
-  bool \
-  operator OP (const double& x, const octave_int<T>& y) \
-  { \
-    double ty = static_cast<double> (y.value ()); \
-    return x OP ty; \
-  }
-
-OCTAVE_DOUBLE_INT_CMP_OP (<)
-OCTAVE_DOUBLE_INT_CMP_OP (<=)
-OCTAVE_DOUBLE_INT_CMP_OP (>=)
-OCTAVE_DOUBLE_INT_CMP_OP (>)
-OCTAVE_DOUBLE_INT_CMP_OP (==)
-OCTAVE_DOUBLE_INT_CMP_OP (!=)
-
-#define OCTAVE_INT_FLOAT_BIN_OP(OP) \
-  template <class T> \
-  octave_int<T> \
-  operator OP (const octave_int<T>& x, float y) \
-  { \
-    double tx = static_cast<double> (x.value ()); \
-    double r = xround (tx OP y); \
-    r = __lo_ieee_isnan (r) ? 0 : xround (r); \
-    return OCTAVE_INT_FIT_TO_RANGE (r, T); \
-  }
-
-OCTAVE_INT_FLOAT_BIN_OP (+)
-OCTAVE_INT_FLOAT_BIN_OP (-)
-OCTAVE_INT_FLOAT_BIN_OP (*)
-OCTAVE_INT_FLOAT_BIN_OP (/)
-
-#define OCTAVE_FLOAT_INT_BIN_OP(OP) \
-  template <class T> \
-  octave_int<T> \
-  operator OP (float x, const octave_int<T>& y) \
-  { \
-    double ty = static_cast<double> (y.value ()); \
-    double r = x OP ty; \
-    r = __lo_ieee_isnan (r) ? 0 : xround (r); \
-    return OCTAVE_INT_FIT_TO_RANGE (r, T); \
-  }
-
-OCTAVE_FLOAT_INT_BIN_OP (+)
-OCTAVE_FLOAT_INT_BIN_OP (-)
-OCTAVE_FLOAT_INT_BIN_OP (*)
-OCTAVE_FLOAT_INT_BIN_OP (/)
-
-#define OCTAVE_INT_FLOAT_CMP_OP(OP) \
-  template <class T> \
-  bool \
-  operator OP (const octave_int<T>& x, const float& y) \
-  { \
-    double tx = static_cast<double> (x.value ()); \
-    return tx OP y; \
-  }
-
-OCTAVE_INT_FLOAT_CMP_OP (<)
-OCTAVE_INT_FLOAT_CMP_OP (<=)
-OCTAVE_INT_FLOAT_CMP_OP (>=)
-OCTAVE_INT_FLOAT_CMP_OP (>)
-OCTAVE_INT_FLOAT_CMP_OP (==)
-OCTAVE_INT_FLOAT_CMP_OP (!=)
-
-#define OCTAVE_FLOAT_INT_CMP_OP(OP) \
-  template <class T> \
-  bool \
-  operator OP (const float& x, const octave_int<T>& y) \
-  { \
-    double ty = static_cast<double> (y.value ()); \
-    return x OP ty; \
-  }
-
-OCTAVE_FLOAT_INT_CMP_OP (<)
-OCTAVE_FLOAT_INT_CMP_OP (<=)
-OCTAVE_FLOAT_INT_CMP_OP (>=)
-OCTAVE_FLOAT_INT_CMP_OP (>)
-OCTAVE_FLOAT_INT_CMP_OP (==)
-OCTAVE_FLOAT_INT_CMP_OP (!=)
+// Bitwise operations
 
 #define OCTAVE_INT_BITCMP_OP(OP) \
   template <class T> \
   octave_int<T> \
   operator OP (const octave_int<T>& x, const octave_int<T>& y) \
-  { \
-    return x.value () OP y.value (); \
-  }
+  { return x.value () OP y.value (); }
 
 OCTAVE_INT_BITCMP_OP (&)
 OCTAVE_INT_BITCMP_OP (|)
 OCTAVE_INT_BITCMP_OP (^)
 
-template <class T1, class T2>
-octave_int<T1>
-operator << (const octave_int<T1>& x, const T2& y)
-{
-  octave_int<T1> retval = x;
-  return retval <<= y;
-}
+# undef OCTAVE_INT_BITCMP_OP
 
-template <class T1, class T2>
-octave_int<T1>
-operator >> (const octave_int<T1>& x, const T2& y)
-{
-  octave_int<T1> retval = x;
-  return retval >>= y;
-}
-
+// General bit shift.
 template <class T>
 octave_int<T>
 bitshift (const octave_int<T>& a, int n,
@@ -816,127 +869,115 @@
     return a;
 }
 
-#define OCTAVE_INT_CMP_OP(OP) \
-  template <class T1, class T2> \
-  bool \
-  operator OP (const octave_int<T1>& x, const octave_int<T2>& y) \
-  { \
-    return x.value () OP y.value (); \
-  }
+typedef octave_int<int8_t> octave_int8;
+typedef octave_int<int16_t> octave_int16;
+typedef octave_int<int32_t> octave_int32;
+typedef octave_int<int64_t> octave_int64;
 
-OCTAVE_INT_CMP_OP (<)
-OCTAVE_INT_CMP_OP (<=)
-OCTAVE_INT_CMP_OP (>=)
-OCTAVE_INT_CMP_OP (>)
-OCTAVE_INT_CMP_OP (==)
-OCTAVE_INT_CMP_OP (!=)
-
-// The following apply if the unsigned type is at least as wide as the
-// signed type (then we can cast postive signed values to the unsigned
-// type and compare).
-
-#define OCTAVE_US_TYPE1_CMP_OP_DECL(OP, LTZ_VAL, UT, ST) \
-  template <> \
-  bool \
-  OCTAVE_API operator OP (const octave_int<UT>& lhs, const octave_int<ST>& rhs);
+typedef octave_int<uint8_t> octave_uint8;
+typedef octave_int<uint16_t> octave_uint16;
+typedef octave_int<uint32_t> octave_uint32;
+typedef octave_int<uint64_t> octave_uint64;
 
-#define OCTAVE_US_TYPE1_CMP_OP_DECLS(UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP_DECL (<, false, UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP_DECL (<=, false, UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP_DECL (>=, true, UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP_DECL (>, true, UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP_DECL (==, false, UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP_DECL (!=, true, UT, ST)
-
-#define OCTAVE_SU_TYPE1_CMP_OP_DECL(OP, LTZ_VAL, ST, UT) \
+#define OCTAVE_INT_DOUBLE_BIN_OP(OP) \
+  template <class T> \
+  inline octave_int<T> \
+  operator OP (const octave_int<T>& x, const double& y) \
+  { return octave_int<T> (static_cast<double> (x) OP y); } \
+  template <> \
+  OCTAVE_API octave_int64 \
+  operator OP (const octave_int64&, const double&); \
   template <> \
-  bool \
-  OCTAVE_API operator OP (const octave_int<ST>& lhs, const octave_int<UT>& rhs);
+  OCTAVE_API octave_uint64 \
+  operator OP (const octave_uint64&, const double&); \
+  template <class T> \
+  inline octave_int<T> \
+  operator OP (const double& x, const octave_int<T>& y) \
+  { return octave_int<T> (x OP static_cast<double> (y)); } \
+  template <> \
+  OCTAVE_API octave_int64 \
+  operator OP (const double&, const octave_int64&); \
+  template <> \
+  OCTAVE_API octave_uint64 \
+  operator OP (const double&, const octave_uint64&);
 
-#define OCTAVE_SU_TYPE1_CMP_OP_DECLS(ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP_DECL (<, true, ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP_DECL (<=, true, ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP_DECL (>=, false, ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP_DECL (>, false, ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP_DECL (==, false, ST, UT) \
-  OCTAVE_SU_TYPE1_CMP_OP_DECL (!=, true, ST, UT)
 
-#define OCTAVE_TYPE1_CMP_OP_DECLS(UT, ST) \
-  OCTAVE_US_TYPE1_CMP_OP_DECLS (UT, ST) \
-  OCTAVE_SU_TYPE1_CMP_OP_DECLS (ST, UT)
+OCTAVE_INT_DOUBLE_BIN_OP (+)
+OCTAVE_INT_DOUBLE_BIN_OP (-)
+OCTAVE_INT_DOUBLE_BIN_OP (*)
+OCTAVE_INT_DOUBLE_BIN_OP (/)
 
-OCTAVE_TYPE1_CMP_OP_DECLS (uint32_t, int8_t)
-OCTAVE_TYPE1_CMP_OP_DECLS (uint32_t, int16_t)
-OCTAVE_TYPE1_CMP_OP_DECLS (uint32_t, int32_t)
-
-OCTAVE_TYPE1_CMP_OP_DECLS (uint64_t, int8_t)
-OCTAVE_TYPE1_CMP_OP_DECLS (uint64_t, int16_t)
-OCTAVE_TYPE1_CMP_OP_DECLS (uint64_t, int32_t)
-OCTAVE_TYPE1_CMP_OP_DECLS (uint64_t, int64_t)
+# undef OCTAVE_INT_DOUBLE_BIN_OP
 
-// The following apply if the signed type is wider than the unsigned
-// type (then we can cast unsigned values to the signed type and
-// compare if the signed value is positive).
-
-#define OCTAVE_US_TYPE2_CMP_OP_DECL(OP, LTZ_VAL, UT, ST) \
+#define OCTAVE_INT_DOUBLE_CMP_OP(OP) \
+  template <class T> \
+  inline bool \
+  operator OP (const octave_int<T>& x, const double& y) \
+  { return static_cast<double> (x.value ()) OP y; } \
+  template <> \
+  OCTAVE_API bool \
+  operator OP (const octave_int64&, const double&); \
   template <> \
-  bool \
-  OCTAVE_API operator OP (const octave_int<UT>& lhs, const octave_int<ST>& rhs);
+  OCTAVE_API bool \
+  operator OP (const octave_uint64&, const double&); \
+  template <class T> \
+  inline bool \
+  operator OP (const double& x, const octave_int<T>& y) \
+  { return x OP static_cast<double> (y.value ()); } \
+  template <> \
+  OCTAVE_API bool \
+  operator OP (const double&, const octave_int64&); \
+  template <> \
+  OCTAVE_API bool \
+  operator OP (const double&, const octave_uint64&);
 
-#define OCTAVE_US_TYPE2_CMP_OP_DECLS(ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP_DECL (<, false, ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP_DECL (<=, false, ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP_DECL (>=, true, ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP_DECL (>, true, ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP_DECL (==, false, ST, UT) \
-  OCTAVE_US_TYPE2_CMP_OP_DECL (!=, true, ST, UT)
 
-#define OCTAVE_SU_TYPE2_CMP_OP_DECL(OP, LTZ_VAL, ST, UT) \
-  template <> \
-  bool \
-  OCTAVE_API operator OP (const octave_int<ST>& lhs, const octave_int<UT>& rhs);
+OCTAVE_INT_DOUBLE_CMP_OP (<)
+OCTAVE_INT_DOUBLE_CMP_OP (<=)
+OCTAVE_INT_DOUBLE_CMP_OP (>=)
+OCTAVE_INT_DOUBLE_CMP_OP (>)
+OCTAVE_INT_DOUBLE_CMP_OP (==)
+OCTAVE_INT_DOUBLE_CMP_OP (!=)
 
-#define OCTAVE_SU_TYPE2_CMP_OP_DECLS(ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP_DECL (<, true, ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP_DECL (<=, true, ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP_DECL (>=, false, ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP_DECL (>, false, ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP_DECL (==, false, ST, UT) \
-  OCTAVE_SU_TYPE2_CMP_OP_DECL (!=, true, ST, UT)
+# undef OCTAVE_INT_DOUBLE_CMP_OP
+
+// Floats are handled by simply converting to doubles.
 
-#define OCTAVE_TYPE2_CMP_OP_DECLS(UT, ST) \
-  OCTAVE_US_TYPE2_CMP_OP_DECLS (UT, ST) \
-  OCTAVE_SU_TYPE2_CMP_OP_DECLS (ST, UT)
+#define OCTAVE_INT_FLOAT_BIN_OP(OP) \
+  template <class T> \
+  inline octave_int<T> \
+  operator OP (const octave_int<T>& x, float y) \
+  { return x OP static_cast<double> (y); } \
+  template <class T> \
+  inline octave_int<T> \
+  operator OP (float x, const octave_int<T>& y) \
+  { return static_cast<double> (x) OP y; }
 
-OCTAVE_TYPE2_CMP_OP_DECLS (uint32_t, int64_t)
+OCTAVE_INT_FLOAT_BIN_OP (+)
+OCTAVE_INT_FLOAT_BIN_OP (-)
+OCTAVE_INT_FLOAT_BIN_OP (*)
+OCTAVE_INT_FLOAT_BIN_OP (/)
+
+# undef OCTAVE_INT_FLOAT_BIN_OP
 
-#undef OCTAVE_INT_BINOP_TRAIT
-#undef OCTAVE_US_S_FTR
-#undef OCTAVE_US_S_FTR_FCNS
-#undef OCTAVE_S_US_FTR
-#undef OCTAVE_S_US_FTR_FCNS
-#undef OCTAVE_INT_FIT_TO_RANGE
-#undef OCTAVE_INT_MIN_VAL2
-#undef OCTAVE_INT_MAX_VAL2
-#undef OCTAVE_INT_FIT_TO_RANGE2
-#undef OCTAVE_INT_BIN_OP
-#undef OCTAVE_INT_DOUBLE_BIN_OP
-#undef OCTAVE_DOUBLE_INT_BIN_OP
-#undef OCTAVE_INT_DOUBLE_CMP_OP
-#undef OCTAVE_DOUBLE_INT_CMP_OP
-#undef OCTAVE_INT_BITCMP_OP
-#undef OCTAVE_INT_CMP_OP
-#undef OCTAVE_US_TYPE1_CMP_OP_DECL
-#undef OCTAVE_US_TYPE1_CMP_OP_DECLS
-#undef OCTAVE_SU_TYPE1_CMP_OP_DECL
-#undef OCTAVE_SU_TYPE1_CMP_OP_DECLS
-#undef OCTAVE_TYPE1_CMP_OP_DECLS
-#undef OCTAVE_US_TYPE2_CMP_OP_DECL
-#undef OCTAVE_US_TYPE2_CMP_OP_DECLS
-#undef OCTAVE_SU_TYPE2_CMP_OP_DECL
-#undef OCTAVE_SU_TYPE2_CMP_OP_DECLS
-#undef OCTAVE_TYPE2_CMP_OP_DECLS
+#define OCTAVE_INT_FLOAT_CMP_OP(OP) \
+  template <class T> \
+  inline bool \
+  operator OP (const octave_int<T>& x, const float& y) \
+  { return x OP static_cast<double> (y); } \
+  template <class T> \
+  bool \
+  operator OP (const float& x, const octave_int<T>& y) \
+  { return static_cast<double> (x) OP y; }
 
+OCTAVE_INT_FLOAT_CMP_OP (<)
+OCTAVE_INT_FLOAT_CMP_OP (<=)
+OCTAVE_INT_FLOAT_CMP_OP (>=)
+OCTAVE_INT_FLOAT_CMP_OP (>)
+OCTAVE_INT_FLOAT_CMP_OP (==)
+OCTAVE_INT_FLOAT_CMP_OP (!=)
+
+# undef OCTAVE_INT_FLOAT_CMP_OP
 #endif
 
 /*