# HG changeset patch # User David Bateman # Date 1278443109 -7200 # Node ID 38bdcbb58df7d079b33786aec870839272cb8ad5 # Parent 6cc789b3f0e3724be05a2ebab1889f919edbcd49 Add engineering formats. eg 'fomat short eng' (Feature Request #30163) diff --git a/src/ChangeLog b/src/ChangeLog --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,29 @@ +2010-07-06 David Bateman + + * pr-output.cc (static bool print_eng): Flag engineering format, + (float_format::float_format (int, int, int, int)): New constructor. + (int float_format::ex): New field in the class. + (static int maybe_mod3 (const int&), static int + engineering_exponent (const double&), + static int calc_digits (const double&)): New functions + (class pr_engineering_float): New class + (std::ostream& operator << (std::ostream&, + const pr_formatted_float&)): New operator. Make it a friend of the + float_format class. + (static void set_real_format(...), + static void set_real_matrix_format (...), + static void set_complex_format(...), + static void set_complex_matrix_format (...), + static void set_range_format (...)): Set width for engineering format. + (static void set_format (...)): Call calc_digits to find the number + of digits in a value. + (static void pr_any_float (const float_format *, std::ostream&, + double, int)): Print engineering formats. + (static void init_format_state (void)): Set default state of print_eng. + (static void set_format_style (int, const string_vector&)): Parse + the "eng" argument. + (Fformat): Document the new engineering format. + 2010-07-04 Soren Hauberg * DLD_FUNCTIONS/__magick_read__.cc: restore locale after GraphicsMagick initialisation. diff --git a/src/pr-output.cc b/src/pr-output.cc --- a/src/pr-output.cc +++ b/src/pr-output.cc @@ -118,6 +118,10 @@ // TRUE means print E instead of e for exponent field. static bool print_big_e = false; +// TRUE means use an engineering format. +static bool print_eng = false; + +class pr_engineering_float; class pr_formatted_float; class pr_rational_float; @@ -140,16 +144,20 @@ float_format (int w = current_output_max_field_width (), int p = current_output_precision (), int f = 0) - : fw (w), prec (p), fmt (f), up (0), sp (0) { } + : fw (w), ex (0), prec (p), fmt (f), up (0), sp (0) { } + + float_format (int w, int e, int p, int f) + : fw (w), ex (e), prec (p), fmt (f), up (0), sp (0) { } float_format (const float_format& ff) - : fw (ff.fw), prec (ff.prec), fmt (ff.fmt), up (ff.up), sp (ff.sp) { } + : fw (ff.fw), ex (ff.ex), prec (ff.prec), fmt (ff.fmt), up (ff.up), sp (ff.sp) { } float_format& operator = (const float_format& ff) { if (&ff != this) { fw = ff.fw; + ex = ff.ex; prec = ff.prec; fmt = ff.fmt; up = ff.up; @@ -176,6 +184,9 @@ { sp = tz ? std::ios::showpoint : 0; return *this; } friend std::ostream& operator << (std::ostream& os, + const pr_engineering_float& pff); + + friend std::ostream& operator << (std::ostream& os, const pr_formatted_float& pff); friend std::ostream& operator << (std::ostream& os, @@ -186,6 +197,9 @@ // Field width. Zero means as wide as necessary. int fw; + // Exponent Field width. Zero means as wide as necessary. + int ex; + // Precision. int prec; @@ -199,6 +213,90 @@ int sp; }; +static int +maybe_mod3 (const int& x) +{ + return print_eng ? x - (x % 3) : x; +} + +static int +engineering_exponent (const double& x) +{ + int ex = 0; + if (x != 0) + { + double absval = (x < 0.0 ? -x : x); + int logabsval = static_cast (floor (log10 (absval))); + if (logabsval < 0.0) + ex = maybe_mod3 (logabsval - 2); + else + ex = maybe_mod3 (logabsval); + } + return ex; +} + +static int +calc_digits (const double& x) +{ + return print_eng ? engineering_exponent (x) + : static_cast (floor (log10 (x))); +} + +class +pr_engineering_float +{ +public: + + const float_format& f; + + double val; + + int exponent (void) const + { + return engineering_exponent (val); + } + + double mantissa (void) const + { + return val / std::pow (10.0, exponent ()); + } + + pr_engineering_float (const float_format& f_arg, double val_arg) + : f (f_arg), val (val_arg) { } +}; + +std::ostream& +operator << (std::ostream& os, const pr_engineering_float& pff) +{ + if (pff.f.fw >= 0) + os << std::setw (pff.f.fw - pff.f.ex); + + if (pff.f.prec >= 0) + os << std::setprecision (pff.f.prec); + + std::ios::fmtflags oflags = + os.flags (static_cast + (pff.f.fmt | pff.f.up | pff.f.sp)); + + os << pff.mantissa (); + + int ex = pff.exponent (); + if (ex < 0) + { + os << std::setw (0) << "e-"; + ex = -ex; + } + else + os << std::setw (0) << "e+"; + + os << std::setw (pff.f.ex - 2) << std::setfill('0') << ex + << std::setfill(' '); + + os.flags (oflags); + + return os; +} + class pr_formatted_float { @@ -485,21 +583,30 @@ } if (! (rat_format || bank_format || hex_format || bit_format) - && (fw > Voutput_max_field_width || print_e || print_g)) + && (fw > Voutput_max_field_width || print_e || print_g || print_eng)) { if (print_g) fmt = float_format (); else { - int exp_field = 4; + int ex = 4; if (digits > 100) - exp_field++; - - fw = 2 + prec + exp_field; - if (inf_or_nan && fw < 4) - fw = 4; - - fmt = float_format (fw, prec - 1, std::ios::scientific); + ex++; + + if (print_eng) + { + fw = 4 + prec + ex; + if (inf_or_nan && fw < 6) + fw = 6; + fmt = float_format (fw, ex, prec - 1, std::ios::fixed); + } + else + { + fw = 2 + prec + ex; + if (inf_or_nan && fw < 4) + fw = 4; + fmt = float_format (fw, prec - 1, std::ios::scientific); + } } if (print_big_e) @@ -529,7 +636,7 @@ double d_abs = d < 0.0 ? -d : d; int digits = (inf_or_nan || d_abs == 0.0) - ? 0 : static_cast (floor (log10 (d_abs) + 1.0)); + ? 0 : (calc_digits (d_abs) + 1); set_real_format (digits, inf_or_nan, int_only, fw); } @@ -629,22 +736,31 @@ if (! (rat_format || bank_format || hex_format || bit_format) && (print_e - || print_g + || print_eng || print_g || (! Vfixed_point_format && fw > Voutput_max_field_width))) { if (print_g) fmt = float_format (); else { - int exp_field = 4; + int ex = 4; if (x_max > 100 || x_min > 100) - exp_field++; - - fw = 2 + prec + exp_field; - if (inf_or_nan && fw < 4) - fw = 4; - - fmt = float_format (fw, prec - 1, std::ios::scientific); + ex++; + + if (print_eng) + { + fw = 4 + prec + ex; + if (inf_or_nan && fw < 6) + fw = 6; + fmt = float_format (fw, ex, prec - 1, std::ios::fixed); + } + else + { + fw = 2 + prec + ex; + if (inf_or_nan && fw < 4) + fw = 4; + fmt = float_format (fw, prec - 1, std::ios::scientific); + } } if (print_big_e) @@ -675,13 +791,12 @@ double max_abs = pr_max_internal (m_abs); double min_abs = pr_min_internal (m_abs); - int x_max = max_abs == 0.0 - ? 0 : static_cast (floor (log10 (max_abs) + 1.0)); - - int x_min = min_abs == 0.0 - ? 0 : static_cast (floor (log10 (min_abs) + 1.0)); - - scale = (x_max == 0 || int_or_inf_or_nan) ? 1.0 : std::pow (10.0, x_max - 1); + int x_max = max_abs == 0.0 ? 0 : (calc_digits (max_abs) + 1); + + int x_min = min_abs == 0.0 ? 0 : (calc_digits (min_abs) + 1); + + scale = (x_max == 0 || int_or_inf_or_nan) ? 1.0 + : std::pow (10.0, maybe_mod3 (x_max - 1)); set_real_matrix_format (x_max, x_min, inf_or_nan, int_or_inf_or_nan, fw); } @@ -787,7 +902,7 @@ } if (! (rat_format || bank_format || hex_format || bit_format) - && (r_fw > Voutput_max_field_width || print_e || print_g)) + && (r_fw > Voutput_max_field_width || print_e || print_eng || print_g)) { if (print_g) { @@ -796,20 +911,34 @@ } else { - int exp_field = 4; + int ex = 4; if (x_max > 100 || x_min > 100) - exp_field++; - - i_fw = prec + exp_field; - r_fw = i_fw + 1; - if (inf_or_nan && i_fw < 3) + ex++; + + if (print_eng) { - i_fw = 3; - r_fw = 4; + i_fw = 3 + prec + ex; + r_fw = i_fw + 1; + if (inf_or_nan && i_fw < 5) + { + i_fw = 5; + r_fw = 6; + } + r_fmt = float_format (r_fw, ex, prec - 1, std::ios::fixed); + i_fmt = float_format (i_fw, ex, prec - 1, std::ios::fixed); } - - r_fmt = float_format (r_fw, prec - 1, std::ios::scientific); - i_fmt = float_format (i_fw, prec - 1, std::ios::scientific); + else + { + i_fw = 1 + prec + ex; + r_fw = i_fw + 1; + if (inf_or_nan && i_fw < 3) + { + i_fw = 3; + r_fw = 4; + } + r_fmt = float_format (r_fw, prec - 1, std::ios::scientific); + i_fmt = float_format (i_fw, prec - 1, std::ios::scientific); + } } if (print_big_e) @@ -853,10 +982,10 @@ double i_abs = ip < 0.0 ? -ip : ip; int r_x = (xisinf (rp) || xisnan (rp) || r_abs == 0.0) - ? 0 : static_cast (floor (log10 (r_abs) + 1.0)); + ? 0 : (calc_digits (r_abs) + 1); int i_x = (xisinf (ip) || xisnan (ip) || i_abs == 0.0) - ? 0 : static_cast (floor (log10 (i_abs) + 1.0)); + ? 0 : (calc_digits (i_abs) + 1); int x_max, x_min; @@ -987,7 +1116,7 @@ if (! (rat_format || bank_format || hex_format || bit_format) && (print_e - || print_g + || print_eng || print_g || (! Vfixed_point_format && r_fw > Voutput_max_field_width))) { if (print_g) @@ -997,20 +1126,34 @@ } else { - int exp_field = 4; + int ex = 4; if (x_max > 100 || x_min > 100) - exp_field++; - - i_fw = prec + exp_field; - r_fw = i_fw + 1; - if (inf_or_nan && i_fw < 3) + ex++; + + if (print_eng) { - i_fw = 3; - r_fw = 4; + i_fw = 3 + prec + ex; + r_fw = i_fw + 1; + if (inf_or_nan && i_fw < 5) + { + i_fw = 5; + r_fw = 6; + } + r_fmt = float_format (r_fw, ex, prec - 1, std::ios::fixed); + i_fmt = float_format (i_fw, ex, prec - 1, std::ios::fixed); } - - r_fmt = float_format (r_fw, prec - 1, std::ios::scientific); - i_fmt = float_format (i_fw, prec - 1, std::ios::scientific); + else + { + i_fw = 1 + prec + ex; + r_fw = i_fw + 1; + if (inf_or_nan && i_fw < 3) + { + i_fw = 3; + r_fw = 4; + } + r_fmt = float_format (r_fw, prec - 1, std::ios::scientific); + i_fmt = float_format (i_fw, prec - 1, std::ios::scientific); + } } if (print_big_e) @@ -1059,22 +1202,19 @@ double i_max_abs = pr_max_internal (i_m_abs); double i_min_abs = pr_min_internal (i_m_abs); - int r_x_max = r_max_abs == 0.0 - ? 0 : static_cast (floor (log10 (r_max_abs) + 1.0)); - - int r_x_min = r_min_abs == 0.0 - ? 0 : static_cast (floor (log10 (r_min_abs) + 1.0)); - - int i_x_max = i_max_abs == 0.0 - ? 0 : static_cast (floor (log10 (i_max_abs) + 1.0)); - - int i_x_min = i_min_abs == 0.0 - ? 0 : static_cast (floor (log10 (i_min_abs) + 1.0)); + int r_x_max = r_max_abs == 0.0 ? 0 : (calc_digits (r_max_abs) + 1); + + int r_x_min = r_min_abs == 0.0 ? 0 : (calc_digits (r_min_abs) + 1); + + int i_x_max = i_max_abs == 0.0 ? 0 : (calc_digits (i_max_abs) + 1); + + int i_x_min = i_min_abs == 0.0 ? 0 : (calc_digits (i_min_abs) + 1); int x_max = r_x_max > i_x_max ? r_x_max : i_x_max; int x_min = r_x_min > i_x_min ? r_x_min : i_x_min; - scale = (x_max == 0 || int_or_inf_or_nan) ? 1.0 : std::pow (10.0, x_max - 1); + scale = (x_max == 0 || int_or_inf_or_nan) ? 1.0 + : std::pow (10.0, maybe_mod3 (x_max - 1)); set_complex_matrix_format (x_max, x_min, r_x_max, r_x_min, inf_or_nan, int_or_inf_or_nan, r_fw, i_fw); @@ -1167,20 +1307,27 @@ if (! (rat_format || bank_format || hex_format || bit_format) && (print_e - || print_g + || print_eng || print_g || (! Vfixed_point_format && fw > Voutput_max_field_width))) { if (print_g) fmt = float_format (); else { - int exp_field = 4; + int ex = 4; if (x_max > 100 || x_min > 100) - exp_field++; - - fw = 3 + prec + exp_field; - - fmt = float_format (fw, prec - 1, std::ios::scientific); + ex++; + + if (print_eng) + { + fw = 5 + prec + ex; + fmt = float_format (fw, ex, prec - 1, std::ios::fixed); + } + else + { + fw = 3 + prec + ex; + fmt = float_format (fw, prec - 1, std::ios::scientific); + } } if (print_big_e) @@ -1218,13 +1365,12 @@ double max_abs = r_max < 0.0 ? -r_max : r_max; double min_abs = r_min < 0.0 ? -r_min : r_min; - int x_max = max_abs == 0.0 - ? 0 : static_cast (floor (log10 (max_abs) + 1.0)); - - int x_min = min_abs == 0.0 - ? 0 : static_cast (floor (log10 (min_abs) + 1.0)); - - scale = (x_max == 0 || all_ints) ? 1.0 : std::pow (10.0, x_max - 1); + int x_max = max_abs == 0.0 ? 0 : (calc_digits (max_abs) + 1); + + int x_min = min_abs == 0.0 ? 0 : (calc_digits (min_abs) + 1); + + scale = (x_max == 0 || all_ints) ? 1.0 + : std::pow (10.0, maybe_mod3 (x_max - 1)); set_range_format (x_max, x_min, all_ints, fw); } @@ -1391,6 +1537,8 @@ else os << "NaN"; } + else if (print_eng) + os << pr_engineering_float (*fmt, d); else os << pr_formatted_float (*fmt, d); } @@ -3381,6 +3529,7 @@ print_e = false; print_big_e = false; print_g = false; + print_eng = false; } static void @@ -3427,6 +3576,11 @@ print_g = true; print_big_e = true; } + else if (arg == "eng") + { + init_format_state (); + print_eng = true; + } else { error ("format: unrecognized option `short %s'", @@ -3467,6 +3621,11 @@ print_g = true; print_big_e = true; } + else if (arg == "eng") + { + init_format_state (); + print_eng = true; + } else { error ("format: unrecognized option `long %s'", @@ -3626,6 +3785,13 @@ @end group\n\ @end example\n\ \n\ +@item short eng\n\ +@itemx long eng\n\ +Identical to @samp{short e} or @samp{long e} but displays the value\n\ +using an engineering format, where the exponent is divisible by 3. For\n\ +example, with the @samp{short eng} format, @code{10 * pi} is displayed as\n\ +@code{31.4159e+00}.\n\ +\n\ @item long G\n\ @itemx short G\n\ Identical to @samp{short g} or @samp{long g} but displays an uppercase\n\