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.  *      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. package org.apache.commons.math4.legacy.core.dfp;

  18. /** Mathematical routines for use with {@link Dfp}.
  19.  * The constants are defined in {@link DfpField}
  20.  * @since 2.2
  21.  */
  22. public final class DfpMath {

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

  25.     /**
  26.      * Private Constructor.
  27.      */
  28.     private DfpMath() {
  29.     }

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

  45.         buf = new char[a.length()];

  46.         for (int i = 0; i < buf.length; i++) {
  47.             buf[i] = a.charAt(i);

  48.             if (buf[i] >= '1' && buf[i] <= '9') {
  49.                 leading = false;
  50.             }

  51.             if (buf[i] == '.') {
  52.                 sig += (400 - sig) % 4;
  53.                 leading = false;
  54.             }

  55.             if (sig == (field.getRadixDigits() / 2) * 4) {
  56.                 sp = i;
  57.                 break;
  58.             }

  59.             if (buf[i] >= '0' && buf[i] <= '9' && !leading) {
  60.                 sig++;
  61.             }
  62.         }

  63.         result[0] = field.newDfp(String.valueOf(buf, 0, sp));

  64.         for (int i = 0; i < buf.length; i++) {
  65.             buf[i] = a.charAt(i);
  66.             if (buf[i] >= '0' && buf[i] <= '9' && i < sp) {
  67.                 buf[i] = '0';
  68.             }
  69.         }

  70.         result[1] = field.newDfp(String.valueOf(buf));

  71.         return result;
  72.     }

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

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

  94.         result[1] = a[0].getZero();
  95.         result[0] = a[0].multiply(b[0]);

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

  99.         if (result[0].classify() == Dfp.INFINITE || result[0].equals(result[1])) {
  100.             return result;
  101.         }

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

  103.         return result;
  104.     }

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

  114.         result = new Dfp[2];

  115.         result[0] = a[0].divide(b[0]);
  116.         result[1] = a[1].multiply(b[0]).subtract(a[0].multiply(b[1]));
  117.         result[1] = result[1].divide(b[0].multiply(b[0]).add(b[0].multiply(b[1])));

  118.         return result;
  119.     }

  120.     /** Raise a split base to the a power.
  121.      * @param base number to raise
  122.      * @param a power
  123.      * @return base<sup>a</sup>
  124.      */
  125.     protected static Dfp splitPow(final Dfp[] base, int a) {
  126.         boolean invert = false;

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

  128.         Dfp[] result = new Dfp[2];
  129.         result[0] = base[0].getOne();
  130.         result[1] = base[0].getZero();

  131.         if (a == 0) {
  132.             // Special case a = 0
  133.             return result[0].add(result[1]);
  134.         }

  135.         if (a < 0) {
  136.             // If a is less than zero
  137.             invert = true;
  138.             a = -a;
  139.         }

  140.         // Exponentiate by successive squaring
  141.         do {
  142.             r[0] = new Dfp(base[0]);
  143.             r[1] = new Dfp(base[1]);
  144.             int trial = 1;

  145.             int prevtrial;
  146.             while (true) {
  147.                 prevtrial = trial;
  148.                 trial *= 2;
  149.                 if (trial > a) {
  150.                     break;
  151.                 }
  152.                 r = splitMult(r, r);
  153.             }

  154.             trial = prevtrial;

  155.             a -= trial;
  156.             result = splitMult(result, r);
  157.         } while (a >= 1);

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

  159.         if (invert) {
  160.             result[0] = base[0].getOne().divide(result[0]);
  161.         }

  162.         return result[0];
  163.     }

  164.     /** Raises base to the power a by successive squaring.
  165.      * @param base number to raise
  166.      * @param a power
  167.      * @return base<sup>a</sup>
  168.      */
  169.     public static Dfp pow(Dfp base, int a) {
  170.         boolean invert = false;

  171.         Dfp result = base.getOne();

  172.         if (a == 0) {
  173.             // Special case
  174.             return result;
  175.         }

  176.         if (a < 0) {
  177.             invert = true;
  178.             a = -a;
  179.         }

  180.         // Exponentiate by successive squaring
  181.         do {
  182.             Dfp r = new Dfp(base);
  183.             Dfp prevr;
  184.             int trial = 1;
  185.             int prevtrial;

  186.             do {
  187.                 prevr = new Dfp(r);
  188.                 prevtrial = trial;
  189.                 r = r.multiply(r);
  190.                 trial *= 2;
  191.             } while (a > trial);

  192.             r = prevr;
  193.             trial = prevtrial;

  194.             a -= trial;
  195.             result = result.multiply(r);
  196.         } while (a >= 1);

  197.         if (invert) {
  198.             result = base.getOne().divide(result);
  199.         }

  200.         return base.newInstance(result);
  201.     }

  202.     /** Computes e to the given power.
  203.      * a is broken into two parts, such that a = n+m  where n is an integer.
  204.      * We use pow() to compute e<sup>n</sup> and a Taylor series to compute
  205.      * e<sup>m</sup>.  We return e*<sup>n</sup> &times; e<sup>m</sup>
  206.      * @param a power at which e should be raised
  207.      * @return e<sup>a</sup>
  208.      */
  209.     public static Dfp exp(final Dfp a) {

  210.         final Dfp inta = a.rint();
  211.         final Dfp fraca = a.subtract(inta);

  212.         final int ia = inta.intValue();
  213.         if (ia > 2147483646) {
  214.             // return +Infinity
  215.             return a.newInstance((byte)1, Dfp.INFINITE);
  216.         }

  217.         if (ia < -2147483646) {
  218.             // return 0;
  219.             return a.newInstance();
  220.         }

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

  223.         return einta.multiply(efraca);
  224.     }

  225.     /** Computes e to the given power.
  226.      * Where {@code -1 < a < 1}.  Use the classic Taylor series.
  227.      * {@code 1 + x**2/2! + x**3/3! + x**4/4!  ... }
  228.      * @param a power at which e should be raised
  229.      * @return e<sup>a</sup>
  230.      */
  231.     protected static Dfp expInternal(final Dfp a) {
  232.         Dfp y = a.getOne();
  233.         Dfp x = a.getOne();
  234.         Dfp fact = a.getOne();
  235.         Dfp py = new Dfp(y);

  236.         for (int i = 1; i < 90; i++) {
  237.             x = x.multiply(a);
  238.             fact = fact.divide(i);
  239.             y = y.add(x.multiply(fact));
  240.             if (y.equals(py)) {
  241.                 break;
  242.             }
  243.             py = new Dfp(y);
  244.         }

  245.         return y;
  246.     }

  247.     /** Returns the natural logarithm of a.
  248.      * a is first split into three parts such that {@code a = (10000^h)(2^j)k}.
  249.      * ln(a) is computed by {@code ln(a) = ln(5)*4h + ln(2)*(4h+j) + ln(k)}.
  250.      * k is in the range {@code 2/3 < k <4/3} and is passed on to a series expansion.
  251.      * @param a number from which logarithm is requested
  252.      * @return log(a)
  253.      */
  254.     public static Dfp log(Dfp a) {
  255.         int lr;
  256.         Dfp x;
  257.         int ix;
  258.         int p2 = 0;

  259.         // Check the arguments somewhat here
  260.         if (a.equals(a.getZero()) || a.lessThan(a.getZero()) || a.isNaN()) {
  261.             // negative, zero or NaN
  262.             a.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  263.             return a.dotrap(DfpField.FLAG_INVALID, "ln", a, a.newInstance((byte)1, Dfp.QNAN));
  264.         }

  265.         if (a.classify() == Dfp.INFINITE) {
  266.             return a;
  267.         }

  268.         x = new Dfp(a);
  269.         lr = x.log10K();

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

  272.         while (ix > 2) {
  273.             ix >>= 1;
  274.             p2++;
  275.         }


  276.         Dfp[] spx = split(x);
  277.         Dfp[] spy = new Dfp[2];
  278.         spy[0] = pow(a.getTwo(), p2);          // use spy[0] temporarily as a divisor
  279.         spx[0] = spx[0].divide(spy[0]);
  280.         spx[1] = spx[1].divide(spy[0]);

  281.         spy[0] = a.newInstance("1.33333");    // Use spy[0] for comparison
  282.         while (spx[0].add(spx[1]).greaterThan(spy[0])) {
  283.             spx[0] = spx[0].divide(2);
  284.             spx[1] = spx[1].divide(2);
  285.             p2++;
  286.         }

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

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

  292.         spz[0] = spz[0].add(spy[0]);
  293.         spz[1] = spz[1].add(spy[1]);

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

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

  299.         return a.newInstance(spz[0].add(spz[1]));
  300.     }

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

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

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

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

  380.         return split(y);
  381.     }

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

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

  430.         final Dfp zero = x.getZero();
  431.         final Dfp one  = x.getOne();
  432.         final Dfp two  = x.getTwo();
  433.         boolean invert = false;
  434.         int ui;

  435.         /* Check for special cases */
  436.         if (y.equals(zero)) {
  437.             return x.newInstance(one);
  438.         }

  439.         if (y.equals(one)) {
  440.             if (x.isNaN()) {
  441.                 // Test for NaNs
  442.                 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  443.                 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x);
  444.             }
  445.             return x;
  446.         }

  447.         if (x.isNaN() || y.isNaN()) {
  448.             // Test for NaNs
  449.             x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  450.             return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
  451.         }

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

  480.         if (x.lessThan(zero)) {
  481.             // Make x positive, but keep track of it
  482.             x = x.negate();
  483.             invert = true;
  484.         }

  485.         if (x.greaterThan(one) && y.classify() == Dfp.INFINITE) {
  486.             if (y.greaterThan(zero)) {
  487.                 return y;
  488.             } else {
  489.                 return x.newInstance(zero);
  490.             }
  491.         }

  492.         if (x.lessThan(one) && y.classify() == Dfp.INFINITE) {
  493.             if (y.greaterThan(zero)) {
  494.                 return x.newInstance(zero);
  495.             } else {
  496.                 return x.newInstance(Dfp.copySign(y, one));
  497.             }
  498.         }

  499.         if (x.equals(one) && y.classify() == Dfp.INFINITE) {
  500.             x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  501.             return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
  502.         }

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

  531.         if (invert && !y.rint().equals(y)) {
  532.             x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  533.             return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
  534.         }

  535.         // End special cases

  536.         Dfp r;
  537.         if (y.lessThan(x.newInstance(100000000)) && y.greaterThan(x.newInstance(-100000000))) {
  538.             final Dfp u = y.rint();
  539.             ui = u.intValue();

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

  541.             if (v.unequal(zero)) {
  542.                 final Dfp a = v.multiply(log(x));
  543.                 final Dfp b = a.divide(x.getField().getLn2()).rint();

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

  555.         if (invert && y.rint().equals(y) && !y.remainder(two).equals(zero)) {
  556.             // if y is odd integer
  557.             r = r.negate();
  558.         }

  559.         return x.newInstance(r);
  560.     }

  561.     /** Computes sin(a)  Used when {@code {@code 0 < a < pi/4}}.
  562.      * Uses the classic Taylor series.  {@code x - x**3/3! + x**5/5!  ... }
  563.      * @param a number from which sine is desired, in split form
  564.      * @return sin(a)
  565.      */
  566.     protected static Dfp sinInternal(Dfp[] a) {

  567.         Dfp c = a[0].add(a[1]);
  568.         Dfp y = c;
  569.         c = c.multiply(c);
  570.         Dfp x = y;
  571.         Dfp fact = a[0].getOne();
  572.         Dfp py = new Dfp(y);

  573.         for (int i = 3; i < 90; i += 2) {
  574.             x = x.multiply(c);
  575.             x = x.negate();

  576.             fact = fact.divide((i - 1) * i); // 1 over fact
  577.             y = y.add(x.multiply(fact));
  578.             if (y.equals(py)) {
  579.                 break;
  580.             }
  581.             py = new Dfp(y);
  582.         }

  583.         return y;
  584.     }

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


  592.         Dfp x = one;
  593.         Dfp y = one;
  594.         Dfp c = a[0].add(a[1]);
  595.         c = c.multiply(c);

  596.         Dfp fact = one;
  597.         Dfp py = new Dfp(y);

  598.         for (int i = 2; i < 90; i += 2) {
  599.             x = x.multiply(c);
  600.             x = x.negate();

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

  602.             y = y.add(x.multiply(fact));
  603.             if (y.equals(py)) {
  604.                 break;
  605.             }
  606.             py = new Dfp(y);
  607.         }

  608.         return y;
  609.     }

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

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

  620.         /* if x < 0 then apply identity sin(-x) = -sin(x) */
  621.         /* This puts x in the range 0 < x < PI            */
  622.         if (x.lessThan(zero)) {
  623.             x = x.negate();
  624.             neg = true;
  625.         }

  626.         /* Since sine(x) = sine(pi - x) we can reduce the range to
  627.          * 0 < x < pi/2
  628.          */

  629.         if (x.greaterThan(pi.divide(2))) {
  630.             x = pi.subtract(x);
  631.         }

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

  642.         if (neg) {
  643.             y = y.negate();
  644.         }

  645.         return a.newInstance(y);
  646.     }

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

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

  657.         /* if x < 0 then apply identity cos(-x) = cos(x) */
  658.         /* This puts x in the range 0 < x < PI           */
  659.         if (x.lessThan(zero)) {
  660.             x = x.negate();
  661.         }

  662.         /* Since cos(x) = -cos(pi - x) we can reduce the range to
  663.          * 0 < x < pi/2
  664.          */

  665.         if (x.greaterThan(pi.divide(2))) {
  666.             x = pi.subtract(x);
  667.             neg = true;
  668.         }

  669.         Dfp y;
  670.         if (x.lessThan(pi.divide(4))) {
  671.             Dfp[] c = new Dfp[2];
  672.             c[0] = x;
  673.             c[1] = zero;

  674.             y = cosInternal(c);
  675.         } else {
  676.             final Dfp[] c = new Dfp[2];
  677.             final Dfp[] piSplit = a.getField().getPiSplit();
  678.             c[0] = piSplit[0].divide(2).subtract(x);
  679.             c[1] = piSplit[1].divide(2);
  680.             y = sinInternal(c);
  681.         }

  682.         if (neg) {
  683.             y = y.negate();
  684.         }

  685.         return a.newInstance(y);
  686.     }

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

  694.     /** computes the arc-tangent of the argument.
  695.      * @param a number from which arc-tangent is desired
  696.      * @return atan(a)
  697.      */
  698.     protected static Dfp atanInternal(final Dfp a) {

  699.         Dfp y = new Dfp(a);
  700.         Dfp x = new Dfp(y);
  701.         Dfp py = new Dfp(y);

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

  712.         return y;
  713.     }

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

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

  736.         Dfp x = new Dfp(a);
  737.         if (x.lessThan(zero)) {
  738.             neg = true;
  739.             x = x.negate();
  740.         }

  741.         if (x.greaterThan(one)) {
  742.             recp = true;
  743.             x = one.divide(x);
  744.         }

  745.         if (x.greaterThan(ty)) {
  746.             Dfp[] sty = new Dfp[2];
  747.             sub = true;

  748.             sty[0] = sqr2Split[0].subtract(one);
  749.             sty[1] = sqr2Split[1];

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

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

  753.             xs[0] = xs[0].subtract(sty[0]);
  754.             xs[1] = xs[1].subtract(sty[1]);

  755.             xs = splitDiv(xs, ds);
  756.             x = xs[0].add(xs[1]);

  757.             //x = x.subtract(ty).divide(dfp.one.add(x.multiply(ty)));
  758.         }

  759.         Dfp y = atanInternal(x);

  760.         if (sub) {
  761.             y = y.add(piSplit[0].divide(8)).add(piSplit[1].divide(8));
  762.         }

  763.         if (recp) {
  764.             y = piSplit[0].divide(2).subtract(y).add(piSplit[1].divide(2));
  765.         }

  766.         if (neg) {
  767.             y = y.negate();
  768.         }

  769.         return a.newInstance(y);
  770.     }

  771.     /** computes the arc-sine of the argument.
  772.      * @param a number from which arc-sine is desired
  773.      * @return asin(a)
  774.      */
  775.     public static Dfp asin(final Dfp a) {
  776.         return atan(a.divide(a.getOne().subtract(a.multiply(a)).sqrt()));
  777.     }

  778.     /** computes the arc-cosine of the argument.
  779.      * @param a number from which arc-cosine is desired
  780.      * @return acos(a)
  781.      */
  782.     public static Dfp acos(Dfp a) {
  783.         Dfp result;
  784.         boolean negative = a.lessThan(a.getZero());

  785.         a = Dfp.copySign(a, a.getOne());  // absolute value

  786.         result = atan(a.getOne().subtract(a.multiply(a)).sqrt().divide(a));

  787.         if (negative) {
  788.             result = a.getField().getPi().subtract(result);
  789.         }

  790.         return a.newInstance(result);
  791.     }
  792. }