changeset 24784:4d945f2e5914

eliminate output_max_field width; limit output precision (bug #53167) * pr-flt-fmt.h, pr-flt-fmt.cc (Voutput_max_field_width, output_max_field_width): Delete. Eliminate all uses. (set_output_prec): Rename from set_output_prec_and_fw. Change all uses. (Foutput_max_field_width): Always return 20. Don't do anything with input. Document new behavior. (Foutput_precision): Limit value to be in the range 0 to 16. (class float_format): Always set width to 0. * pr-output.h, pr-output.cc (pr_output_traits): New template. (make_real_format): Limit output precision. (octave_print_real_matrix_internal, octave_print_real_diag_matrix_internal, octave_print_complex_matrix_internal, octave_print_complex_diag_matrix_internal): New template functions. Use them to define float and double versions of octave_print_internal for real and complex matrix and diag matrix functions. (octave_print_internal): Define separate versions for float and float complex N-d arrays. (Fformat): Update doc string.
author John W. Eaton <jwe@octave.org>
date Wed, 21 Feb 2018 08:24:41 -0500
parents db6fb8b8bbde
children 504869574c89
files libinterp/corefcn/pr-flt-fmt.cc libinterp/corefcn/pr-flt-fmt.h libinterp/corefcn/pr-output.cc libinterp/corefcn/pr-output.h liboctave/array/fCDiagMatrix.h
diffstat 5 files changed, 171 insertions(+), 118 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/pr-flt-fmt.cc	Wed Feb 21 11:51:32 2018 -0500
+++ b/libinterp/corefcn/pr-flt-fmt.cc	Wed Feb 21 08:24:41 2018 -0500
@@ -29,49 +29,30 @@
 #include "pr-flt-fmt.h"
 #include "variables.h"
 
-// The maximum field width for a number printed by the default output
-// routines.
-static int Voutput_max_field_width = 10;
-
 // The precision of the numbers printed by the default output
 // routines.
 static int Voutput_precision = 5;
 
 int
-output_max_field_width (void)
-{
-  return Voutput_max_field_width;
-}
-
-int
 output_precision (void)
 {
   return Voutput_precision;
 }
 
 void
-set_output_prec_and_fw (int prec, int fw)
+set_output_prec (int prec)
 {
   Voutput_precision = prec;
-  Voutput_max_field_width = fw;
 }
 
-DEFUN (output_max_field_width, args, nargout,
+DEFUN (output_max_field_width, , ,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{val} =} output_max_field_width ()
-@deftypefnx {} {@var{old_val} =} output_max_field_width (@var{new_val})
-@deftypefnx {} {} output_max_field_width (@var{new_val}, "local")
-Query or set the internal variable that specifies the maximum width
-of a numeric output field.
-
-When called from inside a function with the @qcode{"local"} option, the
-variable is changed locally for the function and any subroutines it calls.
-The original variable value is restored when exiting the function.
-@seealso{format, fixed_point_format, output_precision}
+@deftypefn  {} {} output_max_field_width
+This function is obsolete and will be removed from a future version
+of Octave.
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE_WITH_LIMITS (output_max_field_width, 0,
-                                            std::numeric_limits<int>::max ());
+  return octave_value (20);
 }
 
 DEFUN (output_precision, args, nargout,
@@ -82,12 +63,16 @@
 Query or set the internal variable that specifies the minimum number of
 significant figures to display for numeric output.
 
+Note that regardless of the value set for @code{output_precision}, the
+number of digits of precision displayed is limited to 16 for double
+precision values and 7 for single precision values.
+
 When called from inside a function with the @qcode{"local"} option, the
 variable is changed locally for the function and any subroutines it calls.
 The original variable value is restored when exiting the function.
-@seealso{format, fixed_point_format, output_max_field_width}
+
+@seealso{format, fixed_point_format}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE_WITH_LIMITS (output_precision, -1,
-                                            std::numeric_limits<int>::max ());
+  return SET_INTERNAL_VARIABLE_WITH_LIMITS (output_precision, 0, 16);
 }
--- a/libinterp/corefcn/pr-flt-fmt.h	Wed Feb 21 11:51:32 2018 -0500
+++ b/libinterp/corefcn/pr-flt-fmt.h	Wed Feb 21 08:24:41 2018 -0500
@@ -37,19 +37,16 @@
 template <typename T>
 class pr_rational_float;
 
-extern int output_max_field_width (void);
-
 extern int output_precision (void);
 
-extern void set_output_prec_and_fw (int prec, int fw);
+extern void set_output_prec (int prec);
 
 class
 float_format
 {
 public:
 
-  float_format (int w = output_max_field_width (),
-                int p = output_precision (), int f = 0)
+  float_format (int w = 0, int p = output_precision (), int f = 0)
     : fw (w), ex (0), prec (p), fmt (f), up (0), sp (0) { }
 
   float_format (int w, int e, int p, int f)
--- a/libinterp/corefcn/pr-output.cc	Wed Feb 21 11:51:32 2018 -0500
+++ b/libinterp/corefcn/pr-output.cc	Wed Feb 21 08:24:41 2018 -0500
@@ -432,8 +432,32 @@
   return result;
 }
 
+template <typename>
+struct pr_output_traits
+{
+  static const int digits10;
+};
+
+template <>
+struct pr_output_traits<double>
+{
+  static const int digits10;
+};
+
+const int pr_output_traits<double>::digits10 = 16;
+
+template <>
+struct pr_output_traits<float>
+{
+  static const int digits10;
+};
+
+const int pr_output_traits<float>::digits10 = 8;
+
 // FIXME: it would be nice to share more code among these functions,..
 
+// Works for double and float.
+
 template <typename T>
 static inline float_display_format
 make_real_format (int digits, bool inf_or_nan,
@@ -441,7 +465,7 @@
 {
   float_format fmt;
 
-  int prec = output_precision ();
+  int prec = std::min (output_precision (), pr_output_traits<T>::digits10);
 
   int ld, rd;
 
@@ -493,7 +517,7 @@
     }
 
   if (! (rat_format || bank_format || hex_format || bit_format)
-      && (fw > output_max_field_width () || print_e || print_g || print_eng))
+      && (print_e || print_g || print_eng))
     {
       if (print_g)
         fmt = float_format ();
@@ -531,6 +555,8 @@
   return float_display_format (fmt);
 }
 
+// Works for double and float.
+
 template <typename T>
 float_display_format
 make_format (T val, int& fw)
@@ -556,7 +582,7 @@
 {
   float_format fmt;
 
-  int prec = output_precision ();
+  int prec = std::min (output_precision (), pr_output_traits<T>::digits10);
 
   int ld, rd;
 
@@ -637,9 +663,7 @@
     }
 
   if (! (rat_format || bank_format || hex_format || bit_format)
-      && (print_e
-          || print_eng || print_g
-          || (! Vfixed_point_format && fw > output_max_field_width ())))
+      && (print_e || print_eng || print_g))
     {
       if (print_g)
         fmt = float_format ();
@@ -724,7 +748,7 @@
   float_format r_fmt;
   float_format i_fmt;
 
-  int prec = output_precision ();
+  int prec = std::min (output_precision (), pr_output_traits<T>::digits10);
 
   int ld, rd;
 
@@ -810,7 +834,7 @@
     }
 
   if (! (rat_format || bank_format || hex_format || bit_format)
-      && (r_fw > output_max_field_width () || print_e || print_eng || print_g))
+      && (print_e || print_eng || print_g))
     {
       if (print_g)
         {
@@ -919,7 +943,7 @@
   float_format r_fmt;
   float_format i_fmt;
 
-  int prec = output_precision ();
+  int prec = std::min (output_precision (), pr_output_traits<T>::digits10);
 
   int ld, rd;
 
@@ -1016,9 +1040,7 @@
     }
 
   if (! (rat_format || bank_format || hex_format || bit_format)
-      && (print_e
-          || print_eng || print_g
-          || (! Vfixed_point_format && r_fw > output_max_field_width ())))
+      && (print_e || print_eng || print_g))
     {
       if (print_g)
         {
@@ -1137,7 +1159,7 @@
 {
   float_format fmt;
 
-  int prec = output_precision ();
+  int prec = std::min (output_precision (), pr_output_traits<T>::digits10);
 
   int ld, rd;
 
@@ -1210,9 +1232,7 @@
     }
 
   if (! (rat_format || bank_format || hex_format || bit_format)
-      && (print_e
-          || print_eng || print_g
-          || (! Vfixed_point_format && fw > output_max_field_width ())))
+      && (print_e || print_eng || print_g))
     {
       if (print_g)
         fmt = float_format ();
@@ -1864,9 +1884,10 @@
     }
 }
 
-void
-octave_print_internal (std::ostream& os, const Matrix& m,
-                       bool pr_as_read_syntax, int extra_indent)
+template <typename MT>
+static void
+octave_print_real_matrix_internal (std::ostream& os, const MT& m,
+                                   bool pr_as_read_syntax, int extra_indent)
 {
   octave_idx_type nr = m.rows ();
   octave_idx_type nc = m.columns ();
@@ -1878,7 +1899,7 @@
   else
     {
       int fw = 0;
-      double scale = 1;
+      typename MT::element_type scale = 1;
       float_display_format fmt = make_format (m, fw, scale);
       int column_width = fw + 2;
       octave_idx_type total_width = nc * column_width;
@@ -1980,9 +2001,10 @@
     }
 }
 
-void
-octave_print_internal (std::ostream& os, const DiagMatrix& m,
-                       bool pr_as_read_syntax, int extra_indent)
+template <typename DMT>
+static void
+octave_print_real_diag_matrix_internal (std::ostream& os, const DMT& m,
+                                        bool pr_as_read_syntax, int extra_indent)
 {
   octave_idx_type nr = m.rows ();
   octave_idx_type nc = m.columns ();
@@ -1994,7 +2016,7 @@
   else
     {
       int fw;
-      double scale = 1;
+      typename DMT::element_type scale = 1;
       float_display_format fmt = make_format (Matrix (m.diag ()), fw, scale);
       int column_width = fw + 2;
       octave_idx_type total_width = nc * column_width;
@@ -2071,7 +2093,8 @@
           int zero_fw;
           {
             std::ostringstream tmp_oss;
-            pr_float (tmp_oss, fmt, 0.0, fw, scale);
+            typename DMT::element_type zero = 0;
+            pr_float (tmp_oss, fmt, zero, fw, scale);
             zero_fw = tmp_oss.str ().length ();
           }
 
@@ -2201,6 +2224,24 @@
     }
 }
 
+void
+octave_print_internal (std::ostream& os, const FloatNDArray& nda,
+                       bool pr_as_read_syntax, int extra_indent)
+{
+  switch (nda.ndims ())
+    {
+    case 1:
+    case 2:
+      octave_print_internal (os, FloatMatrix (nda),
+                             pr_as_read_syntax, extra_indent);
+      break;
+
+    default:
+      print_nd_array <FloatNDArray, float, FloatMatrix> (os, nda, pr_as_read_syntax);
+      break;
+    }
+}
+
 template <typename T>
 static inline void
 pr_plus_format (std::ostream& os, const std::complex<T>& c)
@@ -2255,9 +2296,10 @@
     }
 }
 
-void
-octave_print_internal (std::ostream& os, const ComplexMatrix& cm,
-                       bool pr_as_read_syntax, int extra_indent)
+template <typename MT>
+static void
+octave_print_complex_matrix_internal (std::ostream& os, const MT& cm,
+                                      bool pr_as_read_syntax, int extra_indent)
 {
   octave_idx_type nr = cm.rows ();
   octave_idx_type nc = cm.columns ();
@@ -2269,7 +2311,7 @@
   else
     {
       int r_fw, i_fw;
-      double scale = 1;
+      typename MT::real_elt_type scale = 1;
       float_display_format fmt = make_format (cm, r_fw, i_fw, scale);
       int column_width = i_fw + r_fw;
       column_width += (rat_format || bank_format || hex_format
@@ -2373,9 +2415,10 @@
     }
 }
 
-void
-octave_print_internal (std::ostream& os, const ComplexDiagMatrix& cm,
-                       bool pr_as_read_syntax, int extra_indent)
+template <typename DMT>
+static void
+octave_print_complex_diag_matrix_internal (std::ostream& os, const DMT& cm,
+                                           bool pr_as_read_syntax, int extra_indent)
 {
   octave_idx_type nr = cm.rows ();
   octave_idx_type nc = cm.columns ();
@@ -2387,7 +2430,7 @@
   else
     {
       int r_fw, i_fw;
-      double scale = 1;
+      typename DMT::real_elt_type scale = 1;
       float_display_format fmt
         = make_format (ComplexMatrix (cm.diag ()), r_fw, i_fw, scale);
       int column_width = i_fw + r_fw;
@@ -2467,7 +2510,8 @@
           int zero_fw;
           {
             std::ostringstream tmp_oss;
-            pr_complex (tmp_oss, fmt, Complex (0), r_fw, i_fw, scale);
+            typename DMT::element_type zero = 0;
+            pr_complex (tmp_oss, fmt, zero, r_fw, i_fw, scale);
             zero_fw = tmp_oss.str ().length ();
           }
 
@@ -2635,51 +2679,81 @@
     }
 }
 
+void
+octave_print_internal (std::ostream& os, const FloatComplexNDArray& nda,
+                       bool pr_as_read_syntax, int extra_indent)
+{
+  switch (nda.ndims ())
+    {
+    case 1:
+    case 2:
+      octave_print_internal (os, FloatComplexMatrix (nda),
+                             pr_as_read_syntax, extra_indent);
+      break;
+
+    default:
+      print_nd_array <FloatComplexNDArray, FloatComplex, FloatComplexMatrix>
+                     (os, nda, pr_as_read_syntax);
+      break;
+    }
+}
+
 // FIXME: write single precision versions of the printing functions.
 
 void
+octave_print_internal (std::ostream& os, const Matrix& m,
+                       bool pr_as_read_syntax, int extra_indent)
+{
+  octave_print_real_matrix_internal (os, m, pr_as_read_syntax, extra_indent);
+}
+
+void
 octave_print_internal (std::ostream& os, const FloatMatrix& m,
                        bool pr_as_read_syntax, int extra_indent)
 {
-  octave_print_internal (os, Matrix (m), pr_as_read_syntax, extra_indent);
+  octave_print_real_matrix_internal (os, m, pr_as_read_syntax, extra_indent);
+}
+
+void
+octave_print_internal (std::ostream& os, const DiagMatrix& m,
+                       bool pr_as_read_syntax, int extra_indent)
+{
+  octave_print_real_diag_matrix_internal (os, m, pr_as_read_syntax, extra_indent);
 }
 
 void
 octave_print_internal (std::ostream& os, const FloatDiagMatrix& m,
                        bool pr_as_read_syntax, int extra_indent)
 {
-  octave_print_internal (os, DiagMatrix (m), pr_as_read_syntax, extra_indent);
+  octave_print_real_diag_matrix_internal (os, m, pr_as_read_syntax, extra_indent);
 }
 
 void
-octave_print_internal (std::ostream& os, const FloatNDArray& nda,
+octave_print_internal (std::ostream& os, const ComplexMatrix& cm,
                        bool pr_as_read_syntax, int extra_indent)
 {
-  octave_print_internal (os, NDArray (nda), pr_as_read_syntax, extra_indent);
+  octave_print_complex_matrix_internal (os, cm, pr_as_read_syntax, extra_indent);
 }
 
 void
 octave_print_internal (std::ostream& os, const FloatComplexMatrix& cm,
                        bool pr_as_read_syntax, int extra_indent)
 {
-  octave_print_internal (os, ComplexMatrix (cm), pr_as_read_syntax,
-                         extra_indent);
+  octave_print_complex_matrix_internal (os, cm, pr_as_read_syntax, extra_indent);
+}
+
+void
+octave_print_internal (std::ostream& os, const ComplexDiagMatrix& cm,
+                       bool pr_as_read_syntax, int extra_indent)
+{
+  octave_print_complex_diag_matrix_internal (os, cm, pr_as_read_syntax, extra_indent);
 }
 
 void
 octave_print_internal (std::ostream& os, const FloatComplexDiagMatrix& cm,
                        bool pr_as_read_syntax, int extra_indent)
 {
-  octave_print_internal (os, ComplexDiagMatrix (cm), pr_as_read_syntax,
-                         extra_indent);
-}
-
-void
-octave_print_internal (std::ostream& os, const FloatComplexNDArray& nda,
-                       bool pr_as_read_syntax, int extra_indent)
-{
-  octave_print_internal (os, ComplexNDArray (nda), pr_as_read_syntax,
-                         extra_indent);
+  octave_print_complex_diag_matrix_internal (os, cm, pr_as_read_syntax, extra_indent);
 }
 
 void
@@ -3690,7 +3764,7 @@
   print_eng = false;
 }
 
-static inline std::string format_string ("short");
+static std::string format_string ("short");
 
 static inline void
 set_format_style (int argc, const string_vector& argv)
@@ -3743,39 +3817,39 @@
           else
             init_format_state ();
 
-          set_output_prec_and_fw (5, 10);
+          set_output_prec (5);
         }
       else if (arg == "shorte")
         {
           init_format_state ();
           print_e = true;
-          set_output_prec_and_fw (5, 10);
+          set_output_prec (5);
         }
       else if (arg == "shortE")
         {
           init_format_state ();
           print_e = true;
           print_big_e = true;
-          set_output_prec_and_fw (5, 10);
+          set_output_prec (5);
         }
       else if (arg == "shortg")
         {
           init_format_state ();
           print_g = true;
-          set_output_prec_and_fw (5, 10);
+          set_output_prec (5);
         }
       else if (arg == "shortG")
         {
           init_format_state ();
           print_g = true;
           print_big_e = true;
-          set_output_prec_and_fw (5, 10);
+          set_output_prec (5);
         }
       else if (arg == "shortEng")
         {
           init_format_state ();
           print_eng = true;
-          set_output_prec_and_fw (5, 10);
+          set_output_prec (5);
         }
       else if (arg == "long")
         {
@@ -3817,39 +3891,39 @@
           else
             init_format_state ();
 
-          set_output_prec_and_fw (15, 20);
+          set_output_prec (16);
         }
       else if (arg == "longe")
         {
           init_format_state ();
           print_e = true;
-          set_output_prec_and_fw (15, 20);
+          set_output_prec (16);
         }
       else if (arg == "longE")
         {
           init_format_state ();
           print_e = true;
           print_big_e = true;
-          set_output_prec_and_fw (15, 20);
+          set_output_prec (16);
         }
       else if (arg == "longg")
         {
           init_format_state ();
           print_g = true;
-          set_output_prec_and_fw (15, 20);
+          set_output_prec (16);
         }
       else if (arg == "longG")
         {
           init_format_state ();
           print_g = true;
           print_big_e = true;
-          set_output_prec_and_fw (15, 20);
+          set_output_prec (16);
         }
       else if (arg == "longEng")
         {
           init_format_state ();
           print_eng = true;
-          set_output_prec_and_fw (15, 20);
+          set_output_prec (16);
         }
       else if (arg == "hex")
         {
@@ -3925,7 +3999,7 @@
   else
     {
       init_format_state ();
-      set_output_prec_and_fw (5, 10);
+      set_output_prec (5);
       format = "short";
     }
 
@@ -3954,16 +4028,10 @@
 
 @table @code
 @item short
-Fixed point format with 5 significant figures in a field that is a maximum of
-10 characters wide.  (default).
-
-If Octave is unable to format a matrix so that columns line up on the decimal
-point and all numbers fit within the maximum field width then it switches to an
-exponential @samp{e} format.
+Fixed point format with 5 significant figures (default).
 
 @item long
-Fixed point format with 15 significant figures in a field that is a maximum of
-20 characters wide.
+Fixed point format with 16 significant figures.
 
 As with the @samp{short} format, Octave will switch to an exponential @samp{e}
 format if it is unable to format a matrix properly using the current format.
@@ -3972,14 +4040,15 @@
 @itemx long e
 Exponential format.  The number to be represented is split between a mantissa
 and an exponent (power of 10).  The mantissa has 5 significant digits in the
-short format and 15 digits in the long format.  For example, with the
-@samp{short e} format, @code{pi} is displayed as @code{3.1416e+00}.
+short format.  In the long format, double values are displayed with 16
+significant digits and single values are displayed with 8.  For example,
+with the @samp{short e} format, @code{pi} is displayed as @code{3.1416e+00}.
 
 @item  short E
 @itemx long E
 Identical to @samp{short e} or @samp{long e} but displays an uppercase @samp{E}
 to indicate the exponent.  For example, with the @samp{long E} format,
-@code{pi} is displayed as @code{3.14159265358979E+00}.
+@code{pi} is displayed as @code{3.141592653589793E+00}.
 
 @item  short g
 @itemx long g
@@ -4003,7 +4072,7 @@
 @itemx long eng
 Identical to @samp{short e} or @samp{long e} but displays the value using an
 engineering format, where the exponent is divisible by 3.  For example, with
-the @samp{short eng} format, @code{10 * pi} is displayed as @code{31.4159e+00}.
+the @samp{short eng} format, @code{10 * pi} is displayed as @code{31.416e+00}.
 
 @item  long G
 @itemx short G
@@ -4104,7 +4173,7 @@
 If called with one or two output arguments, and no inputs, return the current
 format and format spacing.
 
-@seealso{fixed_point_format, output_max_field_width, output_precision, split_long_rows, print_empty_dimensions, rats}
+@seealso{fixed_point_format, output_precision, split_long_rows, print_empty_dimensions, rats}
 @end deftypefn */)
 {
   octave_value_list retval (std::min (nargout, 2));
@@ -4135,7 +4204,9 @@
 %!   ## Test one of the formats
 %!   format long;
 %!   str = disp (pi);
-%!   assert (str, " 3.14159265358979\n");
+%!   assert (str, " 3.141592653589793\n");
+%!   str = disp (single (pi));
+%!   assert (str, " 3.1415927\n");
 %!   new_fmt = format ();
 %!   assert (new_fmt, "long");
 %!   ## Test resetting format
@@ -4187,7 +4258,7 @@
 When called from inside a function with the @qcode{"local"} option, the
 variable is changed locally for the function and any subroutines it calls.
 The original variable value is restored when exiting the function.
-@seealso{format, output_max_field_width, output_precision}
+@seealso{format, output_precision}
 @end deftypefn */)
 {
   return SET_INTERNAL_VARIABLE (fixed_point_format);
--- a/libinterp/corefcn/pr-output.h	Wed Feb 21 11:51:32 2018 -0500
+++ b/libinterp/corefcn/pr-output.h	Wed Feb 21 08:24:41 2018 -0500
@@ -56,10 +56,6 @@
 
 template <typename T> class intNDArray;
 
-template <typename T>
-extern float_display_format
-make_format (T val, int& fw);
-
 extern float_display_format
 make_format (const Matrix& m, int& fw, double& scale);
 
@@ -240,12 +236,12 @@
                        int extra_indent = 0);
 
 extern OCTINTERP_API void
-octave_print_internal (std::ostream& os, const DiagMatrix& m,
+octave_print_internal (std::ostream& os, const FloatMatrix& m,
                        bool pr_as_read_syntax = false,
                        int extra_indent = 0);
 
 extern OCTINTERP_API void
-octave_print_internal (std::ostream& os, const FloatMatrix& m,
+octave_print_internal (std::ostream& os, const DiagMatrix& m,
                        bool pr_as_read_syntax = false,
                        int extra_indent = 0);
 
--- a/liboctave/array/fCDiagMatrix.h	Wed Feb 21 11:51:32 2018 -0500
+++ b/liboctave/array/fCDiagMatrix.h	Wed Feb 21 08:24:41 2018 -0500
@@ -39,6 +39,10 @@
 {
 public:
 
+  typedef float real_elt_type;
+  typedef FloatComplex complex_elt_type;
+  typedef FloatComplex element_type;
+
   FloatComplexDiagMatrix (void) : MDiagArray2<FloatComplex> () { }
 
   FloatComplexDiagMatrix (octave_idx_type r,