Kaynağa Gözat

MathHelper#ulp

Ranides Atterwim 4 yıl önce
ebeveyn
işleme
31fac1a9bc

+ 45 - 3
assira.core/src/main/java/net/ranides/assira/math/MathUtils.java

@@ -6,11 +6,14 @@
  */
 package net.ranides.assira.math;
 
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
 public final class MathUtils {
 
-    private MathUtils() {
-        // utility class
-    }
+    private static double EPSILON = Math.pow(2, -52);
+    private static double MAX_VALUE = (2 - EPSILON) * Math.pow(2, 1023);
+    private static double MIN_VALUE = Math.pow(2, -1022);
 
     public static boolean between(int value, int min, int max) {
         return value >= min && value <= max;
@@ -274,5 +277,44 @@ public final class MathUtils {
     public static long adds(long x, long y, long min, long max) {
         return clip(adds(x,y), min, max);
     }
+
+    public static double ulp(double x) {
+        return x < 0 ? nextUp(x) - x : x - nextDown(x);
+    }
+
+    public static double nextDown(double x) {
+        return -nextUp(-x);
+    }
+
+    public static double nextUp(double x) {
+        if (x != x) {
+            return x;
+        }
+        if (x == -1 / 0) {
+            return -MAX_VALUE;
+        }
+        if (x == +1 / 0) {
+            return +1 / 0;
+        }
+        if (x == +MAX_VALUE) {
+            return +1 / 0;
+        }
+        double y = x * (x < 0 ? 1 - EPSILON / 2 : 1 + EPSILON);
+        if (y == x) {
+            y = MIN_VALUE * EPSILON > 0 ? x + MIN_VALUE * EPSILON : x + MIN_VALUE;
+        }
+        if (y == +1 / 0) {
+            y = +MAX_VALUE;
+        }
+        double b = x + (y - x) / 2;
+        if (x < b && b < y) {
+            y = b;
+        }
+        double c = (y + x) / 2;
+        if (x < c && c < y) {
+            y = c;
+        }
+        return y == 0 ? -0 : y;
+    }
 }