From 0997a6559608cd02cb754c0b9f00fdb2b9e19043 Mon Sep 17 00:00:00 2001 From: Ivan Hetman Date: Tue, 19 Sep 2023 10:52:10 +0300 Subject: [PATCH] classlib: math fixes (#742) --- .../org/teavm/classlib/java/lang/TMath.java | 79 ++++++++++++++----- .../teavm/classlib/java/lang/MathTest.java | 55 +++++++++++++ 2 files changed, 116 insertions(+), 18 deletions(-) diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java index 8ca6069c5..fc30307fa 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java @@ -21,6 +21,7 @@ import org.teavm.classlib.PlatformDetector; import org.teavm.interop.Import; import org.teavm.interop.NoSideEffects; import org.teavm.interop.Unmanaged; +import org.teavm.jso.JSBody; @NoSideEffects public final class TMath extends TObject { @@ -207,19 +208,33 @@ public final class TMath extends TObject { } public static int abs(int n) { - return n > 0 ? n : -n; + return n >= 0 ? n : -n; } public static long abs(long n) { - return n > 0 ? n : -n; + return n >= 0 ? n : -n; } + @JSBody(params = "d", script = "return Math.abs(d);") + @NoSideEffects + private static native float jsAbs(float d); + public static float abs(float n) { - return n > 0 ? n : -n; + if (PlatformDetector.isJavaScript()) { + return jsAbs(n); + } + return n <= 0.0f ? 0.0f - n : n; } + @JSBody(params = "d", script = "return Math.abs(d);") + @NoSideEffects + private static native double jsAbs(double d); + public static double abs(double n) { - return n > 0 ? n : -n; + if (PlatformDetector.isJavaScript()) { + return jsAbs(n); + } + return n <= 0.0d ? 0.0d - n : n; } public static double ulp(double d) { @@ -241,7 +256,7 @@ public final class TMath extends TObject { bits -= 52L << 52L; } else { int exponent = (int) (bits >> 52); - bits = 1 << Math.max(0, exponent - 1); + bits = 1L << Math.max(0, exponent - 1); } return TDouble.longBitsToDouble(bits); } @@ -255,8 +270,8 @@ public final class TMath extends TObject { int bits = TFloat.floatToIntBits(d); bits &= 0x7F800000; - if (bits >= 24L << 23L) { - bits -= 23L << 23L; + if (bits >= 24 << 23) { + bits -= 23 << 23; } else { int exponent = bits >> 23; bits = 1 << Math.max(0, exponent - 1); @@ -264,12 +279,32 @@ public final class TMath extends TObject { return TFloat.intBitsToFloat(bits); } + @JSBody(params = "d", script = "return Math.sign(d);") + @NoSideEffects + private static native double sign(double d); + public static double signum(double d) { - return d > 0 ? 1 : d < -0 ? -1 : d; + if (PlatformDetector.isJavaScript()) { + return sign(d); + } + if (d == 0.0 || Double.isNaN(d)) { + return d; + } + return d < 0.0 ? -1.0 : 1.0; } + @JSBody(params = "d", script = "return Math.sign(d);") + @NoSideEffects + private static native float sign(float d); + public static float signum(float d) { - return d > 0 ? 1 : d < -0 ? -1 : d; + if (PlatformDetector.isJavaScript()) { + return sign(d); + } + if (d == 0.0f || Float.isNaN(d)) { + return d; + } + return d < 0.0f ? -1.0f : 1.0f; } public static double sinh(double x) { @@ -343,12 +378,14 @@ public final class TMath extends TObject { if (TDouble.isNaN(d)) { return d; } + if (d == 0.0d) { + return Double.MIN_VALUE; + } if (d == TDouble.POSITIVE_INFINITY) { return d; } long bits = TDouble.doubleToLongBits(d); - boolean negative = (bits & (1L << 63)) != 0; - if (negative) { + if (d < 0.0d) { bits--; } else { bits++; @@ -360,12 +397,14 @@ public final class TMath extends TObject { if (TFloat.isNaN(d)) { return d; } + if (d == 0.0f) { + return Float.MIN_VALUE; + } if (d == TFloat.POSITIVE_INFINITY) { return d; } int bits = TFloat.floatToIntBits(d); - boolean negative = (bits & (1L << 31)) != 0; - if (negative) { + if (d < 0.0f) { bits--; } else { bits++; @@ -377,12 +416,14 @@ public final class TMath extends TObject { if (TDouble.isNaN(d)) { return d; } + if (d == 0.0d) { + return -Double.MIN_VALUE; + } if (d == TDouble.NEGATIVE_INFINITY) { return d; } long bits = TDouble.doubleToLongBits(d); - boolean negative = (bits & (1L << 63)) != 0; - if (negative) { + if (d < 0.0d) { bits++; } else { bits--; @@ -394,12 +435,14 @@ public final class TMath extends TObject { if (TFloat.isNaN(d)) { return d; } - if (d == TFloat.POSITIVE_INFINITY) { + if (d == 0.0f) { + return -Float.MIN_VALUE; + } + if (d == TFloat.NEGATIVE_INFINITY) { return d; } int bits = TFloat.floatToIntBits(d); - boolean negative = (bits & (1L << 31)) != 0; - if (negative) { + if (d < 0.0f) { bits++; } else { bits--; diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/MathTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/MathTest.java index 7fe043f84..38d9d2c28 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/MathTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/MathTest.java @@ -16,6 +16,7 @@ package org.teavm.classlib.java.lang; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.junit.Test; import org.junit.runner.RunWith; import org.teavm.junit.TeaVMTestRunner; @@ -59,6 +60,32 @@ public class MathTest { assertEquals(6, Math.getExponent(123.456)); } + @Test + public void testAbs() { + assertEquals(Float.valueOf(Float.POSITIVE_INFINITY), Float.valueOf(Math.abs(Float.NEGATIVE_INFINITY))); + assertEquals(Double.valueOf(Double.POSITIVE_INFINITY), Double.valueOf(Math.abs(Double.NEGATIVE_INFINITY))); + assertEquals(Double.valueOf(5.0), Double.valueOf(Math.abs(-5.0))); + assertEquals(Double.valueOf(3.0), Double.valueOf(Math.abs(3.0))); + assertEquals(Double.valueOf(3.0), Double.valueOf(Math.abs(-3.0))); + assertEquals(Double.valueOf(5.0), Double.valueOf(Math.abs(5.0))); + assertEquals(Float.valueOf(0.0f), Float.valueOf(Math.abs(-0.0f))); + assertEquals(Float.valueOf(0.0f), Float.valueOf(Math.abs(0.0f))); + assertEquals(Double.valueOf(0.0), Double.valueOf(Math.abs(-0.0))); + assertEquals(Double.valueOf(0.0), Double.valueOf(Math.abs(0.0))); + } + + @Test + public void signumWorks() { + assertEquals(Double.valueOf(0.0), Double.valueOf(Math.signum(0.0))); + assertEquals(Double.valueOf(-0.0), Double.valueOf(Math.signum(-0.0))); + assertTrue(Double.isNaN(Math.signum(Double.NaN))); + assertEquals(Float.valueOf(0.0f), Float.valueOf(Math.signum(0.0f))); + assertEquals(Float.valueOf(-0.0f), Float.valueOf(Math.signum(-0.0f))); + assertTrue(Float.isNaN(Math.signum(Float.NaN))); + assertEquals(Double.valueOf(-1.0), Double.valueOf(Math.signum(-Double.MIN_VALUE))); + assertEquals(Double.valueOf(1.0), Double.valueOf(Math.signum(Double.MIN_VALUE))); + } + @Test public void roundWorks() { assertEquals(1, Math.round(1.3)); @@ -66,4 +93,32 @@ public class MathTest { assertEquals(-1, Math.round(-1.3)); assertEquals(-2, Math.round(-1.8)); } + + @Test + public void nextWorks() { + assertEquals(Double.valueOf(-Double.MIN_VALUE), Double.valueOf(Math.nextDown(0.0))); + assertEquals(Double.valueOf(Double.MIN_VALUE), Double.valueOf(Math.nextUp(0.0))); + assertEquals(Float.valueOf(-Float.MIN_VALUE), Float.valueOf(Math.nextDown(0.0f))); + assertEquals(Float.valueOf(Float.MIN_VALUE), Float.valueOf(Math.nextUp(0.0f))); + assertEquals(Double.valueOf(0.10000000000000002), Double.valueOf(Math.nextUp(0.1))); + assertEquals(Double.valueOf(0.9999999999999999), Double.valueOf(Math.nextDown(1.0))); + assertEquals(Double.valueOf(-0.09999999999999999), Double.valueOf(Math.nextUp(-0.1))); + assertEquals(Double.valueOf(-1.0000000000000002), Double.valueOf(Math.nextDown(-1.0))); + assertEquals(Float.valueOf(0.10000001f), Float.valueOf(Math.nextUp(0.1f))); + assertEquals(Float.valueOf(0.99999994f), Float.valueOf(Math.nextDown(1.0f))); + assertEquals(Float.valueOf(-0.099999994f), Float.valueOf(Math.nextUp(-0.1f))); + assertEquals(Float.valueOf(-1.0000001f), Float.valueOf(Math.nextDown(-1.0f))); + assertEquals(Float.valueOf(Float.NEGATIVE_INFINITY), Float.valueOf(Math.nextDown(Float.NEGATIVE_INFINITY))); + assertEquals(Float.valueOf(Float.intBitsToFloat(Float.floatToIntBits(Float.POSITIVE_INFINITY) - 1)), + Float.valueOf(Math.nextDown(Float.POSITIVE_INFINITY))); + assertEquals(Float.valueOf(Float.POSITIVE_INFINITY), Float.valueOf(Math.nextUp(Float.POSITIVE_INFINITY))); + assertEquals(Float.valueOf(Float.intBitsToFloat(Float.floatToIntBits(Float.NEGATIVE_INFINITY) - 1)), + Float.valueOf(Math.nextUp(Float.NEGATIVE_INFINITY))); + assertEquals(Double.valueOf(Double.NEGATIVE_INFINITY), Double.valueOf(Math.nextDown(Double.NEGATIVE_INFINITY))); + assertEquals(Double.valueOf(Double.longBitsToDouble(Double.doubleToLongBits(Double.POSITIVE_INFINITY) - 1)), + Double.valueOf(Math.nextDown(Double.POSITIVE_INFINITY))); + assertEquals(Double.valueOf(Double.POSITIVE_INFINITY), Double.valueOf(Math.nextUp(Double.POSITIVE_INFINITY))); + assertEquals(Double.valueOf(Double.longBitsToDouble(Double.doubleToLongBits(Double.NEGATIVE_INFINITY) - 1)), + Double.valueOf(Math.nextUp(Double.NEGATIVE_INFINITY))); + } }