Mercurial > hg > octave-lojdl
diff src/pr-output.cc @ 6788:c81a0f3f5a82
[project @ 2007-07-23 22:05:29 by dbateman]
author | dbateman |
---|---|
date | Mon, 23 Jul 2007 22:05:30 +0000 |
parents | 14992092ab06 |
children | fe19c6cb5bc6 |
line wrap: on
line diff
--- a/src/pr-output.cc +++ b/src/pr-output.cc @@ -90,6 +90,12 @@ // First char for > 0, second for < 0, third for == 0. static std::string plus_format_chars = "+ "; +// TRUE means always print in a rational approximation +static bool rat_format = false; + +// Used to force the length of the rational approximation string for Frats +static int rat_string_len = -1; + // TRUE means always print like dollars and cents. static bool bank_format = false; @@ -112,6 +118,7 @@ static bool print_big_e = false; class pr_formatted_float; +class pr_rational_float; static int current_output_max_field_width (void) @@ -170,6 +177,9 @@ friend std::ostream& operator << (std::ostream& os, const pr_formatted_float& pff); + friend std::ostream& operator << (std::ostream& os, + const pr_rational_float& pff); + private: // Field width. Zero means as wide as necessary. @@ -221,6 +231,131 @@ return os; } +static inline std::string +rational_approx (double val, int len) +{ + std::string s; + + if (len <= 0) + len = 10; + + if (xisinf (val)) + s = "1/0"; + else if (xisnan (val)) + s = "0/0"; + else if (val < INT_MIN || val > INT_MAX || D_NINT (val) == val) + { + std::ostringstream buf; + buf.flags (std::ios::fixed); + buf << std::setprecision (0) << xround(val); + s = buf.str (); + } + else + { + double lastn = 1.; + double lastd = 0.; + double n = xround (val); + double d = 1.; + double 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(); + + while (1) + { + double flip = 1. / frac; + double step = xround (flip); + double nextn = n; + double nextd = d; + frac = flip - step; + n = n * step + lastn; + d = d * step + lastd; + lastn = nextn; + lastd = nextd; + + std::ostringstream buf; + buf.flags (std::ios::fixed); + buf << std::setprecision (0) << static_cast<int>(n) + << "/" << static_cast<int>(d); + m++; + + if (n < 0 && d < 0) + { + // Double negative, string can be two characters longer.. + if (buf.str().length() > static_cast<unsigned int>(len + 2) && + m > 1) + break; + } + else if (buf.str().length() > static_cast<unsigned int>(len) && + m > 1) + break; + + s = buf.str(); + + // Have we converged to 1/intmax ? + if (m > 100 || fabs (frac) < 1 / static_cast<double>(INT_MAX)) + { + lastn = n; + lastd = d; + break; + } + } + + if (lastd < 0.) + { + // Move sign to the top + lastd = - lastd; + lastn = - lastn; + std::ostringstream buf; + buf.flags (std::ios::fixed); + buf << std::setprecision (0) << static_cast<int>(lastn) + << "/" << static_cast<int>(lastd); + s = buf.str(); + } + } + + return s; +} + +class +pr_rational_float +{ +public: + + const float_format& f; + + double val; + + pr_rational_float (const float_format& f_arg, double val_arg) + : f (f_arg), val (val_arg) { } +}; + +std::ostream& +operator << (std::ostream& os, const pr_rational_float& prf) +{ + int fw = (rat_string_len > 0 ? rat_string_len : prf.f.fw); + std::string s = rational_approx (prf.val, fw); + + if (fw >= 0) + os << std::setw (fw); + + std::ios::fmtflags oflags = + os.flags (static_cast<std::ios::fmtflags> + (prf.f.fmt | prf.f.up | prf.f.sp)); + + if (fw > 0 && s.length() > static_cast<unsigned int>(fw)) + os << "*"; + else + os << s; + + os.flags (oflags); + + return os; +} + // Current format for real numbers and the real part of complex // numbers. static float_format *curr_real_fmt = 0; @@ -299,7 +434,12 @@ int ld, rd; - if (bank_format) + if (rat_format) + { + fw = 0; + rd = 0; + } + else if (bank_format) { fw = digits < 0 ? 4 : digits + 3; if (inf_or_nan && fw < 4) @@ -343,7 +483,7 @@ fw = 4; } - if (! (bank_format || hex_format || bit_format) + if (! (rat_format || bank_format || hex_format || bit_format) && (fw > Voutput_max_field_width || print_e || print_g)) { if (print_g) @@ -412,7 +552,12 @@ int ld, rd; - if (bank_format) + if (rat_format) + { + fw = 9; + rd = 0; + } + else if (bank_format) { int digits = x_max > x_min ? x_max : x_min; fw = digits <= 0 ? 4 : digits + 3; @@ -483,7 +628,7 @@ fw = 4; } - if (! (bank_format || hex_format || bit_format) + if (! (rat_format || bank_format || hex_format || bit_format) && (print_e || print_g || (! Vfixed_point_format && fw > Voutput_max_field_width))) @@ -564,7 +709,13 @@ int ld, rd; - if (bank_format) + if (rat_format) + { + i_fw = 0; + r_fw = 0; + rd = 0; + } + else if (bank_format) { int digits = r_x; i_fw = 0; @@ -639,7 +790,7 @@ } } - if (! (bank_format || hex_format || bit_format) + if (! (rat_format || bank_format || hex_format || bit_format) && (r_fw > Voutput_max_field_width || print_e || print_g)) { if (print_g) @@ -749,7 +900,13 @@ int ld, rd; - if (bank_format) + if (rat_format) + { + i_fw = 9; + r_fw = 9; + rd = 0; + } + else if (bank_format) { int digits = r_x_max > r_x_min ? r_x_max : r_x_min; i_fw = 0; @@ -835,7 +992,7 @@ } } - if (! (bank_format || hex_format || bit_format) + if (! (rat_format || bank_format || hex_format || bit_format) && (print_e || print_g || (! Vfixed_point_format && r_fw > Voutput_max_field_width))) @@ -949,7 +1106,12 @@ int ld, rd; - if (bank_format) + if (rat_format) + { + fw = 9; + rd = 0; + } + else if (bank_format) { int digits = x_max > x_min ? x_max : x_min; fw = sign + digits < 0 ? 4 : digits + 3; @@ -1012,7 +1174,7 @@ fw = sign + 1 + ld + 1 + rd; } - if (! (bank_format || hex_format || bit_format) + if (! (rat_format || bank_format || hex_format || bit_format) && (print_e || print_g || (! Vfixed_point_format && fw > Voutput_max_field_width))) @@ -1211,6 +1373,15 @@ } } } + else if (octave_is_NA (d)) + { + if (fw > 0) + os << std::setw (fw) << "NA"; + else + os << "NA"; + } + else if (rat_format) + os << pr_rational_float (*fmt, d); else if (xisinf (d)) { const char *s; @@ -1224,13 +1395,6 @@ else os << s; } - else if (octave_is_NA (d)) - { - if (fw > 0) - os << std::setw (fw) << "NA"; - else - os << "NA"; - } else if (xisnan (d)) { if (fw > 0) @@ -1695,7 +1859,8 @@ double scale = 1.0; set_format (cm, r_fw, i_fw, scale); int column_width = i_fw + r_fw; - column_width += (bank_format || hex_format|| bit_format) ? 2 : 7; + column_width += (rat_format || bank_format || hex_format + || bit_format) ? 2 : 7; octave_idx_type total_width = nc * column_width; octave_idx_type max_width = command_editor::terminal_cols (); @@ -2363,7 +2528,7 @@ fw = digits + isneg; } - int column_width = fw + (bank_format ? 5 : 2); + int column_width = fw + (rat_format ? 0 : (bank_format ? 5 : 2)); octave_idx_type total_width = nc * column_width; int max_width = command_editor::terminal_cols () - extra_indent; octave_idx_type inc = nc; @@ -2570,6 +2735,47 @@ panic_impossible (); } +DEFUN (rats, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} rats (@var{x}, @var{len})\n\ +Convert @var{x} into a rational approximation represented as a string.\n\ +You can convert the string back into a matrix as follows:\n\ +\n\ +@example\n\ + eval(['[',rats(hilb(4)),'];'])\n\ +@end example\n\ +\n\ +The optional second argument defines the maximum length of the string\n\ +representing the elements of @var{x}. By default @var{len} is 9.\n\ +@seealso{format, rat}\n\ +@end deftypefn") +{ + octave_value retval; + int nargin = args.length (); + + rat_string_len = 9; + if (nargin == 2) + rat_string_len = args(1).nint_value (); + + if (!error_state) + { + if (nargin < 3 && nargout < 2) + { + bool save_rat_format = rat_format; + rat_format = true; + std::ostringstream buf; + args(0).print (buf); + retval = buf.str (); + rat_format = save_rat_format; + } + else + print_usage (); + } + + rat_string_len = -1; + return retval; +} + DEFUN (disp, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} disp (@var{x})\n\ @@ -2659,6 +2865,7 @@ { free_format = false; plus_format = false; + rat_format = false; bank_format = false; hex_format = 0; bit_format = 0; @@ -2804,6 +3011,11 @@ init_format_state (); plus_format = true; } + else if (arg == "rat") + { + init_format_state (); + rat_format = true; + } else if (arg == "bank") { init_format_state (); @@ -2981,6 +3193,9 @@ @item loose\n\ Insert blank lines above and below column number labels (this is the\n\ default).\n\ +@item rat\n\ +Print a rational approximation. That is the values are approximated\n\ +by one small integer divided by another.\n\ @end table\n\ \n\ By default, Octave will try to print numbers with at least 5 significant\n\