changeset 29351:326a7ca62c43

also define range<float>::nnz specialization * Range.h, Range.cc (xnnz): New template function. (range<float>::nnz): New specialization. (range<double>::nnz, range<float>::nnz): Forward to xnnz.
author John W. Eaton <jwe@octave.org>
date Fri, 05 Feb 2021 13:25:42 -0500
parents 9ae39daf5ff5
children 03c283f73b9a
files liboctave/array/Range.cc liboctave/array/Range.h
diffstat 2 files changed, 42 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/array/Range.cc	Thu Feb 04 10:11:00 2021 -0500
+++ b/liboctave/array/Range.cc	Fri Feb 05 13:25:42 2021 -0500
@@ -220,41 +220,52 @@
     return xfinal_value (m_base, m_limit, m_increment, m_numel);
   }
 
+  template <typename T>
+  octave_idx_type
+  xnnz (T base, T limit, T inc, T final_val, octave_idx_type nel)
+  {
+    // Note that the order of the following checks matters.
+
+    // If there are no elements, there can be no non-zero elements.
+    if (nel == 0)
+      return 0;
+
+    // All elements have the same sign, hence there are no zeros.
+    if ((base > 0 && limit > 0) || (base < 0 && limit < 0))
+      return nel;
+
+    // All elements are equal (inc = 0) but we know from the previous
+    // condition that they are not positive or negative, therefore all
+    // elements are zero.
+    if (inc == 0)
+      return 0;
+
+    // Exactly one zero at beginning or end of range.
+    if (base == 0 || final_val == 0)
+      return nel - 1;
+
+    // Range crosses negative/positive without hitting zero.
+    // FIXME: Is this test sufficiently tolerant or do we need to be
+    // more careful?
+    if (math::mod (-base, inc) != 0)
+      return nel;
+
+    // Range crosses negative/positive and hits zero.
+    return nel - 1;
+  }
+
   template <>
   octave_idx_type
   range<double>::nnz (void) const
   {
-    octave_idx_type retval = 0;
+    return xnnz (m_base, m_limit, m_increment, m_final, m_numel);
+  }
 
-    if (! isempty ())
-      {
-        if ((m_base > 0 && m_limit > 0)
-            || (m_base < 0 && m_limit < 0))
-          {
-            // All elements have the same sign, hence there are no zeros.
-            retval = m_numel;
-          }
-        else if (m_increment != 0)
-          {
-            if (m_base == 0 || m_limit == 0)
-              // Exactly one zero at beginning or end of range.
-              retval = m_numel - 1;
-            else if (math::mod (-m_base, m_increment) != 0)
-              // Range crosses negative/positive without hitting zero.
-              retval = m_numel;
-            else
-              // Range crosses negative/positive and hits zero.
-              retval = m_numel - 1;
-          }
-        else
-          {
-            // All elements are equal (m_increment = 0) but not
-            // positive or negative, therefore all elements are zero.
-            retval = 0;
-          }
-      }
-
-    return retval;
+  template <>
+  octave_idx_type
+  range<float>::nnz (void) const
+  {
+    return xnnz (m_base, m_limit, m_increment, m_final, m_numel);
   }
 }
 
--- a/liboctave/array/Range.h	Thu Feb 04 10:11:00 2021 -0500
+++ b/liboctave/array/Range.h	Fri Feb 05 13:25:42 2021 -0500
@@ -355,6 +355,7 @@
   template <> OCTAVE_API float range<float>::get_final_value (void) const;
 
   template <> OCTAVE_API octave_idx_type range<double>::nnz (void) const;
+  template <> OCTAVE_API octave_idx_type range<float>::nnz (void) const;
 }
 
 class