summaryrefslogtreecommitdiff
path: root/src/org/unitConverter/math/DecimalComparison.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/unitConverter/math/DecimalComparison.java')
-rw-r--r--src/org/unitConverter/math/DecimalComparison.java67
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();