1*d30dc8cbSJohn Marino /* mpc_sin_cos -- combined sine and cosine of a complex number.
2*d30dc8cbSJohn Marino
3*d30dc8cbSJohn Marino Copyright (C) 2010, 2011 INRIA
4*d30dc8cbSJohn Marino
5*d30dc8cbSJohn Marino This file is part of GNU MPC.
6*d30dc8cbSJohn Marino
7*d30dc8cbSJohn Marino GNU MPC is free software; you can redistribute it and/or modify it under
8*d30dc8cbSJohn Marino the terms of the GNU Lesser General Public License as published by the
9*d30dc8cbSJohn Marino Free Software Foundation; either version 3 of the License, or (at your
10*d30dc8cbSJohn Marino option) any later version.
11*d30dc8cbSJohn Marino
12*d30dc8cbSJohn Marino GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
13*d30dc8cbSJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14*d30dc8cbSJohn Marino FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15*d30dc8cbSJohn Marino more details.
16*d30dc8cbSJohn Marino
17*d30dc8cbSJohn Marino You should have received a copy of the GNU Lesser General Public License
18*d30dc8cbSJohn Marino along with this program. If not, see http://www.gnu.org/licenses/ .
19*d30dc8cbSJohn Marino */
20*d30dc8cbSJohn Marino
21*d30dc8cbSJohn Marino #include "mpc-impl.h"
22*d30dc8cbSJohn Marino
23*d30dc8cbSJohn Marino static int
mpc_sin_cos_nonfinite(mpc_ptr rop_sin,mpc_ptr rop_cos,mpc_srcptr op,mpc_rnd_t rnd_sin,mpc_rnd_t rnd_cos)24*d30dc8cbSJohn Marino mpc_sin_cos_nonfinite (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
25*d30dc8cbSJohn Marino mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
26*d30dc8cbSJohn Marino /* assumes that op (that is, its real or imaginary part) is not finite */
27*d30dc8cbSJohn Marino {
28*d30dc8cbSJohn Marino int overlap;
29*d30dc8cbSJohn Marino mpc_t op_loc;
30*d30dc8cbSJohn Marino
31*d30dc8cbSJohn Marino overlap = (rop_sin == op || rop_cos == op);
32*d30dc8cbSJohn Marino if (overlap) {
33*d30dc8cbSJohn Marino mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op));
34*d30dc8cbSJohn Marino mpc_set (op_loc, op, MPC_RNDNN);
35*d30dc8cbSJohn Marino }
36*d30dc8cbSJohn Marino else
37*d30dc8cbSJohn Marino op_loc [0] = op [0];
38*d30dc8cbSJohn Marino
39*d30dc8cbSJohn Marino if (rop_sin != NULL) {
40*d30dc8cbSJohn Marino if (mpfr_nan_p (mpc_realref (op_loc)) || mpfr_nan_p (mpc_imagref (op_loc))) {
41*d30dc8cbSJohn Marino mpc_set (rop_sin, op_loc, rnd_sin);
42*d30dc8cbSJohn Marino if (mpfr_nan_p (mpc_imagref (op_loc))) {
43*d30dc8cbSJohn Marino /* sin(x +i*NaN) = NaN +i*NaN, except for x=0 */
44*d30dc8cbSJohn Marino /* sin(-0 +i*NaN) = -0 +i*NaN */
45*d30dc8cbSJohn Marino /* sin(+0 +i*NaN) = +0 +i*NaN */
46*d30dc8cbSJohn Marino if (!mpfr_zero_p (mpc_realref (op_loc)))
47*d30dc8cbSJohn Marino mpfr_set_nan (mpc_realref (rop_sin));
48*d30dc8cbSJohn Marino }
49*d30dc8cbSJohn Marino else /* op = NaN + i*y */
50*d30dc8cbSJohn Marino if (!mpfr_inf_p (mpc_imagref (op_loc)) && !mpfr_zero_p (mpc_imagref (op_loc)))
51*d30dc8cbSJohn Marino /* sin(NaN -i*Inf) = NaN -i*Inf */
52*d30dc8cbSJohn Marino /* sin(NaN -i*0) = NaN -i*0 */
53*d30dc8cbSJohn Marino /* sin(NaN +i*0) = NaN +i*0 */
54*d30dc8cbSJohn Marino /* sin(NaN +i*Inf) = NaN +i*Inf */
55*d30dc8cbSJohn Marino /* sin(NaN +i*y) = NaN +i*NaN, when 0<|y|<Inf */
56*d30dc8cbSJohn Marino mpfr_set_nan (mpc_imagref (rop_sin));
57*d30dc8cbSJohn Marino }
58*d30dc8cbSJohn Marino else if (mpfr_inf_p (mpc_realref (op_loc))) {
59*d30dc8cbSJohn Marino mpfr_set_nan (mpc_realref (rop_sin));
60*d30dc8cbSJohn Marino
61*d30dc8cbSJohn Marino if (!mpfr_inf_p (mpc_imagref (op_loc)) && !mpfr_zero_p (mpc_imagref (op_loc)))
62*d30dc8cbSJohn Marino /* sin(+/-Inf +i*y) = NaN +i*NaN, when 0<|y|<Inf */
63*d30dc8cbSJohn Marino mpfr_set_nan (mpc_imagref (rop_sin));
64*d30dc8cbSJohn Marino else
65*d30dc8cbSJohn Marino /* sin(+/-Inf -i*Inf) = NaN -i*Inf */
66*d30dc8cbSJohn Marino /* sin(+/-Inf +i*Inf) = NaN +i*Inf */
67*d30dc8cbSJohn Marino /* sin(+/-Inf -i*0) = NaN -i*0 */
68*d30dc8cbSJohn Marino /* sin(+/-Inf +i*0) = NaN +i*0 */
69*d30dc8cbSJohn Marino mpfr_set (mpc_imagref (rop_sin), mpc_imagref (op_loc), MPC_RND_IM (rnd_sin));
70*d30dc8cbSJohn Marino }
71*d30dc8cbSJohn Marino else if (mpfr_zero_p (mpc_realref (op_loc))) {
72*d30dc8cbSJohn Marino /* sin(-0 -i*Inf) = -0 -i*Inf */
73*d30dc8cbSJohn Marino /* sin(+0 -i*Inf) = +0 -i*Inf */
74*d30dc8cbSJohn Marino /* sin(-0 +i*Inf) = -0 +i*Inf */
75*d30dc8cbSJohn Marino /* sin(+0 +i*Inf) = +0 +i*Inf */
76*d30dc8cbSJohn Marino mpc_set (rop_sin, op_loc, rnd_sin);
77*d30dc8cbSJohn Marino }
78*d30dc8cbSJohn Marino else {
79*d30dc8cbSJohn Marino /* sin(x -i*Inf) = +Inf*(sin(x) -i*cos(x)) */
80*d30dc8cbSJohn Marino /* sin(x +i*Inf) = +Inf*(sin(x) +i*cos(x)) */
81*d30dc8cbSJohn Marino mpfr_t s, c;
82*d30dc8cbSJohn Marino mpfr_init2 (s, 2);
83*d30dc8cbSJohn Marino mpfr_init2 (c, 2);
84*d30dc8cbSJohn Marino mpfr_sin_cos (s, c, mpc_realref (op_loc), GMP_RNDZ);
85*d30dc8cbSJohn Marino mpfr_set_inf (mpc_realref (rop_sin), MPFR_SIGN (s));
86*d30dc8cbSJohn Marino mpfr_set_inf (mpc_imagref (rop_sin), MPFR_SIGN (c)*MPFR_SIGN (mpc_imagref (op_loc)));
87*d30dc8cbSJohn Marino mpfr_clear (s);
88*d30dc8cbSJohn Marino mpfr_clear (c);
89*d30dc8cbSJohn Marino }
90*d30dc8cbSJohn Marino }
91*d30dc8cbSJohn Marino
92*d30dc8cbSJohn Marino if (rop_cos != NULL) {
93*d30dc8cbSJohn Marino if (mpfr_nan_p (mpc_realref (op_loc))) {
94*d30dc8cbSJohn Marino /* cos(NaN + i * NaN) = NaN + i * NaN */
95*d30dc8cbSJohn Marino /* cos(NaN - i * Inf) = +Inf + i * NaN */
96*d30dc8cbSJohn Marino /* cos(NaN + i * Inf) = +Inf + i * NaN */
97*d30dc8cbSJohn Marino /* cos(NaN - i * 0) = NaN - i * 0 */
98*d30dc8cbSJohn Marino /* cos(NaN + i * 0) = NaN + i * 0 */
99*d30dc8cbSJohn Marino /* cos(NaN + i * y) = NaN + i * NaN, when y != 0 */
100*d30dc8cbSJohn Marino if (mpfr_inf_p (mpc_imagref (op_loc)))
101*d30dc8cbSJohn Marino mpfr_set_inf (mpc_realref (rop_cos), +1);
102*d30dc8cbSJohn Marino else
103*d30dc8cbSJohn Marino mpfr_set_nan (mpc_realref (rop_cos));
104*d30dc8cbSJohn Marino
105*d30dc8cbSJohn Marino if (mpfr_zero_p (mpc_imagref (op_loc)))
106*d30dc8cbSJohn Marino mpfr_set (mpc_imagref (rop_cos), mpc_imagref (op_loc), MPC_RND_IM (rnd_cos));
107*d30dc8cbSJohn Marino else
108*d30dc8cbSJohn Marino mpfr_set_nan (mpc_imagref (rop_cos));
109*d30dc8cbSJohn Marino }
110*d30dc8cbSJohn Marino else if (mpfr_nan_p (mpc_imagref (op_loc))) {
111*d30dc8cbSJohn Marino /* cos(-Inf + i * NaN) = NaN + i * NaN */
112*d30dc8cbSJohn Marino /* cos(+Inf + i * NaN) = NaN + i * NaN */
113*d30dc8cbSJohn Marino /* cos(-0 + i * NaN) = NaN - i * 0 */
114*d30dc8cbSJohn Marino /* cos(+0 + i * NaN) = NaN + i * 0 */
115*d30dc8cbSJohn Marino /* cos(x + i * NaN) = NaN + i * NaN, when x != 0 */
116*d30dc8cbSJohn Marino if (mpfr_zero_p (mpc_realref (op_loc)))
117*d30dc8cbSJohn Marino mpfr_set (mpc_imagref (rop_cos), mpc_realref (op_loc), MPC_RND_IM (rnd_cos));
118*d30dc8cbSJohn Marino else
119*d30dc8cbSJohn Marino mpfr_set_nan (mpc_imagref (rop_cos));
120*d30dc8cbSJohn Marino
121*d30dc8cbSJohn Marino mpfr_set_nan (mpc_realref (rop_cos));
122*d30dc8cbSJohn Marino }
123*d30dc8cbSJohn Marino else if (mpfr_inf_p (mpc_realref (op_loc))) {
124*d30dc8cbSJohn Marino /* cos(-Inf -i*Inf) = cos(+Inf +i*Inf) = -Inf +i*NaN */
125*d30dc8cbSJohn Marino /* cos(-Inf +i*Inf) = cos(+Inf -i*Inf) = +Inf +i*NaN */
126*d30dc8cbSJohn Marino /* cos(-Inf -i*0) = cos(+Inf +i*0) = NaN -i*0 */
127*d30dc8cbSJohn Marino /* cos(-Inf +i*0) = cos(+Inf -i*0) = NaN +i*0 */
128*d30dc8cbSJohn Marino /* cos(-Inf +i*y) = cos(+Inf +i*y) = NaN +i*NaN, when y != 0 */
129*d30dc8cbSJohn Marino
130*d30dc8cbSJohn Marino const int same_sign =
131*d30dc8cbSJohn Marino mpfr_signbit (mpc_realref (op_loc)) == mpfr_signbit (mpc_imagref (op_loc));
132*d30dc8cbSJohn Marino
133*d30dc8cbSJohn Marino if (mpfr_inf_p (mpc_imagref (op_loc)))
134*d30dc8cbSJohn Marino mpfr_set_inf (mpc_realref (rop_cos), (same_sign ? -1 : +1));
135*d30dc8cbSJohn Marino else
136*d30dc8cbSJohn Marino mpfr_set_nan (mpc_realref (rop_cos));
137*d30dc8cbSJohn Marino
138*d30dc8cbSJohn Marino if (mpfr_zero_p (mpc_imagref (op_loc)))
139*d30dc8cbSJohn Marino mpfr_setsign (mpc_imagref (rop_cos), mpc_imagref (op_loc), same_sign,
140*d30dc8cbSJohn Marino MPC_RND_IM(rnd_cos));
141*d30dc8cbSJohn Marino else
142*d30dc8cbSJohn Marino mpfr_set_nan (mpc_imagref (rop_cos));
143*d30dc8cbSJohn Marino }
144*d30dc8cbSJohn Marino else if (mpfr_zero_p (mpc_realref (op_loc))) {
145*d30dc8cbSJohn Marino /* cos(-0 -i*Inf) = cos(+0 +i*Inf) = +Inf -i*0 */
146*d30dc8cbSJohn Marino /* cos(-0 +i*Inf) = cos(+0 -i*Inf) = +Inf +i*0 */
147*d30dc8cbSJohn Marino const int same_sign =
148*d30dc8cbSJohn Marino mpfr_signbit (mpc_realref (op_loc)) == mpfr_signbit (mpc_imagref (op_loc));
149*d30dc8cbSJohn Marino
150*d30dc8cbSJohn Marino mpfr_setsign (mpc_imagref (rop_cos), mpc_realref (op_loc), same_sign,
151*d30dc8cbSJohn Marino MPC_RND_IM (rnd_cos));
152*d30dc8cbSJohn Marino mpfr_set_inf (mpc_realref (rop_cos), +1);
153*d30dc8cbSJohn Marino }
154*d30dc8cbSJohn Marino else {
155*d30dc8cbSJohn Marino /* cos(x -i*Inf) = +Inf*cos(x) +i*Inf*sin(x), when x != 0 */
156*d30dc8cbSJohn Marino /* cos(x +i*Inf) = +Inf*cos(x) -i*Inf*sin(x), when x != 0 */
157*d30dc8cbSJohn Marino mpfr_t s, c;
158*d30dc8cbSJohn Marino mpfr_init2 (c, 2);
159*d30dc8cbSJohn Marino mpfr_init2 (s, 2);
160*d30dc8cbSJohn Marino mpfr_sin_cos (s, c, mpc_realref (op_loc), GMP_RNDN);
161*d30dc8cbSJohn Marino mpfr_set_inf (mpc_realref (rop_cos), mpfr_sgn (c));
162*d30dc8cbSJohn Marino mpfr_set_inf (mpc_imagref (rop_cos),
163*d30dc8cbSJohn Marino (mpfr_sgn (mpc_imagref (op_loc)) == mpfr_sgn (s) ? -1 : +1));
164*d30dc8cbSJohn Marino mpfr_clear (s);
165*d30dc8cbSJohn Marino mpfr_clear (c);
166*d30dc8cbSJohn Marino }
167*d30dc8cbSJohn Marino }
168*d30dc8cbSJohn Marino
169*d30dc8cbSJohn Marino if (overlap)
170*d30dc8cbSJohn Marino mpc_clear (op_loc);
171*d30dc8cbSJohn Marino
172*d30dc8cbSJohn Marino return MPC_INEX12 (MPC_INEX (0,0), MPC_INEX (0,0));
173*d30dc8cbSJohn Marino /* everything is exact */
174*d30dc8cbSJohn Marino }
175*d30dc8cbSJohn Marino
176*d30dc8cbSJohn Marino
177*d30dc8cbSJohn Marino static int
mpc_sin_cos_real(mpc_ptr rop_sin,mpc_ptr rop_cos,mpc_srcptr op,mpc_rnd_t rnd_sin,mpc_rnd_t rnd_cos)178*d30dc8cbSJohn Marino mpc_sin_cos_real (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
179*d30dc8cbSJohn Marino mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
180*d30dc8cbSJohn Marino /* assumes that op is real */
181*d30dc8cbSJohn Marino {
182*d30dc8cbSJohn Marino int inex_sin_re = 0, inex_cos_re = 0;
183*d30dc8cbSJohn Marino /* Until further notice, assume computations exact; in particular,
184*d30dc8cbSJohn Marino by definition, for not computed values. */
185*d30dc8cbSJohn Marino mpfr_t s, c;
186*d30dc8cbSJohn Marino int inex_s, inex_c;
187*d30dc8cbSJohn Marino int sign_im = mpfr_signbit (mpc_imagref (op));
188*d30dc8cbSJohn Marino
189*d30dc8cbSJohn Marino /* sin(x +-0*i) = sin(x) +-0*i*sign(cos(x)) */
190*d30dc8cbSJohn Marino /* cos(x +-i*0) = cos(x) -+i*0*sign(sin(x)) */
191*d30dc8cbSJohn Marino if (rop_sin != 0)
192*d30dc8cbSJohn Marino mpfr_init2 (s, MPC_PREC_RE (rop_sin));
193*d30dc8cbSJohn Marino else
194*d30dc8cbSJohn Marino mpfr_init2 (s, 2); /* We need only the sign. */
195*d30dc8cbSJohn Marino if (rop_cos != NULL)
196*d30dc8cbSJohn Marino mpfr_init2 (c, MPC_PREC_RE (rop_cos));
197*d30dc8cbSJohn Marino else
198*d30dc8cbSJohn Marino mpfr_init2 (c, 2);
199*d30dc8cbSJohn Marino inex_s = mpfr_sin (s, mpc_realref (op), MPC_RND_RE (rnd_sin));
200*d30dc8cbSJohn Marino inex_c = mpfr_cos (c, mpc_realref (op), MPC_RND_RE (rnd_cos));
201*d30dc8cbSJohn Marino /* We cannot use mpfr_sin_cos since we may need two distinct rounding
202*d30dc8cbSJohn Marino modes and the exact return values. If we need only the sign, an
203*d30dc8cbSJohn Marino arbitrary rounding mode will work. */
204*d30dc8cbSJohn Marino
205*d30dc8cbSJohn Marino if (rop_sin != NULL) {
206*d30dc8cbSJohn Marino mpfr_set (mpc_realref (rop_sin), s, GMP_RNDN); /* exact */
207*d30dc8cbSJohn Marino inex_sin_re = inex_s;
208*d30dc8cbSJohn Marino mpfr_set_zero (mpc_imagref (rop_sin),
209*d30dc8cbSJohn Marino ( ( sign_im && !mpfr_signbit(c))
210*d30dc8cbSJohn Marino || (!sign_im && mpfr_signbit(c)) ? -1 : 1));
211*d30dc8cbSJohn Marino }
212*d30dc8cbSJohn Marino
213*d30dc8cbSJohn Marino if (rop_cos != NULL) {
214*d30dc8cbSJohn Marino mpfr_set (mpc_realref (rop_cos), c, GMP_RNDN); /* exact */
215*d30dc8cbSJohn Marino inex_cos_re = inex_c;
216*d30dc8cbSJohn Marino mpfr_set_zero (mpc_imagref (rop_cos),
217*d30dc8cbSJohn Marino ( ( sign_im && mpfr_signbit(s))
218*d30dc8cbSJohn Marino || (!sign_im && !mpfr_signbit(s)) ? -1 : 1));
219*d30dc8cbSJohn Marino }
220*d30dc8cbSJohn Marino
221*d30dc8cbSJohn Marino mpfr_clear (s);
222*d30dc8cbSJohn Marino mpfr_clear (c);
223*d30dc8cbSJohn Marino
224*d30dc8cbSJohn Marino return MPC_INEX12 (MPC_INEX (inex_sin_re, 0), MPC_INEX (inex_cos_re, 0));
225*d30dc8cbSJohn Marino }
226*d30dc8cbSJohn Marino
227*d30dc8cbSJohn Marino
228*d30dc8cbSJohn Marino static int
mpc_sin_cos_imag(mpc_ptr rop_sin,mpc_ptr rop_cos,mpc_srcptr op,mpc_rnd_t rnd_sin,mpc_rnd_t rnd_cos)229*d30dc8cbSJohn Marino mpc_sin_cos_imag (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
230*d30dc8cbSJohn Marino mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
231*d30dc8cbSJohn Marino /* assumes that op is purely imaginary, but not zero */
232*d30dc8cbSJohn Marino {
233*d30dc8cbSJohn Marino int inex_sin_im = 0, inex_cos_re = 0;
234*d30dc8cbSJohn Marino /* assume exact if not computed */
235*d30dc8cbSJohn Marino int overlap;
236*d30dc8cbSJohn Marino mpc_t op_loc;
237*d30dc8cbSJohn Marino
238*d30dc8cbSJohn Marino overlap = (rop_sin == op || rop_cos == op);
239*d30dc8cbSJohn Marino if (overlap) {
240*d30dc8cbSJohn Marino mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op));
241*d30dc8cbSJohn Marino mpc_set (op_loc, op, MPC_RNDNN);
242*d30dc8cbSJohn Marino }
243*d30dc8cbSJohn Marino else
244*d30dc8cbSJohn Marino op_loc [0] = op [0];
245*d30dc8cbSJohn Marino
246*d30dc8cbSJohn Marino if (rop_sin != NULL) {
247*d30dc8cbSJohn Marino /* sin(+-O +i*y) = +-0 +i*sinh(y) */
248*d30dc8cbSJohn Marino mpfr_set (mpc_realref(rop_sin), mpc_realref(op_loc), GMP_RNDN);
249*d30dc8cbSJohn Marino inex_sin_im = mpfr_sinh (mpc_imagref(rop_sin), mpc_imagref(op_loc), MPC_RND_IM(rnd_sin));
250*d30dc8cbSJohn Marino }
251*d30dc8cbSJohn Marino
252*d30dc8cbSJohn Marino if (rop_cos != NULL) {
253*d30dc8cbSJohn Marino /* cos(-0 - i * y) = cos(+0 + i * y) = cosh(y) - i * 0,
254*d30dc8cbSJohn Marino cos(-0 + i * y) = cos(+0 - i * y) = cosh(y) + i * 0,
255*d30dc8cbSJohn Marino where y > 0 */
256*d30dc8cbSJohn Marino inex_cos_re = mpfr_cosh (mpc_realref (rop_cos), mpc_imagref (op_loc), MPC_RND_RE (rnd_cos));
257*d30dc8cbSJohn Marino
258*d30dc8cbSJohn Marino mpfr_set_ui (mpc_imagref (rop_cos), 0ul, MPC_RND_IM (rnd_cos));
259*d30dc8cbSJohn Marino if (mpfr_signbit (mpc_realref (op_loc)) == mpfr_signbit (mpc_imagref (op_loc)))
260*d30dc8cbSJohn Marino MPFR_CHANGE_SIGN (mpc_imagref (rop_cos));
261*d30dc8cbSJohn Marino }
262*d30dc8cbSJohn Marino
263*d30dc8cbSJohn Marino if (overlap)
264*d30dc8cbSJohn Marino mpc_clear (op_loc);
265*d30dc8cbSJohn Marino
266*d30dc8cbSJohn Marino return MPC_INEX12 (MPC_INEX (0, inex_sin_im), MPC_INEX (inex_cos_re, 0));
267*d30dc8cbSJohn Marino }
268*d30dc8cbSJohn Marino
269*d30dc8cbSJohn Marino
270*d30dc8cbSJohn Marino int
mpc_sin_cos(mpc_ptr rop_sin,mpc_ptr rop_cos,mpc_srcptr op,mpc_rnd_t rnd_sin,mpc_rnd_t rnd_cos)271*d30dc8cbSJohn Marino mpc_sin_cos (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
272*d30dc8cbSJohn Marino mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
273*d30dc8cbSJohn Marino /* Feature not documented in the texinfo file: One of rop_sin or
274*d30dc8cbSJohn Marino rop_cos may be NULL, in which case it is not computed, and the
275*d30dc8cbSJohn Marino corresponding ternary inexact value is set to 0 (exact). */
276*d30dc8cbSJohn Marino {
277*d30dc8cbSJohn Marino if (!mpc_fin_p (op))
278*d30dc8cbSJohn Marino return mpc_sin_cos_nonfinite (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
279*d30dc8cbSJohn Marino else if (mpfr_zero_p (mpc_imagref (op)))
280*d30dc8cbSJohn Marino return mpc_sin_cos_real (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
281*d30dc8cbSJohn Marino else if (mpfr_zero_p (mpc_realref (op)))
282*d30dc8cbSJohn Marino return mpc_sin_cos_imag (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
283*d30dc8cbSJohn Marino else {
284*d30dc8cbSJohn Marino /* let op = a + i*b, then sin(op) = sin(a)*cosh(b) + i*cos(a)*sinh(b)
285*d30dc8cbSJohn Marino and cos(op) = cos(a)*cosh(b) - i*sin(a)*sinh(b).
286*d30dc8cbSJohn Marino
287*d30dc8cbSJohn Marino For Re(sin(op)) (and analogously, the other parts), we use the
288*d30dc8cbSJohn Marino following algorithm, with rounding to nearest for all operations
289*d30dc8cbSJohn Marino and working precision w:
290*d30dc8cbSJohn Marino
291*d30dc8cbSJohn Marino (1) x = o(sin(a))
292*d30dc8cbSJohn Marino (2) y = o(cosh(b))
293*d30dc8cbSJohn Marino (3) r = o(x*y)
294*d30dc8cbSJohn Marino then the error on r is at most 4 ulps, since we can write
295*d30dc8cbSJohn Marino r = sin(a)*cosh(b)*(1+t)^3 with |t| <= 2^(-w),
296*d30dc8cbSJohn Marino thus for w >= 2, r = sin(a)*cosh(b)*(1+4*t) with |t| <= 2^(-w),
297*d30dc8cbSJohn Marino thus the relative error is bounded by 4*2^(-w) <= 4*ulp(r).
298*d30dc8cbSJohn Marino */
299*d30dc8cbSJohn Marino mpfr_t s, c, sh, ch, sch, csh;
300*d30dc8cbSJohn Marino mpfr_prec_t prec;
301*d30dc8cbSJohn Marino int ok;
302*d30dc8cbSJohn Marino int inex_re, inex_im, inex_sin, inex_cos;
303*d30dc8cbSJohn Marino
304*d30dc8cbSJohn Marino prec = 2;
305*d30dc8cbSJohn Marino if (rop_sin != NULL)
306*d30dc8cbSJohn Marino prec = MPC_MAX (prec, MPC_MAX_PREC (rop_sin));
307*d30dc8cbSJohn Marino if (rop_cos != NULL)
308*d30dc8cbSJohn Marino prec = MPC_MAX (prec, MPC_MAX_PREC (rop_cos));
309*d30dc8cbSJohn Marino
310*d30dc8cbSJohn Marino mpfr_init2 (s, 2);
311*d30dc8cbSJohn Marino mpfr_init2 (c, 2);
312*d30dc8cbSJohn Marino mpfr_init2 (sh, 2);
313*d30dc8cbSJohn Marino mpfr_init2 (ch, 2);
314*d30dc8cbSJohn Marino mpfr_init2 (sch, 2);
315*d30dc8cbSJohn Marino mpfr_init2 (csh, 2);
316*d30dc8cbSJohn Marino
317*d30dc8cbSJohn Marino do {
318*d30dc8cbSJohn Marino ok = 1;
319*d30dc8cbSJohn Marino prec += mpc_ceil_log2 (prec) + 5;
320*d30dc8cbSJohn Marino
321*d30dc8cbSJohn Marino mpfr_set_prec (s, prec);
322*d30dc8cbSJohn Marino mpfr_set_prec (c, prec);
323*d30dc8cbSJohn Marino mpfr_set_prec (sh, prec);
324*d30dc8cbSJohn Marino mpfr_set_prec (ch, prec);
325*d30dc8cbSJohn Marino mpfr_set_prec (sch, prec);
326*d30dc8cbSJohn Marino mpfr_set_prec (csh, prec);
327*d30dc8cbSJohn Marino
328*d30dc8cbSJohn Marino mpfr_sin_cos (s, c, mpc_realref(op), GMP_RNDN);
329*d30dc8cbSJohn Marino mpfr_sinh_cosh (sh, ch, mpc_imagref(op), GMP_RNDN);
330*d30dc8cbSJohn Marino
331*d30dc8cbSJohn Marino if (rop_sin != NULL) {
332*d30dc8cbSJohn Marino /* real part of sine */
333*d30dc8cbSJohn Marino mpfr_mul (sch, s, ch, GMP_RNDN);
334*d30dc8cbSJohn Marino ok = (!mpfr_number_p (sch))
335*d30dc8cbSJohn Marino || mpfr_can_round (sch, prec - 2, GMP_RNDN, GMP_RNDZ,
336*d30dc8cbSJohn Marino MPC_PREC_RE (rop_sin)
337*d30dc8cbSJohn Marino + (MPC_RND_RE (rnd_sin) == GMP_RNDN));
338*d30dc8cbSJohn Marino
339*d30dc8cbSJohn Marino if (ok) {
340*d30dc8cbSJohn Marino /* imaginary part of sine */
341*d30dc8cbSJohn Marino mpfr_mul (csh, c, sh, GMP_RNDN);
342*d30dc8cbSJohn Marino ok = (!mpfr_number_p (csh))
343*d30dc8cbSJohn Marino || mpfr_can_round (csh, prec - 2, GMP_RNDN, GMP_RNDZ,
344*d30dc8cbSJohn Marino MPC_PREC_IM (rop_sin)
345*d30dc8cbSJohn Marino + (MPC_RND_IM (rnd_sin) == GMP_RNDN));
346*d30dc8cbSJohn Marino }
347*d30dc8cbSJohn Marino }
348*d30dc8cbSJohn Marino
349*d30dc8cbSJohn Marino if (rop_cos != NULL && ok) {
350*d30dc8cbSJohn Marino /* real part of cosine */
351*d30dc8cbSJohn Marino mpfr_mul (c, c, ch, GMP_RNDN);
352*d30dc8cbSJohn Marino ok = (!mpfr_number_p (c))
353*d30dc8cbSJohn Marino || mpfr_can_round (c, prec - 2, GMP_RNDN, GMP_RNDZ,
354*d30dc8cbSJohn Marino MPC_PREC_RE (rop_cos)
355*d30dc8cbSJohn Marino + (MPC_RND_RE (rnd_cos) == GMP_RNDN));
356*d30dc8cbSJohn Marino
357*d30dc8cbSJohn Marino if (ok) {
358*d30dc8cbSJohn Marino /* imaginary part of cosine */
359*d30dc8cbSJohn Marino mpfr_mul (s, s, sh, GMP_RNDN);
360*d30dc8cbSJohn Marino mpfr_neg (s, s, GMP_RNDN);
361*d30dc8cbSJohn Marino ok = (!mpfr_number_p (s))
362*d30dc8cbSJohn Marino || mpfr_can_round (s, prec - 2, GMP_RNDN, GMP_RNDZ,
363*d30dc8cbSJohn Marino MPC_PREC_IM (rop_cos)
364*d30dc8cbSJohn Marino + (MPC_RND_IM (rnd_cos) == GMP_RNDN));
365*d30dc8cbSJohn Marino }
366*d30dc8cbSJohn Marino }
367*d30dc8cbSJohn Marino } while (ok == 0);
368*d30dc8cbSJohn Marino
369*d30dc8cbSJohn Marino if (rop_sin != NULL) {
370*d30dc8cbSJohn Marino inex_re = mpfr_set (mpc_realref (rop_sin), sch, MPC_RND_RE (rnd_sin));
371*d30dc8cbSJohn Marino if (mpfr_inf_p (sch))
372*d30dc8cbSJohn Marino inex_re = mpfr_sgn (sch);
373*d30dc8cbSJohn Marino inex_im = mpfr_set (mpc_imagref (rop_sin), csh, MPC_RND_IM (rnd_sin));
374*d30dc8cbSJohn Marino if (mpfr_inf_p (csh))
375*d30dc8cbSJohn Marino inex_im = mpfr_sgn (csh);
376*d30dc8cbSJohn Marino inex_sin = MPC_INEX (inex_re, inex_im);
377*d30dc8cbSJohn Marino }
378*d30dc8cbSJohn Marino else
379*d30dc8cbSJohn Marino inex_sin = MPC_INEX (0,0); /* return exact if not computed */
380*d30dc8cbSJohn Marino
381*d30dc8cbSJohn Marino if (rop_cos != NULL) {
382*d30dc8cbSJohn Marino inex_re = mpfr_set (mpc_realref (rop_cos), c, MPC_RND_RE (rnd_cos));
383*d30dc8cbSJohn Marino if (mpfr_inf_p (c))
384*d30dc8cbSJohn Marino inex_re = mpfr_sgn (c);
385*d30dc8cbSJohn Marino inex_im = mpfr_set (mpc_imagref (rop_cos), s, MPC_RND_IM (rnd_cos));
386*d30dc8cbSJohn Marino if (mpfr_inf_p (s))
387*d30dc8cbSJohn Marino inex_im = mpfr_sgn (s);
388*d30dc8cbSJohn Marino inex_cos = MPC_INEX (inex_re, inex_im);
389*d30dc8cbSJohn Marino }
390*d30dc8cbSJohn Marino else
391*d30dc8cbSJohn Marino inex_cos = MPC_INEX (0,0); /* return exact if not computed */
392*d30dc8cbSJohn Marino
393*d30dc8cbSJohn Marino mpfr_clear (s);
394*d30dc8cbSJohn Marino mpfr_clear (c);
395*d30dc8cbSJohn Marino mpfr_clear (sh);
396*d30dc8cbSJohn Marino mpfr_clear (ch);
397*d30dc8cbSJohn Marino mpfr_clear (sch);
398*d30dc8cbSJohn Marino mpfr_clear (csh);
399*d30dc8cbSJohn Marino
400*d30dc8cbSJohn Marino return (MPC_INEX12 (inex_sin, inex_cos));
401*d30dc8cbSJohn Marino }
402*d30dc8cbSJohn Marino }
403