• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
18 package 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  */
25 public class DfpMath {
26 
27     /** Name for traps triggered by pow. */
28     private static final String POW_TRAP = "pow";
29 
30     /**
31      * Private Constructor.
32      */
DfpMath()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      */
split(final DfpField field, final String a)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      */
split(final Dfp a)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      */
splitMult(final Dfp[] a, final Dfp[] b)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      */
splitDiv(final Dfp[] a, final Dfp[] b)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      */
splitPow(final Dfp[] base, int a)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      */
pow(Dfp base, int a)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      */
exp(final Dfp a)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      */
expInternal(final Dfp a)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      */
log(Dfp a)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      */
logInternal(final Dfp a[])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      */
pow(Dfp x, final Dfp y)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      */
sinInternal(Dfp a[])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      */
cosInternal(Dfp a[])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      */
sin(final Dfp a)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      */
cos(Dfp a)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      */
tan(final Dfp a)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      */
atanInternal(final Dfp a)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      */
atan(final Dfp a)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      */
asin(final Dfp a)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      */
acos(Dfp a)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 }
970