Home | History | Annotate | Line # | Download | only in src
      1 /* mpfr_rint -- Round to an integer.
      2 
      3 Copyright 1999-2023 Free Software Foundation, Inc.
      4 Contributed by the AriC and Caramba projects, INRIA.
      5 
      6 This file is part of the GNU MPFR Library.
      7 
      8 The GNU MPFR Library is free software; you can redistribute it and/or modify
      9 it under the terms of the GNU Lesser General Public License as published by
     10 the Free Software Foundation; either version 3 of the License, or (at your
     11 option) any later version.
     12 
     13 The GNU MPFR Library is distributed in the hope that it will be useful, but
     14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
     16 License for more details.
     17 
     18 You should have received a copy of the GNU Lesser General Public License
     19 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
     20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
     21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
     22 
     23 #include "mpfr-impl.h"
     24 
     25 /* Merge the following mpfr_rint code with mpfr_round_raw_generic? */
     26 
     27 /* For all the round-to-integer functions, we don't need to extend the
     28  * exponent range. And it is better not to do so, so that we can test
     29  * the flag setting for intermediate overflow in the test suite without
     30  * involving huge non-integer numbers (thus in huge precision). This
     31  * should also be faster.
     32  *
     33  * We also need to be careful with the flags.
     34  */
     35 
     36 int
     37 mpfr_rint (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
     38 {
     39   int sign;
     40   int rnd_away;
     41   mpfr_exp_t exp;
     42 
     43   if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(u) ))
     44     {
     45       if (MPFR_IS_NAN(u))
     46         {
     47           MPFR_SET_NAN(r);
     48           MPFR_RET_NAN;
     49         }
     50       MPFR_SET_SAME_SIGN(r, u);
     51       if (MPFR_IS_INF(u))
     52         {
     53           MPFR_SET_INF(r);
     54           MPFR_RET(0);  /* infinity is exact */
     55         }
     56       else /* now u is zero */
     57         {
     58           MPFR_ASSERTD(MPFR_IS_ZERO(u));
     59           MPFR_SET_ZERO(r);
     60           MPFR_RET(0);  /* zero is exact */
     61         }
     62     }
     63   MPFR_SET_SAME_SIGN (r, u); /* Does nothing if r==u */
     64 
     65   sign = MPFR_INT_SIGN (u);
     66   exp = MPFR_GET_EXP (u);
     67 
     68   rnd_away =
     69     rnd_mode == MPFR_RNDD ? sign < 0 :
     70     rnd_mode == MPFR_RNDU ? sign > 0 :
     71     rnd_mode == MPFR_RNDZ ? 0        :
     72     rnd_mode == MPFR_RNDA ? 1        :
     73     -1; /* round to nearest-even (RNDN) or nearest-away (RNDNA) */
     74 
     75   /* rnd_away:
     76      1 if round away from zero,
     77      0 if round to zero,
     78      -1 if not decided yet.
     79    */
     80 
     81   if (MPFR_UNLIKELY (exp <= 0))  /* 0 < |u| < 1 ==> round |u| to 0 or 1 */
     82     {
     83       /* Note: in the MPFR_RNDN mode, 0.5 must be rounded to 0. */
     84       if (rnd_away != 0 &&
     85           (rnd_away > 0 ||
     86            (exp == 0 && (rnd_mode == MPFR_RNDNA ||
     87                          !mpfr_powerof2_raw (u)))))
     88         {
     89           /* The flags will correctly be set and overflow will correctly
     90              be handled by mpfr_set_si. */
     91           mpfr_set_si (r, sign, rnd_mode);
     92           MPFR_RET(sign > 0 ? 2 : -2);
     93         }
     94       else
     95         {
     96           MPFR_SET_ZERO(r);  /* r = 0 */
     97           MPFR_RET(sign > 0 ? -2 : 2);
     98         }
     99     }
    100   else  /* exp > 0, |u| >= 1 */
    101     {
    102       mp_limb_t *up, *rp;
    103       mp_size_t un, rn, ui;
    104       int sh, idiff;
    105       int uflags;
    106 
    107       /*
    108        * uflags will contain:
    109        *   _ 0 if u is an integer representable in r,
    110        *   _ 1 if u is an integer not representable in r,
    111        *   _ 2 if u is not an integer.
    112        */
    113 
    114       up = MPFR_MANT(u);
    115       rp = MPFR_MANT(r);
    116 
    117       un = MPFR_LIMB_SIZE(u);
    118       rn = MPFR_LIMB_SIZE(r);
    119       MPFR_UNSIGNED_MINUS_MODULO (sh, MPFR_PREC (r));
    120 
    121       /* exp is in the current exponent range: obtained from the input. */
    122       MPFR_SET_EXP (r, exp); /* Does nothing if r==u */
    123 
    124       if ((exp - 1) / GMP_NUMB_BITS >= un)
    125         {
    126           ui = un;
    127           idiff = 0;
    128           uflags = 0;  /* u is an integer, representable or not in r */
    129         }
    130       else
    131         {
    132           mp_size_t uj;
    133 
    134           ui = (exp - 1) / GMP_NUMB_BITS + 1;  /* #limbs of the int part */
    135           MPFR_ASSERTD (un >= ui);
    136           uj = un - ui;  /* lowest limb of the integer part */
    137           idiff = exp % GMP_NUMB_BITS;  /* #int-part bits in up[uj] or 0 */
    138 
    139           uflags = idiff == 0 || MPFR_LIMB_LSHIFT(up[uj],idiff) == 0 ? 0 : 2;
    140           if (uflags == 0)
    141             while (uj > 0)
    142               if (up[--uj] != 0)
    143                 {
    144                   uflags = 2;
    145                   break;
    146                 }
    147         }
    148 
    149       if (ui > rn)
    150         {
    151           /* More limbs in the integer part of u than in r.
    152              Just round u with the precision of r. */
    153           MPFR_ASSERTD (rp != up && un > rn);
    154           MPN_COPY (rp, up + (un - rn), rn); /* r != u */
    155           if (rnd_away < 0)
    156             {
    157               /* This is a rounding to nearest mode (MPFR_RNDN or MPFR_RNDNA).
    158                  Decide the rounding direction here. */
    159               if (rnd_mode == MPFR_RNDN &&
    160                   (rp[0] & (MPFR_LIMB_ONE << sh)) == 0)
    161                 { /* halfway cases rounded toward zero */
    162                   mp_limb_t a, b;
    163                   /* a: rounding bit and some of the following bits */
    164                   /* b: boundary for a (weight of the rounding bit in a) */
    165                   if (sh != 0)
    166                     {
    167                       a = rp[0] & ((MPFR_LIMB_ONE << sh) - 1);
    168                       b = MPFR_LIMB_ONE << (sh - 1);
    169                     }
    170                   else
    171                     {
    172                       a = up[un - rn - 1];
    173                       b = MPFR_LIMB_HIGHBIT;
    174                     }
    175                   rnd_away = a > b;
    176                   if (a == b)
    177                     {
    178                       mp_size_t i;
    179                       for (i = un - rn - 1 - (sh == 0); i >= 0; i--)
    180                         if (up[i] != 0)
    181                           {
    182                             rnd_away = 1;
    183                             break;
    184                           }
    185                     }
    186                 }
    187               else  /* halfway cases rounded away from zero */
    188                 rnd_away =  /* rounding bit */
    189                   ((sh != 0 && (rp[0] & (MPFR_LIMB_ONE << (sh - 1))) != 0) ||
    190                    (sh == 0 && (up[un - rn - 1] & MPFR_LIMB_HIGHBIT) != 0));
    191             }
    192           if (uflags == 0)
    193             { /* u is an integer; determine if it is representable in r */
    194               if (sh != 0 && MPFR_LIMB_LSHIFT(rp[0], GMP_NUMB_BITS - sh) != 0)
    195                 uflags = 1;  /* u is not representable in r */
    196               else
    197                 {
    198                   mp_size_t i;
    199                   for (i = un - rn - 1; i >= 0; i--)
    200                     if (up[i] != 0)
    201                       {
    202                         uflags = 1;  /* u is not representable in r */
    203                         break;
    204                       }
    205                 }
    206             }
    207         }
    208       else  /* ui <= rn */
    209         {
    210           mp_size_t uj, rj;
    211           int ush;
    212 
    213           uj = un - ui;  /* lowest limb of the integer part in u */
    214           rj = rn - ui;  /* lowest limb of the integer part in r */
    215 
    216           if (rp != up)
    217             MPN_COPY(rp + rj, up + uj, ui);
    218 
    219           /* Ignore the lowest rj limbs, all equal to zero. */
    220           rp += rj;
    221           rn = ui;
    222 
    223           /* number of fractional bits in whole rp[0] */
    224           ush = idiff == 0 ? 0 : GMP_NUMB_BITS - idiff;
    225 
    226           if (rj == 0 && ush < sh)
    227             {
    228               /* If u is an integer (uflags == 0), we need to determine
    229                  if it is representable in r, i.e. if its sh - ush bits
    230                  in the non-significant part of r are all 0. */
    231               if (uflags == 0 && (rp[0] & ((MPFR_LIMB_ONE << sh) -
    232                                            (MPFR_LIMB_ONE << ush))) != 0)
    233                 uflags = 1;  /* u is an integer not representable in r */
    234             }
    235           else  /* The integer part of u fits in r, we'll round to it. */
    236             sh = ush;
    237 
    238           if (rnd_away < 0)
    239             {
    240               /* This is a rounding to nearest mode.
    241                  Decide the rounding direction here. */
    242               if (uj == 0 && sh == 0)
    243                 rnd_away = 0; /* rounding bit = 0 (not represented in u) */
    244               else if (rnd_mode == MPFR_RNDN &&
    245                        (rp[0] & (MPFR_LIMB_ONE << sh)) == 0)
    246                 { /* halfway cases rounded toward zero */
    247                   mp_limb_t a, b;
    248                   /* a: rounding bit and some of the following bits */
    249                   /* b: boundary for a (weight of the rounding bit in a) */
    250                   if (sh != 0)
    251                     {
    252                       a = rp[0] & ((MPFR_LIMB_ONE << sh) - 1);
    253                       b = MPFR_LIMB_ONE << (sh - 1);
    254                     }
    255                   else
    256                     {
    257                       MPFR_ASSERTD (uj >= 1);  /* see above */
    258                       a = up[uj - 1];
    259                       b = MPFR_LIMB_HIGHBIT;
    260                     }
    261                   rnd_away = a > b;
    262                   if (a == b)
    263                     {
    264                       mp_size_t i;
    265                       for (i = uj - 1 - (sh == 0); i >= 0; i--)
    266                         if (up[i] != 0)
    267                           {
    268                             rnd_away = 1;
    269                             break;
    270                           }
    271                     }
    272                 }
    273               else  /* halfway cases rounded away from zero */
    274                 rnd_away =  /* rounding bit */
    275                   ((sh != 0 && (rp[0] & (MPFR_LIMB_ONE << (sh - 1))) != 0) ||
    276                    (sh == 0 && (MPFR_ASSERTD (uj >= 1),
    277                                 up[uj - 1] & MPFR_LIMB_HIGHBIT) != 0));
    278             }
    279           /* Now we can make the low rj limbs to 0 */
    280           MPN_ZERO (rp-rj, rj);
    281         }
    282 
    283       if (sh != 0)
    284         rp[0] &= MPFR_LIMB_MAX << sh;
    285 
    286       /* If u is a representable integer, there is no rounding. */
    287       if (uflags == 0)
    288         MPFR_RET(0);
    289 
    290       MPFR_ASSERTD (rnd_away >= 0);  /* rounding direction is defined */
    291       if (rnd_away && mpn_add_1 (rp, rp, rn, MPFR_LIMB_ONE << sh))
    292         {
    293           if (exp == __gmpfr_emax)
    294             return mpfr_overflow (r, rnd_mode, sign) >= 0 ?
    295               uflags : -uflags;
    296           else  /* no overflow */
    297             {
    298               MPFR_SET_EXP(r, exp + 1);
    299               rp[rn-1] = MPFR_LIMB_HIGHBIT;
    300             }
    301         }
    302 
    303       MPFR_RET (rnd_away ^ (sign < 0) ? uflags : -uflags);
    304     }  /* exp > 0, |u| >= 1 */
    305 }
    306 
    307 #undef mpfr_roundeven
    308 
    309 int
    310 mpfr_roundeven (mpfr_ptr r, mpfr_srcptr u)
    311 {
    312   return mpfr_rint (r, u, MPFR_RNDN);
    313 }
    314 
    315 #undef mpfr_round
    316 
    317 int
    318 mpfr_round (mpfr_ptr r, mpfr_srcptr u)
    319 {
    320   return mpfr_rint (r, u, MPFR_RNDNA);
    321 }
    322 
    323 #undef mpfr_trunc
    324 
    325 int
    326 mpfr_trunc (mpfr_ptr r, mpfr_srcptr u)
    327 {
    328   return mpfr_rint (r, u, MPFR_RNDZ);
    329 }
    330 
    331 #undef mpfr_ceil
    332 
    333 int
    334 mpfr_ceil (mpfr_ptr r, mpfr_srcptr u)
    335 {
    336   return mpfr_rint (r, u, MPFR_RNDU);
    337 }
    338 
    339 #undef mpfr_floor
    340 
    341 int
    342 mpfr_floor (mpfr_ptr r, mpfr_srcptr u)
    343 {
    344   return mpfr_rint (r, u, MPFR_RNDD);
    345 }
    346 
    347 /* We need to save the flags and restore them after calling the mpfr_round,
    348  * mpfr_trunc, mpfr_ceil, mpfr_floor functions because these functions set
    349  * the inexact flag when the argument is not an integer.
    350  */
    351 
    352 #undef mpfr_rint_roundeven
    353 
    354 int
    355 mpfr_rint_roundeven (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
    356 {
    357   if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(u) ) || mpfr_integer_p (u))
    358     return mpfr_set (r, u, rnd_mode);
    359   else
    360     {
    361       mpfr_t tmp;
    362       int inex;
    363       mpfr_flags_t saved_flags = __gmpfr_flags;
    364       MPFR_BLOCK_DECL (flags);
    365 
    366       mpfr_init2 (tmp, MPFR_PREC (u));
    367       /* round(u) is representable in tmp unless an overflow occurs */
    368       MPFR_BLOCK (flags, mpfr_roundeven (tmp, u));
    369       __gmpfr_flags = saved_flags;
    370       inex = (MPFR_OVERFLOW (flags)
    371               ? mpfr_overflow (r, rnd_mode, MPFR_SIGN (u))
    372               : mpfr_set (r, tmp, rnd_mode));
    373       mpfr_clear (tmp);
    374       return inex;
    375     }
    376 }
    377 
    378 #undef mpfr_rint_round
    379 
    380 int
    381 mpfr_rint_round (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
    382 {
    383   if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(u) ) || mpfr_integer_p (u))
    384     return mpfr_set (r, u, rnd_mode);
    385   else
    386     {
    387       mpfr_t tmp;
    388       int inex;
    389       mpfr_flags_t saved_flags = __gmpfr_flags;
    390       MPFR_BLOCK_DECL (flags);
    391 
    392       mpfr_init2 (tmp, MPFR_PREC (u));
    393       /* round(u) is representable in tmp unless an overflow occurs */
    394       MPFR_BLOCK (flags, mpfr_round (tmp, u));
    395       __gmpfr_flags = saved_flags;
    396       inex = (MPFR_OVERFLOW (flags)
    397               ? mpfr_overflow (r, rnd_mode, MPFR_SIGN (u))
    398               : mpfr_set (r, tmp, rnd_mode));
    399       mpfr_clear (tmp);
    400       return inex;
    401     }
    402 }
    403 
    404 #undef mpfr_rint_trunc
    405 
    406 int
    407 mpfr_rint_trunc (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
    408 {
    409   if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(u) ) || mpfr_integer_p (u))
    410     return mpfr_set (r, u, rnd_mode);
    411   else
    412     {
    413       mpfr_t tmp;
    414       int inex;
    415       mpfr_flags_t saved_flags = __gmpfr_flags;
    416 
    417       mpfr_init2 (tmp, MPFR_PREC (u));
    418       /* trunc(u) is always representable in tmp */
    419       mpfr_trunc (tmp, u);
    420       __gmpfr_flags = saved_flags;
    421       inex = mpfr_set (r, tmp, rnd_mode);
    422       mpfr_clear (tmp);
    423       return inex;
    424     }
    425 }
    426 
    427 #undef mpfr_rint_ceil
    428 
    429 int
    430 mpfr_rint_ceil (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
    431 {
    432   if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(u) ) || mpfr_integer_p (u))
    433     return mpfr_set (r, u, rnd_mode);
    434   else
    435     {
    436       mpfr_t tmp;
    437       int inex;
    438       mpfr_flags_t saved_flags = __gmpfr_flags;
    439       MPFR_BLOCK_DECL (flags);
    440 
    441       mpfr_init2 (tmp, MPFR_PREC (u));
    442       /* ceil(u) is representable in tmp unless an overflow occurs */
    443       MPFR_BLOCK (flags, mpfr_ceil (tmp, u));
    444       __gmpfr_flags = saved_flags;
    445       inex = (MPFR_OVERFLOW (flags)
    446               ? mpfr_overflow (r, rnd_mode, MPFR_SIGN_POS)
    447               : mpfr_set (r, tmp, rnd_mode));
    448       mpfr_clear (tmp);
    449       return inex;
    450     }
    451 }
    452 
    453 #undef mpfr_rint_floor
    454 
    455 int
    456 mpfr_rint_floor (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode)
    457 {
    458   if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(u) ) || mpfr_integer_p (u))
    459     return mpfr_set (r, u, rnd_mode);
    460   else
    461     {
    462       mpfr_t tmp;
    463       int inex;
    464       mpfr_flags_t saved_flags = __gmpfr_flags;
    465       MPFR_BLOCK_DECL (flags);
    466 
    467       mpfr_init2 (tmp, MPFR_PREC (u));
    468       /* floor(u) is representable in tmp unless an overflow occurs */
    469       MPFR_BLOCK (flags, mpfr_floor (tmp, u));
    470       __gmpfr_flags = saved_flags;
    471       inex = (MPFR_OVERFLOW (flags)
    472               ? mpfr_overflow (r, rnd_mode, MPFR_SIGN_NEG)
    473               : mpfr_set (r, tmp, rnd_mode));
    474       mpfr_clear (tmp);
    475       return inex;
    476     }
    477 }
    478