changeset 11776:78d3faa70aaa release-3-0-x

Treat integer types for mod/rem correctly
author David Bateman <dbateman@free.fr>
date Mon, 18 Feb 2008 18:08:29 +0100
parents bd72c5e49dcb
children c5d9aaeb306a
files scripts/ChangeLog scripts/general/mod.m scripts/general/rem.m src/data.cc
diffstat 4 files changed, 114 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog
+++ b/scripts/ChangeLog
@@ -1,3 +1,7 @@
+2008-05-22  David Bateman  <dbateman@free.fr>
+
+	* general/rem.m, general/mod.m: Treat integer types correctly.
+
 2008-04-29  David Bateman  <dbateman@free.fr>
 
 	pkg/pkg.m: Also set archprefix with the -local and -global options.
--- a/scripts/general/mod.m
+++ b/scripts/general/mod.m
@@ -18,14 +18,15 @@
 
 ## -*- texinfo -*-
 ## @deftypefn {Mapping Function} {} mod (@var{x}, @var{y})
-## Compute modulo function, using
+## Compute modulo function. Conceptually this is given by
 ##
 ## @example
 ## x - y .* floor (x ./ y)
 ## @end example
 ##
-## Note that this handles negative numbers correctly:
-## @code{mod (-1, 3)} is 2, not -1 as @code{rem (-1, 3)} returns.
+## and is written in a manner that the correct modulus is returned for
+##integer types. This function handles negative values correctly. That
+##is @code{mod (-1, 3)} is 2, not -1 as @code{rem (-1, 3)} returns.
 ## Also, @code{mod (@var{x}, 0)} returns @var{x}.
 ##
 ## An error message is printed if the dimensions of the arguments do not
@@ -47,27 +48,42 @@
     error ("mod: argument sizes must agree");
   endif
 
-  ## Matlab allows complex arguments, but as far as I can tell, that's a
-  ## bunch of hooey.
-
   if (isreal (x) && isreal (y))
     nz = y != 0.0;
     if (all (nz(:)))
       ## No elements of y are zero.
-      r = x - y .* floor (x ./ y);
+      if (isinteger(x) || isinteger(y))
+	if (isinteger (x))
+	  typ = class (x);
+	else
+	  typ = class (y);
+	endif
+	r = x - y .* cast (floor (double(x) ./ double(y)), typ);
+      else
+	r = x - y .* floor (x ./ y);
+      endif
     elseif (isscalar (y))
       ## y must be zero.
       r = x;
     else
       ## Some elements of y are zero.
       if (isscalar (x))
-	r = x * ones (size (y));
+	r = x * ones (size(y), class(y));
       else
 	r = x;
 	x = x(nz);
       endif
       y = y(nz);
-      r(nz) = x - y .* floor (x ./ y);
+      if (isinteger(x) || isinteger(y))
+	if (isinteger (x))
+	  typ = class (x);
+	else
+	  typ = class (y);
+	endif
+	r(nz) = x - y .* floor (double(x) ./ double(y));
+      else
+	r(nz) = x - y .* floor (x ./ y);
+      endif
     endif
   else
     error ("mod: complex arguments are not allowed");
@@ -101,3 +117,14 @@
 %!assert (mod(-5,[3,0; 3,1]), [1, -5; 1, 0]);
 %!assert (mod(-5,[3,2; 3,1]), [1, 1; 1, 0]);
 
+## integer types
+%!assert (mod(uint8(5),uint8(4)),uint8(1))
+%!assert (mod(uint8([1:5]),uint8(4)),uint8([1,2,3,0,1]))
+%!assert (mod(uint8([1:5]),uint8(0)),uint8([1:5]))
+%!error (mod(uint8(5),int8(4)))
+
+## mixed integer/real types
+%!assert (mod(uint8(5),4),uint8(1))
+%!assert (mod(5,uint8(4)),uint8(1))
+%!assert (mod(uint8([1:5]),4),uint8([1,2,3,0,1]))
+%!error (mod([1:5],uint8(4)))
--- a/scripts/general/rem.m
+++ b/scripts/general/rem.m
@@ -43,13 +43,26 @@
     error ("rem: argument sizes must agree");
   endif
 
-  ## Matlab allows complex arguments, but as far as I can tell, that's a
-  ## bunch of hooey.
-
   if (isreal (x) && isreal (y))
-    r = x - y .* fix (x ./ y);
+      if (isinteger(x) || isinteger(y))
+	if (isinteger (x))
+	  typ = class (x);
+	else
+	  typ = class (y);
+	endif
+	r = x - y .* cast (fix (double (x) ./ double (y)), typ);
+      else
+	r = x - y .* fix (x ./ y);
+      endif
   else
     error ("rem: complex arguments are not allowed");
   endif
 
+%!assert(rem (uint8([1, 2, 3; -1, -2, -3]), uint8 (2)), uint8([1, 0, 1; -1, 0, -1]));
+
+%!assert(uint8(rem ([1, 2, 3; -1, -2, -3], 2 * ones (2, 3))),uint8([1, 0, 1; -1, 0, -1]));
+
+%!error rem (uint(8),int8(5));
+
+%!error rem (uint8([1, 2]), uint8([3, 4, 5]));
 endfunction
--- a/src/data.cc
+++ b/src/data.cc
@@ -202,76 +202,81 @@
 
   if (nargin == 2 && args(0).is_defined () && args(1).is_defined ())
     {
-      octave_value arg_y = args(0);
-      octave_value arg_x = args(1);
-
-      octave_idx_type y_nr = arg_y.rows ();
-      octave_idx_type y_nc = arg_y.columns ();
-
-      octave_idx_type x_nr = arg_x.rows ();
-      octave_idx_type x_nc = arg_x.columns ();
-
-      int arg_y_empty = empty_arg ("atan2", y_nr, y_nc);
-      int arg_x_empty = empty_arg ("atan2", x_nr, x_nc);
-
-      if (arg_y_empty > 0 && arg_x_empty > 0)
-	return octave_value (Matrix ());
-      else if (arg_y_empty || arg_x_empty)
-	return retval;
-
-      octave_idx_type y_is_scalar = (y_nr == 1 && y_nc == 1);
-      octave_idx_type x_is_scalar = (x_nr == 1 && x_nc == 1);
-
-      if (y_is_scalar && x_is_scalar)
+      if (args(0).is_integer_type () || args(0).is_integer_type ())
+	error ("atan2: not defined for integer types");
+      else
 	{
-	  double y = arg_y.double_value ();
-
-	  if (! error_state)
+	  octave_value arg_y = args(0);
+	  octave_value arg_x = args(1);
+
+	  octave_idx_type y_nr = arg_y.rows ();
+	  octave_idx_type y_nc = arg_y.columns ();
+
+	  octave_idx_type x_nr = arg_x.rows ();
+	  octave_idx_type x_nc = arg_x.columns ();
+
+	  int arg_y_empty = empty_arg ("atan2", y_nr, y_nc);
+	  int arg_x_empty = empty_arg ("atan2", x_nr, x_nc);
+
+	  if (arg_y_empty > 0 && arg_x_empty > 0)
+	    return octave_value (Matrix ());
+	  else if (arg_y_empty || arg_x_empty)
+	    return retval;
+
+	  octave_idx_type y_is_scalar = (y_nr == 1 && y_nc == 1);
+	  octave_idx_type x_is_scalar = (x_nr == 1 && x_nc == 1);
+
+	  if (y_is_scalar && x_is_scalar)
 	    {
-	      double x = arg_x.double_value ();
+	      double y = arg_y.double_value ();
 
 	      if (! error_state)
-		retval = atan2 (y, x);
+		{
+		  double x = arg_x.double_value ();
+
+		  if (! error_state)
+		    retval = atan2 (y, x);
+		}
 	    }
-	}
-      else if (y_is_scalar)
-	{
-	  double y = arg_y.double_value ();
-
-	  if (! error_state)
+	  else if (y_is_scalar)
 	    {
-	      Matrix x = arg_x.matrix_value ();
+	      double y = arg_y.double_value ();
 
 	      if (! error_state)
-		retval = map_d_m (atan2, y, x);
+		{
+		  Matrix x = arg_x.matrix_value ();
+
+		  if (! error_state)
+		    retval = map_d_m (atan2, y, x);
+		}
 	    }
-	}
-      else if (x_is_scalar)
-	{
-	  Matrix y = arg_y.matrix_value ();
-
-	  if (! error_state)
+	  else if (x_is_scalar)
 	    {
-	      double x = arg_x.double_value ();
+	      Matrix y = arg_y.matrix_value ();
 
 	      if (! error_state)
-		retval = map_m_d (atan2, y, x);
+		{
+		  double x = arg_x.double_value ();
+
+		  if (! error_state)
+		    retval = map_m_d (atan2, y, x);
+		}
 	    }
-	}
-      else if (y_nr == x_nr && y_nc == x_nc)
-	{
-	  Matrix y = arg_y.matrix_value ();
-
-	  if (! error_state)
+	  else if (y_nr == x_nr && y_nc == x_nc)
 	    {
-	      Matrix x = arg_x.matrix_value ();
+	      Matrix y = arg_y.matrix_value ();
 
 	      if (! error_state)
-		retval = map_m_m (atan2, y, x);
+		{
+		  Matrix x = arg_x.matrix_value ();
+
+		  if (! error_state)
+		    retval = map_m_m (atan2, y, x);
+		}
 	    }
+	  else
+	    error ("atan2: nonconformant matrices");
 	}
-      else
-	error ("atan2: nonconformant matrices");
     }
   else
     print_usage ();