diff options
author | zimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4> | 2017-06-02 10:44:12 +0000 |
---|---|---|
committer | zimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4> | 2017-06-02 10:44:12 +0000 |
commit | f97a9c17ef78ce4c4e1197d11a95cf68e8679a71 (patch) | |
tree | 4453d0ea3f6fbf2dda803f9281e10a4eeae33002 | |
parent | bd811b9b51d306146b07e2c630d34b82341de8fe (diff) | |
download | mpfr-f97a9c17ef78ce4c4e1197d11a95cf68e8679a71.tar.gz |
added new function mpfr_get_q
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@11563 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | doc/mpfr.texi | 6 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/get_q.c | 53 | ||||
-rw-r--r-- | src/mpf2mpfr.h | 2 | ||||
-rw-r--r-- | src/mpfr.h | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/tget_q.c | 111 |
8 files changed, 176 insertions, 2 deletions
@@ -49,6 +49,7 @@ Changes from versions 3.1.* to version 4.0.0: - New functions mpfr_log_ui to compute the logarithm of an integer, mpfr_gamma_inc for the incomplete Gamma function, and mpfr_beta for the Beta function. +- New function mpfr_get_q to convert a floating-point number into rational. - The mpfr_eint function now returns the value of the E1/eint1 function for negative argument. - The behavior of the mpfr_set_exp function changed, as it could easily diff --git a/doc/mpfr.texi b/doc/mpfr.texi index 66c62f433..00e86ec97 100644 --- a/doc/mpfr.texi +++ b/doc/mpfr.texi @@ -1565,6 +1565,12 @@ when it is smaller than @var{op}; moreover, if @var{rop} differs from @var{op}, i.e., if @var{op} is not an integer, the inexact flag is set. @end deftypefun +@deftypefun void mpfr_get_q (mpq_t @var{rop}, mpfr_t @var{op}, mpfr_rnd_t) +Convert @var{op} to a @code{mpq_t}. +If @var{op} is NaN or an infinity, the @emph{erange} flag is +set, @var{rop} is set to 0. Otherwise the conversion is always exact. +@end deftypefun + @deftypefun int mpfr_get_f (mpf_t @var{rop}, mpfr_t @var{op}, mpfr_rnd_t @var{rnd}) Convert @var{op} to a @code{mpf_t}, after rounding it with respect to @var{rnd}. diff --git a/src/Makefile.am b/src/Makefile.am index c002950b6..5ec64760c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,7 +60,7 @@ scale2.c set_z_exp.c ai.c gammaonethird.c ieee_floats.h \ grandom.c fpif.c set_float128.c get_float128.c rndna.c nrandom.c \ random_deviate.h random_deviate.c erandom.c mpfr-mini-gmp.c \ mpfr-mini-gmp.h fmma.c log_ui.c gamma_inc.c ubf.c invert_limb.h \ -invsqrt_limb.h beta.c odd_p.c +invsqrt_limb.h beta.c odd_p.c get_q.c libmpfr_la_LIBADD = @LIBOBJS@ diff --git a/src/get_q.c b/src/get_q.c new file mode 100644 index 000000000..c332880ba --- /dev/null +++ b/src/get_q.c @@ -0,0 +1,53 @@ +/* mpfr_get_q -- get a multiple-precision rational from + a floating-point number + +Copyright 2004, 2006-2017 Free Software Foundation, Inc. +Contributed by the AriC and Caramba projects, INRIA. + +This file is part of the GNU MPFR Library. + +The GNU MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +The GNU MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see +http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., +51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "mpfr-impl.h" + +/* part of the code was copied from get_z.c */ +void +mpfr_get_q (mpq_ptr q, mpfr_srcptr f) +{ + mpfr_exp_t exp; + mpz_ptr u = mpq_numref (q); + mpz_ptr v = mpq_denref (q); + + + mpz_set_ui (v, 1); + if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (f))) + { + if (MPFR_UNLIKELY (MPFR_NOTZERO (f))) + MPFR_SET_ERANGEFLAG (); + mpz_set_ui (u, 0); + /* The ternary value is 0 even for infinity. Giving the rounding + direction in this case would not make much sense anyway, and + the direction would not necessarily match rnd. */ + } + else + { + exp = mpfr_get_z_2exp (u, f); + if (exp >= 0) + mpz_mul_2exp (u, u, exp); + else + mpz_mul_2exp (v, v, -exp); + } +} diff --git a/src/mpf2mpfr.h b/src/mpf2mpfr.h index b08964166..3ecbdf97b 100644 --- a/src/mpf2mpfr.h +++ b/src/mpf2mpfr.h @@ -176,5 +176,7 @@ http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., #undef mpz_set_f #define mpz_set_f(z,f) mpfr_get_z(z,f,MPFR_DEFAULT_RND) +#undef mpq_set_f +#define mpq_set_f(q,f) mpfr_get_q(q,f) #endif /* __MPFR_FROM_MPF__ */ diff --git a/src/mpfr.h b/src/mpfr.h index c54d24aca..421e53de1 100644 --- a/src/mpfr.h +++ b/src/mpfr.h @@ -475,6 +475,7 @@ __MPFR_DECLSPEC unsigned long mpfr_get_ui (mpfr_srcptr, mpfr_rnd_t); __MPFR_DECLSPEC char * mpfr_get_str (char*, mpfr_exp_t*, int, size_t, mpfr_srcptr, mpfr_rnd_t); __MPFR_DECLSPEC int mpfr_get_z (mpz_ptr z, mpfr_srcptr f, mpfr_rnd_t); +__MPFR_DECLSPEC void mpfr_get_q (mpq_ptr q, mpfr_srcptr f); __MPFR_DECLSPEC void mpfr_free_str (char *); diff --git a/tests/Makefile.am b/tests/Makefile.am index f2c0502a6..772196e8f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -33,7 +33,7 @@ check_PROGRAMS = tversion tabort_prec_max tassert tabort_defalloc1 \ tsprintf tsqr tsqrt tsqrt_ui tstckintc tstdint tstrtofr tsub \ tsub1sp tsub_d tsub_ui tsubnormal tsum tswap ttan ttanh ttrunc \ tui_div tui_pow tui_sub turandom tvalist ty0 ty1 tyn tzeta \ - tzeta_ui tbeta + tzeta_ui tbeta tget_q # Before Automake 1.13, we ran tversion at the beginning and at the end # of the tests, and output from tversion appeared at the same place as diff --git a/tests/tget_q.c b/tests/tget_q.c new file mode 100644 index 000000000..0bafd4817 --- /dev/null +++ b/tests/tget_q.c @@ -0,0 +1,111 @@ +/* Test file for mpfr_get_q. + +Copyright 2017 Free Software Foundation, Inc. +Contributed by the AriC and Caramba projects, INRIA. + +This file is part of the GNU MPFR Library. + +The GNU MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +The GNU MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see +http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., +51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "mpfr-test.h" + +static void +special (void) +{ + mpfr_t f; + mpq_t q; + + mpfr_init2 (f, MPFR_PREC_MIN); + mpq_init (q); + + /* check NaN */ + mpfr_set_nan (f); + mpfr_clear_erangeflag (); + mpfr_get_q (q, f); + MPFR_ASSERTN(mpq_cmp_ui (q, 0, 1) == 0); + MPFR_ASSERTN(mpfr_erangeflag_p ()); + + /* check +Inf */ + mpfr_set_inf (f, 1); + mpfr_clear_erangeflag (); + mpfr_get_q (q, f); + MPFR_ASSERTN(mpq_cmp_ui (q, 0, 1) == 0); + MPFR_ASSERTN(mpfr_erangeflag_p ()); + + /* check -Inf */ + mpfr_set_inf (f, -1); + mpfr_clear_erangeflag (); + mpfr_get_q (q, f); + MPFR_ASSERTN(mpq_cmp_ui (q, 0, 1) == 0); + MPFR_ASSERTN(mpfr_erangeflag_p ()); + + /* check +0 */ + mpfr_set_zero (f, 1); + mpfr_clear_erangeflag (); + mpfr_get_q (q, f); + MPFR_ASSERTN(mpq_cmp_ui (q, 0, 1) == 0); + MPFR_ASSERTN(!mpfr_erangeflag_p ()); + + /* check -0 */ + mpfr_set_zero (f, -1); + mpfr_clear_erangeflag (); + mpfr_get_q (q, f); + MPFR_ASSERTN(mpq_cmp_ui (q, 0, 1) == 0); + MPFR_ASSERTN(!mpfr_erangeflag_p ()); + + mpq_clear (q); + mpfr_clear (f); +} + +static void +random_tests (void) +{ + mpfr_t f, g; + mpq_t q; + int inex; + mpfr_rnd_t rnd; + int i; + + mpfr_init2 (f, MPFR_PREC_MIN + (randlimb() % 100)); + mpfr_init2 (g, mpfr_get_prec (f)); + mpq_init (q); + + for (i = 0; i < 1000; i++) + { + mpfr_urandomb (f, RANDS); + mpfr_get_q (q, f); + rnd = RND_RAND (); + inex = mpfr_set_q (g, q, rnd); + MPFR_ASSERTN(inex == 0); + MPFR_ASSERTN(mpfr_cmp (f, g) == 0); + } + + mpq_clear (q); + mpfr_clear (f); + mpfr_clear (g); +} + +int +main (void) +{ + tests_start_mpfr (); + + special (); + random_tests (); + + tests_end_mpfr (); + return 0; +} |