(root)/
mpfr-4.2.1/
src/
pow_ui.c
       1  /* mpfr_pow_ui -- compute the power of a floating-point by a machine 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  #define MPFR_NEED_LONGLONG_H
      24  #include "mpfr-impl.h"
      25  
      26  #ifndef POW_U
      27  #define POW_U mpfr_pow_ui
      28  #define MPZ_SET_U mpz_set_ui
      29  #define UTYPE unsigned long int
      30  #define FSPEC "l"
      31  #endif
      32  
      33  /* sets y to x^n, and return 0 if exact, non-zero otherwise */
      34  int
      35  POW_U (mpfr_ptr y, mpfr_srcptr x, UTYPE n, mpfr_rnd_t rnd)
      36  {
      37    UTYPE m;
      38    mpfr_t res;
      39    mpfr_prec_t prec, err, nlen;
      40    int inexact;
      41    mpfr_rnd_t rnd1;
      42    MPFR_SAVE_EXPO_DECL (expo);
      43    MPFR_ZIV_DECL (loop);
      44    MPFR_BLOCK_DECL (flags);
      45  
      46    MPFR_LOG_FUNC
      47      (("x[%Pd]=%.*Rg n=%" FSPEC "u rnd=%d",
      48        mpfr_get_prec (x), mpfr_log_prec, x, n, rnd),
      49       ("y[%Pd]=%.*Rg inexact=%d",
      50        mpfr_get_prec (y), mpfr_log_prec, y, inexact));
      51  
      52    /* x^0 = 1 for any x, even a NaN */
      53    if (MPFR_UNLIKELY (n == 0))
      54      return mpfr_set_ui (y, 1, rnd);
      55  
      56    if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
      57      {
      58        if (MPFR_IS_NAN (x))
      59          {
      60            MPFR_SET_NAN (y);
      61            MPFR_RET_NAN;
      62          }
      63        else if (MPFR_IS_INF (x))
      64          {
      65            /* Inf^n = Inf, (-Inf)^n = Inf for n even, -Inf for n odd */
      66            if (MPFR_IS_NEG (x) && (n & 1) == 1)
      67              MPFR_SET_NEG (y);
      68            else
      69              MPFR_SET_POS (y);
      70            MPFR_SET_INF (y);
      71            MPFR_RET (0);
      72          }
      73        else /* x is zero */
      74          {
      75            MPFR_ASSERTD (MPFR_IS_ZERO (x));
      76            /* 0^n = 0 for any n */
      77            MPFR_SET_ZERO (y);
      78            if (MPFR_IS_POS (x) || (n & 1) == 0)
      79              MPFR_SET_POS (y);
      80            else
      81              MPFR_SET_NEG (y);
      82            MPFR_RET (0);
      83          }
      84      }
      85    else if (MPFR_UNLIKELY (n <= 2))
      86      {
      87        if (n < 2)
      88          /* x^1 = x */
      89          return mpfr_set (y, x, rnd);
      90        else
      91          /* x^2 = sqr(x) */
      92          return mpfr_sqr (y, x, rnd);
      93      }
      94  
      95    /* Augment exponent range */
      96    MPFR_SAVE_EXPO_MARK (expo);
      97  
      98    for (m = n, nlen = 0; m != 0; nlen++, m >>= 1)
      99      ;
     100    /* 2^(nlen-1) <= n < 2^nlen */
     101  
     102    /* set up initial precision */
     103    prec = MPFR_PREC (y) + 3 + GMP_NUMB_BITS
     104      + MPFR_INT_CEIL_LOG2 (MPFR_PREC (y));
     105    if (prec <= nlen)
     106      prec = nlen + 1;
     107    mpfr_init2 (res, prec);
     108  
     109    rnd1 = MPFR_IS_POS (x) ? MPFR_RNDU : MPFR_RNDD; /* away */
     110  
     111    MPFR_ZIV_INIT (loop, prec);
     112    for (;;)
     113      {
     114        int i;
     115  
     116        MPFR_ASSERTD (prec > nlen);
     117        err = prec - 1 - nlen;
     118        /* First step: compute square from x */
     119        MPFR_BLOCK (flags,
     120                    inexact = mpfr_sqr (res, x, MPFR_RNDU);
     121                    MPFR_ASSERTD (nlen >= 2 && nlen <= INT_MAX);
     122                    i = nlen;
     123                    if (n & ((UTYPE) 1 << (i-2)))
     124                      inexact |= mpfr_mul (res, res, x, rnd1);
     125                    for (i -= 3; i >= 0 && !MPFR_BLOCK_EXCEP; i--)
     126                      {
     127                        inexact |= mpfr_sqr (res, res, MPFR_RNDU);
     128                        if (n & ((UTYPE) 1 << i))
     129                          inexact |= mpfr_mul (res, res, x, rnd1);
     130                      });
     131        /* let r(n) be the number of roundings: we have r(2)=1, r(3)=2,
     132           and r(2n)=2r(n)+1, r(2n+1)=2r(n)+2, thus r(n)=n-1.
     133           Using Higham's method, to each rounding corresponds a factor
     134           (1-theta) with 0 <= theta <= 2^(1-p), thus at the end the
     135           absolute error is bounded by (n-1)*2^(1-p)*res <= 2*(n-1)*ulp(res)
     136           since 2^(-p)*x <= ulp(x). Since n < 2^i, this gives a maximal
     137           error of 2^(1+i)*ulp(res).
     138        */
     139        if (MPFR_LIKELY (inexact == 0
     140                         || MPFR_OVERFLOW (flags) || MPFR_UNDERFLOW (flags)
     141                         || MPFR_CAN_ROUND (res, err, MPFR_PREC (y), rnd)))
     142          break;
     143        /* Actualisation of the precision */
     144        MPFR_ZIV_NEXT (loop, prec);
     145        mpfr_set_prec (res, prec);
     146      }
     147    MPFR_ZIV_FREE (loop);
     148  
     149    if (MPFR_UNLIKELY (MPFR_OVERFLOW (flags) || MPFR_UNDERFLOW (flags)))
     150      {
     151        mpz_t z;
     152  
     153        /* Internal overflow or underflow. However, the approximation error has
     154         * not been taken into account. So, let's solve this problem by using
     155         * mpfr_pow_z, which can handle it. This case could be improved in the
     156         * future, without having to use mpfr_pow_z.
     157         */
     158        MPFR_LOG_MSG (("Internal overflow or underflow,"
     159                       " let's use mpfr_pow_z.\n", 0));
     160        mpfr_clear (res);
     161        MPFR_SAVE_EXPO_FREE (expo);
     162        mpz_init (z);
     163        MPZ_SET_U (z, n);
     164        inexact = mpfr_pow_z (y, x, z, rnd);
     165        mpz_clear (z);
     166        return inexact;
     167      }
     168  
     169    inexact = mpfr_set (y, res, rnd);
     170    mpfr_clear (res);
     171  
     172    MPFR_SAVE_EXPO_FREE (expo);
     173    return mpfr_check_range (y, inexact, rnd);
     174  }