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