2 * Copyright (C) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (C) 2008-2011 Robert Ancell.
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
18 #include "mp-private.h"
21 static gboolean have_pi
= FALSE
;
24 mp_compare_mp_to_int(const MPNumber
*x
, int i
)
27 mp_set_from_integer(i
, &t
);
28 return mp_compare_mp_to_mp(x
, &t
);
32 /* Convert x to radians */
34 convert_to_radians(const MPNumber
*x
, MPAngleUnit unit
, MPNumber
*z
)
46 mp_multiply(x
, &t1
, &t2
);
47 mp_divide_integer(&t2
, 180, z
);
52 mp_multiply(x
, &t1
, &t2
);
53 mp_divide_integer(&t2
, 200, z
);
60 mp_get_pi(MPNumber
*z
)
62 if (mp_is_zero(&pi
)) {
63 mp_set_from_string("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679", 10, &pi
);
66 mp_set_from_mp(&pi
, z
);
71 convert_from_radians(const MPNumber
*x
, MPAngleUnit unit
, MPNumber
*z
)
82 mp_multiply_integer(x
, 180, &t2
);
84 mp_divide(&t2
, &t1
, z
);
88 mp_multiply_integer(x
, 200, &t2
);
90 mp_divide(&t2
, &t1
, z
);
96 /* z = sin(x) -1 >= x >= 1, do_sin = 1
97 * z = cos(x) -1 >= x >= 1, do_sin = 0
100 mpsin1(const MPNumber
*x
, MPNumber
*z
, int do_sin
)
105 /* sin(0) = 0, cos(0) = 1 */
108 mp_set_from_integer(1, z
);
110 mp_set_from_integer(0, z
);
114 mp_multiply(x
, x
, &t2
);
115 if (mp_compare_mp_to_int(&t2
, 1) > 0) {
116 mperr("*** ABS(X) > 1 IN CALL TO MPSIN1 ***");
120 mp_set_from_integer(1, &t1
);
121 mp_set_from_integer(0, z
);
124 mp_set_from_mp(x
, &t1
);
125 mp_set_from_mp(&t1
, z
);
130 /* POWER SERIES LOOP. REDUCE T IF POSSIBLE */
131 b2
= 2 * max(MP_BASE
, 64);
133 if (MP_T
+ t1
.exponent
<= 0)
136 /* IF I*(I+1) IS NOT REPRESENTABLE AS AN INTEGER, THE FOLLOWING
137 * DIVISION BY I*(I+1) HAS TO BE SPLIT UP.
139 mp_multiply(&t2
, &t1
, &t1
);
141 mp_divide_integer(&t1
, -i
, &t1
);
142 mp_divide_integer(&t1
, i
+ 1, &t1
);
144 mp_divide_integer(&t1
, -i
* (i
+ 1), &t1
);
149 } while (t1
.sign
!= 0);
152 mp_add_integer(z
, 1, z
);
157 mp_sin_real(const MPNumber
*x
, MPAngleUnit unit
, MPNumber
*z
)
164 mp_set_from_integer(0, z
);
168 convert_to_radians(x
, unit
, &x_radians
);
171 mp_abs(&x_radians
, &x_radians
);
173 /* USE MPSIN1 IF ABS(X) <= 1 */
174 if (mp_compare_mp_to_int(&x_radians
, 1) <= 0) {
175 mpsin1(&x_radians
, z
, 1);
177 /* FIND ABS(X) MODULO 2PI */
180 mp_divide_integer(z
, 4, z
);
181 mp_divide(&x_radians
, z
, &x_radians
);
182 mp_divide_integer(&x_radians
, 8, &x_radians
);
183 mp_fractional_component(&x_radians
, &x_radians
);
185 /* SUBTRACT 1/2, SAVE SIGN AND TAKE ABS */
186 mp_add_fraction(&x_radians
, -1, 2, &x_radians
);
187 xs
= -xs
* x_radians
.sign
;
189 mp_set_from_integer(0, z
);
194 mp_multiply_integer(&x_radians
, 4, &x_radians
);
196 /* IF NOT LESS THAN 1, SUBTRACT FROM 2 */
197 if (x_radians
.exponent
> 0)
198 mp_add_integer(&x_radians
, -2, &x_radians
);
200 if (mp_is_zero(&x_radians
)) {
201 mp_set_from_integer(0, z
);
206 mp_multiply_integer(&x_radians
, 2, &x_radians
);
208 /* NOW REDUCED TO FIRST QUADRANT, IF LESS THAN PI/4 USE
209 * POWER SERIES, ELSE COMPUTE COS OF COMPLEMENT
211 if (x_radians
.exponent
> 0) {
212 mp_add_integer(&x_radians
, -2, &x_radians
);
213 mp_multiply(&x_radians
, z
, &x_radians
);
214 mpsin1(&x_radians
, z
, 0);
216 mp_multiply(&x_radians
, z
, &x_radians
);
217 mpsin1(&x_radians
, z
, 1);
226 mp_cos_real(const MPNumber
*x
, MPAngleUnit unit
, MPNumber
*z
)
230 mp_set_from_integer(1, z
);
234 convert_to_radians(x
, unit
, z
);
236 /* Use power series if |x| <= 1 */
238 if (mp_compare_mp_to_int(z
, 1) <= 0) {
243 /* cos(x) = sin(π/2 - |x|) */
245 mp_divide_integer(&t
, 2, &t
);
246 mp_subtract(&t
, z
, z
);
247 mp_sin(z
, MP_RADIANS
, z
);
253 mp_sin(const MPNumber
*x
, MPAngleUnit unit
, MPNumber
*z
)
255 if (mp_is_complex(x
)) {
256 MPNumber x_real
, x_im
, z_real
, z_im
, t
;
258 mp_real_component(x
, &x_real
);
259 mp_imaginary_component(x
, &x_im
);
261 mp_sin_real(&x_real
, unit
, &z_real
);
263 mp_multiply(&z_real
, &t
, &z_real
);
265 mp_cos_real(&x_real
, unit
, &z_im
);
267 mp_multiply(&z_im
, &t
, &z_im
);
269 mp_set_from_complex(&z_real
, &z_im
, z
);
272 mp_sin_real(x
, unit
, z
);
277 mp_cos(const MPNumber
*x
, MPAngleUnit unit
, MPNumber
*z
)
279 if (mp_is_complex(x
)) {
280 MPNumber x_real
, x_im
, z_real
, z_im
, t
;
282 mp_real_component(x
, &x_real
);
283 mp_imaginary_component(x
, &x_im
);
285 mp_cos_real(&x_real
, unit
, &z_real
);
287 mp_multiply(&z_real
, &t
, &z_real
);
289 mp_sin_real(&x_real
, unit
, &z_im
);
291 mp_multiply(&z_im
, &t
, &z_im
);
292 mp_invert_sign(&z_im
, &z_im
);
294 mp_set_from_complex(&z_real
, &z_im
, z
);
297 mp_cos_real(x
, unit
, z
);
302 mp_tan(const MPNumber
*x
, MPAngleUnit unit
, MPNumber
*z
)
304 MPNumber cos_x
, sin_x
;
306 /* Check for undefined values */
307 mp_cos(x
, unit
, &cos_x
);
308 if (mp_is_zero(&cos_x
)) {
309 /* Translators: Error displayed when tangent value is undefined */
310 mperr(_("Tangent is undefined for angles that are multiples of π (180°) from π∕2 (90°)"));
311 mp_set_from_integer(0, z
);
315 /* tan(x) = sin(x) / cos(x) */
316 mp_sin(x
, unit
, &sin_x
);
317 mp_divide(&sin_x
, &cos_x
, z
);
322 mp_asin(const MPNumber
*x
, MPAngleUnit unit
, MPNumber
*z
)
328 mp_set_from_integer(0, z
);
332 /* sin⁻¹(x) = tan⁻¹(x / √(1 - x²)), |x| < 1 */
333 if (x
->exponent
<= 0) {
334 mp_set_from_integer(1, &t1
);
335 mp_set_from_mp(&t1
, &t2
);
336 mp_subtract(&t1
, x
, &t1
);
338 mp_multiply(&t1
, &t2
, &t2
);
339 mp_root(&t2
, -2, &t2
);
340 mp_multiply(x
, &t2
, z
);
345 /* sin⁻¹(1) = π/2, sin⁻¹(-1) = -π/2 */
346 mp_set_from_integer(x
->sign
, &t2
);
347 if (mp_is_equal(x
, &t2
)) {
349 mp_divide_integer(z
, 2 * t2
.sign
, z
);
350 convert_from_radians(z
, unit
, z
);
354 /* Translators: Error displayed when inverse sine value is undefined */
355 mperr(_("Inverse sine is undefined for values outside [-1, 1]"));
356 mp_set_from_integer(0, z
);
361 mp_acos(const MPNumber
*x
, MPAngleUnit unit
, MPNumber
*z
)
364 MPNumber MPn1
, pi
, MPy
;
367 mp_set_from_integer(1, &t1
);
368 mp_set_from_integer(-1, &MPn1
);
370 if (mp_is_greater_than(x
, &t1
) || mp_is_less_than(x
, &MPn1
)) {
371 /* Translators: Error displayed when inverse cosine value is undefined */
372 mperr(_("Inverse cosine is undefined for values outside [-1, 1]"));
373 mp_set_from_integer(0, z
);
374 } else if (mp_is_zero(x
)) {
375 mp_divide_integer(&pi
, 2, z
);
376 } else if (mp_is_equal(x
, &t1
)) {
377 mp_set_from_integer(0, z
);
378 } else if (mp_is_equal(x
, &MPn1
)) {
379 mp_set_from_mp(&pi
, z
);
381 /* cos⁻¹(x) = tan⁻¹(√(1 - x²) / x) */
382 mp_multiply(x
, x
, &t2
);
383 mp_subtract(&t1
, &t2
, &t2
);
385 mp_divide(&t2
, x
, &t2
);
386 mp_atan(&t2
, MP_RADIANS
, &MPy
);
388 mp_set_from_mp(&MPy
, z
);
390 mp_add(&MPy
, &pi
, z
);
394 convert_from_radians(z
, unit
, z
);
399 mp_atan(const MPNumber
*x
, MPAngleUnit unit
, MPNumber
*z
)
406 mp_set_from_integer(0, z
);
410 mp_set_from_mp(x
, &t2
);
411 if (abs(x
->exponent
) <= 2)
412 rx
= mp_cast_to_float(x
);
414 /* REDUCE ARGUMENT IF NECESSARY BEFORE USING SERIES */
416 while (t2
.exponent
>= 0)
418 if (t2
.exponent
== 0 && 2 * (t2
.fraction
[0] + 1) <= MP_BASE
)
423 /* t = t / (√(t² + 1) + 1) */
424 mp_multiply(&t2
, &t2
, z
);
425 mp_add_integer(z
, 1, z
);
427 mp_add_integer(z
, 1, z
);
428 mp_divide(&t2
, z
, &t2
);
431 /* USE POWER SERIES NOW ARGUMENT IN (-0.5, 0.5) */
432 mp_set_from_mp(&t2
, z
);
433 mp_multiply(&t2
, &t2
, &t1
);
435 /* SERIES LOOP. REDUCE T IF POSSIBLE. */
436 for (i
= 1; ; i
+= 2) {
437 if (MP_T
+ 2 + t2
.exponent
<= 1)
440 mp_multiply(&t2
, &t1
, &t2
);
441 mp_multiply_fraction(&t2
, -i
, i
+ 2, &t2
);
448 /* CORRECT FOR ARGUMENT REDUCTION */
449 mp_multiply_integer(z
, q
, z
);
451 /* CHECK THAT RELATIVE ERROR LESS THAN 0.01 UNLESS EXPONENT
452 * OF X IS LARGE (WHEN ATAN MIGHT NOT WORK)
454 if (abs(x
->exponent
) <= 2) {
455 float ry
= mp_cast_to_float(z
);
456 /* THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL. */
457 if (fabs(ry
- atan(rx
)) >= fabs(ry
) * 0.01)
458 mperr("*** ERROR OCCURRED IN MP_ATAN, RESULT INCORRECT ***");
461 convert_from_radians(z
, unit
, z
);
466 mp_sinh(const MPNumber
*x
, MPNumber
*z
)
472 mp_set_from_integer(0, z
);
476 /* WORK WITH ABS(X) */
479 /* If |x| < 1 USE MPEXP TO AVOID CANCELLATION, otherwise IF TOO LARGE MP_EPOWY GIVES ERROR MESSAGE */
480 if (abs_x
.exponent
<= 0) {
481 MPNumber exp_x
, a
, b
;
483 /* ((e^|x| + 1) * (e^|x| - 1)) / e^|x| */
484 // FIXME: Solves to e^|x| - e^-|x|, why not lower branch always? */
485 mp_epowy(&abs_x
, &exp_x
);
486 mp_add_integer(&exp_x
, 1, &a
);
487 mp_add_integer(&exp_x
, -1, &b
);
488 mp_multiply(&a
, &b
, z
);
489 mp_divide(z
, &exp_x
, z
);
495 mp_epowy(&abs_x
, &exp_x
);
496 mp_reciprocal(&exp_x
, z
);
497 mp_subtract(&exp_x
, z
, z
);
500 /* DIVIDE BY TWO AND RESTORE SIGN */
501 mp_divide_integer(z
, 2, z
);
502 mp_multiply_integer(z
, x
->sign
, z
);
507 mp_cosh(const MPNumber
*x
, MPNumber
*z
)
513 mp_set_from_integer(1, z
);
517 /* cosh(x) = (e^x + e^-x) / 2 */
520 mp_reciprocal(&t
, z
);
522 mp_divide_integer(z
, 2, z
);
527 mp_tanh(const MPNumber
*x
, MPNumber
*z
)
534 mp_set_from_integer(0, z
);
540 /* SEE IF ABS(X) SO LARGE THAT RESULT IS +-1 */
541 r__1
= (float) MP_T
* 0.5 * log((float) MP_BASE
);
542 mp_set_from_float(r__1
, z
);
543 if (mp_compare_mp_to_mp(&t
, z
) > 0) {
544 mp_set_from_integer(x
->sign
, z
);
548 /* If |x| >= 1/2 use ?, otherwise use ? to avoid cancellation */
549 /* |tanh(x)| = (e^|2x| - 1) / (e^|2x| + 1) */
550 mp_multiply_integer(&t
, 2, &t
);
551 if (t
.exponent
> 0) {
553 mp_add_integer(&t
, -1, z
);
554 mp_add_integer(&t
, 1, &t
);
558 mp_add_integer(&t
, 1, z
);
559 mp_add_integer(&t
, -1, &t
);
564 z
->sign
= x
->sign
* z
->sign
;
569 mp_asinh(const MPNumber
*x
, MPNumber
*z
)
573 /* sinh⁻¹(x) = ln(x + √(x² + 1)) */
574 mp_multiply(x
, x
, &t
);
575 mp_add_integer(&t
, 1, &t
);
583 mp_acosh(const MPNumber
*x
, MPNumber
*z
)
588 mp_set_from_integer(1, &t
);
589 if (mp_is_less_than(x
, &t
)) {
590 /* Translators: Error displayed when inverse hyperbolic cosine value is undefined */
591 mperr(_("Inverse hyperbolic cosine is undefined for values less than one"));
592 mp_set_from_integer(0, z
);
596 /* cosh⁻¹(x) = ln(x + √(x² - 1)) */
597 mp_multiply(x
, x
, &t
);
598 mp_add_integer(&t
, -1, &t
);
606 mp_atanh(const MPNumber
*x
, MPNumber
*z
)
608 MPNumber one
, minus_one
, n
, d
;
610 /* Check -1 <= x <= 1 */
611 mp_set_from_integer(1, &one
);
612 mp_set_from_integer(-1, &minus_one
);
613 if (mp_is_greater_equal(x
, &one
) || mp_is_less_equal(x
, &minus_one
)) {
614 /* Translators: Error displayed when inverse hyperbolic tangent value is undefined */
615 mperr(_("Inverse hyperbolic tangent is undefined for values outside [-1, 1]"));
616 mp_set_from_integer(0, z
);
620 /* atanh(x) = 0.5 * ln((1 + x) / (1 - x)) */
621 mp_add_integer(x
, 1, &n
);
622 mp_set_from_mp(x
, &d
);
623 mp_invert_sign(&d
, &d
);
624 mp_add_integer(&d
, 1, &d
);
625 mp_divide(&n
, &d
, z
);
627 mp_divide_integer(z
, 2, z
);