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