changeset 7922:935be827eaf8

error for NaN values in & and | expressions
author John W. Eaton <jwe@octave.org>
date Fri, 11 Jul 2008 14:56:30 -0400
parents fcc70f30fe31
children c3d21b9b94b6
files liboctave/Array-util.cc liboctave/Array-util.h liboctave/CMatrix.cc liboctave/CMatrix.h liboctave/CNDArray.cc liboctave/CNDArray.h liboctave/CSparse.cc liboctave/CSparse.h liboctave/ChangeLog liboctave/dMatrix.cc liboctave/dMatrix.h liboctave/dNDArray.cc liboctave/dNDArray.h liboctave/dSparse.cc liboctave/dSparse.h liboctave/fCMatrix.cc liboctave/fCMatrix.h liboctave/fCNDArray.cc liboctave/fCNDArray.h liboctave/fMatrix.cc liboctave/fMatrix.h liboctave/fNDArray.cc liboctave/fNDArray.h liboctave/lo-mappers.h liboctave/mx-op-defs.h liboctave/oct-inttypes.h scripts/general/logical.m src/ChangeLog src/OPERATORS/op-fs-fs.cc src/OPERATORS/op-s-s.cc src/ops.h src/ov-float.h src/ov-flt-re-mat.cc src/ov-range.h src/ov-re-mat.cc src/ov-re-sparse.cc src/ov-scalar.h
diffstat 37 files changed, 322 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/Array-util.cc
+++ b/liboctave/Array-util.cc
@@ -480,6 +480,11 @@
   return pva->pidx > pvb->pidx;
 }
 
+void
+gripe_nan_to_logical_conversion (void)
+{
+  (*current_liboctave_error_handler) ("invalid conversion of NaN to logical");
+}
 
 void
 gripe_nonconformant (const char *op, int op1_len, int op2_len)
--- a/liboctave/Array-util.h
+++ b/liboctave/Array-util.h
@@ -89,6 +89,8 @@
 
 extern int OCTAVE_API permute_vector_compare (const void *a, const void *b);
 
+extern void OCTAVE_API gripe_nan_to_logical_conversion (void);
+
 extern void OCTAVE_API gripe_nonconformant (const char *op, int op1_len, int op2_len);
 
 extern void OCTAVE_API gripe_nonconformant (const char *op, int op1_nr, int op1_nc,
--- a/liboctave/CMatrix.cc
+++ b/liboctave/CMatrix.cc
@@ -3302,6 +3302,23 @@
 }
 
 bool
+ComplexMatrix::any_element_is_nan (void) const
+{
+  octave_idx_type nr = rows ();
+  octave_idx_type nc = cols ();
+
+  for (octave_idx_type j = 0; j < nc; j++)
+    for (octave_idx_type i = 0; i < nr; i++)
+      {
+	Complex val = elem (i, j);
+	if (xisnan (val))
+	  return true;
+      }
+
+  return false;
+}
+
+bool
 ComplexMatrix::any_element_is_inf_or_nan (void) const
 {
   octave_idx_type nr = rows ();
--- a/liboctave/CMatrix.h
+++ b/liboctave/CMatrix.h
@@ -327,6 +327,7 @@
   ComplexMatrix map (cmapper fcn) const;
   boolMatrix map (bmapper fcn) const;
 
+  bool any_element_is_nan (void) const;
   bool any_element_is_inf_or_nan (void) const;
   bool all_elements_are_real (void) const;
   bool all_integers (double& max_val, double& min_val) const;
--- a/liboctave/CNDArray.cc
+++ b/liboctave/CNDArray.cc
@@ -497,6 +497,20 @@
 // FIXME -- this is not quite the right thing.
 
 bool
+ComplexNDArray::any_element_is_nan (void) const
+{
+  octave_idx_type nel = nelem ();
+
+  for (octave_idx_type i = 0; i < nel; i++)
+    {
+      Complex val = elem (i);
+      if (xisnan (val))
+	return true;
+    }
+  return false;
+}
+
+bool
 ComplexNDArray::any_element_is_inf_or_nan (void) const
 {
   octave_idx_type nel = nelem ();
--- a/liboctave/CNDArray.h
+++ b/liboctave/CNDArray.h
@@ -64,6 +64,7 @@
 
   // FIXME -- this is not quite the right thing.
 
+  bool any_element_is_nan (void) const;
   bool any_element_is_inf_or_nan (void) const;
   bool all_elements_are_real (void) const;
   bool all_integers (double& max_val, double& min_val) const;
--- a/liboctave/CSparse.cc
+++ b/liboctave/CSparse.cc
@@ -7179,6 +7179,21 @@
 // other operations
 
 bool
+SparseComplexMatrix::any_element_is_nan (void) const
+{
+  octave_idx_type nel = nnz ();
+
+  for (octave_idx_type i = 0; i < nel; i++)
+    {
+      Complex val = data (i);
+      if (xisnan (val))
+	return true;
+    }
+
+  return false;
+}
+
+bool
 SparseComplexMatrix::any_element_is_inf_or_nan (void) const
 {
   octave_idx_type nel = nnz ();
--- a/liboctave/CSparse.h
+++ b/liboctave/CSparse.h
@@ -402,6 +402,7 @@
 
   SparseComplexMatrix ipermute (const Array<octave_idx_type>& vec) const;
 
+  bool any_element_is_nan (void) const;
   bool any_element_is_inf_or_nan (void) const;
   bool all_elements_are_real (void) const;
   bool all_integers (double& max_val, double& min_val) const;
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,3 +1,19 @@
+2008-07-11  John W. Eaton  <jwe@octave.org>
+
+	* mx-op-defs.h (MS_BOOL_OP, SM_BOOL_OP, MM_BOOL_OP, NDS_BOOL_OP,
+	SND_BOOL_OP, NDND_BOOL_OP): Detect NaN values.
+	* Array-util.cc (gripe_nan_to_logical_conversion): New function.
+	* Array-util.h: Provide decl.
+	* oct-inttypes.h (xisnan (octave_int<T>)): New function.
+	* lo-mappers.h (xisnan (bool), xisnan (char)): New inline functions.
+
+	* CMatrix.cc, CNDArray.cc, CSparse.cc, dMatrix.cc, dNDArray.cc,
+	dSparse.cc, fCMatrix.cc, fCNDArray.cc, fMatrix.cc, fNDArray.cc:
+	New member function, any_element_is_nan.
+	* CMatrix.h, CNDArray.h, CSparse.h, dMatrix.h, dNDArray.h,
+	dSparse.h, fCMatrix.h, fCNDArray.h, fMatrix.h, fNDArray.h:
+	Provide decl.
+
 2008-07-10  David Bateman  <dbateman@free.fr>
 
 	* dNDArray.cc (NDArray::NDArray (const Array<octave_idx_type>&,
--- a/liboctave/dMatrix.cc
+++ b/liboctave/dMatrix.cc
@@ -2849,6 +2849,20 @@
   return false;
 }
 
+bool
+Matrix::any_element_is_nan (void) const
+{
+  octave_idx_type nel = nelem ();
+
+  for (octave_idx_type i = 0; i < nel; i++)
+    {
+      double val = elem (i);
+      if (xisnan (val))
+	return true;
+    }
+
+  return false;
+}
 
 bool
 Matrix::any_element_is_inf_or_nan (void) const
--- a/liboctave/dMatrix.h
+++ b/liboctave/dMatrix.h
@@ -282,6 +282,7 @@
   boolMatrix map (bmapper fcn) const;
 
   bool any_element_is_negative (bool = false) const;
+  bool any_element_is_nan (void) const;
   bool any_element_is_inf_or_nan (void) const;
   bool any_element_not_one_or_zero (void) const;
   bool all_elements_are_int_or_inf_or_nan (void) const;
--- a/liboctave/dNDArray.cc
+++ b/liboctave/dNDArray.cc
@@ -556,6 +556,20 @@
   return false;
 }
 
+bool
+NDArray::any_element_is_nan (void) const
+{
+  octave_idx_type nel = nelem ();
+
+  for (octave_idx_type i = 0; i < nel; i++)
+    {
+      double val = elem (i);
+      if (xisnan (val))
+	return true;
+    }
+
+  return false;
+}
 
 bool
 NDArray::any_element_is_inf_or_nan (void) const
--- a/liboctave/dNDArray.h
+++ b/liboctave/dNDArray.h
@@ -70,6 +70,7 @@
   boolNDArray operator ! (void) const;
 
   bool any_element_is_negative (bool = false) const;
+  bool any_element_is_nan (void) const;
   bool any_element_is_inf_or_nan (void) const;
   bool any_element_not_one_or_zero (void) const;
   bool all_elements_are_zero (void) const;
--- a/liboctave/dSparse.cc
+++ b/liboctave/dSparse.cc
@@ -7237,6 +7237,21 @@
 }
 
 bool
+SparseMatrix::any_element_is_nan (void) const
+{
+  octave_idx_type nel = nnz ();
+
+  for (octave_idx_type i = 0; i < nel; i++)
+    {
+      double val = data (i);
+      if (xisnan (val))
+	return true;
+    }
+
+  return false;
+}
+
+bool
 SparseMatrix::any_element_is_inf_or_nan (void) const
 {
   octave_idx_type nel = nnz ();
--- a/liboctave/dSparse.h
+++ b/liboctave/dSparse.h
@@ -372,6 +372,7 @@
   // other operations
 
   bool any_element_is_negative (bool = false) const;
+  bool any_element_is_nan (void) const;
   bool any_element_is_inf_or_nan (void) const;
   bool all_elements_are_zero (void) const;
   bool all_elements_are_int_or_inf_or_nan (void) const;
--- a/liboctave/fCMatrix.cc
+++ b/liboctave/fCMatrix.cc
@@ -3295,6 +3295,23 @@
 }
 
 bool
+FloatComplexMatrix::any_element_is_nan (void) const
+{
+  octave_idx_type nr = rows ();
+  octave_idx_type nc = cols ();
+
+  for (octave_idx_type j = 0; j < nc; j++)
+    for (octave_idx_type i = 0; i < nr; i++)
+      {
+	FloatComplex val = elem (i, j);
+	if (xisnan (val))
+	  return true;
+      }
+
+  return false;
+}
+
+bool
 FloatComplexMatrix::any_element_is_inf_or_nan (void) const
 {
   octave_idx_type nr = rows ();
--- a/liboctave/fCMatrix.h
+++ b/liboctave/fCMatrix.h
@@ -327,6 +327,7 @@
   FloatComplexMatrix map (cmapper fcn) const;
   boolMatrix map (bmapper fcn) const;
 
+  bool any_element_is_nan (void) const;
   bool any_element_is_inf_or_nan (void) const;
   bool all_elements_are_real (void) const;
   bool all_integers (float& max_val, float& min_val) const;
--- a/liboctave/fCNDArray.cc
+++ b/liboctave/fCNDArray.cc
@@ -492,6 +492,20 @@
 // FIXME -- this is not quite the right thing.
 
 bool
+FloatComplexNDArray::any_element_is_nan (void) const
+{
+  octave_idx_type nel = nelem ();
+
+  for (octave_idx_type i = 0; i < nel; i++)
+    {
+      FloatComplex val = elem (i);
+      if (xisnan (val))
+	return true;
+    }
+  return false;
+}
+
+bool
 FloatComplexNDArray::any_element_is_inf_or_nan (void) const
 {
   octave_idx_type nel = nelem ();
--- a/liboctave/fCNDArray.h
+++ b/liboctave/fCNDArray.h
@@ -64,6 +64,7 @@
 
   // FIXME -- this is not quite the right thing.
 
+  bool any_element_is_nan (void) const;
   bool any_element_is_inf_or_nan (void) const;
   bool all_elements_are_real (void) const;
   bool all_integers (float& max_val, float& min_val) const;
--- a/liboctave/fMatrix.cc
+++ b/liboctave/fMatrix.cc
@@ -2848,6 +2848,20 @@
   return false;
 }
 
+bool
+FloatMatrix::any_element_is_nan (void) const
+{
+  octave_idx_type nel = nelem ();
+
+  for (octave_idx_type i = 0; i < nel; i++)
+    {
+      float val = elem (i);
+      if (xisnan (val))
+	return true;
+    }
+
+  return false;
+}
 
 bool
 FloatMatrix::any_element_is_inf_or_nan (void) const
--- a/liboctave/fMatrix.h
+++ b/liboctave/fMatrix.h
@@ -282,6 +282,7 @@
   boolMatrix map (bmapper fcn) const;
 
   bool any_element_is_negative (bool = false) const;
+  bool any_element_is_nan (void) const;
   bool any_element_is_inf_or_nan (void) const;
   bool any_element_not_one_or_zero (void) const;
   bool all_elements_are_int_or_inf_or_nan (void) const;
--- a/liboctave/fNDArray.cc
+++ b/liboctave/fNDArray.cc
@@ -514,6 +514,20 @@
   return false;
 }
 
+bool
+FloatNDArray::any_element_is_nan (void) const
+{
+  octave_idx_type nel = nelem ();
+
+  for (octave_idx_type i = 0; i < nel; i++)
+    {
+      float val = elem (i);
+      if (xisnan (val))
+	return true;
+    }
+
+  return false;
+}
 
 bool
 FloatNDArray::any_element_is_inf_or_nan (void) const
--- a/liboctave/fNDArray.h
+++ b/liboctave/fNDArray.h
@@ -67,6 +67,7 @@
   boolNDArray operator ! (void) const;
 
   bool any_element_is_negative (bool = false) const;
+  bool any_element_is_nan (void) const;
   bool any_element_is_inf_or_nan (void) const;
   bool any_element_not_one_or_zero (void) const;
   bool all_elements_are_zero (void) const;
--- a/liboctave/lo-mappers.h
+++ b/liboctave/lo-mappers.h
@@ -42,6 +42,10 @@
 extern OCTAVE_API Complex xlog2 (const Complex& x, int& exp);
 extern OCTAVE_API double xexp2 (double x);
 
+// These are used by the BOOL_OP macros in mx-op-defs.h.
+inline bool xisnan (bool) { return false; }
+inline bool xisnan (char) { return false; }
+
 extern OCTAVE_API bool xisnan (double x);
 extern OCTAVE_API bool xfinite (double x);
 extern OCTAVE_API bool xisinf (double x);
--- a/liboctave/mx-op-defs.h
+++ b/liboctave/mx-op-defs.h
@@ -228,9 +228,21 @@
       { \
         r.resize (nr, nc); \
  \
-        for (int j = 0; j < nc; j++) \
-          for (int i = 0; i < nr; i++) \
-	    r.elem(i, j) = (m.elem(i, j) != LHS_ZERO) OP (s != RHS_ZERO); \
+	if (xisnan (s)) \
+	  gripe_nan_to_logical_conversion (); \
+	else \
+	  { \
+ \
+	    for (int j = 0; j < nc; j++) \
+	      for (int i = 0; i < nr; i++) \
+		if (xisnan (m.elem(i, j))) \
+		  { \
+		    gripe_nan_to_logical_conversion (); \
+		    return r; \
+		  } \
+		else \
+		  r.elem(i, j) = (m.elem(i, j) != LHS_ZERO) OP (s != RHS_ZERO); \
+	    } \
       } \
  \
     return r; \
@@ -331,9 +343,20 @@
       { \
         r.resize (nr, nc); \
  \
-        for (int j = 0; j < nc; j++) \
-          for (int i = 0; i < nr; i++) \
-	    r.elem(i, j) = (s != LHS_ZERO) OP (m.elem(i, j) != RHS_ZERO); \
+	if (xisnan (s)) \
+	  gripe_nan_to_logical_conversion (); \
+	else \
+	  { \
+	    for (int j = 0; j < nc; j++) \
+	      for (int i = 0; i < nr; i++) \
+		if (xisnan (m.elem(i, j))) \
+		  { \
+		    gripe_nan_to_logical_conversion (); \
+		    return r; \
+		  } \
+		else \
+		  r.elem(i, j) = (s != LHS_ZERO) OP (m.elem(i, j) != RHS_ZERO); \
+	  } \
       } \
  \
     return r; \
@@ -456,8 +479,14 @@
  \
 	    for (int j = 0; j < m1_nc; j++) \
 	      for (int i = 0; i < m1_nr; i++) \
-		r.elem(i, j) = (m1.elem(i, j) != LHS_ZERO) \
-                                OP (m2.elem(i, j) != RHS_ZERO); \
+		if (xisnan (m1.elem(i, j)) || xisnan (m2.elem(i, j))) \
+		  { \
+		    gripe_nan_to_logical_conversion (); \
+		    return r; \
+		  } \
+		else \
+		  r.elem(i, j) = (m1.elem(i, j) != LHS_ZERO) \
+		    OP (m2.elem(i, j) != RHS_ZERO); \
 	  } \
       } \
     else \
@@ -605,8 +634,19 @@
       { \
         r.resize (m.dims ()); \
  \
-        for (int i = 0; i < len; i++) \
-	  r.elem(i) = (m.elem(i) != LHS_ZERO) OP (s != RHS_ZERO); \
+	if (xisnan (s)) \
+	  gripe_nan_to_logical_conversion (); \
+	else \
+	  { \
+	    for (int i = 0; i < len; i++) \
+	      if (xisnan (m.elem(i))) \
+		{ \
+		  gripe_nan_to_logical_conversion (); \
+		  return r; \
+		} \
+	      else \
+		r.elem(i) = (m.elem(i) != LHS_ZERO) OP (s != RHS_ZERO); \
+	  } \
       } \
  \
     return r; \
@@ -748,8 +788,19 @@
       { \
         r.resize (m.dims ()); \
  \
-        for (int i = 0; i < len; i++) \
-	    r.elem(i) = (s != LHS_ZERO) OP (m.elem(i) != RHS_ZERO); \
+	if (xisnan (s)) \
+	  gripe_nan_to_logical_conversion (); \
+	else \
+	  { \
+	    for (int i = 0; i < len; i++) \
+	      if (xisnan (m.elem(i))) \
+		{ \
+	          gripe_nan_to_logical_conversion (); \
+		  return r; \
+		} \
+	      else \
+		r.elem(i) = (s != LHS_ZERO) OP (m.elem(i) != RHS_ZERO); \
+	    } \
       } \
  \
     return r; \
@@ -863,7 +914,13 @@
 	    r.resize (m1_dims); \
  \
 	    for (int i = 0; i < m1.length (); i++) \
-	      r.elem(i) = (m1.elem(i) != LHS_ZERO) OP (m2.elem(i) != RHS_ZERO); \
+	      if (xisnan (m1.elem(i)) || xisnan (m2.elem(i))) \
+		{ \
+	          gripe_nan_to_logical_conversion (); \
+		  return r; \
+		} \
+	      else \
+		r.elem(i) = (m1.elem(i) != LHS_ZERO) OP (m2.elem(i) != RHS_ZERO); \
 	  } \
       } \
     else \
--- a/liboctave/oct-inttypes.h
+++ b/liboctave/oct-inttypes.h
@@ -408,6 +408,13 @@
 };
 
 template <class T>
+bool
+xisnan (const octave_int<T>&)
+{
+  return false;
+}
+
+template <class T>
 octave_int<T>
 pow (const octave_int<T>& a, const octave_int<T>& b)
 {
--- a/scripts/general/logical.m
+++ b/scripts/general/logical.m
@@ -42,7 +42,11 @@
     elseif (isempty (x))
       y = zeros (size (x), "logical");
     elseif (isnumeric (x))
-      y = x != 0;
+      if (any (isnan (x(:))))
+	error ("invalid conversion from NaN to logical");
+      else
+	y = x != 0;
+      endif
     else
       error ("logical not defined for type `%s'", typeinfo (x));
     endif
@@ -59,4 +63,6 @@
 %!assert (logical (-13), true);
 %!assert (logical (int8 (13)), true);
 %!assert (logical (int8 (-13)), true);
-%!assert (logical ([-1, 0, 1, NaN, Inf]), [-1, 0, 1, NaN, Inf] != 0);
+%!assert (logical ([-1, 0, 1, Inf]), [-1, 0, 1, Inf] != 0);
+%!error (logical ([-1, 0, 1, NaN, Inf]))
+%!error (logical (NaN))
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,13 @@
+2008-07-11  John W. Eaton  <jwe@octave.org>
+
+	* ov-float.h, ov-flt-re-mat.cc, ov-range.h, ov-re-mat.h,
+	ov-re-sparse.cc, ov-scalar.h: Check for NaN in bool_value and
+	bool_array_value member functions to bool.
+
+	* ops.h (DEFSCALARBOOLOP_OP): New macro.
+	* OPERATORS/op-s-s.cc, OPERATORS/op-fs-fs.cc: Use it to define
+	el_and and el_or ops.
+
 2008-07-10  David Bateman  <dbateman@free.fr>
 
 	* DLD-FUNCTIONS/lookup.cc (assign): Delete.
--- a/src/OPERATORS/op-fs-fs.cc
+++ b/src/OPERATORS/op-fs-fs.cc
@@ -114,8 +114,8 @@
   return octave_value (v2.float_value () / d);
 }
 
-DEFBINOP_OP (el_and, float_scalar, float_scalar, &&)
-DEFBINOP_OP (el_or, float_scalar, float_scalar, ||)
+DEFSCALARBOOLOP_OP (el_and, float_scalar, float_scalar, &&)
+DEFSCALARBOOLOP_OP (el_or, float_scalar, float_scalar, ||)
 
 DEFNDCATOP_FN (fs_fs, float_scalar, float_scalar, float_array, float_array, concat)
 DEFNDCATOP_FN (s_fs, scalar, float_scalar, float_array, float_array, concat)
--- a/src/OPERATORS/op-s-s.cc
+++ b/src/OPERATORS/op-s-s.cc
@@ -115,8 +115,8 @@
   return octave_value (v2.double_value () / d);
 }
 
-DEFBINOP_OP (el_and, scalar, scalar, &&)
-DEFBINOP_OP (el_or, scalar, scalar, ||)
+DEFSCALARBOOLOP_OP (el_and, scalar, scalar, &&)
+DEFSCALARBOOLOP_OP (el_or, scalar, scalar, ||)
 
 DEFNDCATOP_FN (s_s, scalar, scalar, array, array, concat)
 
--- a/src/ops.h
+++ b/src/ops.h
@@ -293,6 +293,20 @@
       (v1.t1 ## _value () op v2.t2 ## _value ()); \
   }
 
+#define DEFSCALARBOOLOP_OP(name, t1, t2, op) \
+  BINOPDECL (name, a1, a2) \
+  { \
+    CAST_BINOP_ARGS (const octave_ ## t1&, const octave_ ## t2&); \
+    if (xisnan (v1.t1 ## _value ()) || xisnan (v2.t2 ## _value ())) \
+      { \
+        error ("invalid conversion from NaN to logical"); \
+        return octave_value (); \
+      } \
+    else \
+      return octave_value \
+        (v1.t1 ## _value () op v2.t2 ## _value ()); \
+  }
+
 #define DEFNDBINOP_OP(name, t1, t2, e1, e2, op) \
   BINOPDECL (name, a1, a2) \
   { \
--- a/src/ov-float.h
+++ b/src/ov-float.h
@@ -191,7 +191,9 @@
 
   bool bool_value (bool warn = false) const
   {
-    if (warn && scalar != 0 && scalar != 1)
+    if (xisnan (scalar))
+      error ("invalid conversion from NaN to logical");
+    else if (warn && scalar != 0 && scalar != 1)
       gripe_logical_conversion ();
 
     return scalar;
@@ -199,7 +201,9 @@
 
   boolNDArray bool_array_value (bool warn = false) const
   {
-    if (warn && scalar != 0 && scalar != 1)
+    if (xisnan (scalar))
+      error ("invalid conversion from NaN to logical");
+    else if (warn && scalar != 0 && scalar != 1)
       gripe_logical_conversion ();
 
     return boolNDArray (dim_vector (1, 1), scalar);
--- a/src/ov-flt-re-mat.cc
+++ b/src/ov-flt-re-mat.cc
@@ -218,7 +218,9 @@
 boolNDArray
 octave_float_matrix::bool_array_value (bool warn) const
 {
-  if (warn && matrix.any_element_not_one_or_zero ())
+  if (matrix.any_element_is_nan ())
+    error ("invalid conversion from NaN to logical");
+  else if (warn && matrix.any_element_not_one_or_zero ())
     gripe_logical_conversion ();
 
   return boolNDArray (matrix);
--- a/src/ov-range.h
+++ b/src/ov-range.h
@@ -227,7 +227,9 @@
   {
     Matrix m = range.matrix_value ();
 
-    if (warn && m.any_element_not_one_or_zero ())
+    if (m.any_element_is_nan ())
+      error ("invalid conversion from NaN to logical");
+    else if (warn && m.any_element_not_one_or_zero ())
       gripe_logical_conversion ();
 
     return boolNDArray (m);
--- a/src/ov-re-mat.cc
+++ b/src/ov-re-mat.cc
@@ -224,7 +224,9 @@
 boolNDArray
 octave_matrix::bool_array_value (bool warn) const
 {
-  if (warn && matrix.any_element_not_one_or_zero ())
+  if (matrix.any_element_is_nan ())
+    error ("invalid conversion from NaN to logical");
+  else if (warn && matrix.any_element_not_one_or_zero ())
     gripe_logical_conversion ();
 
   return boolNDArray (matrix);
--- a/src/ov-re-sparse.cc
+++ b/src/ov-re-sparse.cc
@@ -150,7 +150,9 @@
 {
   NDArray m = matrix.matrix_value ();
 
-  if (warn && m.any_element_not_one_or_zero ())
+  if (m.any_element_is_nan ())
+    error ("invalid conversion from NaN to logical");
+  else if (warn && m.any_element_not_one_or_zero ())
     gripe_logical_conversion ();
 
   return boolNDArray (m);
--- a/src/ov-scalar.h
+++ b/src/ov-scalar.h
@@ -192,7 +192,9 @@
 
   bool bool_value (bool warn = false) const
   {
-    if (warn && scalar != 0 && scalar != 1)
+    if (xisnan (scalar))
+      error ("invalid conversion from NaN to logical");
+    else if (warn && scalar != 0 && scalar != 1)
       gripe_logical_conversion ();
 
     return scalar;
@@ -200,7 +202,9 @@
 
   boolNDArray bool_array_value (bool warn = false) const
   {
-    if (warn && scalar != 0 && scalar != 1)
+    if (xisnan (scalar))
+      error ("invalid conversion from NaN to logical");
+    else if (warn && scalar != 0 && scalar != 1)
       gripe_logical_conversion ();
 
     return boolNDArray (dim_vector (1, 1), scalar);