/*******************************************************************************
* Copyright (c) 2010, 2015 itemis AG and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alexander Nyßen (itemis AG) - initial API and implementation
* Matthias Wienand (itemis AG) - contribution for Bugzilla #355997
*
*******************************************************************************/
package org.eclipse.gef.geometry.internal.utils;
/**
* A utility class for floating point calculations and comparisons that should
* guarantee a precision of a given scale, and ignore differences beyond this
* scale.
*
* @author anyssen
* @author mwienand
*
*/
public class PrecisionUtils {
/*
* Precise calculations on doubles are performed based on BigDecimals,
* converting to 8 digits scale, so there are no undesired rounding effects
* beyond this precision.
*/
private static final int DEFAULT_SCALE = 6;
/**
* Computes the smallest double that is yet recognizable (by comparison)
* when shifting the default scale up by the given amount.
*
* @param shift
* the number of digits to shift precision up (may be negative
* number)
* @return the smallest double that will yet be recognizable by the methods
* of this class during comparison, when using the default scale
* shifted by the given amount.
*/
public static final double calculateFraction(int shift) {
return 1 / Math.pow(10, DEFAULT_SCALE + shift);
}
/**
* @see PrecisionUtils#equal(double, double, int)
* @param d1
* The first operand.
* @param d2
* The second operand.
* @return result of the comparison
*/
public static final boolean equal(double d1, double d2) {
return equal(d1, d2, 0);
}
/**
* Tests whether the two values are regarded to be equal w.r.t. the given
* shift.
*
* @param d1
* the first value to test
* @param d2
* the second value to test
* @param shift
* the delta shift used for this test
* @return <code>true</code> in case the given two values are identical or
* differ from each other by an amount that is smaller than what is
* recognizable by the shifted delta, <code>false</code> otherwise
*/
public static final boolean equal(double d1, double d2, int shift) {
// Check for undefined values
if (Double.isNaN(d1) || Double.isNaN(d2)) {
throw new IllegalArgumentException(
"Cannot compare undefined values d1 = " + d1 + ", d2 = "
+ d2);
}
return Math.abs(d1 - d2) <= calculateFraction(shift);
}
/**
* @see PrecisionUtils#greater(double, double, int)
* @param d1
* The first operand.
* @param d2
* The second operand.
* @return result of the comparison
*/
public static final boolean greater(double d1, double d2) {
return greater(d1, d2, 0);
}
/**
* Tests whether the first given value is regarded to be greater than the
* second value w.r.t. the given shift.
*
* @param d1
* the first value to test
* @param d2
* the second value to test
* @param shift
* the delta shift used for this test
* @return <code>true</code> in case the first value is greater than the
* second value by an amount recognizable by the shifted delta,
* <code>false</code> otherwise
*/
public static final boolean greater(double d1, double d2, int shift) {
// Check for undefined values
if (Double.isNaN(d1) || Double.isNaN(d2)) {
throw new IllegalArgumentException(
"Cannot compare undefined values d1 = " + d1 + ", d2 = "
+ d2);
}
return d1 + calculateFraction(shift) > d2;
}
/**
* @see PrecisionUtils#greaterEqual(double, double, int)
* @param d1
* The first operand.
* @param d2
* The second operand.
* @return result of the comparison
*/
public static final boolean greaterEqual(double d1, double d2) {
return greaterEqual(d1, d2, 0);
}
/**
* Tests whether the first given value is regarded to be greater or equal
* than the second value w.r.t. the given shift.
*
* @param d1
* the first value to test
* @param d2
* the second value to test
* @param shift
* the delta shift used for this test
* @return <code>true</code> in case the first value is greater than the
* second value by an amount recognizable by the given scale or
* differs from it by an amount not recognizable by the shifted
* delta, <code>false</code> otherwise
*/
public static final boolean greaterEqual(double d1, double d2, int shift) {
// Check for undefined values
if (Double.isNaN(d1) || Double.isNaN(d2)) {
throw new IllegalArgumentException(
"Cannot compare undefined values d1 = " + d1 + ", d2 = "
+ d2);
}
return d1 + calculateFraction(shift) >= d2;
}
/**
* @see PrecisionUtils#smaller(double, double, int)
* @param d1
* The first operand.
* @param d2
* The second operand.
* @return result of the comparison
*/
public static final boolean smaller(double d1, double d2) {
return smaller(d1, d2, 0);
}
/**
* Tests whether the first given value is regarded to be smaller than the
* second value w.r.t. the given shift.
*
* @param d1
* the first value to test
* @param d2
* the second value to test
* @param shift
* the delta shift used for this test
* @return <code>true</code> in case the first value is smaller than the
* second value by an amount recognizable by the shifted delta,
* <code>false</code> otherwise
*/
public static final boolean smaller(double d1, double d2, int shift) {
// Check for undefined values
if (Double.isNaN(d1) || Double.isNaN(d2)) {
throw new IllegalArgumentException(
"Cannot compare undefined values d1 = " + d1 + ", d2 = "
+ d2);
}
return d1 < d2 + calculateFraction(shift);
}
/**
* @see PrecisionUtils#smallerEqual(double, double, int)
* @param d1
* The first operand.
* @param d2
* The second operand.
* @return result of the comparison
*/
public static final boolean smallerEqual(double d1, double d2) {
return smallerEqual(d1, d2, 0);
}
/**
* Tests whether the first given value is regarded to be smaller or equal
* than the second value w.r.t. the given shift.
*
* @param d1
* the first value to test
* @param d2
* the second value to test
* @param shift
* the delta shift used for this test
* @return <code>true</code> in case the first value is smaller than the
* second value by an amount recognizable by the given scale or
* differs from it by an amount not recognizable by the shifted
* delta, <code>false</code> otherwise
*/
public static final boolean smallerEqual(double d1, double d2, int shift) {
// Check for undefined values
if (Double.isNaN(d1) || Double.isNaN(d2)) {
throw new IllegalArgumentException(
"Cannot compare undefined values d1 = " + d1 + ", d2 = "
+ d2);
}
return d1 <= d2 + calculateFraction(shift);
}
private PrecisionUtils() {
// this class should not be instantiated by clients
}
}