diff options
Diffstat (limited to 'src/org/unitConverter/math/DecimalComparison.java')
-rw-r--r-- | src/org/unitConverter/math/DecimalComparison.java | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/org/unitConverter/math/DecimalComparison.java b/src/org/unitConverter/math/DecimalComparison.java index 7cdbe5b..859e8da 100644 --- a/src/org/unitConverter/math/DecimalComparison.java +++ b/src/org/unitConverter/math/DecimalComparison.java @@ -16,6 +16,8 @@ */ package org.unitConverter.math; +import java.math.BigDecimal; + /** * A class that contains methods to compare float and double values. * @@ -44,6 +46,18 @@ public final class DecimalComparison { /** * Tests for equality of double values using {@link #DOUBLE_EPSILON}. + * <p> + * <strong>WARNING: </strong>this method is not technically transitive. If a and b are off by slightly less than + * {@code epsilon * max(abs(a), abs(b))}, and b and c are off by slightly less than + * {@code epsilon * max(abs(b), abs(c))}, then equals(a, b) and equals(b, c) will both return true, but equals(a, c) + * will return false. However, this situation is very unlikely to ever happen in a real programming situation. + * <p> + * If this does become a concern, some ways to solve this problem: + * <ol> + * <li>Raise the value of epsilon using {@link #equals(double, double, double)} (this does not make a violation of + * transitivity impossible, it just significantly reduces the chances of it happening) + * <li>Use {@link BigDecimal} instead of {@code double} (this will make a violation of transitivity 100% impossible) + * </ol> * * @param a * first value to test @@ -52,6 +66,7 @@ public final class DecimalComparison { * @return whether they are equal * @since 2019-03-18 * @since v0.2.0 + * @see #hashCode(double) */ public static final boolean equals(final double a, final double b) { return DecimalComparison.equals(a, b, DOUBLE_EPSILON); @@ -60,6 +75,19 @@ public final class DecimalComparison { /** * Tests for double equality using a custom epsilon value. * + * <p> + * <strong>WARNING: </strong>this method is not technically transitive. If a and b are off by slightly less than + * {@code epsilon * max(abs(a), abs(b))}, and b and c are off by slightly less than + * {@code epsilon * max(abs(b), abs(c))}, then equals(a, b) and equals(b, c) will both return true, but equals(a, c) + * will return false. However, this situation is very unlikely to ever happen in a real programming situation. + * <p> + * If this does become a concern, some ways to solve this problem: + * <ol> + * <li>Raise the value of epsilon (this does not make a violation of transitivity impossible, it just significantly + * reduces the chances of it happening) + * <li>Use {@link BigDecimal} instead of {@code double} (this will make a violation of transitivity 100% impossible) + * </ol> + * * @param a * first value to test * @param b @@ -77,6 +105,19 @@ public final class DecimalComparison { /** * Tests for equality of float values using {@link #FLOAT_EPSILON}. * + * <p> + * <strong>WARNING: </strong>this method is not technically transitive. If a and b are off by slightly less than + * {@code epsilon * max(abs(a), abs(b))}, and b and c are off by slightly less than + * {@code epsilon * max(abs(b), abs(c))}, then equals(a, b) and equals(b, c) will both return true, but equals(a, c) + * will return false. However, this situation is very unlikely to ever happen in a real programming situation. + * <p> + * If this does become a concern, some ways to solve this problem: + * <ol> + * <li>Raise the value of epsilon using {@link #equals(float, float, float)} (this does not make a violation of + * transitivity impossible, it just significantly reduces the chances of it happening) + * <li>Use {@link BigDecimal} instead of {@code float} (this will make a violation of transitivity 100% impossible) + * </ol> + * * @param a * first value to test * @param b @@ -92,6 +133,19 @@ public final class DecimalComparison { /** * Tests for float equality using a custom epsilon value. * + * <p> + * <strong>WARNING: </strong>this method is not technically transitive. If a and b are off by slightly less than + * {@code epsilon * max(abs(a), abs(b))}, and b and c are off by slightly less than + * {@code epsilon * max(abs(b), abs(c))}, then equals(a, b) and equals(b, c) will both return true, but equals(a, c) + * will return false. However, this situation is very unlikely to ever happen in a real programming situation. + * <p> + * If this does become a concern, some ways to solve this problem: + * <ol> + * <li>Raise the value of epsilon (this does not make a violation of transitivity impossible, it just significantly + * reduces the chances of it happening) + * <li>Use {@link BigDecimal} instead of {@code float} (this will make a violation of transitivity 100% impossible) + * </ol> + * * @param a * first value to test * @param b @@ -106,6 +160,19 @@ public final class DecimalComparison { return Math.abs(a - b) <= epsilon * Math.max(Math.abs(a), Math.abs(b)); } + /** + * Takes the hash code of doubles. Values that are equal according to {@link #equals(double, double)} will have the + * same hash code. + * + * @param d + * double to hash + * @return hash code of double + * @since 2019-10-16 + */ + public static final int hash(final double d) { + return Float.hashCode((float) d); + } + // You may NOT get any DecimalComparison instances private DecimalComparison() { throw new AssertionError(); |