changeset 27473:d503426130bf

Display '*' rather than '0' for small rational approximations (bug #56941) * pr-output.cc (operator << (pr_rational_float)): New boolean variable have_neg_sign to track whether extra character is required in output string to acount for negative sign. Call rational_approx with full width argument for negative numbers and width-1 for positive numbers. Change output to '*' if return value from rational_approx is '0' (which only indicates small). For large integers which aren't in rational approximation format of N/D (no '/') character, use a smaller field width. * oct-string.cc (rational_approx): Change variable name "buf2" to "init_buf" for clarity. Reformat "else if (condition)" to "else { if (condition) }" for readability. Expand comments and correct typos.
author Rik <rik@octave.org>
date Fri, 04 Oct 2019 13:51:47 -0700
parents c0883bfc0f36
children 3fec8e9fa2aa
files libinterp/corefcn/pr-output.cc liboctave/util/oct-string.cc
diffstat 2 files changed, 43 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/pr-output.cc	Fri Oct 04 14:13:06 2019 -0400
+++ b/libinterp/corefcn/pr-output.cc	Fri Oct 04 13:51:47 2019 -0700
@@ -240,19 +240,46 @@
   octave::preserve_stream_state stream_state (os);
 
   float_format real_fmt = prf.m_ff;
+  bool have_neg_sign = prf.m_val < 0;
 
   int fw = (rat_string_len > 0 ? rat_string_len : real_fmt.width ());
-  std::string s = rational_approx (prf.m_val, fw);
+  std::string s;
+
+  if (have_neg_sign)
+    s = rational_approx (prf.m_val, fw);
+  else
+    s = rational_approx (prf.m_val, fw-1);
 
   if (fw >= 0)
     os << std::setw (fw);
 
   os.flags (real_fmt.format_flags ());
 
-  if (fw > 0 && s.length () > static_cast<unsigned int> (fw))
-    os << '*';
-  else
-    os << s;
+  if (s == "0")
+    s = '*';
+  else if (fw > 0)
+    {
+      if (s.find ('/') != std::string::npos)
+        {
+          if (s.length () > (static_cast<unsigned int> (fw)))
+            s = '*';
+        }
+      else
+        {
+          if (have_neg_sign)
+            {
+              if (s.length () > (static_cast<unsigned int> (fw) - 2))
+                s = '*';
+            }
+          else
+            {
+              if (s.length () > (static_cast<unsigned int> (fw) - 3))
+                s = '*';
+            }
+        }
+    }
+
+  os << s;
 
   return os;
 }
--- a/liboctave/util/oct-string.cc	Fri Oct 04 14:13:06 2019 -0400
+++ b/liboctave/util/oct-string.cc	Fri Oct 04 13:51:47 2019 -0700
@@ -586,10 +586,10 @@
       T frac = val - n;
       int m = 0;
 
-      std::ostringstream buf2;
-      buf2.flags (std::ios::fixed);
-      buf2 << std::setprecision (0) << static_cast<int> (n);
-      s = buf2.str ();
+      std::ostringstream init_buf;
+      init_buf.flags (std::ios::fixed);
+      init_buf << std::setprecision (0) << static_cast<int> (n);
+      s = init_buf.str ();
 
       while (true)
         {
@@ -624,8 +624,11 @@
               if (buf.str ().length () > static_cast<unsigned int> (len + 2))
                 break;
             }
-          else if (buf.str ().length () > static_cast<unsigned int> (len))
-            break;
+          else
+            {
+              if (buf.str ().length () > static_cast<unsigned int> (len))
+                break;
+            }
 
           if (std::abs (n) > std::numeric_limits<int>::max ()
               || std::abs (d) > std::numeric_limits<int>::max ())
@@ -636,7 +639,7 @@
 
       if (lastd < 0)
         {
-          // Move sign to the top
+          // Move negative sign from denominator to numerator
           lastd = - lastd;
           lastn = - lastn;
           std::ostringstream buf;
@@ -650,6 +653,6 @@
   return s;
 }
 
-// instanciate the template for float and double
+// instantiate the template for float and double
 template std::string rational_approx <float> (float val, int len);
 template std::string rational_approx <double> (double val, int len);