DfpMath.java

  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.  *      https://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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.dfp;

  22. /** Mathematical routines for use with {@link Dfp}.
  23.  * The constants are defined in {@link DfpField}
  24.  */
  25. public class DfpMath {

  26.     /** Name for traps triggered by pow. */
  27.     private static final String POW_TRAP = "pow";

  28.     /**
  29.      * Private Constructor.
  30.      */
  31.     private DfpMath() {
  32.     }

  33.     /** Breaks a string representation up into two dfp's.
  34.      * <p>The two dfp are such that the sum of them is equivalent
  35.      * to the input string, but has higher precision than using a
  36.      * single dfp. This is useful for improving accuracy of
  37.      * exponentiation and critical multiplies.
  38.      * @param field field to which the Dfp must belong
  39.      * @param a string representation to split
  40.      * @return an array of two {@link Dfp} which sum is a
  41.      */
  42.     protected static Dfp[] split(final DfpField field, final String a) {
  43.         Dfp[] result = new Dfp[2];
  44.         boolean leading = true;
  45.         int sp = 0;
  46.         int sig = 0;

  47.         StringBuilder builder1 = new StringBuilder(a.length());

  48.         for (int i = 0; i < a.length(); i++) {
  49.           final char c = a.charAt(i);
  50.           builder1.append(c);

  51.           if (c >= '1' && c <= '9') {
  52.               leading = false;
  53.           }

  54.           if (c == '.') {
  55.             sig += (400 - sig) % 4;
  56.             leading = false;
  57.           }

  58.           if (sig == (field.getRadixDigits() / 2) * 4) {
  59.             sp = i;
  60.             break;
  61.           }

  62.           if (c >= '0' &&c <= '9' && !leading) {
  63.               sig ++;
  64.           }
  65.         }

  66.         result[0] = field.newDfp(builder1.substring(0, sp));

  67.         StringBuilder builder2 = new StringBuilder(a.length());
  68.         for (int i = 0; i < a.length(); i++) {
  69.             final char c = a.charAt(i);
  70.             if (c >= '0' && c <= '9' && i < sp) {
  71.                 builder2.append('0');
  72.             } else {
  73.                 builder2.append(c);
  74.           }
  75.         }

  76.         result[1] = field.newDfp(builder2.toString());

  77.         return result;
  78.     }

  79.     /** Splits a {@link Dfp} into 2 {@link Dfp}'s such that their sum is equal to the input {@link Dfp}.
  80.      * @param a number to split
  81.      * @return two elements array containing the split number
  82.      */
  83.     protected static Dfp[] split(final Dfp a) {
  84.         final Dfp[] result = new Dfp[2];
  85.         final Dfp shift = a.multiply(a.power10K(a.getRadixDigits() / 2));
  86.         result[0] = a.add(shift).subtract(shift);
  87.         result[1] = a.subtract(result[0]);
  88.         return result;
  89.     }

  90.     /** Multiply two numbers that are split in to two pieces that are
  91.      *  meant to be added together.
  92.      *  Use binomial multiplication so ab = a0 b0 + a0 b1 + a1 b0 + a1 b1
  93.      *  Store the first term in result0, the rest in result1
  94.      *  @param a first factor of the multiplication, in split form
  95.      *  @param b second factor of the multiplication, in split form
  96.      *  @return a &times; b, in split form
  97.      */
  98.     protected static Dfp[] splitMult(final Dfp[] a, final Dfp[] b) {
  99.         final Dfp[] result = new Dfp[2];

  100.         result[1] = a[0].getZero();
  101.         result[0] = a[0].multiply(b[0]);

  102.         /* If result[0] is infinite or zero, don't compute result[1].
  103.          * Attempting to do so may produce NaNs.
  104.          */

  105.         if (result[0].classify() == Dfp.INFINITE || result[0].equals(result[1])) {
  106.             return result;
  107.         }

  108.         result[1] = a[0].multiply(b[1]).add(a[1].multiply(b[0])).add(a[1].multiply(b[1]));

  109.         return result;
  110.     }

  111.     /** Divide two numbers that are split in to two pieces that are meant to be added together.
  112.      * Inverse of split multiply above:
  113.      *  (a+b) / (c+d) = (a/c) + ( (bc-ad)/(c**2+cd) )
  114.      *  @param a dividend, in split form
  115.      *  @param b divisor, in split form
  116.      *  @return a / b, in split form
  117.      */
  118.     protected static Dfp[] splitDiv(final Dfp[] a, final Dfp[] b) {
  119.         final Dfp[] result;

  120.         result = new Dfp[2];

  121.         result[0] = a[0].divide(b[0]);
  122.         result[1] = a[1].multiply(b[0]).subtract(a[0].multiply(b[1]));
  123.         result[1] = result[1].divide(b[0].multiply(b[0]).add(b[0].multiply(b[1])));

  124.         return result;
  125.     }

  126.     /** Raise a split base to the a power.
  127.      * @param base number to raise
  128.      * @param a power
  129.      * @return base<sup>a</sup>
  130.      */
  131.     protected static Dfp splitPow(final Dfp[] base, int a) {
  132.         boolean invert = false;

  133.         Dfp[] r = new Dfp[2];

  134.         Dfp[] result = new Dfp[2];
  135.         result[0] = base[0].getOne();
  136.         result[1] = base[0].getZero();

  137.         if (a == 0) {
  138.             // Special case a = 0
  139.             return result[0].add(result[1]);
  140.         }

  141.         if (a < 0) {
  142.             // If a is less than zero
  143.             invert = true;
  144.             a = -a;
  145.         }

  146.         // Exponentiate by successive squaring
  147.         do {
  148.             r[0] = new Dfp(base[0]);
  149.             r[1] = new Dfp(base[1]);
  150.             int trial = 1;

  151.             int prevtrial;
  152.             while (true) {
  153.                 prevtrial = trial;
  154.                 trial *= 2;
  155.                 if (trial > a) {
  156.                     break;
  157.                 }
  158.                 r = splitMult(r, r);
  159.             }

  160.             trial = prevtrial;

  161.             a -= trial;
  162.             result = splitMult(result, r);

  163.         } while (a >= 1);

  164.         result[0] = result[0].add(result[1]);

  165.         if (invert) {
  166.             result[0] = base[0].getOne().divide(result[0]);
  167.         }

  168.         return result[0];

  169.     }

  170.     /** Raises base to the power a by successive squaring.
  171.      * @param base number to raise
  172.      * @param a power
  173.      * @return base<sup>a</sup>
  174.      */
  175.     public static Dfp pow(Dfp base, int a)
  176.     {
  177.         boolean invert = false;

  178.         Dfp result = base.getOne();

  179.         if (a == 0) {
  180.             // Special case
  181.             return result;
  182.         }

  183.         if (a < 0) {
  184.             invert = true;
  185.             a = -a;
  186.         }

  187.         // Exponentiate by successive squaring
  188.         do {
  189.             Dfp r = new Dfp(base);
  190.             Dfp prevr;
  191.             int trial = 1;
  192.             int prevtrial;

  193.             do {
  194.                 prevr = new Dfp(r);
  195.                 prevtrial = trial;
  196.                 r = r.square();
  197.                 trial *= 2;
  198.             } while (a>trial);

  199.             r = prevr;
  200.             trial = prevtrial;

  201.             a -= trial;
  202.             result = result.multiply(r);

  203.         } while (a >= 1);

  204.         if (invert) {
  205.             result = base.getOne().divide(result);
  206.         }

  207.         return base.newInstance(result);

  208.     }

  209.     /** Computes e to the given power.
  210.      * a is broken into two parts, such that a = n+m  where n is an integer.
  211.      * We use pow() to compute e<sup>n</sup> and a Taylor series to compute
  212.      * e<sup>m</sup>.  We return e*<sup>n</sup> &times; e<sup>m</sup>
  213.      * @param a power at which e should be raised
  214.      * @return e<sup>a</sup>
  215.      */
  216.     public static Dfp exp(final Dfp a) {

  217.         final Dfp inta = a.rint();
  218.         final Dfp fraca = a.subtract(inta);

  219.         final int ia = inta.intValue();
  220.         if (ia > 2147483646) {
  221.             // return +Infinity
  222.             return a.newInstance((byte)1, Dfp.INFINITE);
  223.         }

  224.         if (ia < -2147483646) {
  225.             // return 0;
  226.             return a.newInstance();
  227.         }

  228.         final Dfp einta = splitPow(a.getField().getESplit(), ia);
  229.         final Dfp efraca = expInternal(fraca);

  230.         return einta.multiply(efraca);
  231.     }

  232.     /** Computes e to the given power.
  233.      * Where -1 &lt; a &lt; 1.  Use the classic Taylor series.  1 + x**2/2! + x**3/3! + x**4/4!  ...
  234.      * @param a power at which e should be raised
  235.      * @return e<sup>a</sup>
  236.      */
  237.     protected static Dfp expInternal(final Dfp a) {
  238.         Dfp y = a.getOne();
  239.         Dfp x = a.getOne();
  240.         Dfp fact = a.getOne();
  241.         Dfp py = new Dfp(y);

  242.         for (int i = 1; i < 90; i++) {
  243.             x = x.multiply(a);
  244.             fact = fact.divide(i);
  245.             y = y.add(x.multiply(fact));
  246.             if (y.equals(py)) {
  247.                 break;
  248.             }
  249.             py = new Dfp(y);
  250.         }

  251.         return y;
  252.     }

  253.     /** Returns the natural logarithm of a.
  254.      * a is first split into three parts such that  a = (10000^h)(2^j)k.
  255.      * ln(a) is computed by ln(a) = ln(5)*h + ln(2)*(h+j) + ln(k)
  256.      * k is in the range 2/3 &lt; k &lt; 4/3 and is passed on to a series expansion.
  257.      * @param a number from which logarithm is requested
  258.      * @return log(a)
  259.      */
  260.     public static Dfp log(Dfp a) {
  261.         int lr;
  262.         Dfp x;
  263.         int ix;
  264.         int p2 = 0;

  265.         // Check the arguments somewhat here
  266.         if (a.equals(a.getZero()) || a.lessThan(a.getZero()) || a.isNaN()) {
  267.             // negative, zero or NaN
  268.             a.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  269.             return a.dotrap(DfpField.FLAG_INVALID, "ln", a, a.newInstance((byte)1, Dfp.QNAN));
  270.         }

  271.         if (a.classify() == Dfp.INFINITE) {
  272.             return a;
  273.         }

  274.         x = new Dfp(a);
  275.         lr = x.log10K();

  276.         x = x.divide(pow(a.newInstance(10000), lr));  /* This puts x in the range 0-10000 */
  277.         ix = x.floor().intValue();

  278.         while (ix > 2) {
  279.             ix >>= 1;
  280.             p2++;
  281.         }


  282.         Dfp[] spx = split(x);
  283.         Dfp[] spy = new Dfp[2];
  284.         spy[0] = pow(a.getTwo(), p2);          // use spy[0] temporarily as a divisor
  285.         spx[0] = spx[0].divide(spy[0]);
  286.         spx[1] = spx[1].divide(spy[0]);

  287.         spy[0] = a.newInstance("1.33333");    // Use spy[0] for comparison
  288.         while (spx[0].add(spx[1]).greaterThan(spy[0])) {
  289.             spx[0] = spx[0].divide(2);
  290.             spx[1] = spx[1].divide(2);
  291.             p2++;
  292.         }

  293.         // X is now in the range of 2/3 < x < 4/3
  294.         Dfp[] spz = logInternal(spx);

  295.         spx[0] = a.newInstance(new StringBuilder().append(p2+4*lr).toString());
  296.         spx[1] = a.getZero();
  297.         spy = splitMult(a.getField().getLn2Split(), spx);

  298.         spz[0] = spz[0].add(spy[0]);
  299.         spz[1] = spz[1].add(spy[1]);

  300.         spx[0] = a.newInstance(new StringBuilder().append(4*lr).toString());
  301.         spx[1] = a.getZero();
  302.         spy = splitMult(a.getField().getLn5Split(), spx);

  303.         spz[0] = spz[0].add(spy[0]);
  304.         spz[1] = spz[1].add(spy[1]);

  305.         return a.newInstance(spz[0].add(spz[1]));

  306.     }

  307.     /** Computes the natural log of a number between 0 and 2.
  308.      *  Let f(x) = ln(x),
  309.      *
  310.      *  We know that f'(x) = 1/x, thus from Taylor's theorum we have:
  311.      *
  312.      *           -----          n+1         n
  313.      *  f(x) =   \           (-1)    (x - 1)
  314.      *           /          ----------------    for 1 &lt;= n &lt;= infinity
  315.      *           -----             n
  316.      *
  317.      *  or
  318.      *                       2        3       4
  319.      *                   (x-1)   (x-1)    (x-1)
  320.      *  ln(x) =  (x-1) - ----- + ------ - ------ + ...
  321.      *                     2       3        4
  322.      *
  323.      *  alternatively,
  324.      *
  325.      *                  2    3   4
  326.      *                 x    x   x
  327.      *  ln(x+1) =  x - -  + - - - + ...
  328.      *                 2    3   4
  329.      *
  330.      *  This series can be used to compute ln(x), but it converges too slowly.
  331.      *
  332.      *  If we substitute -x for x above, we get
  333.      *
  334.      *                   2    3    4
  335.      *                  x    x    x
  336.      *  ln(1-x) =  -x - -  - -  - - + ...
  337.      *                  2    3    4
  338.      *
  339.      *  Note that all terms are now negative.  Because the even powered ones
  340.      *  absorbed the sign.  Now, subtract the series above from the previous
  341.      *  one to get ln(x+1) - ln(1-x).  Note the even terms cancel out leaving
  342.      *  only the odd ones
  343.      *
  344.      *                             3     5      7
  345.      *                           2x    2x     2x
  346.      *  ln(x+1) - ln(x-1) = 2x + --- + --- + ---- + ...
  347.      *                            3     5      7
  348.      *
  349.      *  By the property of logarithms that ln(a) - ln(b) = ln (a/b) we have:
  350.      *
  351.      *                                3        5        7
  352.      *      x+1           /          x        x        x          \
  353.      *  ln ----- =   2 *  |  x  +   ----  +  ----  +  ---- + ...  |
  354.      *      x-1           \          3        5        7          /
  355.      *
  356.      *  But now we want to find ln(a), so we need to find the value of x
  357.      *  such that a = (x+1)/(x-1).   This is easily solved to find that
  358.      *  x = (a-1)/(a+1).
  359.      * @param a number from which logarithm is requested, in split form
  360.      * @return log(a)
  361.      */
  362.     protected static Dfp[] logInternal(final Dfp[] a) {

  363.         /* Now we want to compute x = (a-1)/(a+1) but this is prone to
  364.          * loss of precision.  So instead, compute x = (a/4 - 1/4) / (a/4 + 1/4)
  365.          */
  366.         Dfp t = a[0].divide(4).add(a[1].divide(4));
  367.         Dfp x = t.add(a[0].newInstance("-0.25")).divide(t.add(a[0].newInstance("0.25")));

  368.         Dfp y = new Dfp(x);
  369.         Dfp num = new Dfp(x);
  370.         Dfp py = new Dfp(y);
  371.         int den = 1;
  372.         for (int i = 0; i < 10000; i++) {
  373.             num = num.multiply(x);
  374.             num = num.multiply(x);
  375.             den += 2;
  376.             t = num.divide(den);
  377.             y = y.add(t);
  378.             if (y.equals(py)) {
  379.                 break;
  380.             }
  381.             py = new Dfp(y);
  382.         }

  383.         y = y.multiply(a[0].getTwo());

  384.         return split(y);

  385.     }

  386.     /** Computes x to the y power.
  387.      *
  388.      *  <p>Uses the following method:</p>
  389.      *
  390.      *  <ol>
  391.      *  <li> Set u = rint(y), v = y-u
  392.      *  <li> Compute a = v * ln(x)
  393.      *  <li> Compute b = rint( a/ln(2) )
  394.      *  <li> Compute c = a - b*ln(2)
  395.      *  <li> x<sup>y</sup> = x<sup>u</sup>  *   2<sup>b</sup> * e<sup>c</sup>
  396.      *  </ol>
  397.      *  if |y| &gt; 1e8, then we compute by exp(y*ln(x))
  398.      *
  399.      *  <p>Special Cases</p>
  400.      *  <ul>
  401.      *  <li>  if y is 0.0 or -0.0 then result is 1.0</li>
  402.      *  <li>  if y is 1.0 then result is x</li>
  403.      *  <li>  if y is NaN then result is NaN</li>
  404.      *  <li>  if x is NaN and y is not zero then result is NaN</li>
  405.      *  <li>  if |x| &gt; 1.0 and y is +Infinity then result is +Infinity</li>
  406.      *  <li>  if |x| &lt; 1.0 and y is -Infinity then result is +Infinity</li>
  407.      *  <li>  if |x| &gt; 1.0 and y is -Infinity then result is +0</li>
  408.      *  <li>  if |x| &lt; 1.0 and y is +Infinity then result is +0</li>
  409.      *  <li>  if |x| = 1.0 and y is +/-Infinity then result is NaN</li>
  410.      *  <li>  if x = +0 and y &gt; 0 then result is +0</li>
  411.      *  <li>  if x = +Inf and y &lt; 0 then result is +0</li>
  412.      *  <li>  if x = +0 and y &lt; 0 then result is +Inf</li>
  413.      *  <li>  if x = +Inf and y &gt; 0 then result is +Inf</li>
  414.      *  <li>  if x = -0 and y &gt; 0, finite, not odd integer then result is +0</li>
  415.      *  <li>  if x = -0 and y &lt; 0, finite, and odd integer then result is -Inf</li>
  416.      *  <li>  if x = -Inf and y &gt; 0, finite, and odd integer then result is -Inf</li>
  417.      *  <li>  if x = -0 and y &lt; 0, not finite odd integer then result is +Inf</li>
  418.      *  <li>  if x = -Inf and y &gt; 0, not finite odd integer then result is +Inf</li>
  419.      *  <li>  if x &lt; 0 and y &gt; 0, finite, and odd integer then result is -(|x|<sup>y</sup>)</li>
  420.      *  <li>  if x &lt; 0 and y &gt; 0, finite, and not integer then result is NaN</li>
  421.      *  </ul>
  422.      *  @param x base to be raised
  423.      *  @param y power to which base should be raised
  424.      *  @return x<sup>y</sup>
  425.      */
  426.     public static Dfp pow(Dfp x, final Dfp y) {

  427.         // make sure we don't mix number with different precision
  428.         if (x.getField().getRadixDigits() != y.getField().getRadixDigits()) {
  429.             x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  430.             final Dfp result = x.newInstance(x.getZero());
  431.             result.nans = Dfp.QNAN;
  432.             return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, result);
  433.         }

  434.         final Dfp zero = x.getZero();
  435.         final Dfp one  = x.getOne();
  436.         final Dfp two  = x.getTwo();
  437.         boolean invert = false;
  438.         int ui;

  439.         /* Check for special cases */
  440.         if (y.equals(zero)) {
  441.             return x.newInstance(one);
  442.         }

  443.         if (y.equals(one)) {
  444.             if (x.isNaN()) {
  445.                 // Test for NaNs
  446.                 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  447.                 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x);
  448.             }
  449.             return x;
  450.         }

  451.         if (x.isNaN() || y.isNaN()) {
  452.             // Test for NaNs
  453.             x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  454.             return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
  455.         }

  456.         // X == 0
  457.         if (x.equals(zero)) {
  458.             if (Dfp.copysign(one, x).greaterThan(zero)) {
  459.                 // X == +0
  460.                 if (y.greaterThan(zero)) {
  461.                     return x.newInstance(zero);
  462.                 } else {
  463.                     return x.newInstance(x.newInstance((byte)1, Dfp.INFINITE));
  464.                 }
  465.             } else {
  466.                 // X == -0
  467.                 if (y.classify() == Dfp.FINITE && y.rint().equals(y) && !y.remainder(two).equals(zero)) {
  468.                     // If y is odd integer
  469.                     if (y.greaterThan(zero)) {
  470.                         return x.newInstance(zero.negate());
  471.                     } else {
  472.                         return x.newInstance(x.newInstance((byte)-1, Dfp.INFINITE));
  473.                     }
  474.                 } else {
  475.                     // Y is not odd integer
  476.                     if (y.greaterThan(zero)) {
  477.                         return x.newInstance(zero);
  478.                     } else {
  479.                         return x.newInstance(x.newInstance((byte)1, Dfp.INFINITE));
  480.                     }
  481.                 }
  482.             }
  483.         }

  484.         if (x.lessThan(zero)) {
  485.             // Make x positive, but keep track of it
  486.             x = x.negate();
  487.             invert = true;
  488.         }

  489.         if (x.greaterThan(one) && y.classify() == Dfp.INFINITE) {
  490.             if (y.greaterThan(zero)) {
  491.                 return y;
  492.             } else {
  493.                 return x.newInstance(zero);
  494.             }
  495.         }

  496.         if (x.lessThan(one) && y.classify() == Dfp.INFINITE) {
  497.             if (y.greaterThan(zero)) {
  498.                 return x.newInstance(zero);
  499.             } else {
  500.                 return x.newInstance(Dfp.copysign(y, one));
  501.             }
  502.         }

  503.         if (x.equals(one) && y.classify() == Dfp.INFINITE) {
  504.             x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  505.             return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
  506.         }

  507.         if (x.classify() == Dfp.INFINITE) {
  508.             // x = +/- inf
  509.             if (invert) {
  510.                 // negative infinity
  511.                 if (y.classify() == Dfp.FINITE && y.rint().equals(y) && !y.remainder(two).equals(zero)) {
  512.                     // If y is odd integer
  513.                     if (y.greaterThan(zero)) {
  514.                         return x.newInstance(x.newInstance((byte)-1, Dfp.INFINITE));
  515.                     } else {
  516.                         return x.newInstance(zero.negate());
  517.                     }
  518.                 } else {
  519.                     // Y is not odd integer
  520.                     if (y.greaterThan(zero)) {
  521.                         return x.newInstance(x.newInstance((byte)1, Dfp.INFINITE));
  522.                     } else {
  523.                         return x.newInstance(zero);
  524.                     }
  525.                 }
  526.             } else {
  527.                 // positive infinity
  528.                 if (y.greaterThan(zero)) {
  529.                     return x;
  530.                 } else {
  531.                     return x.newInstance(zero);
  532.                 }
  533.             }
  534.         }

  535.         if (invert && !y.rint().equals(y)) {
  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.         // End special cases

  540.         Dfp r;
  541.         if (y.lessThan(x.newInstance(100000000)) && y.greaterThan(x.newInstance(-100000000))) {
  542.             final Dfp u = y.rint();
  543.             ui = u.intValue();

  544.             final Dfp v = y.subtract(u);

  545.             if (v.unequal(zero)) {
  546.                 final Dfp a = v.multiply(log(x));
  547.                 final Dfp b = a.divide(x.getField().getLn2()).rint();

  548.                 final Dfp c = a.subtract(b.multiply(x.getField().getLn2()));
  549.                 r = splitPow(split(x), ui);
  550.                 r = r.multiply(pow(two, b.intValue()));
  551.                 r = r.multiply(exp(c));
  552.             } else {
  553.                 r = splitPow(split(x), ui);
  554.             }
  555.         } else {
  556.             // very large exponent.  |y| > 1e8
  557.             r = exp(log(x).multiply(y));
  558.         }

  559.         if (invert && y.rint().equals(y) && !y.remainder(two).equals(zero)) {
  560.             // if y is odd integer
  561.             r = r.negate();
  562.         }

  563.         return x.newInstance(r);

  564.     }

  565.     /** Computes sin(a)  Used when 0 &lt; a &lt; pi/4.
  566.      * Uses the classic Taylor series.  x - x**3/3! + x**5/5!  ...
  567.      * @param a number from which sine is desired, in split form
  568.      * @return sin(a)
  569.      */
  570.     protected static Dfp sinInternal(Dfp[] a) {

  571.         Dfp c = a[0].add(a[1]);
  572.         Dfp y = c;
  573.         c = c.square();
  574.         Dfp x = y;
  575.         Dfp fact = a[0].getOne();
  576.         Dfp py = new Dfp(y);

  577.         for (int i = 3; i < 90; i += 2) {
  578.             x = x.multiply(c);
  579.             x = x.negate();

  580.             fact = fact.divide((i-1)*i);  // 1 over fact
  581.             y = y.add(x.multiply(fact));
  582.             if (y.equals(py)) {
  583.                 break;
  584.             }
  585.             py = new Dfp(y);
  586.         }

  587.         return y;

  588.     }

  589.     /** Computes cos(a)  Used when 0 &lt; a &lt; pi/4.
  590.      * Uses the classic Taylor series for cosine.  1 - x**2/2! + x**4/4!  ...
  591.      * @param a number from which cosine is desired, in split form
  592.      * @return cos(a)
  593.      */
  594.     protected static Dfp cosInternal(Dfp[] a) {
  595.         final Dfp one = a[0].getOne();


  596.         Dfp x = one;
  597.         Dfp y = one;
  598.         Dfp c = a[0].add(a[1]);
  599.         c = c.square();

  600.         Dfp fact = one;
  601.         Dfp py = new Dfp(y);

  602.         for (int i = 2; i < 90; i += 2) {
  603.             x = x.multiply(c);
  604.             x = x.negate();

  605.             fact = fact.divide((i - 1) * i);  // 1 over fact

  606.             y = y.add(x.multiply(fact));
  607.             if (y.equals(py)) {
  608.                 break;
  609.             }
  610.             py = new Dfp(y);
  611.         }

  612.         return y;

  613.     }

  614.     /** computes the sine of the argument.
  615.      * @param a number from which sine is desired
  616.      * @return sin(a)
  617.      */
  618.     public static Dfp sin(final Dfp a) {
  619.         final Dfp pi = a.getField().getPi();
  620.         final Dfp zero = a.getField().getZero();
  621.         boolean neg = false;

  622.         /* First reduce the argument to the range of +/- PI */
  623.         Dfp x = a.remainder(pi.multiply(2));

  624.         /* if x < 0 then apply identity sin(-x) = -sin(x) */
  625.         /* This puts x in the range 0 < x < PI            */
  626.         if (x.lessThan(zero)) {
  627.             x = x.negate();
  628.             neg = true;
  629.         }

  630.         /* Since sine(x) = sine(pi - x) we can reduce the range to
  631.          * 0 < x < pi/2
  632.          */

  633.         if (x.greaterThan(pi.divide(2))) {
  634.             x = pi.subtract(x);
  635.         }

  636.         Dfp y;
  637.         if (x.lessThan(pi.divide(4))) {
  638.             y = sinInternal(split(x));
  639.         } else {
  640.             final Dfp[] c = new Dfp[2];
  641.             final Dfp[] piSplit = a.getField().getPiSplit();
  642.             c[0] = piSplit[0].divide(2).subtract(x);
  643.             c[1] = piSplit[1].divide(2);
  644.             y = cosInternal(c);
  645.         }

  646.         if (neg) {
  647.             y = y.negate();
  648.         }

  649.         return a.newInstance(y);

  650.     }

  651.     /** computes the cosine of the argument.
  652.      * @param a number from which cosine is desired
  653.      * @return cos(a)
  654.      */
  655.     public static Dfp cos(Dfp a) {
  656.         final Dfp pi = a.getField().getPi();
  657.         final Dfp zero = a.getField().getZero();
  658.         boolean neg = false;

  659.         /* First reduce the argument to the range of +/- PI */
  660.         Dfp x = a.remainder(pi.multiply(2));

  661.         /* if x < 0 then apply identity cos(-x) = cos(x) */
  662.         /* This puts x in the range 0 < x < PI           */
  663.         if (x.lessThan(zero)) {
  664.             x = x.negate();
  665.         }

  666.         /* Since cos(x) = -cos(pi - x) we can reduce the range to
  667.          * 0 < x < pi/2
  668.          */

  669.         if (x.greaterThan(pi.divide(2))) {
  670.             x = pi.subtract(x);
  671.             neg = true;
  672.         }

  673.         Dfp y;
  674.         if (x.lessThan(pi.divide(4))) {
  675.             Dfp[] c = new Dfp[2];
  676.             c[0] = x;
  677.             c[1] = zero;

  678.             y = cosInternal(c);
  679.         } else {
  680.             final Dfp[] c = new Dfp[2];
  681.             final Dfp[] piSplit = a.getField().getPiSplit();
  682.             c[0] = piSplit[0].divide(2).subtract(x);
  683.             c[1] = piSplit[1].divide(2);
  684.             y = sinInternal(c);
  685.         }

  686.         if (neg) {
  687.             y = y.negate();
  688.         }

  689.         return a.newInstance(y);

  690.     }

  691.     /** computes the tangent of the argument.
  692.      * @param a number from which tangent is desired
  693.      * @return tan(a)
  694.      */
  695.     public static Dfp tan(final Dfp a) {
  696.         return sin(a).divide(cos(a));
  697.     }

  698.     /** computes the arc-tangent of the argument.
  699.      * @param a number from which arc-tangent is desired
  700.      * @return atan(a)
  701.      */
  702.     protected static Dfp atanInternal(final Dfp a) {

  703.         Dfp y = new Dfp(a);
  704.         Dfp x = new Dfp(y);
  705.         Dfp py = new Dfp(y);

  706.         for (int i = 3; i < 90; i += 2) {
  707.             x = x.multiply(a);
  708.             x = x.multiply(a);
  709.             x = x.negate();
  710.             y = y.add(x.divide(i));
  711.             if (y.equals(py)) {
  712.                 break;
  713.             }
  714.             py = new Dfp(y);
  715.         }

  716.         return y;

  717.     }

  718.     /** computes the arc tangent of the argument
  719.      *
  720.      *  Uses the typical taylor series
  721.      *
  722.      *  but may reduce arguments using the following identity
  723.      * tan(x+y) = (tan(x) + tan(y)) / (1 - tan(x)*tan(y))
  724.      *
  725.      * since tan(PI/8) = sqrt(2)-1,
  726.      *
  727.      * atan(x) = atan( (x - sqrt(2) + 1) / (1+x*sqrt(2) - x) + PI/8.0
  728.      * @param a number from which arc-tangent is desired
  729.      * @return atan(a)
  730.      */
  731.     public static Dfp atan(final Dfp a) {
  732.         final Dfp   zero      = a.getField().getZero();
  733.         final Dfp   one       = a.getField().getOne();
  734.         final Dfp[] sqr2Split = a.getField().getSqr2Split();
  735.         final Dfp[] piSplit   = a.getField().getPiSplit();
  736.         boolean recp = false;
  737.         boolean neg = false;
  738.         boolean sub = false;

  739.         final Dfp ty = sqr2Split[0].subtract(one).add(sqr2Split[1]);

  740.         Dfp x = new Dfp(a);
  741.         if (x.lessThan(zero)) {
  742.             neg = true;
  743.             x = x.negate();
  744.         }

  745.         if (x.greaterThan(one)) {
  746.             recp = true;
  747.             x = one.divide(x);
  748.         }

  749.         if (x.greaterThan(ty)) {
  750.             Dfp[] sty = new Dfp[2];
  751.             sub = true;

  752.             sty[0] = sqr2Split[0].subtract(one);
  753.             sty[1] = sqr2Split[1];

  754.             Dfp[] xs = split(x);

  755.             Dfp[] ds = splitMult(xs, sty);
  756.             ds[0] = ds[0].add(one);

  757.             xs[0] = xs[0].subtract(sty[0]);
  758.             xs[1] = xs[1].subtract(sty[1]);

  759.             xs = splitDiv(xs, ds);
  760.             x = xs[0].add(xs[1]);

  761.             //x = x.subtract(ty).divide(dfp.one.add(x.multiply(ty)));
  762.         }

  763.         Dfp y = atanInternal(x);

  764.         if (sub) {
  765.             y = y.add(piSplit[0].divide(8)).add(piSplit[1].divide(8));
  766.         }

  767.         if (recp) {
  768.             y = piSplit[0].divide(2).subtract(y).add(piSplit[1].divide(2));
  769.         }

  770.         if (neg) {
  771.             y = y.negate();
  772.         }

  773.         return a.newInstance(y);

  774.     }

  775.     /** computes the arc-sine of the argument.
  776.      * @param a number from which arc-sine is desired
  777.      * @return asin(a)
  778.      */
  779.     public static Dfp asin(final Dfp a) {
  780.         return atan(a.divide(a.getOne().subtract(a.square()).sqrt()));
  781.     }

  782.     /** computes the arc-cosine of the argument.
  783.      * @param a number from which arc-cosine is desired
  784.      * @return acos(a)
  785.      */
  786.     public static Dfp acos(Dfp a) {
  787.         Dfp result;
  788.         boolean negative = false;

  789.         if (a.lessThan(a.getZero())) {
  790.             negative = true;
  791.         }

  792.         a = Dfp.copysign(a, a.getOne());  // absolute value

  793.         result = atan(a.getOne().subtract(a.square()).sqrt().divide(a));

  794.         if (negative) {
  795.             result = a.getField().getPi().subtract(result);
  796.         }

  797.         return a.newInstance(result);
  798.     }

  799. }