Home | History | Annotate | Download | only in dfp
      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 dc. 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      */
     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 }
    970