diff options
author | Sven Göthel <[email protected]> | 2024-04-25 03:20:14 +0200 |
---|---|---|
committer | Sven Göthel <[email protected]> | 2024-04-25 03:20:14 +0200 |
commit | 78f6de75d2645a8cc0c6df0f1f2d01d81645f3de (patch) | |
tree | 73ebd76a6f39f8cd61f550504307023986d00295 | |
parent | 8bb2f6dec8ab731b07387b947715fa1959c680e4 (diff) |
FloatUtil: Add IEC559_SIGN_BIT; Align API doc and implementation w/ native jaulib, i.e. drop 0==epsilon case for performance
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());
}
|