blob: 56af1d2aa3cc3d97807aa835317cb481040d8c49 [file] [log] [blame]
Raymonddee08492015-04-02 10:43:13 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package org.apache.commons.math.dfp;
19
20/** Mathematical routines for use with {@link Dfp}.
21 * The constants are defined in {@link DfpField}
22 * @version $Revision: 1042376 $ $Date: 2010-12-05 16:54:55 +0100 (dim. 05 déc. 2010) $
23 * @since 2.2
24 */
25public class DfpMath {
26
27 /** Name for traps triggered by pow. */
28 private static final String POW_TRAP = "pow";
29
30 /**
31 * Private Constructor.
32 */
33 private DfpMath() {
34 }
35
36 /** Breaks a string representation up into two dfp's.
37 * <p>The two dfp are such that the sum of them is equivalent
38 * to the input string, but has higher precision than using a
39 * single dfp. This is useful for improving accuracy of
40 * exponentiation and critical multiplies.
41 * @param field field to which the Dfp must belong
42 * @param a string representation to split
43 * @return an array of two {@link Dfp} which sum is a
44 */
45 protected static Dfp[] split(final DfpField field, final String a) {
46 Dfp result[] = new Dfp[2];
47 char[] buf;
48 boolean leading = true;
49 int sp = 0;
50 int sig = 0;
51
52 buf = new char[a.length()];
53
54 for (int i = 0; i < buf.length; i++) {
55 buf[i] = a.charAt(i);
56
57 if (buf[i] >= '1' && buf[i] <= '9') {
58 leading = false;
59 }
60
61 if (buf[i] == '.') {
62 sig += (400 - sig) % 4;
63 leading = false;
64 }
65
66 if (sig == (field.getRadixDigits() / 2) * 4) {
67 sp = i;
68 break;
69 }
70
71 if (buf[i] >= '0' && buf[i] <= '9' && !leading) {
72 sig ++;
73 }
74 }
75
76 result[0] = field.newDfp(new String(buf, 0, sp));
77
78 for (int i = 0; i < buf.length; i++) {
79 buf[i] = a.charAt(i);
80 if (buf[i] >= '0' && buf[i] <= '9' && i < sp) {
81 buf[i] = '0';
82 }
83 }
84
85 result[1] = field.newDfp(new String(buf));
86
87 return result;
88 }
89
90 /** Splits a {@link Dfp} into 2 {@link Dfp}'s such that their sum is equal to the input {@link Dfp}.
91 * @param a number to split
92 * @return two elements array containing the split number
93 */
94 protected static Dfp[] split(final Dfp a) {
95 final Dfp[] result = new Dfp[2];
96 final Dfp shift = a.multiply(a.power10K(a.getRadixDigits() / 2));
97 result[0] = a.add(shift).subtract(shift);
98 result[1] = a.subtract(result[0]);
99 return result;
100 }
101
102 /** Multiply two numbers that are split in to two pieces that are
103 * meant to be added together.
104 * Use binomial multiplication so ab = a0 b0 + a0 b1 + a1 b0 + a1 b1
105 * Store the first term in result0, the rest in result1
106 * @param a first factor of the multiplication, in split form
107 * @param b second factor of the multiplication, in split form
108 * @return a &times; b, in split form
109 */
110 protected static Dfp[] splitMult(final Dfp[] a, final Dfp[] b) {
111 final Dfp[] result = new Dfp[2];
112
113 result[1] = a[0].getZero();
114 result[0] = a[0].multiply(b[0]);
115
116 /* If result[0] is infinite or zero, don't compute result[1].
117 * Attempting to do so may produce NaNs.
118 */
119
120 if (result[0].classify() == Dfp.INFINITE || result[0].equals(result[1])) {
121 return result;
122 }
123
124 result[1] = a[0].multiply(b[1]).add(a[1].multiply(b[0])).add(a[1].multiply(b[1]));
125
126 return result;
127 }
128
129 /** Divide two numbers that are split in to two pieces that are meant to be added together.
130 * Inverse of split multiply above:
131 * (a+b) / (c+d) = (a/c) + ( (bc-ad)/(c**2+cd) )
132 * @param a dividend, in split form
133 * @param b divisor, in split form
134 * @return a / b, in split form
135 */
136 protected static Dfp[] splitDiv(final Dfp[] a, final Dfp[] b) {
137 final Dfp[] result;
138
139 result = new Dfp[2];
140
141 result[0] = a[0].divide(b[0]);
142 result[1] = a[1].multiply(b[0]).subtract(a[0].multiply(b[1]));
143 result[1] = result[1].divide(b[0].multiply(b[0]).add(b[0].multiply(b[1])));
144
145 return result;
146 }
147
148 /** Raise a split base to the a power.
149 * @param base number to raise
150 * @param a power
151 * @return base<sup>a</sup>
152 */
153 protected static Dfp splitPow(final Dfp[] base, int a) {
154 boolean invert = false;
155
156 Dfp[] r = new Dfp[2];
157
158 Dfp[] result = new Dfp[2];
159 result[0] = base[0].getOne();
160 result[1] = base[0].getZero();
161
162 if (a == 0) {
163 // Special case a = 0
164 return result[0].add(result[1]);
165 }
166
167 if (a < 0) {
168 // If a is less than zero
169 invert = true;
170 a = -a;
171 }
172
173 // Exponentiate by successive squaring
174 do {
175 r[0] = new Dfp(base[0]);
176 r[1] = new Dfp(base[1]);
177 int trial = 1;
178
179 int prevtrial;
180 while (true) {
181 prevtrial = trial;
182 trial = trial * 2;
183 if (trial > a) {
184 break;
185 }
186 r = splitMult(r, r);
187 }
188
189 trial = prevtrial;
190
191 a -= trial;
192 result = splitMult(result, r);
193
194 } while (a >= 1);
195
196 result[0] = result[0].add(result[1]);
197
198 if (invert) {
199 result[0] = base[0].getOne().divide(result[0]);
200 }
201
202 return result[0];
203
204 }
205
206 /** Raises base to the power a by successive squaring.
207 * @param base number to raise
208 * @param a power
209 * @return base<sup>a</sup>
210 */
211 public static Dfp pow(Dfp base, int a)
212 {
213 boolean invert = false;
214
215 Dfp result = base.getOne();
216
217 if (a == 0) {
218 // Special case
219 return result;
220 }
221
222 if (a < 0) {
223 invert = true;
224 a = -a;
225 }
226
227 // Exponentiate by successive squaring
228 do {
229 Dfp r = new Dfp(base);
230 Dfp prevr;
231 int trial = 1;
232 int prevtrial;
233
234 do {
235 prevr = new Dfp(r);
236 prevtrial = trial;
237 r = r.multiply(r);
238 trial = trial * 2;
239 } while (a>trial);
240
241 r = prevr;
242 trial = prevtrial;
243
244 a = a - trial;
245 result = result.multiply(r);
246
247 } while (a >= 1);
248
249 if (invert) {
250 result = base.getOne().divide(result);
251 }
252
253 return base.newInstance(result);
254
255 }
256
257 /** Computes e to the given power.
258 * a is broken into two parts, such that a = n+m where n is an integer.
259 * We use pow() to compute e<sup>n</sup> and a Taylor series to compute
260 * e<sup>m</sup>. We return e*<sup>n</sup> &times; e<sup>m</sup>
261 * @param a power at which e should be raised
262 * @return e<sup>a</sup>
263 */
264 public static Dfp exp(final Dfp a) {
265
266 final Dfp inta = a.rint();
267 final Dfp fraca = a.subtract(inta);
268
269 final int ia = inta.intValue();
270 if (ia > 2147483646) {
271 // return +Infinity
272 return a.newInstance((byte)1, Dfp.INFINITE);
273 }
274
275 if (ia < -2147483646) {
276 // return 0;
277 return a.newInstance();
278 }
279
280 final Dfp einta = splitPow(a.getField().getESplit(), ia);
281 final Dfp efraca = expInternal(fraca);
282
283 return einta.multiply(efraca);
284 }
285
286 /** Computes e to the given power.
287 * Where -1 < a < 1. Use the classic Taylor series. 1 + x**2/2! + x**3/3! + x**4/4! ...
288 * @param a power at which e should be raised
289 * @return e<sup>a</sup>
290 */
291 protected static Dfp expInternal(final Dfp a) {
292 Dfp y = a.getOne();
293 Dfp x = a.getOne();
294 Dfp fact = a.getOne();
295 Dfp py = new Dfp(y);
296
297 for (int i = 1; i < 90; i++) {
298 x = x.multiply(a);
299 fact = fact.divide(i);
300 y = y.add(x.multiply(fact));
301 if (y.equals(py)) {
302 break;
303 }
304 py = new Dfp(y);
305 }
306
307 return y;
308 }
309
310 /** Returns the natural logarithm of a.
311 * a is first split into three parts such that a = (10000^h)(2^j)k.
312 * ln(a) is computed by ln(a) = ln(5)*h + ln(2)*(h+j) + ln(k)
313 * k is in the range 2/3 < k <4/3 and is passed on to a series expansion.
314 * @param a number from which logarithm is requested
315 * @return log(a)
316 */
317 public static Dfp log(Dfp a) {
318 int lr;
319 Dfp x;
320 int ix;
321 int p2 = 0;
322
323 // Check the arguments somewhat here
324 if (a.equals(a.getZero()) || a.lessThan(a.getZero()) || a.isNaN()) {
325 // negative, zero or NaN
326 a.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
327 return a.dotrap(DfpField.FLAG_INVALID, "ln", a, a.newInstance((byte)1, Dfp.QNAN));
328 }
329
330 if (a.classify() == Dfp.INFINITE) {
331 return a;
332 }
333
334 x = new Dfp(a);
335 lr = x.log10K();
336
337 x = x.divide(pow(a.newInstance(10000), lr)); /* This puts x in the range 0-10000 */
338 ix = x.floor().intValue();
339
340 while (ix > 2) {
341 ix >>= 1;
342 p2++;
343 }
344
345
346 Dfp[] spx = split(x);
347 Dfp[] spy = new Dfp[2];
348 spy[0] = pow(a.getTwo(), p2); // use spy[0] temporarily as a divisor
349 spx[0] = spx[0].divide(spy[0]);
350 spx[1] = spx[1].divide(spy[0]);
351
352 spy[0] = a.newInstance("1.33333"); // Use spy[0] for comparison
353 while (spx[0].add(spx[1]).greaterThan(spy[0])) {
354 spx[0] = spx[0].divide(2);
355 spx[1] = spx[1].divide(2);
356 p2++;
357 }
358
359 // X is now in the range of 2/3 < x < 4/3
360 Dfp[] spz = logInternal(spx);
361
362 spx[0] = a.newInstance(new StringBuilder().append(p2+4*lr).toString());
363 spx[1] = a.getZero();
364 spy = splitMult(a.getField().getLn2Split(), spx);
365
366 spz[0] = spz[0].add(spy[0]);
367 spz[1] = spz[1].add(spy[1]);
368
369 spx[0] = a.newInstance(new StringBuilder().append(4*lr).toString());
370 spx[1] = a.getZero();
371 spy = splitMult(a.getField().getLn5Split(), spx);
372
373 spz[0] = spz[0].add(spy[0]);
374 spz[1] = spz[1].add(spy[1]);
375
376 return a.newInstance(spz[0].add(spz[1]));
377
378 }
379
380 /** Computes the natural log of a number between 0 and 2.
381 * Let f(x) = ln(x),
382 *
383 * We know that f'(x) = 1/x, thus from Taylor's theorum we have:
384 *
385 * ----- n+1 n
386 * f(x) = \ (-1) (x - 1)
387 * / ---------------- for 1 <= n <= infinity
388 * ----- n
389 *
390 * or
391 * 2 3 4
392 * (x-1) (x-1) (x-1)
393 * ln(x) = (x-1) - ----- + ------ - ------ + ...
394 * 2 3 4
395 *
396 * alternatively,
397 *
398 * 2 3 4
399 * x x x
400 * ln(x+1) = x - - + - - - + ...
401 * 2 3 4
402 *
403 * This series can be used to compute ln(x), but it converges too slowly.
404 *
405 * If we substitute -x for x above, we get
406 *
407 * 2 3 4
408 * x x x
409 * ln(1-x) = -x - - - - - - + ...
410 * 2 3 4
411 *
412 * Note that all terms are now negative. Because the even powered ones
413 * absorbed the sign. Now, subtract the series above from the previous
414 * one to get ln(x+1) - ln(1-x). Note the even terms cancel out leaving
415 * only the odd ones
416 *
417 * 3 5 7
418 * 2x 2x 2x
419 * ln(x+1) - ln(x-1) = 2x + --- + --- + ---- + ...
420 * 3 5 7
421 *
422 * By the property of logarithms that ln(a) - ln(b) = ln (a/b) we have:
423 *
424 * 3 5 7
425 * x+1 / x x x \
426 * ln ----- = 2 * | x + ---- + ---- + ---- + ... |
427 * x-1 \ 3 5 7 /
428 *
429 * But now we want to find ln(a), so we need to find the value of x
430 * such that a = (x+1)/(x-1). This is easily solved to find that
431 * x = (a-1)/(a+1).
432 * @param a number from which logarithm is requested, in split form
433 * @return log(a)
434 */
435 protected static Dfp[] logInternal(final Dfp a[]) {
436
437 /* Now we want to compute x = (a-1)/(a+1) but this is prone to
438 * loss of precision. So instead, compute x = (a/4 - 1/4) / (a/4 + 1/4)
439 */
440 Dfp t = a[0].divide(4).add(a[1].divide(4));
441 Dfp x = t.add(a[0].newInstance("-0.25")).divide(t.add(a[0].newInstance("0.25")));
442
443 Dfp y = new Dfp(x);
444 Dfp num = new Dfp(x);
445 Dfp py = new Dfp(y);
446 int den = 1;
447 for (int i = 0; i < 10000; i++) {
448 num = num.multiply(x);
449 num = num.multiply(x);
450 den = den + 2;
451 t = num.divide(den);
452 y = y.add(t);
453 if (y.equals(py)) {
454 break;
455 }
456 py = new Dfp(y);
457 }
458
459 y = y.multiply(a[0].getTwo());
460
461 return split(y);
462
463 }
464
465 /** Computes x to the y power.<p>
466 *
467 * Uses the following method:<p>
468 *
469 * <ol>
470 * <li> Set u = rint(y), v = y-u
471 * <li> Compute a = v * ln(x)
472 * <li> Compute b = rint( a/ln(2) )
473 * <li> Compute c = a - b*ln(2)
474 * <li> x<sup>y</sup> = x<sup>u</sup> * 2<sup>b</sup> * e<sup>c</sup>
475 * </ol>
476 * if |y| > 1e8, then we compute by exp(y*ln(x)) <p>
477 *
478 * <b>Special Cases</b><p>
479 * <ul>
480 * <li> if y is 0.0 or -0.0 then result is 1.0
481 * <li> if y is 1.0 then result is x
482 * <li> if y is NaN then result is NaN
483 * <li> if x is NaN and y is not zero then result is NaN
484 * <li> if |x| > 1.0 and y is +Infinity then result is +Infinity
485 * <li> if |x| < 1.0 and y is -Infinity then result is +Infinity
486 * <li> if |x| > 1.0 and y is -Infinity then result is +0
487 * <li> if |x| < 1.0 and y is +Infinity then result is +0
488 * <li> if |x| = 1.0 and y is +/-Infinity then result is NaN
489 * <li> if x = +0 and y > 0 then result is +0
490 * <li> if x = +Inf and y < 0 then result is +0
491 * <li> if x = +0 and y < 0 then result is +Inf
492 * <li> if x = +Inf and y > 0 then result is +Inf
493 * <li> if x = -0 and y > 0, finite, not odd integer then result is +0
494 * <li> if x = -0 and y < 0, finite, and odd integer then result is -Inf
495 * <li> if x = -Inf and y > 0, finite, and odd integer then result is -Inf
496 * <li> if x = -0 and y < 0, not finite odd integer then result is +Inf
497 * <li> if x = -Inf and y > 0, not finite odd integer then result is +Inf
498 * <li> if x < 0 and y > 0, finite, and odd integer then result is -(|x|<sup>y</sup>)
499 * <li> if x < 0 and y > 0, finite, and not integer then result is NaN
500 * </ul>
501 * @param x base to be raised
502 * @param y power to which base should be raised
503 * @return x<sup>y</sup>
504 */
505 public static Dfp pow(Dfp x, final Dfp y) {
506
507 // make sure we don't mix number with different precision
508 if (x.getField().getRadixDigits() != y.getField().getRadixDigits()) {
509 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
510 final Dfp result = x.newInstance(x.getZero());
511 result.nans = Dfp.QNAN;
512 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, result);
513 }
514
515 final Dfp zero = x.getZero();
516 final Dfp one = x.getOne();
517 final Dfp two = x.getTwo();
518 boolean invert = false;
519 int ui;
520
521 /* Check for special cases */
522 if (y.equals(zero)) {
523 return x.newInstance(one);
524 }
525
526 if (y.equals(one)) {
527 if (x.isNaN()) {
528 // Test for NaNs
529 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
530 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x);
531 }
532 return x;
533 }
534
535 if (x.isNaN() || y.isNaN()) {
536 // Test for NaNs
537 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
538 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
539 }
540
541 // X == 0
542 if (x.equals(zero)) {
543 if (Dfp.copysign(one, x).greaterThan(zero)) {
544 // X == +0
545 if (y.greaterThan(zero)) {
546 return x.newInstance(zero);
547 } else {
548 return x.newInstance(x.newInstance((byte)1, Dfp.INFINITE));
549 }
550 } else {
551 // X == -0
552 if (y.classify() == Dfp.FINITE && y.rint().equals(y) && !y.remainder(two).equals(zero)) {
553 // If y is odd integer
554 if (y.greaterThan(zero)) {
555 return x.newInstance(zero.negate());
556 } else {
557 return x.newInstance(x.newInstance((byte)-1, Dfp.INFINITE));
558 }
559 } else {
560 // Y is not odd integer
561 if (y.greaterThan(zero)) {
562 return x.newInstance(zero);
563 } else {
564 return x.newInstance(x.newInstance((byte)1, Dfp.INFINITE));
565 }
566 }
567 }
568 }
569
570 if (x.lessThan(zero)) {
571 // Make x positive, but keep track of it
572 x = x.negate();
573 invert = true;
574 }
575
576 if (x.greaterThan(one) && y.classify() == Dfp.INFINITE) {
577 if (y.greaterThan(zero)) {
578 return y;
579 } else {
580 return x.newInstance(zero);
581 }
582 }
583
584 if (x.lessThan(one) && y.classify() == Dfp.INFINITE) {
585 if (y.greaterThan(zero)) {
586 return x.newInstance(zero);
587 } else {
588 return x.newInstance(Dfp.copysign(y, one));
589 }
590 }
591
592 if (x.equals(one) && y.classify() == Dfp.INFINITE) {
593 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
594 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
595 }
596
597 if (x.classify() == Dfp.INFINITE) {
598 // x = +/- inf
599 if (invert) {
600 // negative infinity
601 if (y.classify() == Dfp.FINITE && y.rint().equals(y) && !y.remainder(two).equals(zero)) {
602 // If y is odd integer
603 if (y.greaterThan(zero)) {
604 return x.newInstance(x.newInstance((byte)-1, Dfp.INFINITE));
605 } else {
606 return x.newInstance(zero.negate());
607 }
608 } else {
609 // Y is not odd integer
610 if (y.greaterThan(zero)) {
611 return x.newInstance(x.newInstance((byte)1, Dfp.INFINITE));
612 } else {
613 return x.newInstance(zero);
614 }
615 }
616 } else {
617 // positive infinity
618 if (y.greaterThan(zero)) {
619 return x;
620 } else {
621 return x.newInstance(zero);
622 }
623 }
624 }
625
626 if (invert && !y.rint().equals(y)) {
627 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
628 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
629 }
630
631 // End special cases
632
633 Dfp r;
634 if (y.lessThan(x.newInstance(100000000)) && y.greaterThan(x.newInstance(-100000000))) {
635 final Dfp u = y.rint();
636 ui = u.intValue();
637
638 final Dfp v = y.subtract(u);
639
640 if (v.unequal(zero)) {
641 final Dfp a = v.multiply(log(x));
642 final Dfp b = a.divide(x.getField().getLn2()).rint();
643
644 final Dfp c = a.subtract(b.multiply(x.getField().getLn2()));
645 r = splitPow(split(x), ui);
646 r = r.multiply(pow(two, b.intValue()));
647 r = r.multiply(exp(c));
648 } else {
649 r = splitPow(split(x), ui);
650 }
651 } else {
652 // very large exponent. |y| > 1e8
653 r = exp(log(x).multiply(y));
654 }
655
656 if (invert) {
657 // if y is odd integer
658 if (y.rint().equals(y) && !y.remainder(two).equals(zero)) {
659 r = r.negate();
660 }
661 }
662
663 return x.newInstance(r);
664
665 }
666
667 /** Computes sin(a) Used when 0 < a < pi/4.
668 * Uses the classic Taylor series. x - x**3/3! + x**5/5! ...
669 * @param a number from which sine is desired, in split form
670 * @return sin(a)
671 */
672 protected static Dfp sinInternal(Dfp a[]) {
673
674 Dfp c = a[0].add(a[1]);
675 Dfp y = c;
676 c = c.multiply(c);
677 Dfp x = y;
678 Dfp fact = a[0].getOne();
679 Dfp py = new Dfp(y);
680
681 for (int i = 3; i < 90; i += 2) {
682 x = x.multiply(c);
683 x = x.negate();
684
685 fact = fact.divide((i-1)*i); // 1 over fact
686 y = y.add(x.multiply(fact));
687 if (y.equals(py))
688 break;
689 py = new Dfp(y);
690 }
691
692 return y;
693
694 }
695
696 /** Computes cos(a) Used when 0 < a < pi/4.
697 * Uses the classic Taylor series for cosine. 1 - x**2/2! + x**4/4! ...
698 * @param a number from which cosine is desired, in split form
699 * @return cos(a)
700 */
701 protected static Dfp cosInternal(Dfp a[]) {
702 final Dfp one = a[0].getOne();
703
704
705 Dfp x = one;
706 Dfp y = one;
707 Dfp c = a[0].add(a[1]);
708 c = c.multiply(c);
709
710 Dfp fact = one;
711 Dfp py = new Dfp(y);
712
713 for (int i = 2; i < 90; i += 2) {
714 x = x.multiply(c);
715 x = x.negate();
716
717 fact = fact.divide((i - 1) * i); // 1 over fact
718
719 y = y.add(x.multiply(fact));
720 if (y.equals(py)) {
721 break;
722 }
723 py = new Dfp(y);
724 }
725
726 return y;
727
728 }
729
730 /** computes the sine of the argument.
731 * @param a number from which sine is desired
732 * @return sin(a)
733 */
734 public static Dfp sin(final Dfp a) {
735 final Dfp pi = a.getField().getPi();
736 final Dfp zero = a.getField().getZero();
737 boolean neg = false;
738
739 /* First reduce the argument to the range of +/- PI */
740 Dfp x = a.remainder(pi.multiply(2));
741
742 /* if x < 0 then apply identity sin(-x) = -sin(x) */
743 /* This puts x in the range 0 < x < PI */
744 if (x.lessThan(zero)) {
745 x = x.negate();
746 neg = true;
747 }
748
749 /* Since sine(x) = sine(pi - x) we can reduce the range to
750 * 0 < x < pi/2
751 */
752
753 if (x.greaterThan(pi.divide(2))) {
754 x = pi.subtract(x);
755 }
756
757 Dfp y;
758 if (x.lessThan(pi.divide(4))) {
759 Dfp c[] = new Dfp[2];
760 c[0] = x;
761 c[1] = zero;
762
763 //y = sinInternal(c);
764 y = sinInternal(split(x));
765 } else {
766 final Dfp c[] = new Dfp[2];
767 final Dfp[] piSplit = a.getField().getPiSplit();
768 c[0] = piSplit[0].divide(2).subtract(x);
769 c[1] = piSplit[1].divide(2);
770 y = cosInternal(c);
771 }
772
773 if (neg) {
774 y = y.negate();
775 }
776
777 return a.newInstance(y);
778
779 }
780
781 /** computes the cosine of the argument.
782 * @param a number from which cosine is desired
783 * @return cos(a)
784 */
785 public static Dfp cos(Dfp a) {
786 final Dfp pi = a.getField().getPi();
787 final Dfp zero = a.getField().getZero();
788 boolean neg = false;
789
790 /* First reduce the argument to the range of +/- PI */
791 Dfp x = a.remainder(pi.multiply(2));
792
793 /* if x < 0 then apply identity cos(-x) = cos(x) */
794 /* This puts x in the range 0 < x < PI */
795 if (x.lessThan(zero)) {
796 x = x.negate();
797 }
798
799 /* Since cos(x) = -cos(pi - x) we can reduce the range to
800 * 0 < x < pi/2
801 */
802
803 if (x.greaterThan(pi.divide(2))) {
804 x = pi.subtract(x);
805 neg = true;
806 }
807
808 Dfp y;
809 if (x.lessThan(pi.divide(4))) {
810 Dfp c[] = new Dfp[2];
811 c[0] = x;
812 c[1] = zero;
813
814 y = cosInternal(c);
815 } else {
816 final Dfp c[] = new Dfp[2];
817 final Dfp[] piSplit = a.getField().getPiSplit();
818 c[0] = piSplit[0].divide(2).subtract(x);
819 c[1] = piSplit[1].divide(2);
820 y = sinInternal(c);
821 }
822
823 if (neg) {
824 y = y.negate();
825 }
826
827 return a.newInstance(y);
828
829 }
830
831 /** computes the tangent of the argument.
832 * @param a number from which tangent is desired
833 * @return tan(a)
834 */
835 public static Dfp tan(final Dfp a) {
836 return sin(a).divide(cos(a));
837 }
838
839 /** computes the arc-tangent of the argument.
840 * @param a number from which arc-tangent is desired
841 * @return atan(a)
842 */
843 protected static Dfp atanInternal(final Dfp a) {
844
845 Dfp y = new Dfp(a);
846 Dfp x = new Dfp(y);
847 Dfp py = new Dfp(y);
848
849 for (int i = 3; i < 90; i += 2) {
850 x = x.multiply(a);
851 x = x.multiply(a);
852 x = x.negate();
853 y = y.add(x.divide(i));
854 if (y.equals(py)) {
855 break;
856 }
857 py = new Dfp(y);
858 }
859
860 return y;
861
862 }
863
864 /** computes the arc tangent of the argument
865 *
866 * Uses the typical taylor series
867 *
868 * but may reduce arguments using the following identity
869 * tan(x+y) = (tan(x) + tan(y)) / (1 - tan(x)*tan(y))
870 *
871 * since tan(PI/8) = sqrt(2)-1,
872 *
873 * atan(x) = atan( (x - sqrt(2) + 1) / (1+x*sqrt(2) - x) + PI/8.0
874 * @param a number from which arc-tangent is desired
875 * @return atan(a)
876 */
877 public static Dfp atan(final Dfp a) {
878 final Dfp zero = a.getField().getZero();
879 final Dfp one = a.getField().getOne();
880 final Dfp[] sqr2Split = a.getField().getSqr2Split();
881 final Dfp[] piSplit = a.getField().getPiSplit();
882 boolean recp = false;
883 boolean neg = false;
884 boolean sub = false;
885
886 final Dfp ty = sqr2Split[0].subtract(one).add(sqr2Split[1]);
887
888 Dfp x = new Dfp(a);
889 if (x.lessThan(zero)) {
890 neg = true;
891 x = x.negate();
892 }
893
894 if (x.greaterThan(one)) {
895 recp = true;
896 x = one.divide(x);
897 }
898
899 if (x.greaterThan(ty)) {
900 Dfp sty[] = new Dfp[2];
901 sub = true;
902
903 sty[0] = sqr2Split[0].subtract(one);
904 sty[1] = sqr2Split[1];
905
906 Dfp[] xs = split(x);
907
908 Dfp[] ds = splitMult(xs, sty);
909 ds[0] = ds[0].add(one);
910
911 xs[0] = xs[0].subtract(sty[0]);
912 xs[1] = xs[1].subtract(sty[1]);
913
914 xs = splitDiv(xs, ds);
915 x = xs[0].add(xs[1]);
916
917 //x = x.subtract(ty).divide(dfp.one.add(x.multiply(ty)));
918 }
919
920 Dfp y = atanInternal(x);
921
922 if (sub) {
923 y = y.add(piSplit[0].divide(8)).add(piSplit[1].divide(8));
924 }
925
926 if (recp) {
927 y = piSplit[0].divide(2).subtract(y).add(piSplit[1].divide(2));
928 }
929
930 if (neg) {
931 y = y.negate();
932 }
933
934 return a.newInstance(y);
935
936 }
937
938 /** computes the arc-sine of the argument.
939 * @param a number from which arc-sine is desired
940 * @return asin(a)
941 */
942 public static Dfp asin(final Dfp a) {
943 return atan(a.divide(a.getOne().subtract(a.multiply(a)).sqrt()));
944 }
945
946 /** computes the arc-cosine of the argument.
947 * @param a number from which arc-cosine is desired
948 * @return acos(a)
949 */
950 public static Dfp acos(Dfp a) {
951 Dfp result;
952 boolean negative = false;
953
954 if (a.lessThan(a.getZero())) {
955 negative = true;
956 }
957
958 a = Dfp.copysign(a, a.getOne()); // absolute value
959
960 result = atan(a.getOne().subtract(a.multiply(a)).sqrt().divide(a));
961
962 if (negative) {
963 result = a.getField().getPi().subtract(result);
964 }
965
966 return a.newInstance(result);
967 }
968
969}