[PATCH] Expose min/max NaN options to interpreter (3/4)

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[PATCH] Expose min/max NaN options to interpreter (3/4)

Edward Jason Riedy
This is a massive overhaul of src/DLD-FUNCTIONS/minmax.cc.  It's
slightly cpp-happy.  The only advantage to a template-based
solution with a similar structure to the current code would be
cc-mode-friendliness.  It could be re-worked to use a dispatch
system similar to the operators', but that would be a good deal
of work.

Jason

src/ChangeLog
        * DLD-FUNCTIONS/minmax.cc (SM_COMP): Macro added to define scalar-
        matrix comparisons.
        (MS_COMP): Same for matrix-scalar.
        (MM_COMP): Same for matrix-matrix.
        (min): All helper definitions replaced by calls to the above macros.
        (max): Ditto.
        (MINMAX_DISPATCH): Macro to give both DEFUN_DLD (min, ...) and
        DEFUN_DLD (max, ...) the same bodies.
        (interpreter's min): Body replaced by call to MINMAX_DISPATCH (min).
        (interpreter's max): Equivalent change.

--- octave.orig/src/DLD-FUNCTIONS/minmax.cc Tue Apr 11 12:02:05 2000
+++ octave.2/src/DLD-FUNCTIONS/minmax.cc Sun Sep  3 16:43:49 2000
@@ -34,244 +34,388 @@
 #include "gripes.h"
 #include "oct-obj.h"
 
-// XXX FIXME XXX -- it would be nice to share code among the min/max
-// functions below.
-
-static Matrix
-min (double d, const Matrix& m)
-{
-  int nr = m.rows ();
-  int nc = m.columns ();
-
-  Matrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    for (int i = 0; i < nr; i++)
-      result (i, j) = xmin (d, m (i, j));
-
-  return result;
-}
-
-static Matrix
-min (const Matrix& m, double d)
-{
-  int nr = m.rows ();
-  int nc = m.columns ();
-
-  Matrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    for (int i = 0; i < nr; i++)
-      result (i, j) = xmin (m (i, j), d);
-
-  return result;
-}
-
-static ComplexMatrix
-min (const Complex& c, const ComplexMatrix& m)
-{
-  int nr = m.rows ();
-  int nc = m.columns ();
-
-  ComplexMatrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    for (int i = 0; i < nr; i++)
-      result (i, j) = xmin (c, m (i, j));
-
-  return result;
-}
-
-static ComplexMatrix
-min (const ComplexMatrix& m, const Complex& c)
-{
-  int nr = m.rows ();
-  int nc = m.columns ();
-
-  ComplexMatrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    for (int i = 0; i < nr; i++)
-      result (i, j) = xmin (m (i, j), c);
-
-  return result;
-}
-
-static Matrix
-min (const Matrix& a, const Matrix& b)
-{
-  int nr = a.rows ();
-  int nc = a.columns ();
-  if (nr != b.rows () || nc != b.columns ())
-    {
-      error ("two-arg min expecting args of same size");
-      return Matrix ();
-    }
-
-  Matrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    for (int i = 0; i < nr; i++)
-      result (i, j) = xmin (a (i, j), b (i, j));
-
-  return result;
-}
-
-static ComplexMatrix
-min (const ComplexMatrix& a, const ComplexMatrix& b)
-{
-  int nr = a.rows ();
-  int nc = a.columns ();
-  if (nr != b.rows () || nc != b.columns ())
-    {
-      error ("two-arg min expecting args of same size");
-      return ComplexMatrix ();
-    }
-
-  ComplexMatrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    {
-      int columns_are_real_only = 1;
-      for (int i = 0; i < nr; i++)
- if (imag (a (i, j)) != 0.0 || imag (b (i, j)) != 0.0)
-  {
-    columns_are_real_only = 0;
-    break;
-  }
-
-      if (columns_are_real_only)
- {
-  for (int i = 0; i < nr; i++)
-    result (i, j) = xmin (real (a (i, j)), real (b (i, j)));
- }
-      else
- {
-  for (int i = 0; i < nr; i++)
-    result (i, j) = xmin (a (i, j), b (i, j));
- }
-    }
-
-  return result;
-}
-
-static Matrix
-max (double d, const Matrix& m)
-{
-  int nr = m.rows ();
-  int nc = m.columns ();
-
-  Matrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    for (int i = 0; i < nr; i++)
-      result (i, j) = xmax (d, m (i, j));
-
-  return result;
-}
-
-static Matrix
-max (const Matrix& m, double d)
-{
-  int nr = m.rows ();
-  int nc = m.columns ();
-
-  Matrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    for (int i = 0; i < nr; i++)
-      result (i, j) = xmax (m (i, j), d);
-
-  return result;
-}
-
-static ComplexMatrix
-max (const Complex& c, const ComplexMatrix& m)
-{
-  int nr = m.rows ();
-  int nc = m.columns ();
-
-  ComplexMatrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    for (int i = 0; i < nr; i++)
-      result (i, j) = xmax (c, m (i, j));
-
-  return result;
-}
-
-static ComplexMatrix
-max (const ComplexMatrix& m, const Complex& c)
-{
-  int nr = m.rows ();
-  int nc = m.columns ();
-
-  ComplexMatrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    for (int i = 0; i < nr; i++)
-      result (i, j) = xmax (m (i, j), c);
-
-  return result;
-}
-
-static Matrix
-max (const Matrix& a, const Matrix& b)
-{
-  int nr = a.rows ();
-  int nc = a.columns ();
-  if (nr != b.rows () || nc != b.columns ())
-    {
-      error ("two-arg max expecting args of same size");
-      return Matrix ();
-    }
-
-  Matrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    for (int i = 0; i < nr; i++)
-      result (i, j) = xmax (a (i, j), b (i, j));
-
-  return result;
-}
-
-static ComplexMatrix
-max (const ComplexMatrix& a, const ComplexMatrix& b)
-{
-  int nr = a.rows ();
-  int nc = a.columns ();
-  if (nr != b.rows () || nc != b.columns ())
-    {
-      error ("two-arg max expecting args of same size");
-      return ComplexMatrix ();
-    }
-
-  ComplexMatrix result (nr, nc);
-
-  for (int j = 0; j < nc; j++)
-    {
-      int columns_are_real_only = 1;
-      for (int i = 0; i < nr; i++)
- if (imag (a (i, j)) != 0.0 || imag (b (i, j)) != 0.0)
-  {
-    columns_are_real_only = 0;
-    break;
-  }
-
-      if (columns_are_real_only)
- {
-  for (int i = 0; i < nr; i++)
-    result (i, j) = xmax (real (a (i, j)), real (b (i, j)));
- }
-      else
- {
-  for (int i = 0; i < nr; i++)
-    result (i, j) = xmax (a (i, j), b (i, j));
- }
-    }
-
-  return result;
-}
+/*
+  XXX:  Re-write each of the XX_COMP macros to define a member
+  function within an Op class, e.g.
+    struct Min
+    {
+      SM_COMP(double, ComplexMatrix, Min)
+      ...
+    };
+  would produce
+    struct Min
+    {
+      static void apply (const double d, const ComplexMatrix& m, ...)
+      {
+        ...
+      }
+      ...
+    };
+  
+  Then change the MINMAX_DISPATCH macro to a template class.
+  Instantiate it once with each struct.  Then the dispatch
+  routines just call the appropriate template class.
+
+  That's the more C++-ish way to avoid macros, and it's probably
+  more debugger- friendly.  You could also restructure everything
+  to fit a framework like the operators one level up (see
+  ../ov-typeinfo.h and ../ops.h).  However, these are meant to be
+  dynamically loadable, and that framework relies on static
+  initialization.  The two don't play nice on most current (Aug
+  2000) systems.  It also will begin to resemble an unoptimized
+  subset of Common Lisp, but that's another story.
+*/
+
+// Scalar-matrix comparisons
+
+/*
+   Note that a good optimizer should hoist the ignore_nan tests out of the
+   loop.
+*/
+
+#define SM_COMP(ScalarType, MatrixType, Op)             \
+static MatrixType                                       \
+Op (const ScalarType d, const MatrixType& m,            \
+    const bool ignore_nan = OCTAVE_IGNORE_NAN_DEFAULT)  \
+{                                                       \
+  const int nr = m.rows ();                             \
+  const int nc = m.columns ();                          \
+                                                        \
+  MatrixType result (nr, nc);                           \
+                                                        \
+  for (int j = 0; j < nc; j++)                          \
+    for (int i = 0; i < nr; i++)                        \
+      if (ignore_nan)                                   \
+        result (i, j) = x ## Op (d, m (i, j));          \
+      else                                              \
+        result (i, j) = x ## Op ## _nan (d, m (i, j));  \
+                                                        \
+  return result;                                        \
+}
+
+SM_COMP(double, Matrix, min)
+SM_COMP(double, Matrix, max)
+
+SM_COMP(Complex, ComplexMatrix, min)
+SM_COMP(Complex, ComplexMatrix, max)
+
+#undef SM_COMP
+
+// Matrix-scalar comparisons
+    
+#define MS_COMP(ScalarType, MatrixType, Op)             \
+static MatrixType                                       \
+Op (const MatrixType& m, const ScalarType d,            \
+    const bool ignore_nan = OCTAVE_IGNORE_NAN_DEFAULT)  \
+{                                                       \
+  const int nr = m.rows ();                             \
+  const int nc = m.columns ();                          \
+                                                        \
+  MatrixType result (nr, nc);                           \
+                                                        \
+  for (int j = 0; j < nc; j++)                          \
+    for (int i = 0; i < nr; i++)                        \
+      if (ignore_nan)                                   \
+        result (i, j) = x ## Op (m (i, j), d);          \
+      else                                              \
+        result (i, j) = x ## Op ## _nan (m (i, j), d);  \
+                                                        \
+  return result;                                        \
+}
+
+MS_COMP(double, Matrix, min)
+MS_COMP(double, Matrix, max)
+
+MS_COMP(Complex, ComplexMatrix, min)
+MS_COMP(Complex, ComplexMatrix, max)
+
+#undef MS_COMP
+
+// Matrix-matrix comparisons
+    
+#define MM_COMP(Op, MatType)                                    \
+static MatType                                                  \
+Op (const MatType& a, const MatType& b,                         \
+    const bool ignore_nan = OCTAVE_IGNORE_NAN_DEFAULT)          \
+{                                                               \
+  const int nr = a.rows();                                      \
+  int nc = a.columns ();                                        \
+  if (nr != b.rows () || nc != b.columns ())                    \
+    {                                                           \
+      error ("two-arg min expecting args of same size");        \
+      return MatType ();                                        \
+    }                                                           \
+                                                                \
+  MatType result (nr, nc);                                      \
+                                                                \
+  for (int j = 0; j < nc; j++)                                  \
+    for (int i = 0; i < nr; i++)                                \
+      if (ignore_nan)                                           \
+        result (i, j) = x ## Op (a (i, j), b (i, j));           \
+      else                                                      \
+        result (i, j) = x ## Op ## _nan (a (i, j), b (i, j));   \
+                                                                \
+  return result;                                                \
+}
+
+MM_COMP(min, Matrix)
+MM_COMP(max, Matrix)
+
+MM_COMP(min, ComplexMatrix)
+MM_COMP(max, ComplexMatrix)
+
+#undef MM_COMP
+
+// interpreter routines
+    
+#define MINMAX_DISPATCH(op) do                                  \
+{                                                               \
+  octave_value_list retval;                                     \
+                                                                \
+  int nargin = args.length ();                                  \
+  int noptargin = 0;                                            \
+                                                                \
+  /* Find the optional args at the end of the list */           \
+  while (nargin > 0)                                            \
+    {                                                           \
+      if (args(nargin-1).is_numeric_type())                     \
+        break;                                                  \
+      --nargin;                                                 \
+      ++noptargin;                                              \
+    }                                                           \
+                                                                \
+  if (nargin < 1 || nargin > 2 || nargout > 2 || noptargin > 1) \
+    {                                                           \
+      print_usage (#op);                                        \
+      return retval;                                            \
+    }                                                           \
+                                                                \
+  bool ignore_nan = OCTAVE_IGNORE_NAN_DEFAULT;                  \
+                                                                \
+  if (noptargin)                                                \
+    {                                                           \
+      /* nargin is the index of the single optarg */            \
+                                                                \
+      const std::string optarg = args(nargin).string_value();   \
+      bool valid_option = false;                                \
+      if (optarg == "ignore-nan")                               \
+    {                                                       \
+          valid_option = true;                                  \
+          ignore_nan = true;                                    \
+        }                                                       \
+      if (optarg == "prefer-nan")                               \
+        {                                                       \
+          valid_option = true;                                  \
+      ignore_nan = false;                                   \
+        }                                                       \
+                                                                \
+      if (!valid_option)                                        \
+        {                                                       \
+      print_usage ("min");                                  \
+          return retval;                                        \
+        }                                                       \
+    }                                                           \
+                                                                \
+  octave_value arg1;                                            \
+  octave_value arg2;                                            \
+                                                                \
+  switch (nargin)                                               \
+    {                                                           \
+    case 2:                                                     \
+      arg2 = args(1);                                           \
+      /* Fall through... */                                     \
+                                                                \
+    case 1:                                                     \
+      arg1 = args(0);                                           \
+      break;                                                    \
+                                                                \
+    default:                                                    \
+      panic_impossible ();                                      \
+      break;                                                    \
+    }                                                           \
+                                                                \
+  if (nargin == 1 && (nargout == 1 || nargout == 0))            \
+    {                                                           \
+      if (arg1.is_real_type ())                                 \
+ {                                                           \
+  Matrix m = arg1.matrix_value ();                          \
+                                                                \
+  if (! error_state)                                        \
+    {                                                       \
+      if (m.rows () == 1)                                   \
+ retval(0) = m.row_##op (ignore_nan);                    \
+      else                                                  \
+ retval(0) = m.column_##op (ignore_nan);                 \
+    }                                                       \
+ }                                                           \
+      else if (arg1.is_complex_type ())                         \
+ {                                                           \
+  ComplexMatrix m = arg1.complex_matrix_value ();           \
+                                                                \
+  if (! error_state)                                        \
+    {                                                       \
+      if (m.rows () == 1)                                   \
+ retval(0) = m.row_##op (ignore_nan);                    \
+      else                                                  \
+ retval(0) = m.column_##op (ignore_nan);                 \
+    }                                                       \
+ }                                                           \
+      else                                                      \
+ gripe_wrong_type_arg (#op, arg1);                           \
+    }                                                           \
+  else if (nargin == 1 && nargout == 2)                         \
+    {                                                           \
+      Array<int> index;                                         \
+                                                                \
+      if (arg1.is_real_type ())                                 \
+ {                                                           \
+  Matrix m = arg1.matrix_value ();                          \
+                                                                \
+  if (! error_state)                                        \
+    {                                                       \
+      retval.resize (2);                                    \
+                                                                \
+      if (m.rows () == 1)                                   \
+ retval(0) = m.row_##op (index, ignore_nan);             \
+      else                                                  \
+ retval(0) = m.column_##op (index, ignore_nan);          \
+    }                                                       \
+ }                                                           \
+      else if (arg1.is_complex_type ())                         \
+ {                                                           \
+  ComplexMatrix m = arg1.complex_matrix_value ();           \
+                                                                \
+  if (! error_state)                                        \
+    {                                                       \
+      retval.resize (2);                                    \
+                                                                \
+      if (m.rows () == 1)                                   \
+ retval(0) = m.row_##op (index, ignore_nan);             \
+      else                                                  \
+ retval(0) = m.column_##op (index, ignore_nan);          \
+    }                                                       \
+ }                                                           \
+      else                                                      \
+ gripe_wrong_type_arg (#op, arg1);                           \
+                                                                \
+      int len = index.length ();                                \
+                                                                \
+      if (len > 0)                                              \
+ {                                                           \
+  RowVector idx (len);                                      \
+                                                                \
+  for (int i = 0; i < len; i++)                             \
+    {                                                       \
+      int tmp = index.elem (i) + 1;                         \
+      idx.elem (i) = (tmp <= 0)                             \
+ ? octave_NaN : static_cast<double> (tmp);               \
+    }                                                       \
+                                                                \
+  retval(1) = idx;                                          \
+ }                                                           \
+    }                                                           \
+  else if (nargin == 2)                                         \
+    {                                                           \
+      int arg1_is_scalar = arg1.is_scalar_type ();              \
+      int arg2_is_scalar = arg2.is_scalar_type ();              \
+                                                                \
+      int arg1_is_complex = arg1.is_complex_type ();            \
+      int arg2_is_complex = arg2.is_complex_type ();            \
+                                                                \
+      if (arg1_is_scalar)                                       \
+ {                                                           \
+  if (arg1_is_complex || arg2_is_complex)                   \
+    {                                                       \
+      Complex c1 = arg1.complex_value ();                   \
+      ComplexMatrix m2 = arg2.complex_matrix_value ();      \
+      if (! error_state)                                    \
+ {                                                       \
+  ComplexMatrix result = op (c1, m2, ignore_nan);       \
+  if (! error_state)                                    \
+    retval(0) = result;                                 \
+ }                                                       \
+    }                                                       \
+  else                                                      \
+    {                                                       \
+      double d1 = arg1.double_value ();                     \
+      Matrix m2 = arg2.matrix_value ();                     \
+                                                                \
+      if (! error_state)                                    \
+ {                                                       \
+  Matrix result = op (d1, m2, ignore_nan);              \
+  if (! error_state)                                    \
+    retval(0) = result;                                 \
+ }                                                       \
+    }                                                       \
+ }                                                           \
+      else if (arg2_is_scalar)                                  \
+ {                                                           \
+  if (arg1_is_complex || arg2_is_complex)                   \
+    {                                                       \
+      ComplexMatrix m1 = arg1.complex_matrix_value ();      \
+                                                                \
+      if (! error_state)                                    \
+ {                                                       \
+  Complex c2 = arg2.complex_value ();                   \
+  ComplexMatrix result = op (m1, c2, ignore_nan);       \
+  if (! error_state)                                    \
+    retval(0) = result;                                 \
+ }                                                       \
+    }                                                       \
+  else                                                      \
+    {                                                       \
+      Matrix m1 = arg1.matrix_value ();                     \
+                                                                \
+      if (! error_state)                                    \
+ {                                                       \
+  double d2 = arg2.double_value ();                     \
+  Matrix result = op (m1, d2, ignore_nan);              \
+  if (! error_state)                                    \
+    retval(0) = result;                                 \
+ }                                                       \
+    }                                                       \
+ }                                                           \
+      else                                                      \
+ {                                                           \
+  if (arg1_is_complex || arg2_is_complex)                   \
+    {                                                       \
+      ComplexMatrix m1 = arg1.complex_matrix_value ();      \
+                                                                \
+      if (! error_state)                                    \
+ {                                                       \
+  ComplexMatrix m2 = arg2.complex_matrix_value ();      \
+                                                                \
+  if (! error_state)                                    \
+    {                                                   \
+      ComplexMatrix result = op (m1, m2, ignore_nan);   \
+      if (! error_state)                                \
+ retval(0) = result;                                 \
+    }                                                   \
+ }                                                       \
+    }                                                       \
+  else                                                      \
+    {                                                       \
+      Matrix m1 = arg1.matrix_value ();                     \
+                                                                \
+      if (! error_state)                                    \
+ {                                                       \
+  Matrix m2 = arg2.matrix_value ();                     \
+                                                                \
+  if (! error_state)                                    \
+    {                                                   \
+      Matrix result = op (m1, m2, ignore_nan);          \
+      if (! error_state)                                \
+ retval(0) = result;                                 \
+    }                                                   \
+ }                                                       \
+    }                                                       \
+ }                                                           \
+    }                                                           \
+  else                                                          \
+    panic_impossible ();                                        \
+                                                                \
+  return retval;                                                \
+} while (0)
 
 DEFUN_DLD (min, args, nargout,
   "-*- texinfo -*-\n\
@@ -287,7 +431,9 @@
 returns the smallest element of @var{x}.\n\
 \n\
 For complex arguments, the magnitude of the elements are used for\n\
-comparison.\n\
+comparison.  NaNs are ignored if possible unless an optional argument\n\
+of 'prefer-nan' is supplied.  The argument can also be 'ignore-nan'\n\
+to make the default behavior explicit.\n\
 \n\
 If called with two output arguments, also returns the index of the\n\
 minimum value(s). Thus,\n\
@@ -298,215 +444,7 @@
 @noindent\n\
 returns @var{x} = 0 and @var{ix} = 3.")
 {
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin < 1 || nargin > 2 || nargout > 2)
-    {
-      print_usage ("min");
-      return retval;
-    }
-
-  octave_value arg1;
-  octave_value arg2;
-
-  switch (nargin)
-    {
-    case 2:
-      arg2 = args(1);
-      // Fall through...
-
-    case 1:
-      arg1 = args(0);
-      break;
-
-    default:
-      panic_impossible ();
-      break;
-    }
-
-  if (nargin == 1 && (nargout == 1 || nargout == 0))
-    {
-      if (arg1.is_real_type ())
- {
-  Matrix m = arg1.matrix_value ();
-
-  if (! error_state)
-    {
-      if (m.rows () == 1)
- retval(0) = m.row_min ();
-      else
- retval(0) = m.column_min ();
-    }
- }
-      else if (arg1.is_complex_type ())
- {
-  ComplexMatrix m = arg1.complex_matrix_value ();
-
-  if (! error_state)
-    {
-      if (m.rows () == 1)
- retval(0) = m.row_min ();
-      else
- retval(0) = m.column_min ();
-    }
- }
-      else
- gripe_wrong_type_arg ("min", arg1);
-    }
-  else if (nargin == 1 && nargout == 2)
-    {
-      Array<int> index;
-
-      if (arg1.is_real_type ())
- {
-  Matrix m = arg1.matrix_value ();
-
-  if (! error_state)
-    {
-      retval.resize (2);
-
-      if (m.rows () == 1)
- retval(0) = m.row_min (index);
-      else
- retval(0) = m.column_min (index);
-    }
- }
-      else if (arg1.is_complex_type ())
- {
-  ComplexMatrix m = arg1.complex_matrix_value ();
-
-  if (! error_state)
-    {
-      retval.resize (2);
-
-      if (m.rows () == 1)
- retval(0) = m.row_min (index);
-      else
- retval(0) = m.column_min (index);
-    }
- }
-      else
- gripe_wrong_type_arg ("min", arg1);
-
-      int len = index.length ();
-
-      if (len > 0)
- {
-  RowVector idx (len);
-
-  for (int i = 0; i < len; i++)
-    {
-      int tmp = index.elem (i) + 1;
-      idx.elem (i) = (tmp <= 0)
- ? octave_NaN : static_cast<double> (tmp);
-    }
-
-  retval(1) = idx;
- }
-    }
-  else if (nargin == 2)
-    {
-      int arg1_is_scalar = arg1.is_scalar_type ();
-      int arg2_is_scalar = arg2.is_scalar_type ();
-
-      int arg1_is_complex = arg1.is_complex_type ();
-      int arg2_is_complex = arg2.is_complex_type ();
-
-      if (arg1_is_scalar)
- {
-  if (arg1_is_complex || arg2_is_complex)
-    {
-      Complex c1 = arg1.complex_value ();
-      ComplexMatrix m2 = arg2.complex_matrix_value ();
-      if (! error_state)
- {
-  ComplexMatrix result = min (c1, m2);
-  if (! error_state)
-    retval(0) = result;
- }
-    }
-  else
-    {
-      double d1 = arg1.double_value ();
-      Matrix m2 = arg2.matrix_value ();
-
-      if (! error_state)
- {
-  Matrix result = min (d1, m2);
-  if (! error_state)
-    retval(0) = result;
- }
-    }
- }
-      else if (arg2_is_scalar)
- {
-  if (arg1_is_complex || arg2_is_complex)
-    {
-      ComplexMatrix m1 = arg1.complex_matrix_value ();
-
-      if (! error_state)
- {
-  Complex c2 = arg2.complex_value ();
-  ComplexMatrix result = min (m1, c2);
-  if (! error_state)
-    retval(0) = result;
- }
-    }
-  else
-    {
-      Matrix m1 = arg1.matrix_value ();
-
-      if (! error_state)
- {
-  double d2 = arg2.double_value ();
-  Matrix result = min (m1, d2);
-  if (! error_state)
-    retval(0) = result;
- }
-    }
- }
-      else
- {
-  if (arg1_is_complex || arg2_is_complex)
-    {
-      ComplexMatrix m1 = arg1.complex_matrix_value ();
-
-      if (! error_state)
- {
-  ComplexMatrix m2 = arg2.complex_matrix_value ();
-
-  if (! error_state)
-    {
-      ComplexMatrix result = min (m1, m2);
-      if (! error_state)
- retval(0) = result;
-    }
- }
-    }
-  else
-    {
-      Matrix m1 = arg1.matrix_value ();
-
-      if (! error_state)
- {
-  Matrix m2 = arg2.matrix_value ();
-
-  if (! error_state)
-    {
-      Matrix result = min (m1, m2);
-      if (! error_state)
- retval(0) = result;
-    }
- }
-    }
- }
-    }
-  else
-    panic_impossible ();
-
-  return retval;
+  MINMAX_DISPATCH (min);
 }
 
 DEFUN_DLD (max, args, nargout,
@@ -523,7 +461,9 @@
 returns the largest element of @var{x}.\n\
 \n\
 For complex arguments, the magnitude of the elements are used for\n\
-comparison.
+comparison.  NaNs are ignored if possible unless an optional argument\n\
+of 'prefer-nan' is supplied.  The argument can also be 'ignore-nan'\n\
+to make the default behavior explicit.\n\
 \n\
 If called with two output arguments, also returns the index of the\n\
 maximum value(s). Thus,\n\
@@ -534,215 +474,7 @@
 @noindent\n\
 returns @var{x} = 5 and @var{ix} = 3.")
 {
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin < 1 || nargin > 2 || nargout > 2)
-    {
-      print_usage ("max");
-      return retval;
-    }
-
-  octave_value arg1;
-  octave_value arg2;
-
-  switch (nargin)
-    {
-    case 2:
-      arg2 = args(1);
-      // Fall through...
-
-    case 1:
-      arg1 = args(0);
-      break;
-
-    default:
-      panic_impossible ();
-      break;
-    }
-
-  if (nargin == 1 && (nargout == 1 || nargout == 0))
-    {
-      if (arg1.is_real_type ())
- {
-  Matrix m = arg1.matrix_value ();
-
-  if (! error_state)
-    {
-      if (m.rows () == 1)
- retval(0) = m.row_max ();
-      else
- retval(0) = m.column_max ();
-    }
- }
-      else if (arg1.is_complex_type ())
- {
-  ComplexMatrix m = arg1.complex_matrix_value ();
-
-  if (! error_state)
-    {
-      if (m.rows () == 1)
- retval(0) = m.row_max ();
-      else
- retval(0) = m.column_max ();
-    }
- }
-      else
- gripe_wrong_type_arg ("max", arg1);
-    }
-  else if (nargin == 1 && nargout == 2)
-    {
-      Array<int> index;
-
-      if (arg1.is_real_type ())
- {
-  Matrix m = arg1.matrix_value ();
-
-  if (! error_state)
-    {
-      retval.resize (2);
-
-      if (m.rows () == 1)
- retval(0) = m.row_max (index);
-      else
- retval(0) = m.column_max (index);
-    }
- }
-      else if (arg1.is_complex_type ())
- {
-  ComplexMatrix m = arg1.complex_matrix_value ();
-
-  if (! error_state)
-    {
-      retval.resize (2);
-
-      if (m.rows () == 1)
- retval(0) = m.row_max (index);
-      else
- retval(0) = m.column_max (index);
-    }
- }
-      else
- gripe_wrong_type_arg ("max", arg1);
-
-      int len = index.length ();
-
-      if (len > 0)
- {
-  RowVector idx (len);
-
-  for (int i = 0; i < len; i++)
-    {
-      int tmp = index.elem (i) + 1;
-      idx.elem (i) = (tmp <= 0)
- ? octave_NaN : static_cast<double> (tmp);
-    }
-
-  retval(1) = idx;
- }
-    }
-  else if (nargin == 2)
-    {
-      int arg1_is_scalar = arg1.is_scalar_type ();
-      int arg2_is_scalar = arg2.is_scalar_type ();
-
-      int arg1_is_complex = arg1.is_complex_type ();
-      int arg2_is_complex = arg2.is_complex_type ();
-
-      if (arg1_is_scalar)
- {
-  if (arg1_is_complex || arg2_is_complex)
-    {
-      Complex c1 = arg1.complex_value ();
-      ComplexMatrix m2 = arg2.complex_matrix_value ();
-      if (! error_state)
- {
-  ComplexMatrix result = max (c1, m2);
-  if (! error_state)
-    retval(0) = result;
- }
-    }
-  else
-    {
-      double d1 = arg1.double_value ();
-      Matrix m2 = arg2.matrix_value ();
-
-      if (! error_state)
- {
-  Matrix result = max (d1, m2);
-  if (! error_state)
-    retval(0) = result;
- }
-    }
- }
-      else if (arg2_is_scalar)
- {
-  if (arg1_is_complex || arg2_is_complex)
-    {
-      ComplexMatrix m1 = arg1.complex_matrix_value ();
-
-      if (! error_state)
- {
-  Complex c2 = arg2.complex_value ();
-  ComplexMatrix result = max (m1, c2);
-  if (! error_state)
-    retval(0) = result;
- }
-    }
-  else
-    {
-      Matrix m1 = arg1.matrix_value ();
-
-      if (! error_state)
- {
-  double d2 = arg2.double_value ();
-  Matrix result = max (m1, d2);
-  if (! error_state)
-    retval(0) = result;
- }
-    }
- }
-      else
- {
-  if (arg1_is_complex || arg2_is_complex)
-    {
-      ComplexMatrix m1 = arg1.complex_matrix_value ();
-
-      if (! error_state)
- {
-  ComplexMatrix m2 = arg2.complex_matrix_value ();
-
-  if (! error_state)
-    {
-      ComplexMatrix result = max (m1, m2);
-      if (! error_state)
- retval(0) = result;
-    }
- }
-    }
-  else
-    {
-      Matrix m1 = arg1.matrix_value ();
-
-      if (! error_state)
- {
-  Matrix m2 = arg2.matrix_value ();
-
-  if (! error_state)
-    {
-      Matrix result = max (m1, m2);
-      if (! error_state)
- retval(0) = result;
-    }
- }
-    }
- }
-    }
-  else
-    panic_impossible ();
-
-  return retval;
+  MINMAX_DISPATCH (max);
 }
 
 /*