aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Göthel <[email protected]>2024-04-25 03:20:14 +0200
committerSven Göthel <[email protected]>2024-04-25 03:20:14 +0200
commit78f6de75d2645a8cc0c6df0f1f2d01d81645f3de (patch)
tree73ebd76a6f39f8cd61f550504307023986d00295
parent8bb2f6dec8ab731b07387b947715fa1959c680e4 (diff)
FloatUtil: Add IEC559_SIGN_BIT; Align API doc and implementation w/ native jaulib, i.e. drop 0==epsilon case for performance
-rw-r--r--src/jogl/classes/com/jogamp/math/FloatUtil.java63
-rw-r--r--src/jogl/classes/com/jogamp/math/geom/AABBox.java2
-rw-r--r--src/test/com/jogamp/opengl/test/junit/math/TestFloatUtil01NOUI.java71
3 files changed, 60 insertions, 76 deletions
diff --git a/src/jogl/classes/com/jogamp/math/FloatUtil.java b/src/jogl/classes/com/jogamp/math/FloatUtil.java
index 4ca706457..b8eebf0b3 100644
--- a/src/jogl/classes/com/jogamp/math/FloatUtil.java
+++ b/src/jogl/classes/com/jogamp/math/FloatUtil.java
@@ -1278,7 +1278,7 @@ public final class FloatUtil {
* @param aOffset offset to <code>a</code>'s current position
* @param rows
* @param columns
- * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL)
+ * @param rowMajorOrder if true floats are laid out in row-major-order, otherwise column-major-order (OpenGL)
* @return matrix string representation
*/
public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f,
@@ -1410,8 +1410,12 @@ public final class FloatUtil {
*/
public static final float INV_DEVIANCE = 1.0E-5f; // FloatUtil.EPSILON == 1.1920929E-7f; double ALLOWED_DEVIANCE: 1.0E-8f
+ /** Signed bit 31 of IEEE 754 (IEC 559) single float-point bit layout, i.e. `0x80000000`. */
+ public static final int IEC559_SIGN_BIT = 1 << 31; // 0x80000000;
+
/**
- * Return true if both values are equal w/o regarding an epsilon.
+ * Returns true if both values are equal
+ * disregarding {@link EPSILON} but considering {@code NaN}, {@code -Inf} and {@code +Inf}.
* <p>
* Implementation considers following corner cases:
* <ul>
@@ -1428,10 +1432,10 @@ public final class FloatUtil {
}
/**
- * Returns true if both values are equal, i.e. their absolute delta < {@code epsilon} if 0 != {@code epsilon},
- * otherwise == {@code 0}.
+ * Returns true if both values are equal, i.e. their absolute delta < {@code epsilon},
+ * considering {@code epsilon} and {@code NaN}, {@code -Inf} and {@code +Inf}.
* <p>
- * {@code epsilon} is allowed to be {@code 0}.
+ * {@code epsilon} must be > 0.
* </p>
* <p>
* Implementation considers following corner cases:
@@ -1444,8 +1448,7 @@ public final class FloatUtil {
* @see #EPSILON
*/
public static boolean isEqual(final float a, final float b, final float epsilon) {
- if( 0 == epsilon && Math.abs(a - b) == 0 ||
- 0 != epsilon && Math.abs(a - b) < epsilon ) {
+ if( Math.abs(a - b) < epsilon ) {
return true;
} else {
// Values are equal (Inf, Nan .. )
@@ -1454,7 +1457,8 @@ public final class FloatUtil {
}
/**
- * Returns true if both values are equal, i.e. their absolute delta < {@link #EPSILON}.
+ * Returns true if both values are equal, i.e. their absolute delta < {@link #EPSILON},
+ * considering {@link EPSILON} and {@code NaN}, {@code -Inf} and {@code +Inf}.
* <p>
* Implementation considers following corner cases:
* <ul>
@@ -1475,7 +1479,8 @@ public final class FloatUtil {
}
/**
- * Returns true if both values are equal, i.e. their absolute delta < {@link #EPSILON}.
+ * Returns true if both values are equal, i.e. their absolute delta < {@link #EPSILON},
+ * considering {@link EPSILON} but disregarding {@code NaN}, {@code -Inf} and {@code +Inf}.
* <p>
* Implementation does not consider corner cases like {@link #isEqual(float, float, float)}.
* </p>
@@ -1486,7 +1491,8 @@ public final class FloatUtil {
}
/**
- * Returns true if both values are equal w/o regarding an epsilon.
+ * Returns {@code -1}, {@code 0} or {@code 1} if {@code a} is less, equal or greater than {@code b},
+ * disregarding epsilon but considering {@code NaN}, {@code -Inf} and {@code +Inf}.
* <p>
* Implementation considers following corner cases:
* <ul>
@@ -1519,9 +1525,9 @@ public final class FloatUtil {
/**
* Returns {@code -1}, {@code 0} or {@code 1} if {@code a} is less, equal or greater than {@code b},
- * taking {@code epsilon} into account for equality.
+ * considering epsilon and {@code NaN}, {@code -Inf} and {@code +Inf}.
* <p>
- * {@code epsilon} is allowed to be {@code 0}.
+ * {@code epsilon} must be > 0.
* </p>
* <p>
* Implementation considers following corner cases:
@@ -1536,8 +1542,7 @@ public final class FloatUtil {
* @see #EPSILON
*/
public static int compare(final float a, final float b, final float epsilon) {
- if( 0 == epsilon && Math.abs(a - b) == 0 ||
- 0 != epsilon && Math.abs(a - b) < epsilon ) {
+ if( Math.abs(a - b) < epsilon ) {
return 0;
} else {
return compare(a, b);
@@ -1545,21 +1550,16 @@ public final class FloatUtil {
}
/**
- * Returns true if value is zero, i.e. it's absolute value < {@code epsilon} if 0 != {@code epsilon},
- * otherwise {@code 0 == a}.
+ * Returns true if value is zero, i.e. it's absolute value < {@code epsilon}.
* <p>
- * {@code epsilon} is allowed to be {@code 0}.
+ * {@code epsilon} must be > 0.
* </p>
- * <pre>
- * return 0 == epsilon && 0 == a || 0 != epsilon && Math.abs(a) < epsilon
- * </pre>
* @param a value to test
- * @param epsilon optional positive epsilon value, maybe {@code 0}
+ * @param epsilon optional positive epsilon value, must be > 0
* @see #EPSILON
*/
public static boolean isZero(final float a, final float epsilon) {
- return 0 == epsilon && a == 0 ||
- 0 != epsilon && Math.abs(a) < epsilon;
+ return Math.abs(a) < epsilon;
}
/**
@@ -1571,6 +1571,23 @@ public final class FloatUtil {
}
/**
+ * Returns true if value is zero,
+ * disregarding {@link EPSILON} but considering {@code NaN}, {@code -Inf} and {@code +Inf}.
+ * <p>
+ * Implementation considers following corner cases:
+ * <ul>
+ * <li>NaN == NaN</li>
+ * <li>+Inf == +Inf</li>
+ * <li>-Inf == -Inf</li>
+ * </ul>
+ * </p>
+ */
+ public static boolean isZeroRaw(final float a) {
+ // Values are equal (Inf, Nan .. )
+ return ( Float.floatToIntBits(a) & ~IEC559_SIGN_BIT ) == 0;
+ }
+
+ /**
* Invokes {@link Math#abs(float)}
* @param a float to process
* @return absolute value of {@code a}
diff --git a/src/jogl/classes/com/jogamp/math/geom/AABBox.java b/src/jogl/classes/com/jogamp/math/geom/AABBox.java
index 9d6153b7a..2456d6f4b 100644
--- a/src/jogl/classes/com/jogamp/math/geom/AABBox.java
+++ b/src/jogl/classes/com/jogamp/math/geom/AABBox.java
@@ -661,7 +661,7 @@ public class AABBox {
if( !assumeIntersection ) {
// Check final candidate actually inside box
- if( 0 != ( Float.floatToIntBits(maxT[whichPlane]) & 0x80000000 ) ) {
+ if( 0 != ( Float.floatToIntBits(maxT[whichPlane]) & FloatUtil.IEC559_SIGN_BIT ) ) {
return null;
}
diff --git a/src/test/com/jogamp/opengl/test/junit/math/TestFloatUtil01NOUI.java b/src/test/com/jogamp/opengl/test/junit/math/TestFloatUtil01NOUI.java
index c67db9f1d..0b3ae6306 100644
--- a/src/test/com/jogamp/opengl/test/junit/math/TestFloatUtil01NOUI.java
+++ b/src/test/com/jogamp/opengl/test/junit/math/TestFloatUtil01NOUI.java
@@ -68,7 +68,7 @@ public class TestFloatUtil01NOUI extends JunitTracer {
final boolean equalWE = FloatUtil.isEqual(a, b, EPSILON);
final int compWE = FloatUtil.compare(a, b, EPSILON);
final String msgWE = ( expWE != compWE ) ? "**** mismatch ****" : " OK";
- System.err.println("Print.WE."+tstNum+": a: "+a+", b: "+b+" -> d "+delta+", exp "+expWE+", equal "+equalWE+", comp "+compWE+" - "+msgWE+", epsilon "+EPSILON);
+ System.err.println("Print.WE."+tstNum+": a: "+a+", b: "+b+" -> d "+delta+", exp "+expWE+", equal "+equalWE+", comp "+compWE+" - "+msgWE+"testZeroNoEpsilon "+EPSILON);
}
private void dumpTestNE(final int tstNum, final int exp, final float a, final float b) {
final float delta = a-b;
@@ -91,24 +91,27 @@ public class TestFloatUtil01NOUI extends JunitTracer {
testZeroWithEpsilon1(300, MACH_EPSILON);
}
@Test
- public void test01cZeroWithZeroEpsilon() {
- final float EPSILON = 0.0f;
+ public void test01cZeroNoEpsilon() {
int i = 400;
System.err.println();
- testZeroWithEpsilon1(i++, true, 0f, EPSILON);
- testZeroWithEpsilon1(i++, true, 0f-EPSILON/2f, EPSILON);
- testZeroWithEpsilon1(i++, true, 0f+EPSILON/2f, EPSILON);
- testZeroWithEpsilon1(i++, false, 0f-Float.MIN_VALUE, EPSILON);
- testZeroWithEpsilon1(i++, false, 0f+Float.MIN_VALUE, EPSILON);
- testZeroWithEpsilon1(i++, true, -0f, EPSILON);
- testZeroWithEpsilon1(i++, true, +0f, EPSILON);
+ testZeroNoEpsilon(i++, true, 0f);
+ testZeroNoEpsilon(i++, false, 0f-Float.MIN_VALUE);
+ testZeroNoEpsilon(i++, false, 0f+Float.MIN_VALUE);
+ testZeroNoEpsilon(i++, true, -0f);
+ testZeroNoEpsilon(i++, true, +0f);
- testZeroWithEpsilon1(i++, false, 0f+EPSILON+Float.MIN_VALUE, EPSILON);
- testZeroWithEpsilon1(i++, false, 0f-EPSILON-Float.MIN_VALUE, EPSILON);
+ testZeroNoEpsilon(i++, false, 0f+Float.MIN_VALUE);
+ testZeroNoEpsilon(i++, false, 0f-Float.MIN_VALUE);
// Unpredicted .. accuracy beyond epsilon, or deltaMachEpsLEQEpsilon or deltaFixedEpsLEQEpsilon;
- dumpTestWE(i++, 1, 0f, 0f+EPSILON-Float.MIN_VALUE, EPSILON);
- dumpTestWE(i++, 1, 0f, 0f-EPSILON+Float.MIN_VALUE, EPSILON);
+ dumpTestNE(i++, 1, 0f, 0f+Float.MIN_VALUE);
+ dumpTestNE(i++, 1, 0f, 0f-Float.MIN_VALUE);
+ }
+ private void testZeroNoEpsilon(final int tstNum, final boolean exp, final float a) {
+ final boolean zero = FloatUtil.isZeroRaw(a);
+ final float delta = a-0f;
+ System.err.println("Zero."+tstNum+": a: "+a+", -> d "+delta+", exp "+exp+", zero "+zero);
+ Assert.assertEquals("Zero failed a: "+a, exp, zero);
}
private void testZeroWithEpsilon1(int i, final float EPSILON) {
System.err.println();
@@ -169,7 +172,7 @@ public class TestFloatUtil01NOUI extends JunitTracer {
testEqualsNoEpsilon(i++, true, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
testEqualsNoEpsilon(i++, true, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
testEqualsNoEpsilon(i++, true, Float.NaN, Float.NaN);
- testEqualsNoEpsilon(i++, false, -0f, 0f);
+ testEqualsNoEpsilon(i++, false, -0f, 0f);
testEqualsNoEpsilon(i++, false, 0f, -0f);
// Unpredicted .. accuracy beyond epsilon, or deltaMachEpsLEQEpsilon or deltaFixedEpsLEQEpsilon;
@@ -199,37 +202,6 @@ public class TestFloatUtil01NOUI extends JunitTracer {
public void test03bEqualsWithMachEpsilon() {
testEqualsWithEpsilon(200, MACH_EPSILON);
}
- @Test
- public void test03cEqualsWithZeroEpsilon() {
- // testEqualsWithEpsilon(300, 0.0f);
- //
- // Results marked with (***) are actually true epsilon artifacts
- // reversing the result due to no-epsilon comparison
- final float EPSILON = 0.0f;
- int i=400;
- System.err.println();
- testEqualsWithEpsilon(i++, true, 0f, 0f, EPSILON);
- testEqualsWithEpsilon(i++, true, 1f, 1f-EPSILON/2f, EPSILON);
- testEqualsWithEpsilon(i++, true, 1f, 1f+EPSILON/2f, EPSILON);
- testEqualsWithEpsilon(i++, true, 1f, 1f-Float.MIN_VALUE, EPSILON); // ***
- testEqualsWithEpsilon(i++, true, 1f, 1f-Float.MIN_NORMAL, EPSILON); // ***
- testEqualsWithEpsilon(i++, true, 1f, 1f+Float.MIN_VALUE, EPSILON); // ***
- testEqualsWithEpsilon(i++, true, Float.MAX_VALUE, Float.MAX_VALUE, EPSILON);
- testEqualsWithEpsilon(i++, true, Float.MIN_VALUE, Float.MIN_VALUE, EPSILON);
- testEqualsWithEpsilon(i++, true, Float.MIN_NORMAL, Float.MIN_NORMAL, EPSILON);
- testEqualsWithEpsilon(i++, true, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, EPSILON);
- testEqualsWithEpsilon(i++, true, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, EPSILON);
- testEqualsWithEpsilon(i++, true, Float.NaN, Float.NaN, EPSILON);
- testEqualsWithEpsilon(i++, true, -0f, 0f, EPSILON);
- testEqualsWithEpsilon(i++, true, 0f, -0f, EPSILON);
-
- testEqualsWithEpsilon(i++, true, 1f, 1f+EPSILON+Float.MIN_VALUE, EPSILON); // ***
- testEqualsWithEpsilon(i++, true, 1f, 1f-EPSILON-Float.MIN_VALUE, EPSILON); // ***
-
- // Unpredicted .. accuracy beyond epsilon, or deltaMachEpsLEQEpsilon or deltaFixedEpsLEQEpsilon;
- dumpTestWE(i++, 1, 1f, 1f+EPSILON-Float.MIN_VALUE, EPSILON);
- dumpTestWE(i++, 1, 1f, 1f-EPSILON+Float.MIN_VALUE, EPSILON);
- }
private void testEqualsWithEpsilon(int i, final float EPSILON) {
System.err.println();
testEqualsWithEpsilon(i++, true, 0f, 0f, EPSILON);
@@ -285,7 +257,7 @@ public class TestFloatUtil01NOUI extends JunitTracer {
testCompareNoEpsilon(i++, 1, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY);
testCompareNoEpsilon(i++, -1, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
- testCompareNoEpsilon(i++, -1, 0f, Float.NaN);
+ testCompareNoEpsilon(i++, -1, 0f, Float.NaN);
testCompareNoEpsilon(i++, 1, Float.NaN, 0f);
testCompareNoEpsilon(i++, -1, -0f, 0f);
@@ -317,10 +289,6 @@ public class TestFloatUtil01NOUI extends JunitTracer {
public void test05bCompareWithMachEpsilon() {
test05CompareWithEpsilon(200, MACH_EPSILON);
}
- @Test
- public void test05cCompareWithZeroEpsilon() {
- test05CompareWithEpsilon(300, 0.0f);
- }
private void test05CompareWithEpsilon(int i, final float epsilon) {
System.err.println();
testCompareWithEpsilon(i++, 0, 0f, 0f, epsilon);
@@ -359,7 +327,6 @@ public class TestFloatUtil01NOUI extends JunitTracer {
Assert.assertEquals("Compare failed a: "+a+", b: "+b+" within "+epsilon, exp, comp);
}
-
public static void main(final String args[]) {
org.junit.runner.JUnitCore.main(TestFloatUtil01NOUI.class.getName());
}