diff src/bitfcns.cc @ 4915:c638c144d4da

[project @ 2004-07-23 19:01:22 by jwe]
author jwe
date Fri, 23 Jul 2004 19:01:23 +0000
parents 66af4b9f451e
children a1073eef650c
line wrap: on
line diff
--- a/src/bitfcns.cc
+++ b/src/bitfcns.cc
@@ -31,11 +31,53 @@
 #include "error.h"
 #include "ov.h"
 #include "ov-uint64.h"
-
+#include "ov-uint32.h"
+#include "ov-uint16.h"
+#include "ov-uint8.h"
+#include "ov-int64.h"
+#include "ov-int32.h"
+#include "ov-int16.h"
+#include "ov-int8.h"
+#include "ov-scalar.h"
+#include "ov-re-mat.h"
 
 // XXX FIXME XXX -- could probably eliminate some code duplication by
 // clever use of templates.
 
+#define BITOPX(OP, FNAME, RET) \
+      { \
+	int nelx = x.numel (); \
+	int nely = y.numel (); \
+ \
+	bool is_scalar_op = (nelx == 1 || nely == 1); \
+ \
+	dim_vector dvx = x.dims (); \
+	dim_vector dvy = y.dims (); \
+ \
+	bool is_array_op = (dvx == dvy); \
+ \
+	if (is_array_op || is_scalar_op) \
+	  { \
+	    RET result; \
+ \
+	    if (nelx != 1) \
+	      result.resize (dvx); \
+	    else \
+	      result.resize (dvy); \
+ \
+	    for (int i = 0; i < nelx; i++) \
+	      if (is_scalar_op) \
+		for (int k = 0; k < nely; k++) \
+		  result(i+k) = x(i) OP y(k); \
+	      else \
+		result(i) = x(i) OP y(i); \
+ \
+	      retval = result; \
+	  } \
+	else \
+	  error ("%s: size of x and y must match, or one operand must be a scalar", FNAME); \
+      }
+
 #define BITOP(OP, FNAME) \
  \
   octave_value retval; \
@@ -44,44 +86,175 @@
  \
   if (nargin == 2) \
     { \
-      uint64NDArray x = args(0).uint64_array_value (); \
-      uint64NDArray y = args(1).uint64_array_value (); \
- \
-      if (! error_state) \
+      if (args(0).type_id () == octave_matrix::static_type_id () || \
+	  args(0).type_id () == octave_scalar::static_type_id () || \
+	  args(1).type_id () == octave_matrix::static_type_id () || \
+	  args(1).type_id () == octave_scalar::static_type_id ()) \
 	{ \
-	  int nelx = x.numel (); \
-	  int nely = y.numel (); \
- \
-	  bool is_scalar_op = (nelx == 1 || nely == 1); \
+	  bool arg0_is_int = true; \
+	  bool arg1_is_int = true; \
  \
-	  dim_vector dvx = x.dims (); \
-	  dim_vector dvy = y.dims (); \
- \
-	  bool is_array_op = (dvx == dvy); \
+	  if (args(0).type_id () == octave_matrix::static_type_id () || \
+	      args(0).type_id () == octave_scalar::static_type_id ())	\
+	    arg0_is_int = false; \
  \
-	  if (is_array_op || is_scalar_op) \
-	    { \
-	      uint64NDArray result; \
- \
-	      if (nelx != 1) \
-		result.resize (dvx); \
-	      else \
-		result.resize (dvy); \
+	  if (args(1).type_id () == octave_matrix::static_type_id () || \
+	      args(1).type_id () == octave_scalar::static_type_id ())	\
+	    arg1_is_int = false; \
  \
-	      for (int i = 0; i < nelx; i++) \
-		if (is_scalar_op) \
-		  for (int k = 0; k < nely; k++) \
-		    result(i+k) = x(i) OP y(k); \
-		else \
-		  result(i) = x(i) OP y(i); \
- \
-		retval = result; \
+	  if (!arg0_is_int && !arg1_is_int) \
+	    { \
+	      uint64NDArray x (args(0).array_value ());		\
+	      uint64NDArray y (args(1).array_value ());	\
+	      if (! error_state)				\
+		BITOPX (OP, FNAME, uint64NDArray);		\
+	      retval = retval.array_value ();			\
 	    } \
 	  else \
-	    error ("%s: size of x and y must match, or one operand must be a scalar", FNAME); \
-        } \
+	    { \
+	      int p = (arg0_is_int ? 1 : 0); \
+	      int q = (arg0_is_int ? 0 : 1); \
+	      NDArray dx = args(p).array_value (); \
+ \
+	      if (args(q).type_id () == octave_uint64_matrix::static_type_id () || \
+		  args(q).type_id () == octave_uint64_scalar::static_type_id ()) \
+		{							\
+		  uint64NDArray x (dx);					\
+		  uint64NDArray y = args(q).uint64_array_value ();	\
+		  if (! error_state)					\
+		    BITOPX (OP, FNAME, uint64NDArray);			\
+		 } \
+	      else if (args(q).type_id () == octave_uint32_matrix::static_type_id () || \
+		       args(q).type_id () == octave_uint32_scalar::static_type_id ()) \
+		{							\
+		  uint32NDArray x (dx);					\
+		  uint32NDArray y = args(q).uint32_array_value ();	\
+		  if (! error_state)					\
+		    BITOPX (OP, FNAME, uint32NDArray);			\
+		} \
+	      else if (args(q).type_id () == octave_uint16_matrix::static_type_id () || \
+		       args(q).type_id () == octave_uint16_scalar::static_type_id ()) \
+		{							\
+		  uint16NDArray x (dx);					\
+		  uint16NDArray y = args(q).uint16_array_value ();	\
+		  if (! error_state)					\
+		    BITOPX (OP, FNAME, uint16NDArray);			\
+		} \
+	      else if (args(q).type_id () == octave_uint8_matrix::static_type_id () || \
+		       args(q).type_id () == octave_uint8_scalar::static_type_id ()) \
+		{							\
+		  uint8NDArray x (dx);					\
+		  uint8NDArray y = args(q).uint8_array_value ();	\
+		  if (! error_state)					\
+		    BITOPX (OP, FNAME, uint8NDArray);			\
+		}							\
+	      else if (args(q).type_id () == octave_int64_matrix::static_type_id () || \
+		       args(q).type_id () == octave_int64_scalar::static_type_id ()) \
+		{							\
+		  int64NDArray x (dx);					\
+		  int64NDArray y = args(q).int64_array_value ();	\
+		  if (! error_state)					\
+		    BITOPX (OP, FNAME, int64NDArray);			\
+		}							\
+	      else if (args(q).type_id () == octave_int32_matrix::static_type_id () || \
+		       args(q).type_id () == octave_int32_scalar::static_type_id ()) \
+		{							\
+		  int32NDArray x (dx);					\
+		  int32NDArray y = args(q).int32_array_value ();	\
+		  if (! error_state)					\
+		    BITOPX (OP, FNAME, int32NDArray);			\
+		}							\
+	      else if (args(q).type_id () == octave_int16_matrix::static_type_id () || \
+	      args(q).type_id () == octave_int16_scalar::static_type_id ()) \
+		{							\
+		  int16NDArray x (dx);					\
+		  int16NDArray y = args(q).int16_array_value ();	\
+		  if (! error_state)					\
+		    BITOPX (OP, FNAME, int16NDArray);			\
+		}							\
+	      else if (args(q).type_id () == octave_int8_matrix::static_type_id () || \
+		       args(q).type_id () == octave_int8_scalar::static_type_id ()) \
+		{							\
+		  int8NDArray x (dx);					\
+		  int8NDArray y = args(q).int8_array_value ();		\
+		  if (! error_state)					\
+		    BITOPX (OP, FNAME, int8NDArray);			\
+		}							\
+	      else							\
+		error ("%s: illegal operand type", FNAME);		\
+	    }								\
+	}								\
+      else if (args(0).type_id () == args(1).type_id ())		\
+	{ \
+	  if (args(0).type_id () == octave_uint64_matrix::static_type_id () || \
+	      args(0).type_id () == octave_uint64_scalar::static_type_id ()) \
+	    { \
+	      uint64NDArray x = args(0).uint64_array_value ();	\
+	      uint64NDArray y = args(1).uint64_array_value ();	\
+	      if (! error_state)				\
+		BITOPX (OP, FNAME, uint64NDArray);		\
+	    } \
+	  else if (args(0).type_id () == octave_uint32_matrix::static_type_id () || \
+	      args(0).type_id () == octave_uint32_scalar::static_type_id ()) \
+	    { \
+	      uint32NDArray x = args(0).uint32_array_value ();	\
+	      uint32NDArray y = args(1).uint32_array_value ();	\
+	      if (! error_state)				\
+		BITOPX (OP, FNAME, uint32NDArray);		\
+	    } \
+	  else if (args(0).type_id () == octave_uint16_matrix::static_type_id () || \
+	      args(0).type_id () == octave_uint16_scalar::static_type_id ()) \
+	    { \
+	      uint16NDArray x = args(0).uint16_array_value ();	\
+	      uint16NDArray y = args(1).uint16_array_value ();	\
+	      if (! error_state)				\
+		BITOPX (OP, FNAME, uint16NDArray);		\
+	    } \
+	  else if (args(0).type_id () == octave_uint8_matrix::static_type_id () || \
+	      args(0).type_id () == octave_uint8_scalar::static_type_id ()) \
+	    { \
+	      uint8NDArray x = args(0).uint8_array_value ();	\
+	      uint8NDArray y = args(1).uint8_array_value ();	\
+	      if (! error_state)				\
+		BITOPX (OP, FNAME, uint8NDArray);		\
+	    } \
+	  else if (args(0).type_id () == octave_int64_matrix::static_type_id () || \
+	      args(0).type_id () == octave_int64_scalar::static_type_id ()) \
+	    { \
+	      int64NDArray x = args(0).int64_array_value ();	\
+	      int64NDArray y = args(1).int64_array_value ();	\
+	      if (! error_state)				\
+		BITOPX (OP, FNAME, int64NDArray);		\
+	    } \
+	  else if (args(0).type_id () == octave_int32_matrix::static_type_id () || \
+	      args(0).type_id () == octave_int32_scalar::static_type_id ()) \
+	    { \
+	      int32NDArray x = args(0).int32_array_value ();	\
+	      int32NDArray y = args(1).int32_array_value ();	\
+	      if (! error_state)				\
+		BITOPX (OP, FNAME, int32NDArray);		\
+	    } \
+	  else if (args(0).type_id () == octave_int16_matrix::static_type_id () || \
+	      args(0).type_id () == octave_int16_scalar::static_type_id ()) \
+	    { \
+	      int16NDArray x = args(0).int16_array_value ();	\
+	      int16NDArray y = args(1).int16_array_value ();	\
+	      if (! error_state)				\
+		BITOPX (OP, FNAME, int16NDArray);		\
+	    } \
+	  else if (args(0).type_id () == octave_int8_matrix::static_type_id () || \
+	      args(0).type_id () == octave_int8_scalar::static_type_id ()) \
+	    { \
+	      int8NDArray x = args(0).int8_array_value ();	\
+	      int8NDArray y = args(1).int8_array_value ();	\
+	      if (! error_state)				\
+		BITOPX (OP, FNAME, int8NDArray);		\
+	    } \
+	  else \
+	    error ("%s: illegal operand type", FNAME); \
+	} \
       else \
-        error ("%s: expecting uint64 arguments", FNAME); \
+	error ("%s: must have matching operand types", FNAME); \
     } \
   else \
     print_usage (FNAME); \
@@ -121,73 +294,20 @@
   BITOP (^, "bitxor");
 }
 
-DEFUN (bitcmp, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} bitcmp (@var{a}, @var{k})\n\
-returns the @var{k}-bit complement of integers in @var{a}. If\n\
-@var{k} is omitted k = log2(bitmax) is assumed.\n\
-\n\
-@example\n\
-bitcmp (7, 4)\n\
-@result{} 8\n\
-dec2bin (11)\n\
-@result{} 1011\n\
-dec2bin (bitcmp (11))\n\
-@result{} 11111111111111111111111111110100\n\
-@end example\n\
-\n\
-@end deftypefn\n\
-@seealso{bitand, bitor, bitxor, bitset, bitget, bitcmp, bitshift, bitmax}")
+static EIGHT_BYTE_INT
+bitshift (const double& a, int n)
 {
-  octave_value retval;
-  error ("not implemented");
-  return retval;
+  if (n > 0)
+    return static_cast<EIGHT_BYTE_INT> (a) << n;
+  else if (n < 0)
+    return static_cast<EIGHT_BYTE_INT> (a) >> -n;
+  else
+    return static_cast<EIGHT_BYTE_INT> (a);
 }
 
-DEFUN (bitget, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Function File} {} bitget (@var{a}, @var{n})\n\
-returns the status of bit(s) @var{n} of unsigned integers in @var{a}\n\
-the lowest significant bit is @var{n} = 1.\n\
-\n\
-@example\n\
-bitget (100,8:-1:1)\n\
-@result{} 0  1  1  0  0  1  0  0\n\
-@end example\n\
-@end deftypefn\n\
-@seealso{bitand, bitor, bitxor, bitset, bitcmp, bitshift, bitmax}")
-{
-  octave_value retval;
-  error ("not implemented");
-  return retval;
-}
-
-DEFUN (bitset, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Function File} {} bitset (@var{a}, @var{n})\n\
-@deftypefnx {Function File} {} bitset (@var{a}, @var{n}, @var{v})\n\
-sets or resets bit(s) @var{n} of unsigned integers in @var{a}.\n\
-@var{v} = 0 resets and @var{v} = 1 sets the bits.\n\
-The lowest significant bit is: @var{n} = 1\n\
-\n\
-@example\n\
-dec2bin (bitset (10, 1))\n\
-@result{} 1011\n\
-@end example\n\
-\n\
-@end deftypefn\n\
-@seealso{bitand, bitor, bitxor, bitget, bitcmp, bitshift, bitmax}")
-{
-  octave_value retval;
-  error ("not implemented");
-  return retval;
-}
-
+// Note that the bitshift operators are undefined if shifted by more bits than
+// in the type. Therefore need to test for the size of the shift
 #define DO_BITSHIFT(T) \
-  do \
-    { \
-      T ## NDArray m = m_arg.T ## _array_value (); \
- \
       if (! error_state) \
 	{ \
           double d1, d2; \
@@ -216,9 +336,15 @@
 		  for (int i = 0; i < m_nel; i++) \
 		    if (is_scalar_op) \
 		      for (int k = 0; k < n_nel; k++) \
-			result(i+k) = bitshift (m(i), static_cast<int> (n(k))); \
+			if (static_cast<int> (n(k)) >= bits_in_type) \
+			  result(i+k) = 0; \
+			else \
+			  result(i+k) = bitshift (m(i), static_cast<int> (n(k))) & mask; \
 		    else \
-		      result(i) = bitshift (m(i), static_cast<int> (n(i))); \
+		      if (static_cast<int> (n(i)) >= bits_in_type) \
+			result(i) = 0;					\
+		      else 						\
+			result(i) = bitshift (m(i), static_cast<int> (n(i))) & mask; \
  \
 		  retval = result; \
 		} \
@@ -227,8 +353,34 @@
 	    } \
           else \
             error ("bitshift: expecting second argument to be integer"); \
-        } \
-    } \
+        }
+
+#define DO_UBITSHIFT(T, N)					\
+  do								\
+    {								\
+      int bits_in_type = sizeof (octave_ ## T) << 3;		\
+      T ## NDArray m = m_arg.T ## _array_value ();		\
+	octave_ ## T mask = ~0ULL;				\
+      if ((N) < static_cast<int>(sizeof (octave_ ## T) << 3))	\
+	mask = mask >> ((sizeof (octave_ ## T) << 3) - (N));	\
+      else if ((N) < 1)						\
+	mask = 0;						\
+      DO_BITSHIFT (T);						\
+    }								\
+  while (0)
+
+#define DO_SBITSHIFT(T, N)					\
+  do								\
+    {								\
+      int bits_in_type = sizeof (octave_ ## T) << 3;		\
+      T ## NDArray m = m_arg.T ## _array_value ();		\
+	octave_ ## T mask = -1;					\
+      if ((N) < static_cast<int>(sizeof (octave_ ## T) << 3))	\
+	mask = mask >> ((sizeof (octave_ ## T) << 3) - (N));	\
+      else if ((N) < 1)						\
+	mask = 0;						\
+      DO_BITSHIFT (T);						\
+    }								\
   while (0)
 
 DEFUN (bitshift, args, ,
@@ -237,9 +389,9 @@
 @deftypefnx {Function File} {} bitshift (@var{a}, @var{k}, @var{n})\n\
 return a @var{k} bit shift of @var{n}- digit unsigned\n\
 integers in @var{a}. A positive @var{k} leads to a left shift.\n\
-A negative value to a right shift. If @var{N} is omitted it defaults\n\
+A negative value to a right shift. If @var{n} is omitted it defaults\n\
 to log2(bitmax)+1. \n\
-@var{N} must be in range [1,log2(bitmax)+1] usually [1,33]\n\
+@var{n} must be in range [1,log2(bitmax)+1] usually [1,33]\n\
 \n\
 @example\n\
 bitshift (eye (3), 1))\n\
@@ -263,22 +415,53 @@
 
   int nargin = args.length ();
 
-  if (nargin == 2)
+  if (nargin == 2 || nargin == 3)
     {
       NDArray n = args(1).array_value ();
+      int nbits = 64;
+      
+      if (nargin == 3)
+	{
+	  nbits = args(2).nint_value ();
+	  
+	  if (nbits < 0)
+	    error ("bitshift: number of bits to mask must be positive");
+	}
+
+      if (error_state)
+	return retval;
 
       octave_value m_arg = args(0);
-
       std::string cname = m_arg.class_name ();
 
       if (cname == "uint8")
-	DO_BITSHIFT (uint8);
+	DO_UBITSHIFT (uint8, nbits < 8 ? nbits : 8);
       else if (cname == "uint16")
-	DO_BITSHIFT (uint16);
+	DO_UBITSHIFT (uint16, nbits < 16 ? nbits : 16);
       else if (cname == "uint32")
-	DO_BITSHIFT (uint32);
+	DO_UBITSHIFT (uint32, nbits < 32 ? nbits : 32);
       else if (cname == "uint64")
-	DO_BITSHIFT (uint64);
+	DO_UBITSHIFT (uint64, nbits < 64 ? nbits : 64);
+      else if (cname == "int8")
+	DO_SBITSHIFT (int8, nbits < 8 ? nbits : 8);
+      else if (cname == "int16")
+	DO_SBITSHIFT (int16, nbits < 16 ? nbits : 16);
+      else if (cname == "int32")
+	DO_SBITSHIFT (int32, nbits < 32 ? nbits : 32);
+      else if (cname == "int64")
+	DO_SBITSHIFT (int64, nbits < 64 ? nbits : 64);
+      else if (cname == "double")
+	{
+	  nbits = (nbits < 53 ? nbits : 53);
+	  EIGHT_BYTE_INT mask = 0x1FFFFFFFFFFFFFLL;
+	  if (nbits < 53)
+	    mask = mask >> (53 - nbits);
+	  else if (nbits < 1)
+	    mask = 0;
+	  int bits_in_type = 64;
+	  NDArray m = m_arg.array_value ();
+	  DO_BITSHIFT ( );
+	}
       else
 	error ("bitshift: not defined for %s objects", cname.c_str ());
     }
@@ -290,11 +473,94 @@
 
 DEFUN (bitmax, args, ,
   "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} bitmax (@var{x}, @var{y})\n\
+@deftypefn {Built-in Function} {} bitmax ()\n\
+Returns the largest integer that can be represented as a floating point\n\
+value. That is for IEEE-754 compatiable systems with @code{2^53 - 1}.\n\
+@end deftypefn")
+{
+  octave_value retval;
+  if (args.length() != 0)
+    print_usage ("bitmax");
+  else
+    retval = ((double)0x1FFFFFFFFFFFFFLL);
+  return retval;
+}
+
+DEFUN (intmax, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} intmax (@var{type})\n\
 @end deftypefn")
 {
   octave_value retval;
-  error ("not implemented");
+  std::string cname = "int32";
+  int nargin = args.length ();
+
+  if (nargin == 1 && args(0).is_string())
+    cname = args(0).string_value ();
+  else if (nargin != 0)
+    {
+      print_usage ("intmax");
+      return retval;
+    }
+
+  if (cname == "uint8")
+    retval = octave_uint8 (std::numeric_limits<octave_uint8_t>::max());
+  else if (cname == "uint16")
+    retval = octave_uint16 (std::numeric_limits<octave_uint16_t>::max());
+  else if (cname == "uint32")
+    retval = octave_uint32 (std::numeric_limits<octave_uint32_t>::max());
+  else if (cname == "uint64")
+    retval = octave_uint64 (std::numeric_limits<octave_uint64_t>::max());
+  else if (cname == "int8")
+    retval = octave_int8 (std::numeric_limits<octave_int8_t>::max());
+  else if (cname == "int16")
+    retval = octave_int16 (std::numeric_limits<octave_int16_t>::max());
+  else if (cname == "int32")
+    retval = octave_int32 (std::numeric_limits<octave_int32_t>::max());
+  else if (cname == "int64")
+    retval = octave_int64 (std::numeric_limits<octave_int64_t>::max());
+  else
+    error ("intmax: not defined for '%s' objects", cname.c_str ());
+
+  return retval;
+}
+
+DEFUN (intmin, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} intmin (@var{type})\n\
+@end deftypefn")
+{
+  octave_value retval;
+  std::string cname = "int32";
+  int nargin = args.length ();
+
+  if (nargin == 1 && args(0).is_string())
+    cname = args(0).string_value ();
+  else if (nargin != 0)
+    {
+      print_usage ("intmin");
+      return retval;
+    }
+
+  if (cname == "uint8")
+    retval = octave_uint8 (std::numeric_limits<octave_uint8_t>::min());
+  else if (cname == "uint16")
+    retval = octave_uint16 (std::numeric_limits<octave_uint16_t>::min());
+  else if (cname == "uint32")
+    retval = octave_uint32 (std::numeric_limits<octave_uint32_t>::min());
+  else if (cname == "uint64")
+    retval = octave_uint64 (std::numeric_limits<octave_uint64_t>::min());
+  else if (cname == "int8")
+    retval = octave_int8 (std::numeric_limits<octave_int8_t>::min());
+  else if (cname == "int16")
+    retval = octave_int16 (std::numeric_limits<octave_int16_t>::min());
+  else if (cname == "int32")
+    retval = octave_int32 (std::numeric_limits<octave_int32_t>::min());
+  else if (cname == "int64")
+    retval = octave_int64 (std::numeric_limits<octave_int64_t>::min());
+  else
+    error ("intmin: not defined for '%s' objects", cname.c_str ());
+
   return retval;
 }