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