# HG changeset patch # User Markus Mützel # Date 1542552601 -3600 # Node ID 3e44ed9d50b6f34982ab6d832b46ee534f401df1 # Parent b543cf12c63f90d8986057612cc0b53a2a1bc76f 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". diff -r b543cf12c63f -r 3e44ed9d50b6 libinterp/corefcn/pr-output.cc --- 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 -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::min () - || val > std::numeric_limits::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 (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 (std::numeric_limits::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 (n) - << '/' << static_cast (d); - m++; - - if (n < 0 && d < 0) - { - // Double negative, string can be two characters longer.. - if (buf.str ().length () > static_cast (len + 2)) - break; - } - else if (buf.str ().length () > static_cast (len)) - break; - - if (std::abs (n) > std::numeric_limits::max () - || std::abs (d) > std::numeric_limits::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 (lastn) - << '/' << static_cast (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 std::ostream& operator << (std::ostream& os, const pr_rational_float& 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 -*- diff -r b543cf12c63f -r 3e44ed9d50b6 liboctave/util/oct-string.cc --- 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 #include #include - +#include #include #include "Array.h" +#include "lo-ieee.h" +#include "lo-mappers.h" template static bool @@ -481,3 +483,102 @@ return val; } + +template +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::min () + || val > std::numeric_limits::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 (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 (std::numeric_limits::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 (n) + << '/' << static_cast (d); + m++; + + if (n < 0 && d < 0) + { + // Double negative, string can be two characters longer. + if (buf.str ().length () > static_cast (len + 2)) + break; + } + else if (buf.str ().length () > static_cast (len)) + break; + + if (std::abs (n) > std::numeric_limits::max () + || std::abs (d) > std::numeric_limits::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 (lastn) + << '/' << static_cast (lastd); + s = buf.str (); + } + } + + return s; +} + +// instanciate the template for float and double +template std::string rational_approx (float val, int len); +template std::string rational_approx (double val, int len); diff -r b543cf12c63f -r 3e44ed9d50b6 liboctave/util/oct-string.h --- 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 +extern OCTAVE_API std::string +rational_approx (T val, int len); + #endif