Method to test for equality with a given relative tolerance (due to
Yannick Tanguy and Julien Anxionnat). Original patch provided in
JIRA MATH-863 and committed with a few changes.


git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1387941 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Gilles Sadowski 2012-09-20 10:09:37 +00:00
parent b245e08d24
commit 600f00ba58
3 changed files with 53 additions and 0 deletions

View File

@ -52,6 +52,10 @@ If the output is not quite correct, check for invisible trailing spaces!
<body>
<release version="3.1" date="TBD" description="
">
<action dev="erans" type="add" issue="MATH-866" due-to="Yannick Tanguy">
Added method to test for floating-point numbers equality with a
relative tolerance (class "o.a.c.m.util.Precision").
</action>
<action dev="tn" type="fix" issue="MATH-666">
Deprecated "FieldVector#getData()" in favor of "toArray()".
</action>

View File

@ -272,6 +272,28 @@ public class Precision {
return equals(x, y, 1) || FastMath.abs(y - x) <= eps;
}
/**
* Returns {@code true} if there is no double value strictly between the
* arguments or the reltaive difference between them is smaller or equal
* to the given tolerance.
*
* @param x First value.
* @param y Second value.
* @param eps Amount of allowed relative error.
* @return {@code true} if the values are two adjacent floating point
* numbers or they are within range of each other.
*/
public static boolean equalsWithRelativeTolerance(double x, double y, double eps) {
if (equals(x, y, 1)) {
return true;
}
final double absoluteMax = FastMath.max(FastMath.abs(x), FastMath.abs(y));
final double relativeDifference = FastMath.abs((x - y) / absoluteMax);
return relativeDifference <= eps;
}
/**
* Returns true if both arguments are NaN or are equal or within the range
* of allowed error (inclusive).

View File

@ -27,6 +27,33 @@ import org.junit.Test;
* @version $Id$
*/
public class PrecisionTest {
@Test
public void testEqualsWithRelativeTolerance() {
Assert.assertTrue(Precision.equalsWithRelativeTolerance(0d, 0d, 0d));
Assert.assertTrue(Precision.equalsWithRelativeTolerance(0d, 1 / Double.NEGATIVE_INFINITY, 0d));
final double eps = 1e-14;
Assert.assertFalse(Precision.equalsWithRelativeTolerance(1.987654687654968, 1.987654687654988, eps));
Assert.assertTrue(Precision.equalsWithRelativeTolerance(1.987654687654968, 1.987654687654987, eps));
Assert.assertFalse(Precision.equalsWithRelativeTolerance(1.987654687654968, 1.987654687654948, eps));
Assert.assertTrue(Precision.equalsWithRelativeTolerance(1.987654687654968, 1.987654687654949, eps));
Assert.assertFalse(Precision.equalsWithRelativeTolerance(Precision.SAFE_MIN, 0.0, eps));
Assert.assertFalse(Precision.equalsWithRelativeTolerance(1.0000000000001e-300, 1e-300, eps));
Assert.assertTrue(Precision.equalsWithRelativeTolerance(1.00000000000001e-300, 1e-300, eps));
Assert.assertFalse(Precision.equalsWithRelativeTolerance(Double.NEGATIVE_INFINITY, 1.23, eps));
Assert.assertFalse(Precision.equalsWithRelativeTolerance(Double.POSITIVE_INFINITY, 1.23, eps));
Assert.assertTrue(Precision.equalsWithRelativeTolerance(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, eps));
Assert.assertTrue(Precision.equalsWithRelativeTolerance(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, eps));
Assert.assertFalse(Precision.equalsWithRelativeTolerance(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, eps));
Assert.assertFalse(Precision.equalsWithRelativeTolerance(Double.NaN, 1.23, eps));
Assert.assertFalse(Precision.equalsWithRelativeTolerance(Double.NaN, Double.NaN, eps));
}
@Test
public void testEqualsIncludingNaN() {
double[] testArray = {