changeset 18903:23681c9ea7ba stable

better guess if rem or mod could be zero (bug #42627) * lo-mappers.h (xmod, xrem): Don't treat abs(x)<=1 specially. Return 0 if x/y is assumed an integer. * data.cc: New tests for rem and mod.
author Olaf Till <i7tiol@t-online.de>
date Fri, 27 Jun 2014 11:49:22 +0200
parents c457a84bc7d3
children 23e511f3395d 46df2c7b8f4d
files libinterp/corefcn/data.cc liboctave/numeric/lo-mappers.h
diffstat 2 files changed, 27 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/data.cc	Fri Jun 20 18:55:38 2014 -0400
+++ b/libinterp/corefcn/data.cc	Fri Jun 27 11:49:22 2014 +0200
@@ -722,6 +722,8 @@
 %!error rem ([1, 2], [3, 4, 5])
 %!error rem (i, 1)
 
+# bug 42627
+%!assert (rem (0.94, 0.01), 0.0);
 */
 
 DEFALIAS (fmod, rem)
@@ -873,6 +875,9 @@
 ## non-integer real numbers
 %!assert (mod (2.1, 0.1), 0)
 %!assert (mod (2.1, 0.2), 0.1, eps)
+
+# bug 42627
+%!assert (mod (0.94, 0.01), 0.0);
 */
 
 // FIXME: Need to convert reduction functions of this file for single precision
--- a/liboctave/numeric/lo-mappers.h	Fri Jun 20 18:55:38 2014 -0400
+++ b/liboctave/numeric/lo-mappers.h	Fri Jun 27 11:49:22 2014 +0200
@@ -321,33 +321,19 @@
     {
       T q = x / y;
 
-      T n = xfloor (q);
-
-      if (X_NINT (y) != y)
+      if (X_NINT (y) != y
+          && (std::abs ((q - X_NINT (q)) / X_NINT (q))
+              < std::numeric_limits<T>::epsilon ()))
+        retval = 0;
+      else
         {
-          if (X_NINT (q) == q)
-            n = q;
-          else
-            {
-              if (x >= -1 && x <= 1)
-                {
-                  if (std::abs (q - X_NINT (q))
-                      < std::numeric_limits<T>::epsilon ())
-                    n = X_NINT (q);
-                }
-              else
-                {
-                  if (std::abs ((q - X_NINT (q))/ X_NINT (q))
-                      < std::numeric_limits<T>::epsilon ())
-                    n = X_NINT (q);
-                }
-            }
+          T n = xfloor (q);
+
+          // Prevent use of extra precision.
+          volatile T tmp = y * n;
+
+          retval = x - tmp;
         }
-
-      // Prevent use of extra precision.
-      volatile T tmp = y * n;
-
-      retval = x - tmp;
     }
 
   if (x != y && y != 0 && retval != 0)
@@ -368,33 +354,19 @@
     {
       T q = x / y;
 
-      T n = xtrunc (q);
-
-      if (X_NINT (y) != y)
+      if (X_NINT (y) != y
+          && (std::abs ((q - X_NINT (q)) / X_NINT (q))
+              < std::numeric_limits<T>::epsilon ()))
+        retval = 0;
+      else
         {
-          if (X_NINT (q) == q)
-            n = q;
-          else
-            {
-              if (x >= -1 && x <= 1)
-                {
-                  if (std::abs (q - X_NINT (q))
-                      < std::numeric_limits<T>::epsilon ())
-                    n = X_NINT (q);
-                }
-              else
-                {
-                  if (std::abs ((q - X_NINT (q))/ X_NINT (q))
-                      < std::numeric_limits<T>::epsilon ())
-                    n = X_NINT (q);
-                }
-            }
+          T n = xtrunc (q);
+
+          // Prevent use of extra precision.
+          volatile T tmp = y * n;
+
+          retval = x - tmp;
         }
-
-      // Prevent use of extra precision.
-      volatile T tmp = y * n;
-
-      retval = x - tmp;
     }
 
   if (x != y && y != 0 && retval != 0)