summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2004-09-30 16:06:25 +0000
committervlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2004-09-30 16:06:25 +0000
commit046a99a3dded4fe32a2b59194bfa8456e4a7ebce (patch)
treeb78a738e42c6dcdf347e8e91850852a0c46c4a4f
parentda0fbcf750b224a536d3d7c0808e9de7ee9f5eb7 (diff)
downloadmpfr-046a99a3dded4fe32a2b59194bfa8456e4a7ebce.tar.gz
Added functions mpfr_rint_round, mpfr_rint_trunc, mpfr_rint_ceil,
mpfr_rint_floor. git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@3016 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r--mpfr.h4
-rw-r--r--mpfr.texi15
-rw-r--r--rint.c105
-rw-r--r--tests/trint.c22
4 files changed, 135 insertions, 11 deletions
diff --git a/mpfr.h b/mpfr.h
index fa1483734..e0b9a57b3 100644
--- a/mpfr.h
+++ b/mpfr.h
@@ -360,6 +360,10 @@ int mpfr_round _MPFR_PROTO((mpfr_ptr, mpfr_srcptr));
int mpfr_trunc _MPFR_PROTO((mpfr_ptr, mpfr_srcptr));
int mpfr_ceil _MPFR_PROTO((mpfr_ptr, mpfr_srcptr));
int mpfr_floor _MPFR_PROTO((mpfr_ptr, mpfr_srcptr));
+int mpfr_rint_round _MPFR_PROTO((mpfr_ptr, mpfr_srcptr, mpfr_rnd_t));
+int mpfr_rint_trunc _MPFR_PROTO((mpfr_ptr, mpfr_srcptr, mpfr_rnd_t));
+int mpfr_rint_ceil _MPFR_PROTO((mpfr_ptr, mpfr_srcptr, mpfr_rnd_t));
+int mpfr_rint_floor _MPFR_PROTO((mpfr_ptr, mpfr_srcptr, mpfr_rnd_t));
int mpfr_frac _MPFR_PROTO((mpfr_ptr, mpfr_srcptr, mpfr_rnd_t));
int mpfr_fits_ulong_p _MPFR_PROTO((mpfr_srcptr, mpfr_rnd_t));
diff --git a/mpfr.texi b/mpfr.texi
index 1c978f367..e19184ba3 100644
--- a/mpfr.texi
+++ b/mpfr.texi
@@ -1387,6 +1387,21 @@ in binary) in 2-bit precision, though @code{round(4.5)} is equal to 5 and
5 (101 in binary) is rounded to 6 (110 in binary) in 2-bit precision.
@end deftypefun
+@deftypefun int mpfr_rint_ceil (mpfr_t @var{rop}, mpfr_t @var{op}, mp_rnd_t @var{rnd})
+@deftypefunx int mpfr_rint_floor (mpfr_t @var{rop}, mpfr_t @var{op}, mp_rnd_t @var{rnd})
+@deftypefunx int mpfr_rint_round (mpfr_t @var{rop}, mpfr_t @var{op}, mp_rnd_t @var{rnd})
+@deftypefunx int mpfr_rint_trunc (mpfr_t @var{rop}, mpfr_t @var{op}, mp_rnd_t @var{rnd})
+Set @var{rop} to @var{op} rounded to an integer.
+@code{mpfr_rint_ceil} rounds to the next higher or equal integer,
+@code{mpfr_rint_floor} to the next lower or equal integer,
+@code{mpfr_rint_round} to the nearest integer, rounding halfway cases away
+from zero, and @code{mpfr_rint_trunc} to the next integer towards zero.
+If the result is not representable, it is rounded in the direction @var{rnd}.
+The returned value is the ternary value associated with the considered
+round-to-integer function (regarded in the same way as any other
+mathematical function).
+@end deftypefun
+
@deftypefun int mpfr_frac (mpfr_t @var{rop}, mpfr_t @var{op}, mp_rnd_t @var{rnd})
Set @var{rop} to the fractional part of @var{op}, having the same sign as
@var{op}, rounded in the direction @var{rnd} (unlike in @code{mpfr_rint},
diff --git a/rint.c b/rint.c
index 2c726fece..029489aed 100644
--- a/rint.c
+++ b/rint.c
@@ -24,7 +24,7 @@ MA 02111-1307, USA. */
/* Merge the following mpfr_rint code with mpfr_round_raw_generic? */
int
-mpfr_rint (mpfr_ptr r, mpfr_srcptr u, mp_rnd_t rnd_mode)
+mpfr_rint (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
{
int sign;
int rnd_away;
@@ -51,7 +51,7 @@ mpfr_rint (mpfr_ptr r, mpfr_srcptr u, mp_rnd_t rnd_mode)
}
}
MPFR_SET_SAME_SIGN(r, u);
-
+
sign = MPFR_INT_SIGN(u);
exp = MPFR_GET_EXP (u);
@@ -327,3 +327,104 @@ mpfr_floor (mpfr_ptr r, mpfr_srcptr u)
{
return mpfr_rint(r, u, GMP_RNDD);
}
+
+#undef mpfr_rint_round
+
+int
+mpfr_rint_round (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
+{
+ if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(u) ) || mpfr_integer_p (u))
+ return mpfr_set (r, u, rnd_mode);
+ else
+ {
+ mpfr_t tmp;
+ int inex;
+
+ mpfr_save_emin_emax ();
+ mpfr_init2 (tmp, MPFR_PREC (u));
+ /* round(u) is representable in tmp unless an overflow occurs */
+ mpfr_clear_overflow ();
+ mpfr_round (tmp, u);
+ inex = (mpfr_overflow_p ()
+ ? mpfr_set_overflow (r, rnd_mode, MPFR_SIGN (u))
+ : mpfr_set (r, tmp, rnd_mode));
+ mpfr_clear (tmp);
+ mpfr_restore_emin_emax ();
+ return mpfr_check_range (r, inex, rnd_mode);
+ }
+}
+
+#undef mpfr_rint_trunc
+
+int
+mpfr_rint_trunc (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
+{
+ if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(u) ) || mpfr_integer_p (u))
+ return mpfr_set (r, u, rnd_mode);
+ else
+ {
+ mpfr_t tmp;
+ int inex;
+
+ mpfr_save_emin_emax ();
+ mpfr_init2 (tmp, MPFR_PREC (u));
+ /* trunc(u) is always representable in tmp */
+ mpfr_trunc (tmp, u);
+ inex = mpfr_set (r, tmp, rnd_mode);
+ mpfr_clear (tmp);
+ mpfr_restore_emin_emax ();
+ return mpfr_check_range (r, inex, rnd_mode);
+ }
+}
+
+#undef mpfr_rint_ceil
+
+int
+mpfr_rint_ceil (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
+{
+ if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(u) ) || mpfr_integer_p (u))
+ return mpfr_set (r, u, rnd_mode);
+ else
+ {
+ mpfr_t tmp;
+ int inex;
+
+ mpfr_save_emin_emax ();
+ mpfr_init2 (tmp, MPFR_PREC (u));
+ /* ceil(u) is representable in tmp unless an overflow occurs */
+ mpfr_clear_overflow ();
+ mpfr_ceil (tmp, u);
+ inex = (mpfr_overflow_p ()
+ ? mpfr_set_overflow (r, rnd_mode, MPFR_SIGN_POS)
+ : mpfr_set (r, tmp, rnd_mode));
+ mpfr_clear (tmp);
+ mpfr_restore_emin_emax ();
+ return mpfr_check_range (r, inex, rnd_mode);
+ }
+}
+
+#undef mpfr_rint_floor
+
+int
+mpfr_rint_floor (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
+{
+ if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(u) ) || mpfr_integer_p (u))
+ return mpfr_set (r, u, rnd_mode);
+ else
+ {
+ mpfr_t tmp;
+ int inex;
+
+ mpfr_save_emin_emax ();
+ mpfr_init2 (tmp, MPFR_PREC (u));
+ /* floor(u) is representable in tmp unless an overflow occurs */
+ mpfr_clear_overflow ();
+ mpfr_floor (tmp, u);
+ inex = (mpfr_overflow_p ()
+ ? mpfr_set_overflow (r, rnd_mode, MPFR_SIGN_NEG)
+ : mpfr_set (r, tmp, rnd_mode));
+ mpfr_clear (tmp);
+ mpfr_restore_emin_emax ();
+ return mpfr_check_range (r, inex, rnd_mode);
+ }
+}
diff --git a/tests/trint.c b/tests/trint.c
index a7475bed5..e2b66939d 100644
--- a/tests/trint.c
+++ b/tests/trint.c
@@ -243,25 +243,29 @@ main (int argc, char *argv[])
mpfr_set_prec (y, p);
mpfr_set_prec (v, p);
for (r = 0; r < GMP_RND_MAX ; r++)
- for (trint = 0; trint < 2; trint++)
+ for (trint = 0; trint < 3; trint++)
{
- if (trint)
+ if (trint == 2)
inexact = mpfr_rint (y, x, r);
else if (r == GMP_RNDN)
inexact = mpfr_round (y, x);
else if (r == GMP_RNDZ)
- inexact = mpfr_trunc (y, x);
+ inexact = (trint ? mpfr_trunc (y, x) :
+ mpfr_rint_trunc (y, x, GMP_RNDZ));
else if (r == GMP_RNDU)
- inexact = mpfr_ceil (y, x);
+ inexact = (trint ? mpfr_ceil (y, x) :
+ mpfr_rint_ceil (y, x, GMP_RNDU));
else /* r = GMP_RNDD */
- inexact = mpfr_floor (y, x);
+ inexact = (trint ? mpfr_floor (y, x) :
+ mpfr_rint_floor (y, x, GMP_RNDD));
if (mpfr_sub (t, y, x, GMP_RNDN))
err ("subtraction 1 should be exact",
s, x, y, p, r, trint, inexact);
sign_t = mpfr_cmp_ui (t, 0);
- if (((inexact == 0) && (sign_t != 0)) ||
- ((inexact < 0) && (sign_t >= 0)) ||
- ((inexact > 0) && (sign_t <= 0)))
+ if (trint != 0 &&
+ (((inexact == 0) && (sign_t != 0)) ||
+ ((inexact < 0) && (sign_t >= 0)) ||
+ ((inexact > 0) && (sign_t <= 0))))
err ("wrong inexact flag", s, x, y, p, r, trint, inexact);
if (inexact == 0)
continue; /* end of the test for exact results */
@@ -300,7 +304,7 @@ main (int argc, char *argv[])
continue;
/* |t| = |u|: x is the middle of two consecutive
representable integers. */
- if (trint)
+ if (trint == 2)
{
/* halfway case for mpfr_rint in GMP_RNDN rounding
mode: round to an even integer or mantissa. */