/*
* This code is part of Project Waterloo from King's College London
*
*
* Copyright King's College London 2011-
*
* @author Malcolm Lidierth, King's College London [Contact]
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
*/
package kcl.waterloo.math;
//import math.geom2d.circulinear.CirculinearContourArray2D;
/**
* Provides static methods for double arithmetic with corrections for loss of
* precision.
*
* See:
*
*
* Fast and Accurate Computation of Sum and Dot Product
or
*
* Accurate
* Computation of Sum and Dot Product [NOTE TYPO IN THE TWOSUM ALGORITHM IN
* THIS ONE]
*
* @author Malcolm Lidierth, King's College London [Contact]
*/
public class fp {
// public static CirculinearContourArray2D createStatic(){
// return CirculinearContourArray2D.create(null);
// }
/**
* Private constructor. This is a non-instantiable class providing a static
* method library.
*/
private fp() {
}
/**
* Splits a double value into two double values where the sum of the two is
* the input.
*
* See T. J. Dekker, A floating-point technique for extending the available
* precision, Numer. Math., 18 (1971), pp. 224-242.
*
* @param val a double input
* @return a double[2] array - where the sum of values==the input.
*/
public static double[] split(final double val) {
final double factor = Math.scalb(1, 27) + 1;
final double c = val * factor;
final double x = c - (c - val);
return new double[]{x, val - x};
}
/**
* Returns the product of two double values and a correction for loss of
* precision in the multiplication.
*
* @param a a double value.
* @param b a double value.
* @return a double[2] array containing in [0]: the product, and in [1]: the
* required correction.
*/
public static double[] twoProduct(final double a, final double b) {
final double x = a * b;
double[] as = split(a);
double[] bs = split(b);
return new double[]{x, (as[1] * bs[1] - (((x - as[0] * bs[0]) - as[1] * bs[0] - as[0] * bs[1])))};
}
/**
* Returns the sum of two double values and a correction for loss of
* precision in the summation.
*
* @param a a double value.
* @param b a double value.
* @return a double[2] array containing in [0]: the sum, and in [1]: the
* required correction.
*/
public static double[] twoSum(final double a, final double b) {
final double x = a + b;
final double z = x - a;
return new double[]{x, (a - (x - z) + (b - z))};
}
/**
* Returns the sum of {@code in} using Knuth's correction to accumulate the
* error. The accumulated error is added to the output.
*
* @param in
* @return the sum
*/
public static double sum(double[] in) {
double sum = 0d;
double x, y = 0d, z;
for (int k = 0; k < in.length; k++) {
x = sum + in[k];
z = x - sum;
y += ((sum - (x - z)) + (in[k] - z));
sum = x;
}
return sum + y;
}
/**
* Returns the sum between two indices (inclusive).
*
* @param in input array
* @param idx0 start index
* @param idx1 end index
* @return the sum of in[idx0] thtough in[idx1]
*/
public static double sum(double[] in, int idx0, int idx1) {
double sum = 0d;
double x, y = 0d, z;
for (int k = idx0; k <= idx1; k++) {
x = sum + in[k];
z = x - sum;
y += ((sum - (x - z)) + (in[k] - z));
sum = x;
}
return sum + y;
}
/**
* Returns the cumulative sum of the elements of the input using Knuth's
* correction to accumulate the error. The accumulated error for each
* element is added to the output.
*
* @param in
* @return a double[]
*/
public static double[] cusum(double[] in) {
double s[] = new double[in.length];
double sum = 0d;
double x, y = 0d, z;
for (int k = 0; k < in.length; k++) {
x = sum + in[k];
z = x - sum;
y += ((sum - (x - z)) + (in[k] - z));
sum = x;
s[k] = sum + y;
}
return s;
}
/**
*
* Returns the cumulative sum of the elements of the input using Knuth's
* correction to accumulate the error (in-place). The accumulated error for
* each element is added to the output.
*
* @param in
* @return a double[]
*/
public static double[] cusumi(double[] in) {
double sum = 0d;
double x, y = 0d, z;
for (int k = 0; k < in.length; k++) {
x = sum + in[k];
z = x - sum;
y += ((sum - (x - z)) + (in[k] - z));
sum = x;
in[k] = sum + y;
}
return in;
}
/**
* Returns the dot product.
*
* @param a double[] input a
* @param b double[] input b
* @return the sum of a[k]*b[k] for k = 0 .. length(a)-1
*/
public static double dot(double[] a, double[] b) {
assertSameLength(a, b);
double s = 0d;
double[] p = twoProduct(a[0], b[0]);
double[] h;
for (int k = 1; k < a.length; k++) {
h = twoProduct(a[k], b[k]);
p = twoSum(p[0], h[0]);
s += p[1] + h[1];
}
return p[0] + s;
}
public static boolean tolEquals(double a, double b, double tol) {
return a == b || a <= b + tol || a >= b - tol;
}
private static void assertSameLength(double[] X, double[] Y) {
if (X.length != Y.length) {
throw new ArrayIndexOutOfBoundsException(
"Vectors must be the same length: not " + X.length + " and " + Y.length);
}
}
}
Ads help maintain this website.