Author: sebb
Date: Sun Sep 11 20:43:27 2011
New Revision: 1169527
URL: http://svn.apache.org/viewvc?rev=1169527&view=rev
Log:
MATH-650 move static setup methods to helper class
Added:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMathCalc.java
(with props)
Modified:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMath.java
Modified:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMath.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMath.java?rev=1169527&r1=1169526&r2=1169527&view=diff
==============================================================================
---
commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMath.java
(original)
+++
commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMath.java
Sun Sep 11 20:43:27 2011
@@ -16,8 +16,6 @@
*/
package org.apache.commons.math.util;
-import org.apache.commons.math.exception.DimensionMismatchException;
-
/**
* Faster, more accurate, portable alternative to {@link Math} and
* {@link StrictMath} for large scale computation.
@@ -121,13 +119,13 @@ public class FastMath {
// Populate expIntTable
for (int i = 0; i < FastMath.EXP_INT_TABLE_MAX_INDEX; i++) {
- expint(i, tmp);
+ FastMathCalc.expint(i, tmp);
EXP_INT_TABLE_A[i + FastMath.EXP_INT_TABLE_MAX_INDEX] =
tmp[0];
EXP_INT_TABLE_B[i + FastMath.EXP_INT_TABLE_MAX_INDEX] =
tmp[1];
if (i != 0) {
// Negative integer powers
- splitReciprocal(tmp, recip);
+ FastMathCalc.splitReciprocal(tmp, recip);
EXP_INT_TABLE_A[FastMath.EXP_INT_TABLE_MAX_INDEX - i]
= recip[0];
EXP_INT_TABLE_B[FastMath.EXP_INT_TABLE_MAX_INDEX - i]
= recip[1];
}
@@ -3167,7 +3165,7 @@ public class FastMath {
// Populate expFracTable
for (int i = 0; i < EXP_FRAC_TABLE_A.length; i++) {
- slowexp(i/1024.0, tmp); // TWO_POWER_10
+ FastMathCalc.slowexp(i/1024.0, tmp); // TWO_POWER_10
EXP_FRAC_TABLE_A[i] = tmp[0];
EXP_FRAC_TABLE_B[i] = tmp[1];
}
@@ -5231,31 +5229,6 @@ public class FastMath {
}
}
- /** Factorial table, for Taylor series expansions. 0!, 1!, 2!, ... 19! */
- private static final double FACT[] = new double[]
- {
- +1.0d, // 0
- +1.0d, // 1
- +2.0d, // 2
- +6.0d, // 3
- +24.0d, // 4
- +120.0d, // 5
- +720.0d, // 6
- +5040.0d, // 7
- +40320.0d, // 8
- +362880.0d, // 9
- +3628800.0d, // 10
- +39916800.0d, // 11
- +479001600.0d, // 12
- +6227020800.0d, // 13
- +87178291200.0d, // 14
- +1307674368000.0d, // 15
- +20922789888000.0d, // 16
- +355687428096000.0d, // 17
- +6402373705728000.0d, // 18
- +121645100408832000.0d, // 19
- };
-
private static final int LN_MANT_LEN = 1024; // MAGIC NUMBER
// Enclose large data table in nested static class so it's only loaded on
first access
@@ -5270,7 +5243,7 @@ public class FastMath {
// Populate lnMant table
for (int i = 0; i < LN_MANT.length; i++) {
final double d = Double.longBitsToDouble( (((long) i) <<
42) | 0x3ff0000000000000L );
- LN_MANT[i] = slowLog(d);
+ LN_MANT[i] = FastMathCalc.slowLog(d);
}
} else {
LN_MANT = new double[][] {
@@ -6309,26 +6282,6 @@ public class FastMath {
/** log(2) (low bits). */
private static final double LN_2_B = 1.17304635250823482e-7;
- /** Coefficients for slowLog. */
- private static final double LN_SPLIT_COEF[][] = {
- {2.0, 0.0},
- {0.6666666269302368, 3.9736429850260626E-8},
- {0.3999999761581421, 2.3841857910019882E-8},
- {0.2857142686843872, 1.7029898543501842E-8},
- {0.2222222089767456, 1.3245471311735498E-8},
- {0.1818181574344635, 2.4384203044354907E-8},
- {0.1538461446762085, 9.140260083262505E-9},
- {0.13333332538604736, 9.220590270857665E-9},
- {0.11764700710773468, 1.2393345855018391E-8},
- {0.10526403784751892, 8.251545029714408E-9},
- {0.0952233225107193, 1.2675934823758863E-8},
- {0.08713622391223907, 1.1430250008909141E-8},
- {0.07842259109020233, 2.404307984052299E-9},
- {0.08371849358081818, 1.176342548272881E-8},
- {0.030589580535888672, 1.2958646899018938E-9},
- {0.14982303977012634, 1.225743062930824E-8},
- };
-
/** Coefficients for log, when input 0.99 < x < 1.01. */
private static final double LN_QUICK_COEF[][] = {
{1.0, 5.669184079525E-24},
@@ -6539,50 +6492,17 @@ public class FastMath {
// }
public static void main(String[] a){
- printarray("EXP_INT_TABLE_A", EXP_INT_TABLE_LEN,
ExpIntTable.EXP_INT_TABLE_A);
- printarray("EXP_INT_TABLE_B", EXP_INT_TABLE_LEN,
ExpIntTable.EXP_INT_TABLE_B);
- printarray("EXP_FRAC_TABLE_A", EXP_FRAC_TABLE_LEN,
ExpFracTable.EXP_FRAC_TABLE_A);
- printarray("EXP_FRAC_TABLE_B", EXP_FRAC_TABLE_LEN,
ExpFracTable.EXP_FRAC_TABLE_B);
- printarray("LN_MANT",LN_MANT_LEN, lnMant.LN_MANT);
- printarray("SINE_TABLE_A", SINE_TABLE_LEN, SINE_TABLE_A);
- printarray("SINE_TABLE_B", SINE_TABLE_LEN, SINE_TABLE_B);
- printarray("COSINE_TABLE_A", SINE_TABLE_LEN, COSINE_TABLE_A);
- printarray("COSINE_TABLE_B", SINE_TABLE_LEN, COSINE_TABLE_B);
- printarray("TANGENT_TABLE_A", SINE_TABLE_LEN, TANGENT_TABLE_A);
- printarray("TANGENT_TABLE_B", SINE_TABLE_LEN, TANGENT_TABLE_B);
- }
-
- private static void printarray(String string, int expectedLen, double[][]
array2d) {
- System.out.println(string);
- checkLen(expectedLen, array2d.length);
- System.out.println(" { ");
- int i = 0;
- for(double array[] : array2d) {
- System.out.print(" {");
- for(double d : array) { // assume inner array has very few entries
- String ds = d >= 0 ? "+"+Double.toString(d)+"d," :
Double.toString(d)+"d,";
- System.out.printf("%-25.25s",ds); // multiple entries per line
- }
- System.out.println("}, // "+i++);
- }
- System.out.println(" };");
- }
-
- private static void printarray(String string, int expectedLen, double[]
array) {
- System.out.println(string+"=");
- checkLen(expectedLen, array.length);
- System.out.println(" {");
- for(double d : array){
- String ds = d!=d ? "Double.NaN," : d >= 0 ?
"+"+Double.toString(d)+"d," : Double.toString(d)+"d,";
- System.out.printf(" %s%n",ds); // one entry per line
- }
- System.out.println(" };");
- }
-
- private static void checkLen(int expectedLen, int actual) {
- if (expectedLen != actual) {
- throw new DimensionMismatchException(actual, expectedLen);
- }
+ FastMathCalc.printarray("EXP_INT_TABLE_A", EXP_INT_TABLE_LEN,
ExpIntTable.EXP_INT_TABLE_A);
+ FastMathCalc.printarray("EXP_INT_TABLE_B", EXP_INT_TABLE_LEN,
ExpIntTable.EXP_INT_TABLE_B);
+ FastMathCalc.printarray("EXP_FRAC_TABLE_A", EXP_FRAC_TABLE_LEN,
ExpFracTable.EXP_FRAC_TABLE_A);
+ FastMathCalc.printarray("EXP_FRAC_TABLE_B", EXP_FRAC_TABLE_LEN,
ExpFracTable.EXP_FRAC_TABLE_B);
+ FastMathCalc.printarray("LN_MANT",LN_MANT_LEN, lnMant.LN_MANT);
+ FastMathCalc.printarray("SINE_TABLE_A", SINE_TABLE_LEN, SINE_TABLE_A);
+ FastMathCalc.printarray("SINE_TABLE_B", SINE_TABLE_LEN, SINE_TABLE_B);
+ FastMathCalc.printarray("COSINE_TABLE_A", SINE_TABLE_LEN,
COSINE_TABLE_A);
+ FastMathCalc.printarray("COSINE_TABLE_B", SINE_TABLE_LEN,
COSINE_TABLE_B);
+ FastMathCalc.printarray("TANGENT_TABLE_A", SINE_TABLE_LEN,
TANGENT_TABLE_A);
+ FastMathCalc.printarray("TANGENT_TABLE_B", SINE_TABLE_LEN,
TANGENT_TABLE_B);
}
/**
@@ -7334,251 +7254,6 @@ public class FastMath {
}
/**
- * For x between 0 and 1, returns exp(x), uses extended precision
- * @param x argument of exponential
- * @param result placeholder where to place exp(x) split in two terms
- * for extra precision (i.e. exp(x) = result[0] + result[1]
- * @return exp(x)
- */
- private static double slowexp(final double x, final double result[]) {
- final double xs[] = new double[2];
- final double ys[] = new double[2];
- final double facts[] = new double[2];
- final double as[] = new double[2];
- split(x, xs);
- ys[0] = ys[1] = 0.0;
-
- for (int i = FACT.length-1; i >= 0; i--) {
- splitMult(xs, ys, as);
- ys[0] = as[0];
- ys[1] = as[1];
-
- split(FACT[i], as);
- splitReciprocal(as, facts);
-
- splitAdd(ys, facts, as);
- ys[0] = as[0];
- ys[1] = as[1];
- }
-
- if (result != null) {
- result[0] = ys[0];
- result[1] = ys[1];
- }
-
- return ys[0] + ys[1];
- }
-
- /** Compute split[0], split[1] such that their sum is equal to d,
- * and split[0] has its 30 least significant bits as zero.
- * @param d number to split
- * @param split placeholder where to place the result
- */
- private static void split(final double d, final double split[]) {
- if (d < 8e298 && d > -8e298) {
- final double a = d * HEX_40000000;
- split[0] = (d + a) - a;
- split[1] = d - split[0];
- } else {
- final double a = d * 9.31322574615478515625E-10;
- split[0] = (d + a - d) * HEX_40000000;
- split[1] = d - split[0];
- }
- }
-
- /** Recompute a split.
- * @param a input/out array containing the split, changed
- * on output
- */
- private static void resplit(final double a[]) {
- final double c = a[0] + a[1];
- final double d = -(c - a[0] - a[1]);
-
- if (c < 8e298 && c > -8e298) { // MAGIC NUMBER
- double z = c * HEX_40000000;
- a[0] = (c + z) - z;
- a[1] = c - a[0] + d;
- } else {
- double z = c * 9.31322574615478515625E-10;
- a[0] = (c + z - c) * HEX_40000000;
- a[1] = c - a[0] + d;
- }
- }
-
- /** Multiply two numbers in split form.
- * @param a first term of multiplication
- * @param b second term of multiplication
- * @param ans placeholder where to put the result
- */
- private static void splitMult(double a[], double b[], double ans[]) {
- ans[0] = a[0] * b[0];
- ans[1] = a[0] * b[1] + a[1] * b[0] + a[1] * b[1];
-
- /* Resplit */
- resplit(ans);
- }
-
- /** Add two numbers in split form.
- * @param a first term of addition
- * @param b second term of addition
- * @param ans placeholder where to put the result
- */
- private static void splitAdd(final double a[], final double b[], final
double ans[]) {
- ans[0] = a[0] + b[0];
- ans[1] = a[1] + b[1];
-
- resplit(ans);
- }
-
- /** Compute the reciprocal of in. Use the following algorithm.
- * in = c + d.
- * want to find x + y such that x+y = 1/(c+d) and x is much
- * larger than y and x has several zero bits on the right.
- *
- * Set b = 1/(2^22), a = 1 - b. Thus (a+b) = 1.
- * Use following identity to compute (a+b)/(c+d)
- *
- * (a+b)/(c+d) = a/c + (bc - ad) / (c^2 + cd)
- * set x = a/c and y = (bc - ad) / (c^2 + cd)
- * This will be close to the right answer, but there will be
- * some rounding in the calculation of X. So by carefully
- * computing 1 - (c+d)(x+y) we can compute an error and
- * add that back in. This is done carefully so that terms
- * of similar size are subtracted first.
- * @param in initial number, in split form
- * @param result placeholder where to put the result
- */
- private static void splitReciprocal(final double in[], final double
result[]) {
- final double b = 1.0/4194304.0;
- final double a = 1.0 - b;
-
- if (in[0] == 0.0) {
- in[0] = in[1];
- in[1] = 0.0;
- }
-
- result[0] = a / in[0];
- result[1] = (b*in[0]-a*in[1]) / (in[0]*in[0] + in[0]*in[1]);
-
- if (result[1] != result[1]) { // can happen if result[1] is NAN
- result[1] = 0.0;
- }
-
- /* Resplit */
- resplit(result);
-
- for (int i = 0; i < 2; i++) {
- /* this may be overkill, probably once is enough */
- double err = 1.0 - result[0] * in[0] - result[0] * in[1] -
- result[1] * in[0] - result[1] * in[1];
- /*err = 1.0 - err; */
- err = err * (result[0] + result[1]);
- /*printf("err = %16e\n", err); */
- result[1] += err;
- }
- }
-
- /** Compute (a[0] + a[1]) * (b[0] + b[1]) in extended precision.
- * @param a first term of the multiplication
- * @param b second term of the multiplication
- * @param result placeholder where to put the result
- */
- private static void quadMult(final double a[], final double b[], final
double result[]) {
- final double xs[] = new double[2];
- final double ys[] = new double[2];
- final double zs[] = new double[2];
-
- /* a[0] * b[0] */
- split(a[0], xs);
- split(b[0], ys);
- splitMult(xs, ys, zs);
-
- result[0] = zs[0];
- result[1] = zs[1];
-
- /* a[0] * b[1] */
- split(b[1], ys);
- splitMult(xs, ys, zs);
-
- double tmp = result[0] + zs[0];
- result[1] = result[1] - (tmp - result[0] - zs[0]);
- result[0] = tmp;
- tmp = result[0] + zs[1];
- result[1] = result[1] - (tmp - result[0] - zs[1]);
- result[0] = tmp;
-
- /* a[1] * b[0] */
- split(a[1], xs);
- split(b[0], ys);
- splitMult(xs, ys, zs);
-
- tmp = result[0] + zs[0];
- result[1] = result[1] - (tmp - result[0] - zs[0]);
- result[0] = tmp;
- tmp = result[0] + zs[1];
- result[1] = result[1] - (tmp - result[0] - zs[1]);
- result[0] = tmp;
-
- /* a[1] * b[0] */
- split(a[1], xs);
- split(b[1], ys);
- splitMult(xs, ys, zs);
-
- tmp = result[0] + zs[0];
- result[1] = result[1] - (tmp - result[0] - zs[0]);
- result[0] = tmp;
- tmp = result[0] + zs[1];
- result[1] = result[1] - (tmp - result[0] - zs[1]);
- result[0] = tmp;
- }
-
- /** Compute exp(p) for a integer p in extended precision.
- * @param p integer whose exponential is requested
- * @param result placeholder where to put the result in extended precision
- * @return exp(p) in standard precision (equal to result[0] + result[1])
- */
- private static double expint(int p, final double result[]) {
- //double x = M_E;
- final double xs[] = new double[2];
- final double as[] = new double[2];
- final double ys[] = new double[2];
- //split(x, xs);
- //xs[1] = (double)(2.7182818284590452353602874713526625L - xs[0]);
- //xs[0] = 2.71827697753906250000;
- //xs[1] = 4.85091998273542816811e-06;
- //xs[0] = Double.longBitsToDouble(0x4005bf0800000000L);
- //xs[1] = Double.longBitsToDouble(0x3ed458a2bb4a9b00L);
-
- /* E */
- xs[0] = 2.718281828459045;
- xs[1] = 1.4456468917292502E-16;
-
- split(1.0, ys);
-
- while (p > 0) {
- if ((p & 1) != 0) {
- quadMult(ys, xs, as);
- ys[0] = as[0]; ys[1] = as[1];
- }
-
- quadMult(xs, xs, as);
- xs[0] = as[0]; xs[1] = as[1];
-
- p >>= 1;
- }
-
- if (result != null) {
- result[0] = ys[0];
- result[1] = ys[1];
-
- resplit(result);
- }
-
- return ys[0] + ys[1];
- }
-
-
- /**
* Natural logarithm.
*
* @param x a double
@@ -8048,254 +7723,6 @@ public class FastMath {
return result;
}
- /** xi in the range of [1, 2].
- * 3 5 7
- * x+1 / x x x \
- * ln ----- = 2 * | x + ---- + ---- + ---- + ... |
- * 1-x \ 3 5 7 /
- *
- * So, compute a Remez approximation of the following function
- *
- * ln ((sqrt(x)+1)/(1-sqrt(x))) / x
- *
- * This will be an even function with only positive coefficents.
- * x is in the range [0 - 1/3].
- *
- * Transform xi for input to the above function by setting
- * x = (xi-1)/(xi+1). Input to the polynomial is x^2, then
- * the result is multiplied by x.
- * @param xi number from which log is requested
- * @return log(xi)
- */
- private static double[] slowLog(double xi) {
- double x[] = new double[2];
- double x2[] = new double[2];
- double y[] = new double[2];
- double a[] = new double[2];
-
- split(xi, x);
-
- /* Set X = (x-1)/(x+1) */
- x[0] += 1.0;
- resplit(x);
- splitReciprocal(x, a);
- x[0] -= 2.0;
- resplit(x);
- splitMult(x, a, y);
- x[0] = y[0];
- x[1] = y[1];
-
- /* Square X -> X2*/
- splitMult(x, x, x2);
-
-
- //x[0] -= 1.0;
- //resplit(x);
-
- y[0] = LN_SPLIT_COEF[LN_SPLIT_COEF.length-1][0];
- y[1] = LN_SPLIT_COEF[LN_SPLIT_COEF.length-1][1];
-
- for (int i = LN_SPLIT_COEF.length-2; i >= 0; i--) {
- splitMult(y, x2, a);
- y[0] = a[0];
- y[1] = a[1];
- splitAdd(y, LN_SPLIT_COEF[i], a);
- y[0] = a[0];
- y[1] = a[1];
- }
-
- splitMult(y, x, a);
- y[0] = a[0];
- y[1] = a[1];
-
- return y;
- }
-
- /**
- * For x between 0 and pi/4 compute sine using Taylor expansion:
- * sin(x) = x - x^3/3! + x^5/5! - x^7/7! ...
- * @param x number from which sine is requested
- * @param result placeholder where to put the result in extended precision
- * (may be null)
- * @return sin(x)
- */
- private static double slowSin(final double x, final double result[]) {
- final double xs[] = new double[2];
- final double ys[] = new double[2];
- final double facts[] = new double[2];
- final double as[] = new double[2];
- split(x, xs);
- ys[0] = ys[1] = 0.0;
-
- for (int i = FACT.length-1; i >= 0; i--) {
- splitMult(xs, ys, as);
- ys[0] = as[0]; ys[1] = as[1];
-
- if ( (i & 1) == 0) { // Ignore even numbers
- continue;
- }
-
- split(FACT[i], as);
- splitReciprocal(as, facts);
-
- if ( (i & 2) != 0 ) { // alternate terms are negative
- facts[0] = -facts[0];
- facts[1] = -facts[1];
- }
-
- splitAdd(ys, facts, as);
- ys[0] = as[0]; ys[1] = as[1];
- }
-
- if (result != null) {
- result[0] = ys[0];
- result[1] = ys[1];
- }
-
- return ys[0] + ys[1];
- }
-
- /**
- * For x between 0 and pi/4 compute cosine using Talor series
- * cos(x) = 1 - x^2/2! + x^4/4! ...
- * @param x number from which cosine is requested
- * @param result placeholder where to put the result in extended precision
- * (may be null)
- * @return cos(x)
- */
- private static double slowCos(final double x, final double result[]) {
-
- final double xs[] = new double[2];
- final double ys[] = new double[2];
- final double facts[] = new double[2];
- final double as[] = new double[2];
- split(x, xs);
- ys[0] = ys[1] = 0.0;
-
- for (int i = FACT.length-1; i >= 0; i--) {
- splitMult(xs, ys, as);
- ys[0] = as[0]; ys[1] = as[1];
-
- if ( (i & 1) != 0) { // skip odd entries
- continue;
- }
-
- split(FACT[i], as);
- splitReciprocal(as, facts);
-
- if ( (i & 2) != 0 ) { // alternate terms are negative
- facts[0] = -facts[0];
- facts[1] = -facts[1];
- }
-
- splitAdd(ys, facts, as);
- ys[0] = as[0]; ys[1] = as[1];
- }
-
- if (result != null) {
- result[0] = ys[0];
- result[1] = ys[1];
- }
-
- return ys[0] + ys[1];
- }
-
- /** Build the sine and cosine tables.
- */
- @SuppressWarnings("unused")
- private static void buildSinCosTables() {
- final double result[] = new double[2];
-
- /* Use taylor series for 0 <= x <= 6/8 */
- for (int i = 0; i < 7; i++) {
- double x = i / 8.0;
-
- slowSin(x, result);
- SINE_TABLE_A[i] = result[0];
- SINE_TABLE_B[i] = result[1];
-
- slowCos(x, result);
- COSINE_TABLE_A[i] = result[0];
- COSINE_TABLE_B[i] = result[1];
- }
-
- /* Use angle addition formula to complete table to 13/8, just beyond
pi/2 */
- for (int i = 7; i < SINE_TABLE_LEN; i++) {
- double xs[] = new double[2];
- double ys[] = new double[2];
- double as[] = new double[2];
- double bs[] = new double[2];
- double temps[] = new double[2];
-
- if ( (i & 1) == 0) {
- // Even, use double angle
- xs[0] = SINE_TABLE_A[i/2];
- xs[1] = SINE_TABLE_B[i/2];
- ys[0] = COSINE_TABLE_A[i/2];
- ys[1] = COSINE_TABLE_B[i/2];
-
- /* compute sine */
- splitMult(xs, ys, result);
- SINE_TABLE_A[i] = result[0] * 2.0;
- SINE_TABLE_B[i] = result[1] * 2.0;
-
- /* Compute cosine */
- splitMult(ys, ys, as);
- splitMult(xs, xs, temps);
- temps[0] = -temps[0];
- temps[1] = -temps[1];
- splitAdd(as, temps, result);
- COSINE_TABLE_A[i] = result[0];
- COSINE_TABLE_B[i] = result[1];
- } else {
- xs[0] = SINE_TABLE_A[i/2];
- xs[1] = SINE_TABLE_B[i/2];
- ys[0] = COSINE_TABLE_A[i/2];
- ys[1] = COSINE_TABLE_B[i/2];
- as[0] = SINE_TABLE_A[i/2+1];
- as[1] = SINE_TABLE_B[i/2+1];
- bs[0] = COSINE_TABLE_A[i/2+1];
- bs[1] = COSINE_TABLE_B[i/2+1];
-
- /* compute sine */
- splitMult(xs, bs, temps);
- splitMult(ys, as, result);
- splitAdd(result, temps, result);
- SINE_TABLE_A[i] = result[0];
- SINE_TABLE_B[i] = result[1];
-
- /* Compute cosine */
- splitMult(ys, bs, result);
- splitMult(xs, as, temps);
- temps[0] = -temps[0];
- temps[1] = -temps[1];
- splitAdd(result, temps, result);
- COSINE_TABLE_A[i] = result[0];
- COSINE_TABLE_B[i] = result[1];
- }
- }
-
- /* Compute tangent = sine/cosine */
- for (int i = 0; i < SINE_TABLE_LEN; i++) {
- double xs[] = new double[2];
- double ys[] = new double[2];
- double as[] = new double[2];
-
- as[0] = COSINE_TABLE_A[i];
- as[1] = COSINE_TABLE_B[i];
-
- splitReciprocal(as, ys);
-
- xs[0] = SINE_TABLE_A[i];
- xs[1] = SINE_TABLE_B[i];
-
- splitMult(xs, ys, as);
-
- TANGENT_TABLE_A[i] = as[0];
- TANGENT_TABLE_B[i] = as[1];
- }
-
- }
/**
* Computes sin(x) - x, where |x| < 1/16.
Added:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMathCalc.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMathCalc.java?rev=1169527&view=auto
==============================================================================
---
commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMathCalc.java
(added)
+++
commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMathCalc.java
Sun Sep 11 20:43:27 2011
@@ -0,0 +1,610 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.commons.math.util;
+
+import org.apache.commons.math.exception.DimensionMismatchException;
+
+class FastMathCalc {
+
+ /**
+ * 0x40000000 - used to split a double into two parts, both with the low
order bits cleared.
+ * Equivalent to 2^30.
+ */
+ private static final long HEX_40000000 = 0x40000000L; // 1073741824L
+
+ /** Factorial table, for Taylor series expansions. 0!, 1!, 2!, ... 19! */
+ private static final double FACT[] = new double[]
+ {
+ +1.0d, // 0
+ +1.0d, // 1
+ +2.0d, // 2
+ +6.0d, // 3
+ +24.0d, // 4
+ +120.0d, // 5
+ +720.0d, // 6
+ +5040.0d, // 7
+ +40320.0d, // 8
+ +362880.0d, // 9
+ +3628800.0d, // 10
+ +39916800.0d, // 11
+ +479001600.0d, // 12
+ +6227020800.0d, // 13
+ +87178291200.0d, // 14
+ +1307674368000.0d, // 15
+ +20922789888000.0d, // 16
+ +355687428096000.0d, // 17
+ +6402373705728000.0d, // 18
+ +121645100408832000.0d, // 19
+ };
+
+ /** Coefficients for slowLog. */
+ private static final double LN_SPLIT_COEF[][] = {
+ {2.0, 0.0},
+ {0.6666666269302368, 3.9736429850260626E-8},
+ {0.3999999761581421, 2.3841857910019882E-8},
+ {0.2857142686843872, 1.7029898543501842E-8},
+ {0.2222222089767456, 1.3245471311735498E-8},
+ {0.1818181574344635, 2.4384203044354907E-8},
+ {0.1538461446762085, 9.140260083262505E-9},
+ {0.13333332538604736, 9.220590270857665E-9},
+ {0.11764700710773468, 1.2393345855018391E-8},
+ {0.10526403784751892, 8.251545029714408E-9},
+ {0.0952233225107193, 1.2675934823758863E-8},
+ {0.08713622391223907, 1.1430250008909141E-8},
+ {0.07842259109020233, 2.404307984052299E-9},
+ {0.08371849358081818, 1.176342548272881E-8},
+ {0.030589580535888672, 1.2958646899018938E-9},
+ {0.14982303977012634, 1.225743062930824E-8},
+ };
+
+ /** Build the sine and cosine tables.
+ * @param SINE_TABLE_A
+ * @param SINE_TABLE_B
+ * @param COSINE_TABLE_A
+ * @param COSINE_TABLE_B
+ * @param SINE_TABLE_LEN
+ * @param TANGENT_TABLE_A
+ * @param TANGENT_TABLE_B
+ */
+ @SuppressWarnings("unused")
+ private static void buildSinCosTables(double[] SINE_TABLE_A, double[]
SINE_TABLE_B, double[] COSINE_TABLE_A, double[] COSINE_TABLE_B, int
SINE_TABLE_LEN, double[] TANGENT_TABLE_A, double[] TANGENT_TABLE_B) {
+ final double result[] = new double[2];
+
+ /* Use taylor series for 0 <= x <= 6/8 */
+ for (int i = 0; i < 7; i++) {
+ double x = i / 8.0;
+
+ slowSin(x, result);
+ SINE_TABLE_A[i] = result[0];
+ SINE_TABLE_B[i] = result[1];
+
+ slowCos(x, result);
+ COSINE_TABLE_A[i] = result[0];
+ COSINE_TABLE_B[i] = result[1];
+ }
+
+ /* Use angle addition formula to complete table to 13/8, just beyond
pi/2 */
+ for (int i = 7; i < SINE_TABLE_LEN; i++) {
+ double xs[] = new double[2];
+ double ys[] = new double[2];
+ double as[] = new double[2];
+ double bs[] = new double[2];
+ double temps[] = new double[2];
+
+ if ( (i & 1) == 0) {
+ // Even, use double angle
+ xs[0] = SINE_TABLE_A[i/2];
+ xs[1] = SINE_TABLE_B[i/2];
+ ys[0] = COSINE_TABLE_A[i/2];
+ ys[1] = COSINE_TABLE_B[i/2];
+
+ /* compute sine */
+ splitMult(xs, ys, result);
+ SINE_TABLE_A[i] = result[0] * 2.0;
+ SINE_TABLE_B[i] = result[1] * 2.0;
+
+ /* Compute cosine */
+ splitMult(ys, ys, as);
+ splitMult(xs, xs, temps);
+ temps[0] = -temps[0];
+ temps[1] = -temps[1];
+ splitAdd(as, temps, result);
+ COSINE_TABLE_A[i] = result[0];
+ COSINE_TABLE_B[i] = result[1];
+ } else {
+ xs[0] = SINE_TABLE_A[i/2];
+ xs[1] = SINE_TABLE_B[i/2];
+ ys[0] = COSINE_TABLE_A[i/2];
+ ys[1] = COSINE_TABLE_B[i/2];
+ as[0] = SINE_TABLE_A[i/2+1];
+ as[1] = SINE_TABLE_B[i/2+1];
+ bs[0] = COSINE_TABLE_A[i/2+1];
+ bs[1] = COSINE_TABLE_B[i/2+1];
+
+ /* compute sine */
+ splitMult(xs, bs, temps);
+ splitMult(ys, as, result);
+ splitAdd(result, temps, result);
+ SINE_TABLE_A[i] = result[0];
+ SINE_TABLE_B[i] = result[1];
+
+ /* Compute cosine */
+ splitMult(ys, bs, result);
+ splitMult(xs, as, temps);
+ temps[0] = -temps[0];
+ temps[1] = -temps[1];
+ splitAdd(result, temps, result);
+ COSINE_TABLE_A[i] = result[0];
+ COSINE_TABLE_B[i] = result[1];
+ }
+ }
+
+ /* Compute tangent = sine/cosine */
+ for (int i = 0; i < SINE_TABLE_LEN; i++) {
+ double xs[] = new double[2];
+ double ys[] = new double[2];
+ double as[] = new double[2];
+
+ as[0] = COSINE_TABLE_A[i];
+ as[1] = COSINE_TABLE_B[i];
+
+ splitReciprocal(as, ys);
+
+ xs[0] = SINE_TABLE_A[i];
+ xs[1] = SINE_TABLE_B[i];
+
+ splitMult(xs, ys, as);
+
+ TANGENT_TABLE_A[i] = as[0];
+ TANGENT_TABLE_B[i] = as[1];
+ }
+
+ }
+
+ /**
+ * For x between 0 and pi/4 compute cosine using Talor series
+ * cos(x) = 1 - x^2/2! + x^4/4! ...
+ * @param x number from which cosine is requested
+ * @param result placeholder where to put the result in extended precision
+ * (may be null)
+ * @return cos(x)
+ */
+ static double slowCos(final double x, final double result[]) {
+
+ final double xs[] = new double[2];
+ final double ys[] = new double[2];
+ final double facts[] = new double[2];
+ final double as[] = new double[2];
+ split(x, xs);
+ ys[0] = ys[1] = 0.0;
+
+ for (int i = FACT.length-1; i >= 0; i--) {
+ splitMult(xs, ys, as);
+ ys[0] = as[0]; ys[1] = as[1];
+
+ if ( (i & 1) != 0) { // skip odd entries
+ continue;
+ }
+
+ split(FACT[i], as);
+ splitReciprocal(as, facts);
+
+ if ( (i & 2) != 0 ) { // alternate terms are negative
+ facts[0] = -facts[0];
+ facts[1] = -facts[1];
+ }
+
+ splitAdd(ys, facts, as);
+ ys[0] = as[0]; ys[1] = as[1];
+ }
+
+ if (result != null) {
+ result[0] = ys[0];
+ result[1] = ys[1];
+ }
+
+ return ys[0] + ys[1];
+ }
+
+ /**
+ * For x between 0 and pi/4 compute sine using Taylor expansion:
+ * sin(x) = x - x^3/3! + x^5/5! - x^7/7! ...
+ * @param x number from which sine is requested
+ * @param result placeholder where to put the result in extended precision
+ * (may be null)
+ * @return sin(x)
+ */
+ static double slowSin(final double x, final double result[]) {
+ final double xs[] = new double[2];
+ final double ys[] = new double[2];
+ final double facts[] = new double[2];
+ final double as[] = new double[2];
+ split(x, xs);
+ ys[0] = ys[1] = 0.0;
+
+ for (int i = FACT.length-1; i >= 0; i--) {
+ splitMult(xs, ys, as);
+ ys[0] = as[0]; ys[1] = as[1];
+
+ if ( (i & 1) == 0) { // Ignore even numbers
+ continue;
+ }
+
+ split(FACT[i], as);
+ splitReciprocal(as, facts);
+
+ if ( (i & 2) != 0 ) { // alternate terms are negative
+ facts[0] = -facts[0];
+ facts[1] = -facts[1];
+ }
+
+ splitAdd(ys, facts, as);
+ ys[0] = as[0]; ys[1] = as[1];
+ }
+
+ if (result != null) {
+ result[0] = ys[0];
+ result[1] = ys[1];
+ }
+
+ return ys[0] + ys[1];
+ }
+
+
+ /**
+ * For x between 0 and 1, returns exp(x), uses extended precision
+ * @param x argument of exponential
+ * @param result placeholder where to place exp(x) split in two terms
+ * for extra precision (i.e. exp(x) = result[0] + result[1]
+ * @return exp(x)
+ */
+ static double slowexp(final double x, final double result[]) {
+ final double xs[] = new double[2];
+ final double ys[] = new double[2];
+ final double facts[] = new double[2];
+ final double as[] = new double[2];
+ split(x, xs);
+ ys[0] = ys[1] = 0.0;
+
+ for (int i = FACT.length-1; i >= 0; i--) {
+ splitMult(xs, ys, as);
+ ys[0] = as[0];
+ ys[1] = as[1];
+
+ split(FACT[i], as);
+ splitReciprocal(as, facts);
+
+ splitAdd(ys, facts, as);
+ ys[0] = as[0];
+ ys[1] = as[1];
+ }
+
+ if (result != null) {
+ result[0] = ys[0];
+ result[1] = ys[1];
+ }
+
+ return ys[0] + ys[1];
+ }
+
+ /** Compute split[0], split[1] such that their sum is equal to d,
+ * and split[0] has its 30 least significant bits as zero.
+ * @param d number to split
+ * @param split placeholder where to place the result
+ */
+ private static void split(final double d, final double split[]) {
+ if (d < 8e298 && d > -8e298) {
+ final double a = d * HEX_40000000;
+ split[0] = (d + a) - a;
+ split[1] = d - split[0];
+ } else {
+ final double a = d * 9.31322574615478515625E-10;
+ split[0] = (d + a - d) * HEX_40000000;
+ split[1] = d - split[0];
+ }
+ }
+
+ /** Recompute a split.
+ * @param a input/out array containing the split, changed
+ * on output
+ */
+ private static void resplit(final double a[]) {
+ final double c = a[0] + a[1];
+ final double d = -(c - a[0] - a[1]);
+
+ if (c < 8e298 && c > -8e298) { // MAGIC NUMBER
+ double z = c * HEX_40000000;
+ a[0] = (c + z) - z;
+ a[1] = c - a[0] + d;
+ } else {
+ double z = c * 9.31322574615478515625E-10;
+ a[0] = (c + z - c) * HEX_40000000;
+ a[1] = c - a[0] + d;
+ }
+ }
+
+ /** Multiply two numbers in split form.
+ * @param a first term of multiplication
+ * @param b second term of multiplication
+ * @param ans placeholder where to put the result
+ */
+ private static void splitMult(double a[], double b[], double ans[]) {
+ ans[0] = a[0] * b[0];
+ ans[1] = a[0] * b[1] + a[1] * b[0] + a[1] * b[1];
+
+ /* Resplit */
+ resplit(ans);
+ }
+
+ /** Add two numbers in split form.
+ * @param a first term of addition
+ * @param b second term of addition
+ * @param ans placeholder where to put the result
+ */
+ private static void splitAdd(final double a[], final double b[], final
double ans[]) {
+ ans[0] = a[0] + b[0];
+ ans[1] = a[1] + b[1];
+
+ resplit(ans);
+ }
+
+ /** Compute the reciprocal of in. Use the following algorithm.
+ * in = c + d.
+ * want to find x + y such that x+y = 1/(c+d) and x is much
+ * larger than y and x has several zero bits on the right.
+ *
+ * Set b = 1/(2^22), a = 1 - b. Thus (a+b) = 1.
+ * Use following identity to compute (a+b)/(c+d)
+ *
+ * (a+b)/(c+d) = a/c + (bc - ad) / (c^2 + cd)
+ * set x = a/c and y = (bc - ad) / (c^2 + cd)
+ * This will be close to the right answer, but there will be
+ * some rounding in the calculation of X. So by carefully
+ * computing 1 - (c+d)(x+y) we can compute an error and
+ * add that back in. This is done carefully so that terms
+ * of similar size are subtracted first.
+ * @param in initial number, in split form
+ * @param result placeholder where to put the result
+ */
+ static void splitReciprocal(final double in[], final double result[]) {
+ final double b = 1.0/4194304.0;
+ final double a = 1.0 - b;
+
+ if (in[0] == 0.0) {
+ in[0] = in[1];
+ in[1] = 0.0;
+ }
+
+ result[0] = a / in[0];
+ result[1] = (b*in[0]-a*in[1]) / (in[0]*in[0] + in[0]*in[1]);
+
+ if (result[1] != result[1]) { // can happen if result[1] is NAN
+ result[1] = 0.0;
+ }
+
+ /* Resplit */
+ resplit(result);
+
+ for (int i = 0; i < 2; i++) {
+ /* this may be overkill, probably once is enough */
+ double err = 1.0 - result[0] * in[0] - result[0] * in[1] -
+ result[1] * in[0] - result[1] * in[1];
+ /*err = 1.0 - err; */
+ err = err * (result[0] + result[1]);
+ /*printf("err = %16e\n", err); */
+ result[1] += err;
+ }
+ }
+
+ /** Compute (a[0] + a[1]) * (b[0] + b[1]) in extended precision.
+ * @param a first term of the multiplication
+ * @param b second term of the multiplication
+ * @param result placeholder where to put the result
+ */
+ private static void quadMult(final double a[], final double b[], final
double result[]) {
+ final double xs[] = new double[2];
+ final double ys[] = new double[2];
+ final double zs[] = new double[2];
+
+ /* a[0] * b[0] */
+ split(a[0], xs);
+ split(b[0], ys);
+ splitMult(xs, ys, zs);
+
+ result[0] = zs[0];
+ result[1] = zs[1];
+
+ /* a[0] * b[1] */
+ split(b[1], ys);
+ splitMult(xs, ys, zs);
+
+ double tmp = result[0] + zs[0];
+ result[1] = result[1] - (tmp - result[0] - zs[0]);
+ result[0] = tmp;
+ tmp = result[0] + zs[1];
+ result[1] = result[1] - (tmp - result[0] - zs[1]);
+ result[0] = tmp;
+
+ /* a[1] * b[0] */
+ split(a[1], xs);
+ split(b[0], ys);
+ splitMult(xs, ys, zs);
+
+ tmp = result[0] + zs[0];
+ result[1] = result[1] - (tmp - result[0] - zs[0]);
+ result[0] = tmp;
+ tmp = result[0] + zs[1];
+ result[1] = result[1] - (tmp - result[0] - zs[1]);
+ result[0] = tmp;
+
+ /* a[1] * b[0] */
+ split(a[1], xs);
+ split(b[1], ys);
+ splitMult(xs, ys, zs);
+
+ tmp = result[0] + zs[0];
+ result[1] = result[1] - (tmp - result[0] - zs[0]);
+ result[0] = tmp;
+ tmp = result[0] + zs[1];
+ result[1] = result[1] - (tmp - result[0] - zs[1]);
+ result[0] = tmp;
+ }
+
+ /** Compute exp(p) for a integer p in extended precision.
+ * @param p integer whose exponential is requested
+ * @param result placeholder where to put the result in extended precision
+ * @return exp(p) in standard precision (equal to result[0] + result[1])
+ */
+ static double expint(int p, final double result[]) {
+ //double x = M_E;
+ final double xs[] = new double[2];
+ final double as[] = new double[2];
+ final double ys[] = new double[2];
+ //split(x, xs);
+ //xs[1] = (double)(2.7182818284590452353602874713526625L - xs[0]);
+ //xs[0] = 2.71827697753906250000;
+ //xs[1] = 4.85091998273542816811e-06;
+ //xs[0] = Double.longBitsToDouble(0x4005bf0800000000L);
+ //xs[1] = Double.longBitsToDouble(0x3ed458a2bb4a9b00L);
+
+ /* E */
+ xs[0] = 2.718281828459045;
+ xs[1] = 1.4456468917292502E-16;
+
+ split(1.0, ys);
+
+ while (p > 0) {
+ if ((p & 1) != 0) {
+ quadMult(ys, xs, as);
+ ys[0] = as[0]; ys[1] = as[1];
+ }
+
+ quadMult(xs, xs, as);
+ xs[0] = as[0]; xs[1] = as[1];
+
+ p >>= 1;
+ }
+
+ if (result != null) {
+ result[0] = ys[0];
+ result[1] = ys[1];
+
+ resplit(result);
+ }
+
+ return ys[0] + ys[1];
+ }
+ /** xi in the range of [1, 2].
+ * 3 5 7
+ * x+1 / x x x \
+ * ln ----- = 2 * | x + ---- + ---- + ---- + ... |
+ * 1-x \ 3 5 7 /
+ *
+ * So, compute a Remez approximation of the following function
+ *
+ * ln ((sqrt(x)+1)/(1-sqrt(x))) / x
+ *
+ * This will be an even function with only positive coefficents.
+ * x is in the range [0 - 1/3].
+ *
+ * Transform xi for input to the above function by setting
+ * x = (xi-1)/(xi+1). Input to the polynomial is x^2, then
+ * the result is multiplied by x.
+ * @param xi number from which log is requested
+ * @return log(xi)
+ */
+ static double[] slowLog(double xi) {
+ double x[] = new double[2];
+ double x2[] = new double[2];
+ double y[] = new double[2];
+ double a[] = new double[2];
+
+ split(xi, x);
+
+ /* Set X = (x-1)/(x+1) */
+ x[0] += 1.0;
+ resplit(x);
+ splitReciprocal(x, a);
+ x[0] -= 2.0;
+ resplit(x);
+ splitMult(x, a, y);
+ x[0] = y[0];
+ x[1] = y[1];
+
+ /* Square X -> X2*/
+ splitMult(x, x, x2);
+
+
+ //x[0] -= 1.0;
+ //resplit(x);
+
+ y[0] = LN_SPLIT_COEF[LN_SPLIT_COEF.length-1][0];
+ y[1] = LN_SPLIT_COEF[LN_SPLIT_COEF.length-1][1];
+
+ for (int i = LN_SPLIT_COEF.length-2; i >= 0; i--) {
+ splitMult(y, x2, a);
+ y[0] = a[0];
+ y[1] = a[1];
+ splitAdd(y, LN_SPLIT_COEF[i], a);
+ y[0] = a[0];
+ y[1] = a[1];
+ }
+
+ splitMult(y, x, a);
+ y[0] = a[0];
+ y[1] = a[1];
+
+ return y;
+ }
+
+
+ static void printarray(String string, int expectedLen, double[][] array2d)
{
+ System.out.println(string);
+ checkLen(expectedLen, array2d.length);
+ System.out.println(" { ");
+ int i = 0;
+ for(double array[] : array2d) {
+ System.out.print(" {");
+ for(double d : array) { // assume inner array has very few entries
+ String ds = d >= 0 ? "+"+Double.toString(d)+"d," :
Double.toString(d)+"d,";
+ System.out.printf("%-25.25s",ds); // multiple entries per line
+ }
+ System.out.println("}, // "+i++);
+ }
+ System.out.println(" };");
+ }
+
+ static void printarray(String string, int expectedLen, double[] array) {
+ System.out.println(string+"=");
+ checkLen(expectedLen, array.length);
+ System.out.println(" {");
+ for(double d : array){
+ String ds = d!=d ? "Double.NaN," : d >= 0 ?
"+"+Double.toString(d)+"d," : Double.toString(d)+"d,";
+ System.out.printf(" %s%n",ds); // one entry per line
+ }
+ System.out.println(" };");
+ }
+
+ private static void checkLen(int expectedLen, int actual) {
+ if (expectedLen != actual) {
+ throw new DimensionMismatchException(actual, expectedLen);
+ }
+ }
+
+}
Propchange:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMathCalc.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMathCalc.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision