|
|
@@ -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;
|
|
|
+ }
|
|
|
}
|
|
|
|