1 /* mpfr_pow_ui-- compute the power of a floating-point
4 Copyright 1999-2015 Free Software Foundation, Inc.
5 Contributed by the AriC and Caramel projects, INRIA.
7 This file is part of the GNU MPFR Library.
9 The GNU MPFR Library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
14 The GNU MPFR Library is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
21 http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
22 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
24 #define MPFR_NEED_LONGLONG_H
25 #include "mpfr-impl.h"
27 /* sets y to x^n, and return 0 if exact, non-zero otherwise */
29 mpfr_pow_ui (mpfr_ptr y
, mpfr_srcptr x
, unsigned long int n
, mpfr_rnd_t rnd
)
33 mpfr_prec_t prec
, err
;
36 MPFR_SAVE_EXPO_DECL (expo
);
38 MPFR_BLOCK_DECL (flags
);
41 (("x[%Pu]=%.*Rg n=%lu rnd=%d",
42 mpfr_get_prec (x
), mpfr_log_prec
, x
, n
, rnd
),
43 ("y[%Pu]=%.*Rg inexact=%d",
44 mpfr_get_prec (y
), mpfr_log_prec
, y
, inexact
));
46 /* x^0 = 1 for any x, even a NaN */
47 if (MPFR_UNLIKELY (n
== 0))
48 return mpfr_set_ui (y
, 1, rnd
);
50 if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x
)))
57 else if (MPFR_IS_INF (x
))
59 /* Inf^n = Inf, (-Inf)^n = Inf for n even, -Inf for n odd */
60 if (MPFR_IS_NEG (x
) && (n
& 1) == 1)
69 MPFR_ASSERTD (MPFR_IS_ZERO (x
));
70 /* 0^n = 0 for any n */
72 if (MPFR_IS_POS (x
) || (n
& 1) == 0)
79 else if (MPFR_UNLIKELY (n
<= 2))
83 return mpfr_set (y
, x
, rnd
);
86 return mpfr_sqr (y
, x
, rnd
);
89 /* Augment exponent range */
90 MPFR_SAVE_EXPO_MARK (expo
);
92 /* setup initial precision */
93 prec
= MPFR_PREC (y
) + 3 + GMP_NUMB_BITS
94 + MPFR_INT_CEIL_LOG2 (MPFR_PREC (y
));
95 mpfr_init2 (res
, prec
);
97 rnd1
= MPFR_IS_POS (x
) ? MPFR_RNDU
: MPFR_RNDD
; /* away */
99 MPFR_ZIV_INIT (loop
, prec
);
104 for (m
= n
, i
= 0; m
; i
++, m
>>= 1)
106 /* now 2^(i-1) <= n < 2^i */
107 MPFR_ASSERTD (prec
> (mpfr_prec_t
) i
);
108 err
= prec
- 1 - (mpfr_prec_t
) i
;
109 /* First step: compute square from x */
111 inexact
= mpfr_mul (res
, x
, x
, MPFR_RNDU
);
112 MPFR_ASSERTD (i
>= 2);
113 if (n
& (1UL << (i
-2)))
114 inexact
|= mpfr_mul (res
, res
, x
, rnd1
);
115 for (i
-= 3; i
>= 0 && !MPFR_BLOCK_EXCEP
; i
--)
117 inexact
|= mpfr_mul (res
, res
, res
, MPFR_RNDU
);
119 inexact
|= mpfr_mul (res
, res
, x
, rnd1
);
121 /* let r(n) be the number of roundings: we have r(2)=1, r(3)=2,
122 and r(2n)=2r(n)+1, r(2n+1)=2r(n)+2, thus r(n)=n-1.
123 Using Higham's method, to each rounding corresponds a factor
124 (1-theta) with 0 <= theta <= 2^(1-p), thus at the end the
125 absolute error is bounded by (n-1)*2^(1-p)*res <= 2*(n-1)*ulp(res)
126 since 2^(-p)*x <= ulp(x). Since n < 2^i, this gives a maximal
127 error of 2^(1+i)*ulp(res).
129 if (MPFR_LIKELY (inexact
== 0
130 || MPFR_OVERFLOW (flags
) || MPFR_UNDERFLOW (flags
)
131 || MPFR_CAN_ROUND (res
, err
, MPFR_PREC (y
), rnd
)))
133 /* Actualisation of the precision */
134 MPFR_ZIV_NEXT (loop
, prec
);
135 mpfr_set_prec (res
, prec
);
137 MPFR_ZIV_FREE (loop
);
139 if (MPFR_UNLIKELY (MPFR_OVERFLOW (flags
) || MPFR_UNDERFLOW (flags
)))
143 /* Internal overflow or underflow. However the approximation error has
144 * not been taken into account. So, let's solve this problem by using
145 * mpfr_pow_z, which can handle it. This case could be improved in the
146 * future, without having to use mpfr_pow_z.
148 MPFR_LOG_MSG (("Internal overflow or underflow,"
149 " let's use mpfr_pow_z.\n", 0));
151 MPFR_SAVE_EXPO_FREE (expo
);
154 inexact
= mpfr_pow_z (y
, x
, z
, rnd
);
159 inexact
= mpfr_set (y
, res
, rnd
);
162 MPFR_SAVE_EXPO_FREE (expo
);
163 return mpfr_check_range (y
, inexact
, rnd
);