1 /*
2 * Copyright (C) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (C) 2008-2011 Robert Ancell.
4 *
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 2 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9 * license.
10 */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <math.h>
15 #include <libintl.h>
16
17 #include "mp.h"
18
19 /* Convert x to radians */
20 void
convert_to_radians(const MPNumber * x,MPAngleUnit unit,MPNumber * z)21 convert_to_radians(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
22 {
23 int i;
24
25 switch(unit) {
26 default:
27 case MP_RADIANS:
28 mp_set_from_mp(x, z);
29 return;
30
31 case MP_DEGREES:
32 i = 180;
33 break;
34
35 case MP_GRADIANS:
36 i = 200;
37 break;
38 }
39 mpfr_t scale;
40 mpfr_init2(scale, PRECISION);
41 mpfr_const_pi(scale, MPFR_RNDN);
42 mpfr_div_si(scale, scale, i, MPFR_RNDN);
43 mpc_mul_fr(z->num, x->num, scale, MPC_RNDNN);
44 mpfr_clear(scale);
45 }
46
47 void
convert_from_radians(const MPNumber * x,MPAngleUnit unit,MPNumber * z)48 convert_from_radians(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
49 {
50 int i;
51
52 switch(unit) {
53 default:
54 case MP_RADIANS:
55 mp_set_from_mp(x, z);
56 return;
57
58 case MP_DEGREES:
59 i = 180;
60 break;
61
62 case MP_GRADIANS:
63 i = 200;
64 break;
65 }
66 mpfr_t scale;
67 mpfr_init2(scale, PRECISION);
68 mpfr_const_pi(scale, MPFR_RNDN);
69 mpfr_si_div(scale, i, scale, MPFR_RNDN);
70 mpc_mul_fr(z->num, x->num, scale, MPC_RNDNN);
71 mpfr_clear(scale);
72 }
73
74
75 void
mp_get_pi(MPNumber * z)76 mp_get_pi (MPNumber *z)
77 {
78 mpfr_const_pi(mpc_realref(z->num), MPFR_RNDN);
79 mpfr_set_zero(mpc_imagref(z->num), 0);
80 }
81
82
83 void
mp_sin(const MPNumber * x,MPAngleUnit unit,MPNumber * z)84 mp_sin(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
85 {
86 if (mp_is_complex(x))
87 mp_set_from_mp(x, z);
88 else
89 convert_to_radians(x, unit, z);
90 mpc_sin(z->num, z->num, MPC_RNDNN);
91 }
92
93
94 void
mp_cos(const MPNumber * x,MPAngleUnit unit,MPNumber * z)95 mp_cos(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
96 {
97 if (mp_is_complex(x))
98 mp_set_from_mp(x, z);
99 else
100 convert_to_radians(x, unit, z);
101 mpc_cos(z->num, z->num, MPC_RNDNN);
102 }
103
104
105 void
mp_tan(const MPNumber * x,MPAngleUnit unit,MPNumber * z)106 mp_tan(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
107 {
108 MPNumber x_radians = mp_new();
109 MPNumber pi = mp_new();
110 MPNumber t1 = mp_new();
111
112 convert_to_radians(x, unit, &x_radians);
113 mp_get_pi(&pi);
114 mp_divide_integer(&pi, 2, &t1);
115 mp_subtract(&x_radians, &t1, &t1);
116 mp_divide(&t1, &pi, &t1);
117
118 if (mp_is_integer(&t1)) {
119 /* Translators: Error displayed when tangent value is undefined */
120 mperr(_("Tangent is undefined for angles that are multiples of π (180°) from π∕2 (90°)"));
121 mp_set_from_integer(0, z);
122 mp_clear(&x_radians);
123 mp_clear(&pi);
124 mp_clear(&t1);
125 return;
126 }
127
128 if (mp_is_complex(x))
129 mp_set_from_mp(x, z);
130 else
131 mp_set_from_mp(&x_radians, z);
132 mpc_tan(z->num, z->num, MPC_RNDNN);
133 mp_clear(&x_radians);
134 mp_clear(&pi);
135 mp_clear(&t1);
136 }
137
138
139 void
mp_asin(const MPNumber * x,MPAngleUnit unit,MPNumber * z)140 mp_asin(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
141 {
142 MPNumber x_max = mp_new();
143 MPNumber x_min = mp_new();
144 mp_set_from_integer(1, &x_max);
145 mp_set_from_integer(-1, &x_min);
146
147 if (mp_compare(x, &x_max) > 0 || mp_compare(x, &x_min) < 0)
148 {
149 /* Translators: Error displayed when inverse sine value is undefined */
150 mperr(_("Inverse sine is undefined for values outside [-1, 1]"));
151 mp_set_from_integer(0, z);
152 mp_clear(&x_max);
153 mp_clear(&x_min);
154 return;
155 }
156 mpc_asin(z->num, x->num, MPC_RNDNN);
157 if (!mp_is_complex(z))
158 convert_from_radians(z, unit, z);
159 mp_clear(&x_max);
160 mp_clear(&x_min);
161 }
162
163
164 void
mp_acos(const MPNumber * x,MPAngleUnit unit,MPNumber * z)165 mp_acos(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
166 {
167 MPNumber x_max = mp_new();
168 MPNumber x_min = mp_new();
169 mp_set_from_integer(1, &x_max);
170 mp_set_from_integer(-1, &x_min);
171
172 if (mp_compare(x, &x_max) > 0 || mp_compare(x, &x_min) < 0)
173 {
174 /* Translators: Error displayed when inverse sine value is undefined */
175 mperr(_("Inverse cosine is undefined for values outside [-1, 1]"));
176 mp_set_from_integer(0, z);
177 mp_clear(&x_max);
178 mp_clear(&x_min);
179 return;
180 }
181 mpc_acos(z->num, x->num, MPC_RNDNN);
182 if (!mp_is_complex(z))
183 convert_from_radians(z, unit, z);
184 mp_clear(&x_max);
185 mp_clear(&x_min);
186 }
187
188
189 void
mp_atan(const MPNumber * x,MPAngleUnit unit,MPNumber * z)190 mp_atan(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
191 {
192 MPNumber i = mp_new();
193 MPNumber minus_i = mp_new();
194 mpc_set_si_si(i.num, 0, 1, MPC_RNDNN);
195 mpc_set_si_si(minus_i.num, 0, -1, MPC_RNDNN);
196
197 /* Check x != i and x != -i */
198 if (mp_is_equal(x, &i) || mp_is_equal(x, &minus_i))
199 {
200 /* Translators: Error displayed when inverse sine value is undefined */
201 mperr(_("Arctangent function is undefined for values i and -i"));
202 mp_set_from_integer(0, z);
203 mp_clear(&i);
204 mp_clear(&minus_i);
205 return;
206 }
207 mpc_atan(z->num, x->num, MPC_RNDNN);
208 if (!mp_is_complex(z))
209 convert_from_radians(z, unit, z);
210 mp_clear(&i);
211 mp_clear(&minus_i);
212 }
213
214
215 void
mp_sinh(const MPNumber * x,MPNumber * z)216 mp_sinh(const MPNumber *x, MPNumber *z)
217 {
218 mpc_sinh(z->num, x->num, MPC_RNDNN);
219 }
220
221
222 void
mp_cosh(const MPNumber * x,MPNumber * z)223 mp_cosh(const MPNumber *x, MPNumber *z)
224 {
225 mpc_cosh(z->num, x->num, MPC_RNDNN);
226 }
227
228
229 void
mp_tanh(const MPNumber * x,MPNumber * z)230 mp_tanh(const MPNumber *x, MPNumber *z)
231 {
232 mpc_tanh(z->num, x->num, MPC_RNDNN);
233 }
234
235
236 void
mp_asinh(const MPNumber * x,MPNumber * z)237 mp_asinh(const MPNumber *x, MPNumber *z)
238 {
239 mpc_asinh(z->num, x->num, MPC_RNDNN);
240 }
241
242
243 void
mp_acosh(const MPNumber * x,MPNumber * z)244 mp_acosh(const MPNumber *x, MPNumber *z)
245 {
246 MPNumber t = mp_new();
247
248 /* Check x >= 1 */
249 mp_set_from_integer(1, &t);
250 if (mp_is_less_than(x, &t))
251 {
252 /* Translators: Error displayed when inverse hyperbolic cosine value is undefined */
253 mperr(_("Inverse hyperbolic cosine is undefined for values less than one"));
254 mp_set_from_integer(0, z);
255 mp_clear(&t);
256 return;
257 }
258
259 mpc_acosh(z->num, x->num, MPC_RNDNN);
260 mp_clear(&t);
261 }
262
263
264 void
mp_atanh(const MPNumber * x,MPNumber * z)265 mp_atanh(const MPNumber *x, MPNumber *z)
266 {
267 MPNumber x_max = mp_new();
268 MPNumber x_min = mp_new();
269 mp_set_from_integer(1, &x_max);
270 mp_set_from_integer(-1, &x_min);
271
272 if (mp_compare(x, &x_max) >= 0 || mp_compare(x, &x_min) <= 0)
273 {
274 /* Translators: Error displayed when inverse hyperbolic tangent value is undefined */
275 mperr(_("Inverse hyperbolic tangent is undefined for values outside (-1, 1)"));
276 mp_set_from_integer(0, z);
277 mp_clear(&x_max);
278 mp_clear(&x_min);
279 return;
280 }
281 mpc_atanh(z->num, x->num, MPC_RNDNN);
282 mp_clear(&x_max);
283 mp_clear(&x_min);
284 }
285