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