Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public static TDouble valueOf(String string) {
}

public static double parseDouble(String string) throws NumberFormatException {
// TODO: parse infinite and different radix
// TODO: parse different radix

if (string.isEmpty()) {
throw new NumberFormatException();
Expand All @@ -95,6 +95,7 @@ public static double parseDouble(String string) throws NumberFormatException {
while (string.charAt(end - 1) <= ' ') {
--end;
}
int endForNamedDouble = end; // InfinityF/f/D/d, NaNF/f/D/d cannot be parsed
if (string.charAt(end - 1) == 'f' || string.charAt(end - 1) == 'F'
|| string.charAt(end - 1) == 'd' || string.charAt(end - 1) == 'D') {
--end;
Expand All @@ -120,6 +121,16 @@ public static double parseDouble(String string) throws NumberFormatException {
if (c != '.') {
hasOneDigit = true;
if (c < '0' || c > '9') {
if (c == 'I') {
if (endForNamedDouble - index == 8 && string.regionMatches(false, index, "Infinity", 0, 8)) {
return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
}
}
if (c == 'N') {
if (endForNamedDouble - index == 3 && string.regionMatches(false, index, "NaN", 0, 3)) {
return NaN;
}
}
throw new NumberFormatException();
}
while (index < end && string.charAt(index) == '0') {
Expand Down Expand Up @@ -257,11 +268,9 @@ public boolean isInfinite() {
@Unmanaged
public static native boolean isNaN(double v);

@JSBody(params = "v", script = "return !isFinite(v);")
@Import(module = "teavm", name = "isinf")
@NoSideEffects
@Unmanaged
public static native boolean isInfinite(double v);
public static boolean isInfinite(double v) {
return !isFinite(v) && !isNaN(v);
}

@JSBody(params = "v", script = "return isFinite(v);")
@Import(module = "teavm", name = "isfinite")
Expand Down
21 changes: 15 additions & 6 deletions classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,9 @@ public static int hashCode(float f) {
@Unmanaged
public static native boolean isNaN(float v);

@JSBody(params = "v", script = "return !isFinite(v);")
@Import(module = "teavm", name = "isinf")
@NoSideEffects
@Unmanaged
public static native boolean isInfinite(float v);
public static boolean isInfinite(float v) {
return !isFinite(v) && !isNaN(v);
}

@JSBody(params = "v", script = "return isFinite(v);")
@Import(module = "teavm", name = "isfinite")
Expand All @@ -121,7 +119,7 @@ public static int hashCode(float f) {
public static native boolean isFinite(float v);

public static float parseFloat(String string) throws NumberFormatException {
// TODO: parse infinite and different radix
// TODO: parse different radix

if (string.isEmpty()) {
throw new NumberFormatException();
Expand All @@ -136,6 +134,7 @@ public static float parseFloat(String string) throws NumberFormatException {
while (string.charAt(end - 1) <= ' ') {
--end;
}
int endForNamedFloat = end; // InfinityF/f/D/d, NaNF/f/D/d cannot be parsed
if (string.charAt(end - 1) == 'f' || string.charAt(end - 1) == 'F'
|| string.charAt(end - 1) == 'd' || string.charAt(end - 1) == 'D') {
--end;
Expand All @@ -162,6 +161,16 @@ public static float parseFloat(String string) throws NumberFormatException {
if (c != '.') {
hasOneDigit = true;
if (c < '0' || c > '9') {
if (c == 'I') {
if (endForNamedFloat - index == 8 && string.regionMatches(false, index, "Infinity", 0, 8)) {
return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
}
}
if (c == 'N') {
if (endForNamedFloat - index == 3 && string.regionMatches(false, index, "NaN", 0, 3)) {
return NaN;
}
}
throw new NumberFormatException();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ public boolean isApplicable(MethodReference methodReference) {
switch (methodReference.getName()) {
case "getNaN":
case "isNaN":
case "isInfinite":
case "isFinite":
case "doubleToRawLongBits":
case "longBitsToDouble":
return true;
case "isInfinite":
default:
return false;
}
Expand All @@ -64,8 +64,6 @@ public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager mana
return new WasmFloat64Constant(Double.NaN);
case "isNaN":
return testNaN(manager.generate(invocation.getArguments().get(0)), manager);
case "isInfinite":
return testIsInfinite(manager.generate(invocation.getArguments().get(0)));
case "isFinite":
return testIsFinite(manager.generate(invocation.getArguments().get(0)));
case "doubleToRawLongBits": {
Expand Down Expand Up @@ -113,16 +111,6 @@ private WasmExpression testNaN(WasmExpression expression, WasmIntrinsicManager m
return block;
}

private WasmExpression testIsInfinite(WasmExpression expression) {
var conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false, expression);
conversion.setReinterpret(true);

var result = new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.AND,
conversion, new WasmInt64Constant(EXPONENT_BITS));
return new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.EQ, result,
new WasmInt64Constant(EXPONENT_BITS));
}

private WasmExpression testIsFinite(WasmExpression expression) {
var conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false, expression);
conversion.setReinterpret(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ public boolean isApplicable(MethodReference methodReference) {
switch (methodReference.getName()) {
case "getNaN":
case "isNaN":
case "isInfinite":
case "isFinite":
case "floatToRawIntBits":
case "intBitsToFloat":
return true;
case "isInfinite":
default:
return false;
}
Expand All @@ -63,8 +63,6 @@ public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager mana
return new WasmFloat32Constant(Float.NaN);
case "isNaN":
return testNaN(manager.generate(invocation.getArguments().get(0)), manager);
case "isInfinite":
return testIsInfinite(manager.generate(invocation.getArguments().get(0)));
case "isFinite":
return testIsFinite(manager.generate(invocation.getArguments().get(0)));
case "floatToRawIntBits": {
Expand Down Expand Up @@ -112,16 +110,6 @@ private WasmExpression testNaN(WasmExpression expression, WasmIntrinsicManager m
return block;
}

private WasmExpression testIsInfinite(WasmExpression expression) {
var conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false, expression);
conversion.setReinterpret(true);

var result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND,
conversion, new WasmInt32Constant(EXPONENT_BITS));
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ, result,
new WasmInt32Constant(EXPONENT_BITS));
}

private WasmExpression testIsFinite(WasmExpression expression) {
var conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false, expression);
conversion.setReinterpret(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext co
return new WasmFloat64Constant(Double.NaN);
case "isNaN":
return testNaN(context.generate(invocation.getArguments().get(0)), context);
case "isInfinite":
return testIsInfinite(context.generate(invocation.getArguments().get(0)));
case "isFinite":
return testIsFinite(context.generate(invocation.getArguments().get(0)));
case "doubleToRawLongBits": {
Expand Down Expand Up @@ -73,16 +71,6 @@ private WasmExpression testNaN(WasmExpression expression, WasmGCIntrinsicContext
return block;
}

private WasmExpression testIsInfinite(WasmExpression expression) {
var conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false, expression);
conversion.setReinterpret(true);

var result = new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.AND,
conversion, new WasmInt64Constant(EXPONENT_BITS));
return new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.EQ, result,
new WasmInt64Constant(EXPONENT_BITS));
}

private WasmExpression testIsFinite(WasmExpression expression) {
var conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false, expression);
conversion.setReinterpret(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext ma
return new WasmFloat32Constant(Float.NaN);
case "isNaN":
return testNaN(manager.generate(invocation.getArguments().get(0)), manager);
case "isInfinite":
return testIsInfinite(manager.generate(invocation.getArguments().get(0)));
case "isFinite":
return testIsFinite(manager.generate(invocation.getArguments().get(0)));
case "floatToRawIntBits": {
Expand Down Expand Up @@ -73,16 +71,6 @@ private WasmExpression testNaN(WasmExpression expression, WasmGCIntrinsicContext
return block;
}

private WasmExpression testIsInfinite(WasmExpression expression) {
var conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false, expression);
conversion.setReinterpret(true);

var result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND,
conversion, new WasmInt32Constant(EXPONENT_BITS));
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ, result,
new WasmInt32Constant(EXPONENT_BITS));
}

private WasmExpression testIsFinite(WasmExpression expression) {
var conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false, expression);
conversion.setReinterpret(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ private void fillFloat() {
var intrinsic = new FloatIntrinsic();
add(new MethodReference(Float.class, "getNaN", float.class), intrinsic);
add(new MethodReference(Float.class, "isNaN", float.class, boolean.class), intrinsic);
add(new MethodReference(Float.class, "isInfinite", float.class, boolean.class), intrinsic);
add(new MethodReference(Float.class, "isFinite", float.class, boolean.class), intrinsic);
add(new MethodReference(Float.class, "floatToRawIntBits", float.class, int.class), intrinsic);
add(new MethodReference(Float.class, "intBitsToFloat", int.class, float.class), intrinsic);
Expand All @@ -163,7 +162,6 @@ private void fillDouble() {
var intrinsic = new DoubleIntrinsic();
add(new MethodReference(Double.class, "getNaN", double.class), intrinsic);
add(new MethodReference(Double.class, "isNaN", double.class, boolean.class), intrinsic);
add(new MethodReference(Double.class, "isInfinite", double.class, boolean.class), intrinsic);
add(new MethodReference(Double.class, "isFinite", double.class, boolean.class), intrinsic);
add(new MethodReference(Double.class, "doubleToRawLongBits", double.class, long.class), intrinsic);
add(new MethodReference(Double.class, "longBitsToDouble", long.class, double.class), intrinsic);
Expand Down
39 changes: 39 additions & 0 deletions tests/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.teavm.classlib.java.lang;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
Expand Down Expand Up @@ -63,6 +64,15 @@ public void parsed() {
assertEquals(23, Double.parseDouble("23F"), 0.1f);
assertEquals(23, Double.parseDouble("23d"), 0.1f);
assertEquals(23, Double.parseDouble("23D"), 0.1f);

assertEquals(Double.POSITIVE_INFINITY, Double.parseDouble("Infinity"), 1E-12);
assertEquals(Double.POSITIVE_INFINITY, Double.parseDouble("+Infinity"), 1E-12);
assertEquals(Double.NEGATIVE_INFINITY, Double.parseDouble("-Infinity"), 1E-12);
assertEquals(Double.NEGATIVE_INFINITY, Double.parseDouble(" -Infinity "), 1E-12);
assertEquals(Double.NaN, Double.parseDouble("NaN"), 1E-12);
assertEquals(Double.NaN, Double.parseDouble("+NaN"), 1E-12);
assertEquals(Double.NaN, Double.parseDouble("-NaN"), 1E-12);
assertEquals(Double.NaN, Double.parseDouble(" -NaN "), 1E-12);
}

@Test
Expand Down Expand Up @@ -101,6 +111,23 @@ public void parsedWithError() {
checkIllegalFormat(".");
checkIllegalFormat("1e-");
checkIllegalFormat("1e");

checkIllegalFormat("++Infinity");
checkIllegalFormat("--Infinity");
checkIllegalFormat("INFINITY");
checkIllegalFormat("infinity");
checkIllegalFormat("InfinityF");
checkIllegalFormat("InfinityD");
checkIllegalFormat("Infinityf");
checkIllegalFormat("Infinityd");
checkIllegalFormat("++NaN");
checkIllegalFormat("--NaN");
checkIllegalFormat("NAN");
checkIllegalFormat("nan");
checkIllegalFormat("NaNF");
checkIllegalFormat("NaND");
checkIllegalFormat("NaNf");
checkIllegalFormat("NaNd");
}

private void checkIllegalFormat(String string) {
Expand Down Expand Up @@ -166,4 +193,16 @@ public void testNaN() {
assertNotEquals(Double.doubleToRawLongBits(OTHER_NAN), Double.doubleToRawLongBits(Double.NaN));
assertEquals(Double.doubleToLongBits(OTHER_NAN), Double.doubleToLongBits(Double.NaN));
}

@Test
public void testFinity() {
assertTrue(Double.isFinite(1d));
assertFalse(Double.isInfinite(1d));
assertFalse(Double.isFinite(Double.POSITIVE_INFINITY));
assertTrue(Double.isInfinite(Double.POSITIVE_INFINITY));
assertFalse(Double.isFinite(Double.NEGATIVE_INFINITY));
assertTrue(Double.isInfinite(Double.NEGATIVE_INFINITY));
assertFalse(Double.isFinite(Double.NaN));
assertFalse(Double.isInfinite(Double.NaN));
}
}
39 changes: 39 additions & 0 deletions tests/src/test/java/org/teavm/classlib/java/lang/FloatTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.teavm.classlib.java.lang;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
Expand Down Expand Up @@ -60,6 +61,15 @@ public void parsed() {
assertEquals(23, Float.parseFloat("23F"), 0.1f);
assertEquals(23, Float.parseFloat("23d"), 0.1f);
assertEquals(23, Float.parseFloat("23D"), 0.1f);

assertEquals(Float.POSITIVE_INFINITY, Float.parseFloat("Infinity"), 1E-12F);
assertEquals(Float.POSITIVE_INFINITY, Float.parseFloat("+Infinity"), 1E-12F);
assertEquals(Float.NEGATIVE_INFINITY, Float.parseFloat("-Infinity"), 1E-12F);
assertEquals(Float.NEGATIVE_INFINITY, Float.parseFloat(" -Infinity "), 1E-12F);
assertEquals(Float.NaN, Float.parseFloat("NaN"), 1E-12F);
assertEquals(Float.NaN, Float.parseFloat("+NaN"), 1E-12F);
assertEquals(Float.NaN, Float.parseFloat("-NaN"), 1E-12F);
assertEquals(Float.NaN, Float.parseFloat(" -NaN "), 1E-12F);
}

@Test
Expand All @@ -82,6 +92,23 @@ public void parsedWithError() {
checkIllegalFormat(".");
checkIllegalFormat("1e-");
checkIllegalFormat("1e");

checkIllegalFormat("++Infinity");
checkIllegalFormat("--Infinity");
checkIllegalFormat("INFINITY");
checkIllegalFormat("infinity");
checkIllegalFormat("InfinityF");
checkIllegalFormat("InfinityD");
checkIllegalFormat("Infinityf");
checkIllegalFormat("Infinityd");
checkIllegalFormat("++NaN");
checkIllegalFormat("--NaN");
checkIllegalFormat("NAN");
checkIllegalFormat("nan");
checkIllegalFormat("NaNF");
checkIllegalFormat("NaND");
checkIllegalFormat("NaNf");
checkIllegalFormat("NaNd");
}

private void checkIllegalFormat(String string) {
Expand Down Expand Up @@ -147,4 +174,16 @@ public void testNaN() {
assertNotEquals(Float.floatToRawIntBits(OTHER_NAN), Float.floatToRawIntBits(Float.NaN));
assertEquals(Float.floatToIntBits(OTHER_NAN), Float.floatToIntBits(Float.NaN));
}

@Test
public void testFinity() {
assertTrue(Float.isFinite(1f));
assertFalse(Float.isInfinite(1f));
assertFalse(Float.isFinite(Float.POSITIVE_INFINITY));
assertTrue(Float.isInfinite(Float.POSITIVE_INFINITY));
assertFalse(Float.isFinite(Float.NEGATIVE_INFINITY));
assertTrue(Float.isInfinite(Float.NEGATIVE_INFINITY));
assertFalse(Float.isFinite(Float.NaN));
assertFalse(Float.isInfinite(Float.NaN));
}
}
Loading