classlib: fix Math min/max functions

This commit is contained in:
ihromant 2023-09-25 23:13:18 +03:00 committed by Alexey Andreev
parent 5dec78b590
commit 56ff3fbdd8
2 changed files with 150 additions and 69 deletions

View File

@ -195,20 +195,72 @@ public final class TMath extends TObject {
return a > b ? a : b; return a > b ? a : b;
} }
@GeneratedBy(MathNativeGenerator.class)
@NoSideEffects
private static native float minImpl(double a, double b);
public static double min(double a, double b) { public static double min(double a, double b) {
return a < b ? a : b; if (PlatformDetector.isJavaScript()) {
return minImpl(a, b);
} }
if (a != a) {
return a;
}
if (a == 0.0 && b == 0.0 && 1 / b == Double.NEGATIVE_INFINITY) {
return b;
}
return a <= b ? a : b;
}
@GeneratedBy(MathNativeGenerator.class)
@NoSideEffects
private static native float maxImpl(double a, double b);
public static double max(double a, double b) { public static double max(double a, double b) {
return a > b ? a : b; if (PlatformDetector.isJavaScript()) {
return maxImpl(a, b);
} }
if (a != a) {
return a;
}
if (a == 0.0 && b == 0.0 && 1 / a == Double.NEGATIVE_INFINITY) {
return b;
}
return a >= b ? a : b;
}
@GeneratedBy(MathNativeGenerator.class)
@NoSideEffects
private static native float minImpl(float a, float b);
public static float min(float a, float b) { public static float min(float a, float b) {
return a < b ? a : b; if (PlatformDetector.isJavaScript()) {
return minImpl(a, b);
}
if (a != a) {
return a;
}
if (a == 0 && b == 0 && 1 / b == Float.NEGATIVE_INFINITY) {
return b;
}
return a <= b ? a : b;
} }
@GeneratedBy(MathNativeGenerator.class)
@NoSideEffects
private static native float maxImpl(float a, float b);
public static float max(float a, float b) { public static float max(float a, float b) {
return a > b ? a : b; if (PlatformDetector.isJavaScript()) {
return maxImpl(a, b);
}
if (a != a) {
return a;
}
if (a == 0 && b == 0 && 1 / a == Float.NEGATIVE_INFINITY) {
return b;
}
return a >= b ? a : b;
} }
public static int abs(int n) { public static int abs(int n) {

View File

@ -16,13 +16,20 @@
package org.teavm.classlib.java.lang; package org.teavm.classlib.java.lang;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.teavm.junit.TeaVMTestRunner; import org.teavm.junit.TeaVMTestRunner;
@RunWith(TeaVMTestRunner.class) @RunWith(TeaVMTestRunner.class)
public class MathTest { public class MathTest {
private static void sameDouble(double a, double b) {
assertEquals(Double.valueOf(a), Double.valueOf(b));
}
private static void sameFloat(float a, float b) {
assertEquals(Float.valueOf(a), Float.valueOf(b));
}
@Test @Test
public void sinComputed() { public void sinComputed() {
assertEquals(0.90929742682568, Math.sin(2), 1E-14); assertEquals(0.90929742682568, Math.sin(2), 1E-14);
@ -62,52 +69,50 @@ public class MathTest {
@Test @Test
public void testAbs() { public void testAbs() {
assertEquals(Float.valueOf(Float.POSITIVE_INFINITY), Float.valueOf(Math.abs(Float.NEGATIVE_INFINITY))); sameFloat(Float.POSITIVE_INFINITY, Math.abs(Float.NEGATIVE_INFINITY));
assertEquals(Double.valueOf(Double.POSITIVE_INFINITY), Double.valueOf(Math.abs(Double.NEGATIVE_INFINITY))); sameDouble(Double.POSITIVE_INFINITY, Math.abs(Double.NEGATIVE_INFINITY));
assertEquals(Double.valueOf(5.0), Double.valueOf(Math.abs(-5.0))); sameDouble(5.0, Math.abs(-5.0));
assertEquals(Double.valueOf(3.0), Double.valueOf(Math.abs(3.0))); sameDouble(3.0, Math.abs(3.0));
assertEquals(Double.valueOf(3.0), Double.valueOf(Math.abs(-3.0))); sameDouble(3.0, Math.abs(-3.0));
assertEquals(Double.valueOf(5.0), Double.valueOf(Math.abs(5.0))); sameDouble(5.0, Math.abs(5.0));
assertEquals(Float.valueOf(0.0f), Float.valueOf(Math.abs(-0.0f))); sameFloat(0.0f, Math.abs(-0.0f));
assertEquals(Float.valueOf(0.0f), Float.valueOf(Math.abs(0.0f))); sameFloat(0.0f, Math.abs(0.0f));
assertEquals(Double.valueOf(0.0), Double.valueOf(Math.abs(-0.0))); sameDouble(0.0, Math.abs(-0.0));
assertEquals(Double.valueOf(0.0), Double.valueOf(Math.abs(0.0))); sameDouble(0.0, Math.abs(0.0));
} }
@Test @Test
public void signumWorks() { public void signumWorks() {
assertEquals(Double.valueOf(1.0), Double.valueOf(Math.signum(3.0))); sameDouble(1.0, Math.signum(3.0));
assertEquals(Double.valueOf(-1.0), Double.valueOf(Math.signum(-4.0))); sameDouble(-1.0, Math.signum(-4.0));
assertEquals(Float.valueOf(1f), Float.valueOf(Math.signum(3f))); sameFloat(1f, Math.signum(3f));
assertEquals(Float.valueOf(-1f), Float.valueOf(Math.signum(-4f))); sameFloat(-1f, Math.signum(-4f));
assertEquals(Double.valueOf(0.0), Double.valueOf(Math.signum(0.0))); sameDouble(0.0, Math.signum(0.0));
assertEquals(Double.valueOf(-0.0), Double.valueOf(Math.signum(-0.0))); sameDouble(-0.0, Math.signum(-0.0));
assertTrue(Double.isNaN(Math.signum(Double.NaN))); sameDouble(Double.NaN, Math.signum(Double.NaN));
assertEquals(Float.valueOf(0.0f), Float.valueOf(Math.signum(0.0f))); sameFloat(0.0f, Math.signum(0.0f));
assertEquals(Float.valueOf(-0.0f), Float.valueOf(Math.signum(-0.0f))); sameFloat(-0.0f, Math.signum(-0.0f));
assertTrue(Float.isNaN(Math.signum(Float.NaN))); sameFloat(Float.NaN, Math.signum(Float.NaN));
assertEquals(Double.valueOf(-1.0), Double.valueOf(Math.signum(-Double.MIN_VALUE))); sameDouble(-1.0, Math.signum(-Double.MIN_VALUE));
assertEquals(Double.valueOf(1.0), Double.valueOf(Math.signum(Double.MIN_VALUE))); sameDouble(1.0, Math.signum(Double.MIN_VALUE));
assertEquals(Float.valueOf(-1), Float.valueOf(Math.signum(Float.NEGATIVE_INFINITY))); sameFloat((float) -1, Math.signum(Float.NEGATIVE_INFINITY));
assertEquals(Float.valueOf(1), Float.valueOf(Math.signum(Float.POSITIVE_INFINITY))); sameFloat(1F, Math.signum(Float.POSITIVE_INFINITY));
} }
@Test @Test
public void copySignWorks() { public void copySignWorks() {
assertEquals(Double.valueOf(1.0), Double.valueOf(Math.copySign(1.0, 0.0))); sameDouble(1.0, Math.copySign(1.0, 0.0));
assertEquals(Double.valueOf(-1.0), Double.valueOf(Math.copySign(1.0, -0.0))); sameDouble(-1.0, Math.copySign(1.0, -0.0));
assertEquals(Double.valueOf(1.0), Double.valueOf(Math.copySign(1.0, Double.NaN))); sameDouble(1.0, Math.copySign(1.0, Double.NaN));
assertEquals(Double.valueOf(Double.NaN), Double.valueOf(Math.copySign(Double.NaN, -1.0))); sameDouble(Double.NaN, Math.copySign(Double.NaN, -1.0));
assertEquals(Double.valueOf(Double.POSITIVE_INFINITY), sameDouble(Double.POSITIVE_INFINITY, Math.copySign(Double.NEGATIVE_INFINITY, 1.0));
Double.valueOf(Math.copySign(Double.NEGATIVE_INFINITY, 1.0))); sameFloat(1.0f, Math.copySign(1.0f, 0.0f));
assertEquals(Float.valueOf(1.0f), Float.valueOf(Math.copySign(1.0f, 0.0f))); sameFloat(-1.0f, Math.copySign(1.0f, -0.0f));
assertEquals(Float.valueOf(-1.0f), Float.valueOf(Math.copySign(1.0f, -0.0f))); sameFloat(1.0f, Math.copySign(1.0f, Float.NaN));
assertEquals(Float.valueOf(1.0f), Float.valueOf(Math.copySign(1.0f, Float.NaN))); sameFloat(Float.NaN, Math.copySign(Float.NaN, -1.0f));
assertEquals(Float.valueOf(Float.NaN), Float.valueOf(Math.copySign(Float.NaN, -1.0f))); sameFloat(Float.POSITIVE_INFINITY, Math.copySign(Float.NEGATIVE_INFINITY, 1.0f));
assertEquals(Float.valueOf(Float.POSITIVE_INFINITY),
Float.valueOf(Math.copySign(Float.NEGATIVE_INFINITY, 1.0f)));
} }
@Test @Test
@ -120,34 +125,34 @@ public class MathTest {
@Test @Test
public void nextWorks() { public void nextWorks() {
assertEquals(Double.valueOf(-Double.MIN_VALUE), Double.valueOf(Math.nextDown(0.0))); sameDouble(-Double.MIN_VALUE, Math.nextDown(0.0));
assertEquals(Double.valueOf(Double.MIN_VALUE), Double.valueOf(Math.nextUp(0.0))); sameDouble(Double.MIN_VALUE, Math.nextUp(0.0));
assertEquals(Double.valueOf(-Double.MIN_VALUE), Double.valueOf(Math.nextDown(-0.0))); sameDouble(-Double.MIN_VALUE, Math.nextDown(-0.0));
assertEquals(Double.valueOf(Double.MIN_VALUE), Double.valueOf(Math.nextUp(-0.0))); sameDouble(Double.MIN_VALUE, Math.nextUp(-0.0));
assertEquals(Float.valueOf(-Float.MIN_VALUE), Float.valueOf(Math.nextDown(0.0f))); sameFloat(-Float.MIN_VALUE, Math.nextDown(0.0f));
assertEquals(Float.valueOf(Float.MIN_VALUE), Float.valueOf(Math.nextUp(0.0f))); sameFloat(Float.MIN_VALUE, Math.nextUp(0.0f));
assertEquals(Float.valueOf(-Float.MIN_VALUE), Float.valueOf(Math.nextDown(-0.0f))); sameFloat(-Float.MIN_VALUE, Math.nextDown(-0.0f));
assertEquals(Float.valueOf(Float.MIN_VALUE), Float.valueOf(Math.nextUp(-0.0f))); sameFloat(Float.MIN_VALUE, Math.nextUp(-0.0f));
assertEquals(Double.valueOf(0.10000000000000002), Double.valueOf(Math.nextUp(0.1))); sameDouble(0.10000000000000002, Math.nextUp(0.1));
assertEquals(Double.valueOf(0.9999999999999999), Double.valueOf(Math.nextDown(1.0))); sameDouble(0.9999999999999999, Math.nextDown(1.0));
assertEquals(Double.valueOf(-0.09999999999999999), Double.valueOf(Math.nextUp(-0.1))); sameDouble(-0.09999999999999999, Math.nextUp(-0.1));
assertEquals(Double.valueOf(-1.0000000000000002), Double.valueOf(Math.nextDown(-1.0))); sameDouble(-1.0000000000000002, Math.nextDown(-1.0));
assertEquals(Float.valueOf(0.10000001f), Float.valueOf(Math.nextUp(0.1f))); sameFloat(0.10000001f, Math.nextUp(0.1f));
assertEquals(Float.valueOf(0.99999994f), Float.valueOf(Math.nextDown(1.0f))); sameFloat(0.99999994f, Math.nextDown(1.0f));
assertEquals(Float.valueOf(-0.099999994f), Float.valueOf(Math.nextUp(-0.1f))); sameFloat(-0.099999994f, Math.nextUp(-0.1f));
assertEquals(Float.valueOf(-1.0000001f), Float.valueOf(Math.nextDown(-1.0f))); sameFloat(-1.0000001f, Math.nextDown(-1.0f));
assertEquals(Float.valueOf(Float.NEGATIVE_INFINITY), Float.valueOf(Math.nextDown(Float.NEGATIVE_INFINITY))); sameFloat(Float.NEGATIVE_INFINITY, Math.nextDown(Float.NEGATIVE_INFINITY));
assertEquals(Float.valueOf(Float.intBitsToFloat(Float.floatToIntBits(Float.POSITIVE_INFINITY) - 1)), sameFloat(Float.intBitsToFloat(Float.floatToIntBits(Float.POSITIVE_INFINITY) - 1),
Float.valueOf(Math.nextDown(Float.POSITIVE_INFINITY))); Math.nextDown(Float.POSITIVE_INFINITY));
assertEquals(Float.valueOf(Float.POSITIVE_INFINITY), Float.valueOf(Math.nextUp(Float.POSITIVE_INFINITY))); sameFloat(Float.POSITIVE_INFINITY, Math.nextUp(Float.POSITIVE_INFINITY));
assertEquals(Float.valueOf(Float.intBitsToFloat(Float.floatToIntBits(Float.NEGATIVE_INFINITY) - 1)), sameFloat(Float.intBitsToFloat(Float.floatToIntBits(Float.NEGATIVE_INFINITY) - 1),
Float.valueOf(Math.nextUp(Float.NEGATIVE_INFINITY))); Math.nextUp(Float.NEGATIVE_INFINITY));
assertEquals(Double.valueOf(Double.NEGATIVE_INFINITY), Double.valueOf(Math.nextDown(Double.NEGATIVE_INFINITY))); sameDouble(Double.NEGATIVE_INFINITY, Math.nextDown(Double.NEGATIVE_INFINITY));
assertEquals(Double.valueOf(Double.longBitsToDouble(Double.doubleToLongBits(Double.POSITIVE_INFINITY) - 1)), sameDouble(Double.longBitsToDouble(Double.doubleToLongBits(Double.POSITIVE_INFINITY) - 1),
Double.valueOf(Math.nextDown(Double.POSITIVE_INFINITY))); Math.nextDown(Double.POSITIVE_INFINITY));
assertEquals(Double.valueOf(Double.POSITIVE_INFINITY), Double.valueOf(Math.nextUp(Double.POSITIVE_INFINITY))); sameDouble(Double.POSITIVE_INFINITY, Math.nextUp(Double.POSITIVE_INFINITY));
assertEquals(Double.valueOf(Double.longBitsToDouble(Double.doubleToLongBits(Double.NEGATIVE_INFINITY) - 1)), sameDouble(Double.longBitsToDouble(Double.doubleToLongBits(Double.NEGATIVE_INFINITY) - 1),
Double.valueOf(Math.nextUp(Double.NEGATIVE_INFINITY))); Math.nextUp(Double.NEGATIVE_INFINITY));
} }
@Test @Test
@ -165,4 +170,28 @@ public class MathTest {
assertEquals(1024, Math.getExponent(Double.NEGATIVE_INFINITY)); assertEquals(1024, Math.getExponent(Double.NEGATIVE_INFINITY));
assertEquals(1024, Math.getExponent(Double.NaN)); assertEquals(1024, Math.getExponent(Double.NaN));
} }
@Test
public void minMax() {
sameDouble(-1.0, Math.max(-2.0, -1.0));
sameDouble(-2.0, Math.min(-2.0, -1.0));
sameDouble(Double.NaN, Math.min(Double.NaN, Double.POSITIVE_INFINITY));
sameDouble(Double.NaN, Math.min(Double.POSITIVE_INFINITY, Double.NaN));
sameDouble(Double.NaN, Math.max(Double.NaN, Double.POSITIVE_INFINITY));
sameDouble(Double.NaN, Math.max(Double.POSITIVE_INFINITY, Double.NaN));
sameDouble(-0.0, Math.min(-0.0, 0.0));
sameDouble(-0.0, Math.min(0.0, -0.0));
sameDouble(0.0, Math.max(-0.0, 0.0));
sameDouble(0.0, Math.max(0.0, -0.0));
sameFloat(-1.0f, Math.max(-2.0f, -1.0f));
sameFloat(-2.0f, Math.min(-2.0f, -1.0f));
sameFloat(Float.NaN, Math.min(Float.NaN, Float.POSITIVE_INFINITY));
sameFloat(Float.NaN, Math.min(Float.POSITIVE_INFINITY, Float.NaN));
sameFloat(Float.NaN, Math.max(Float.NaN, Float.POSITIVE_INFINITY));
sameFloat(Float.NaN, Math.max(Float.POSITIVE_INFINITY, Float.NaN));
sameFloat(-0.0f, Math.min(-0.0f, 0.0f));
sameFloat(-0.0f, Math.min(0.0f, -0.0f));
sameFloat(0.0f, Math.max(-0.0f, 0.0f));
sameFloat(0.0f, Math.max(0.0f, -0.0f));
}
} }