xref: /netbsd-src/external/lgpl3/mpfr/dist/src/acosu.c (revision ec6772edaf0cdcb5f52a48f4aca5e33a8fb8ecfd)
1 /* mpfr_acosu  -- acosu(x)  = acos(x)*u/(2*pi)
2    mpfr_acospi -- acospi(x) = acos(x)/pi
3 
4 Copyright 2021-2023 Free Software Foundation, Inc.
5 Contributed by the AriC and Caramba projects, INRIA.
6 
7 This file is part of the GNU MPFR Library.
8 
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.
13 
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.
18 
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 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
22 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
23 
24 #define MPFR_NEED_LONGLONG_H
25 #include "mpfr-impl.h"
26 
27 /* put in y the correctly rounded value of acos(x)*u/(2*pi) */
28 int
mpfr_acosu(mpfr_ptr y,mpfr_srcptr x,unsigned long u,mpfr_rnd_t rnd_mode)29 mpfr_acosu (mpfr_ptr y, mpfr_srcptr x, unsigned long u, mpfr_rnd_t rnd_mode)
30 {
31   mpfr_t tmp, pi;
32   mpfr_prec_t prec;
33   mpfr_exp_t expx;
34   int compared, inexact;
35   MPFR_SAVE_EXPO_DECL (expo);
36   MPFR_ZIV_DECL (loop);
37 
38   MPFR_LOG_FUNC
39     (("x[%Pd]=%.*Rg u=%lu rnd=%d", mpfr_get_prec(x), mpfr_log_prec, x, u,
40       rnd_mode),
41      ("y[%Pd]=%.*Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y,
42       inexact));
43 
44   /* Singular cases */
45   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
46     {
47       if (MPFR_IS_NAN (x) || MPFR_IS_INF (x))
48         {
49           MPFR_SET_NAN (y);
50           MPFR_RET_NAN;
51         }
52       else /* necessarily x=0 */
53         {
54           MPFR_ASSERTD(MPFR_IS_ZERO(x));
55           /* acos(0)=Pi/2 thus acosu(0)=u/4 */
56           return mpfr_set_ui_2exp (y, u, -2, rnd_mode);
57         }
58     }
59 
60   compared = mpfr_cmpabs_ui (x, 1);
61   if (compared > 0)
62     {
63       /* acosu(x) = NaN for |x| > 1, included for u=0, since NaN*0 = NaN */
64       MPFR_SET_NAN (y);
65       MPFR_RET_NAN;
66     }
67 
68   if (u == 0) /* return +0 since acos(x)>=0 */
69     {
70       MPFR_SET_ZERO (y);
71       MPFR_SET_POS (y);
72       MPFR_RET (0);
73     }
74 
75   if (compared == 0)
76     {
77       /* |x| = 1: acosu(1,u) = +0, acosu(-1,u)=u/2 */
78       if (MPFR_SIGN(x) > 0) /* IEEE-754 2019: acosPi(1) = +0 */
79         return mpfr_set_ui (y, 0, rnd_mode);
80       else
81         return mpfr_set_ui_2exp (y, u, -1, rnd_mode);
82     }
83 
84   /* acos(1/2) = pi/6 and acos(-1/2) = pi/3, thus in these cases acos(x,u)
85      is exact when u is a multiple of 3 */
86   if (mpfr_cmp_si_2exp (x, MPFR_SIGN(x), -1) == 0 && (u % 3) == 0)
87     return mpfr_set_si_2exp (y, u / 3, MPFR_IS_NEG (x) ? 0 : -1, rnd_mode);
88 
89   prec = MPFR_PREC (y);
90 
91   MPFR_SAVE_EXPO_MARK (expo);
92 
93   /* For |x|<0.5, we have acos(x) = pi/2 - x*r(x) with |r(x)| < 1.05
94      thus acosu(x,u) = u/4*(1 - x*s(x)) with 0 <= s(x) < 1.
95      If EXP(x) <= -prec-3, then |u/4*x*s(x)| < u/4*2^(-prec-3) < ulp(u/4)/8
96      <= ulp(RN(u/4))/4, thus the result will be u/4, nextbelow(u/4) or
97      nextabove(u/4).
98      Warning: when u/4 is a power of two, the difference between u/4 and
99      nextbelow(u/4) is only 1/4*ulp(u/4).
100      We also require x < 2^-64, so that in the case u/4 is not exact,
101      the contribution of x*s(x) is smaller compared to the last bit of u. */
102   expx = MPFR_GET_EXP(x);
103   if (expx <= -64 && expx <= - (mpfr_exp_t) prec - 3)
104     {
105       prec = (MPFR_PREC(y) <= 63) ? 65 : MPFR_PREC(y) + 2;
106       /* now prec > 64 and prec > MPFR_PREC(y)+1 */
107       mpfr_init2 (tmp, prec);
108       inexact = mpfr_set_ui (tmp, u, MPFR_RNDN); /* exact since prec >= 64 */
109       MPFR_ASSERTD(inexact == 0);
110       /* for x>0, we have acos(x) < pi/2; for x<0, we have acos(x) > pi/2 */
111       if (MPFR_IS_POS(x))
112         mpfr_nextbelow (tmp);
113       else
114         mpfr_nextabove (tmp);
115       /* Since prec >= 65, the last significant bit of tmp is 1, and since
116          prec > PREC(y), tmp is not representable in the target precision,
117          which ensures we will get a correct ternary value below. */
118       MPFR_ASSERTD(mpfr_min_prec(tmp) > MPFR_PREC(y));
119       /* since prec >= PREC(y)+2, the rounding of tmp is correct */
120       inexact = mpfr_div_2ui (y, tmp, 2, rnd_mode);
121       mpfr_clear (tmp);
122       goto end;
123     }
124 
125   prec += MPFR_INT_CEIL_LOG2(prec) + 10;
126 
127   mpfr_init2 (tmp, prec);
128   mpfr_init2 (pi, prec);
129 
130   MPFR_ZIV_INIT (loop, prec);
131   for (;;)
132     {
133       /* In the error analysis below, each thetax denotes a variable such that
134          |thetax| <= 2^-prec */
135       mpfr_acos (tmp, x, MPFR_RNDN);
136       /* tmp = acos(x) * (1 + theta1) */
137       mpfr_const_pi (pi, MPFR_RNDN);
138       /* pi = Pi * (1 + theta2) */
139       mpfr_div (tmp, tmp, pi, MPFR_RNDN);
140       /* tmp = acos(x)/Pi * (1 + theta3)^3 */
141       mpfr_mul_ui (tmp, tmp, u, MPFR_RNDN);
142       /* tmp = acos(x)*u/Pi * (1 + theta4)^4 */
143       mpfr_div_2ui (tmp, tmp, 1, MPFR_RNDN); /* exact */
144       /* tmp = acos(x)*u/(2*Pi) * (1 + theta4)^4 */
145       /* since |(1 + theta4)^4 - 1| <= 8*|theta4| for prec >= 2,
146          the relative error is less than 2^(3-prec) */
147       if (MPFR_LIKELY (MPFR_CAN_ROUND (tmp, prec - 3,
148                                        MPFR_PREC (y), rnd_mode)))
149         break;
150       MPFR_ZIV_NEXT (loop, prec);
151       mpfr_set_prec (tmp, prec);
152       mpfr_set_prec (pi, prec);
153     }
154   MPFR_ZIV_FREE (loop);
155 
156   inexact = mpfr_set (y, tmp, rnd_mode);
157   mpfr_clear (tmp);
158   mpfr_clear (pi);
159 
160  end:
161   MPFR_SAVE_EXPO_FREE (expo);
162   return mpfr_check_range (y, inexact, rnd_mode);
163 }
164 
165 int
mpfr_acospi(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)166 mpfr_acospi (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
167 {
168   return mpfr_acosu (y, x, 2, rnd_mode);
169 }
170