Mercurial > octave
changeset 26111:3e44ed9d50b6
Move rational_approx to liboctave (patch #9084).
* libinterp/corefcn/pr-output.cc, liboctave/util/oct-string.[cc/h]: Move
"rational_approx" from "pr-output.cc" to "oct-string.cc".
author | Markus Mützel <markus.muetzel@gmx.de> |
---|---|
date | Sun, 18 Nov 2018 15:50:01 +0100 |
parents | b543cf12c63f |
children | 36e0e5b428e7 |
files | libinterp/corefcn/pr-output.cc liboctave/util/oct-string.cc liboctave/util/oct-string.h |
diffstat | 3 files changed, 121 insertions(+), 110 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/pr-output.cc Sun Nov 18 15:44:36 2018 +0100 +++ b/libinterp/corefcn/pr-output.cc Sun Nov 18 15:50:01 2018 +0100 @@ -40,6 +40,7 @@ #include "lo-mappers.h" #include "mach-info.h" #include "oct-cmplx.h" +#include "oct-string.h" #include "quit.h" #include "Cell.h" @@ -235,115 +236,6 @@ } template <typename T> -static inline std::string -rational_approx (T val, int len) -{ - std::string s; - - if (len <= 0) - len = 10; - - if (octave::math::isinf (val)) - s = "1/0"; - else if (octave::math::isnan (val)) - s = "0/0"; - else if (val < std::numeric_limits<int>::min () - || val > std::numeric_limits<int>::max () - || octave::math::x_nint (val) == val) - { - std::ostringstream buf; - buf.flags (std::ios::fixed); - buf << std::setprecision (0) << octave::math::round (val); - s = buf.str (); - } - else - { - T lastn = 1; - T lastd = 0; - T n = octave::math::round (val); - T d = 1; - 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 (); - - while (true) - { - T flip = 1 / frac; - T step = octave::math::round (flip); - T nextn = n; - T nextd = d; - - // Have we converged to 1/intmax ? - if (std::abs (flip) > static_cast<T> (std::numeric_limits<int>::max ())) - { - lastn = n; - lastd = d; - break; - } - - frac = flip - step; - n = step * n + lastn; - d = step * d + 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)) - 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 ()) - break; - - s = buf.str (); - } - - 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; -} - -/* -%!assert (rats (2.0005, 9), "4001/2000") -%!assert (rats (-2.0005, 10), "-4001/2000") -%!assert (strtrim (rats (2.0005, 30)), "4001/2000") -%!assert (pi - str2num (rats (pi, 30)), 0, 4 * eps) -%!assert (e - str2num (rats (e, 30)), 0, 4 * eps) -%!assert (rats (123, 2), " *") - -%!test -%! v = 1 / double (intmax); -%! err = v - str2num (rats(v, 12)); -%! assert (err, 0, 4 * eps); -*/ - -template <typename T> std::ostream& operator << (std::ostream& os, const pr_rational_float<T>& prf) { @@ -3285,6 +3177,20 @@ return ovl (string_vector (lst)); } +/* +%!assert (rats (2.0005, 9), "4001/2000") +%!assert (rats (-2.0005, 10), "-4001/2000") +%!assert (strtrim (rats (2.0005, 30)), "4001/2000") +%!assert (pi - str2num (rats (pi, 30)), 0, 4 * eps) +%!assert (e - str2num (rats (e, 30)), 0, 4 * eps) +%!assert (rats (123, 2), " *") + +%!test +%! v = 1 / double (intmax); +%! err = v - str2num (rats(v, 12)); +%! assert (err, 0, 4 * eps); +*/ + DEFUN (disp, args, nargout, classes: cell char double function_handle int8 int16 int32 int64 logical single struct uint8 uint16 uint32 uint64 doc: /* -*- texinfo -*-
--- a/liboctave/util/oct-string.cc Sun Nov 18 15:44:36 2018 +0100 +++ b/liboctave/util/oct-string.cc Sun Nov 18 15:50:01 2018 +0100 @@ -28,10 +28,12 @@ #include <algorithm> #include <cctype> #include <cstring> - +#include <iomanip> #include <string> #include "Array.h" +#include "lo-ieee.h" +#include "lo-mappers.h" template <typename T> static bool @@ -481,3 +483,102 @@ return val; } + +template <typename T> +std::string +rational_approx (T val, int len) +{ + std::string s; + + if (len <= 0) + len = 10; + + if (octave::math::isinf (val)) + s = "1/0"; + else if (octave::math::isnan (val)) + s = "0/0"; + else if (val < std::numeric_limits<int>::min () + || val > std::numeric_limits<int>::max () + || octave::math::x_nint (val) == val) + { + std::ostringstream buf; + buf.flags (std::ios::fixed); + buf << std::setprecision (0) << octave::math::round (val); + s = buf.str (); + } + else + { + T lastn = 1; + T lastd = 0; + T n = octave::math::round (val); + T d = 1; + 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 (); + + while (true) + { + T flip = 1 / frac; + T step = octave::math::round (flip); + T nextn = n; + T nextd = d; + + // Have we converged to 1/intmax ? + if (std::abs (flip) > static_cast<T> (std::numeric_limits<int>::max ())) + { + lastn = n; + lastd = d; + break; + } + + frac = flip - step; + n = step * n + lastn; + d = step * d + 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)) + 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 ()) + break; + + s = buf.str (); + } + + 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; +} + +// instanciate 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);
--- a/liboctave/util/oct-string.h Sun Nov 18 15:44:36 2018 +0100 +++ b/liboctave/util/oct-string.h Sun Nov 18 15:50:01 2018 +0100 @@ -128,4 +128,8 @@ extern OCTAVE_API Complex octave_str2double (const std::string& str_arg); +template <typename T> +extern OCTAVE_API std::string +rational_approx (T val, int len); + #endif