classlib: make difference between raw and normal floating points to int conversion

This commit is contained in:
Ivan Hetman 2023-09-20 23:51:55 +03:00 committed by GitHub
parent 3b6b31ff8f
commit 8277671376
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 54 additions and 19 deletions

View File

@ -252,15 +252,18 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
@Unmanaged @Unmanaged
public static native boolean isFinite(double v); public static native boolean isFinite(double v);
public static long doubleToRawLongBits(double value) {
return doubleToLongBits(value);
}
@InjectedBy(DoubleGenerator.class) @InjectedBy(DoubleGenerator.class)
@Import(name = "teavm_reinterpretDoubleToLong") @Import(name = "teavm_reinterpretDoubleToLong")
@NoSideEffects @NoSideEffects
@Unmanaged @Unmanaged
public static native long doubleToLongBits(double value); public static native long doubleToRawLongBits(double value);
public static long doubleToLongBits(double value) {
if (isNaN(value)) {
return 0x7ff8000000000000L;
}
return doubleToRawLongBits(value);
}
@InjectedBy(DoubleGenerator.class) @InjectedBy(DoubleGenerator.class)
@Import(name = "teavm_reinterpretLongToDouble") @Import(name = "teavm_reinterpretLongToDouble")

View File

@ -256,15 +256,18 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
return compare(value, other.value); return compare(value, other.value);
} }
public static int floatToRawIntBits(float value) { @JSBody(params = "value", script = "return $rt_floatToRawIntBits(value);")
return floatToIntBits(value);
}
@JSBody(params = "value", script = "return $rt_floatToIntBits(value);")
@Import(name = "teavm_reinterpretFloatToInt") @Import(name = "teavm_reinterpretFloatToInt")
@NoSideEffects @NoSideEffects
@Unmanaged @Unmanaged
public static native int floatToIntBits(float value); public static native int floatToRawIntBits(float value);
public static int floatToIntBits(float value) {
if (isNaN(value)) {
return 0x7fc00000;
}
return floatToRawIntBits(value);
}
@JSBody(params = "bits", script = "return $rt_intBitsToFloat(bits);") @JSBody(params = "bits", script = "return $rt_intBitsToFloat(bits);")
@Import(name = "teavm_reinterpretIntToFloat") @Import(name = "teavm_reinterpretIntToFloat")

View File

@ -379,7 +379,7 @@ class TByteBufferImpl extends TByteBuffer {
@Override @Override
public TByteBuffer putDouble(double value) { public TByteBuffer putDouble(double value) {
return putLong(Double.doubleToLongBits(value)); return putLong(Double.doubleToRawLongBits(value));
} }
@Override @Override
@ -389,7 +389,7 @@ class TByteBufferImpl extends TByteBuffer {
@Override @Override
public TByteBuffer putDouble(int index, double value) { public TByteBuffer putDouble(int index, double value) {
return putLong(index, Double.doubleToLongBits(value)); return putLong(index, Double.doubleToRawLongBits(value));
} }
@Override @Override

View File

@ -658,10 +658,10 @@ function $rt_eraseClinit(target) {
var $rt_numberConversionView = new DataView(new ArrayBuffer(8)); var $rt_numberConversionView = new DataView(new ArrayBuffer(8));
var $rt_doubleToLongBits; var $rt_doubleToRawLongBits;
var $rt_longBitsToDouble; var $rt_longBitsToDouble;
if (typeof BigInt !== 'function') { if (typeof BigInt !== 'function') {
$rt_doubleToLongBits = function(n) { $rt_doubleToRawLongBits = function(n) {
$rt_numberConversionView.setFloat64(0, n, true); $rt_numberConversionView.setFloat64(0, n, true);
return new Long($rt_numberConversionView.getInt32(0, true), $rt_numberConversionView.getInt32(4, true)); return new Long($rt_numberConversionView.getInt32(0, true), $rt_numberConversionView.getInt32(4, true));
} }
@ -671,7 +671,7 @@ if (typeof BigInt !== 'function') {
return $rt_numberConversionView.getFloat64(0, true); return $rt_numberConversionView.getFloat64(0, true);
} }
} else { } else {
$rt_doubleToLongBits = function(n) { $rt_doubleToRawLongBits = function(n) {
$rt_numberConversionView.setFloat64(0, n, true); $rt_numberConversionView.setFloat64(0, n, true);
// For compatibility with Safari // For compatibility with Safari
var lo = $rt_numberConversionView.getInt32(0, true); var lo = $rt_numberConversionView.getInt32(0, true);
@ -688,7 +688,7 @@ if (typeof BigInt !== 'function') {
} }
} }
function $rt_floatToIntBits(n) { function $rt_floatToRawIntBits(n) {
$rt_numberConversionView.setFloat32(0, n); $rt_numberConversionView.setFloat32(0, n);
return $rt_numberConversionView.getInt32(0); return $rt_numberConversionView.getInt32(0);
} }

View File

@ -25,6 +25,8 @@ import org.teavm.junit.TeaVMTestRunner;
@RunWith(TeaVMTestRunner.class) @RunWith(TeaVMTestRunner.class)
public class DoubleTest { public class DoubleTest {
public static final double OTHER_NAN = Double.longBitsToDouble(Double.doubleToLongBits(Double.NaN) + 1);
@Test @Test
public void parsed() { public void parsed() {
assertEquals(23, Double.parseDouble("23"), 1E-12); assertEquals(23, Double.parseDouble("23"), 1E-12);
@ -60,7 +62,6 @@ public class DoubleTest {
public void testEquals() { public void testEquals() {
assertNotEquals(Double.valueOf(-0.0), Double.valueOf(0.0)); assertNotEquals(Double.valueOf(-0.0), Double.valueOf(0.0));
assertEquals(Double.valueOf(3.0), Double.valueOf(3.0)); assertEquals(Double.valueOf(3.0), Double.valueOf(3.0));
assertEquals(Double.valueOf(Double.NaN), Double.valueOf(Double.NaN));
assertEquals(Double.valueOf(Double.POSITIVE_INFINITY), Double.valueOf(Double.POSITIVE_INFINITY)); assertEquals(Double.valueOf(Double.POSITIVE_INFINITY), Double.valueOf(Double.POSITIVE_INFINITY));
assertNotEquals(Double.valueOf(Double.NEGATIVE_INFINITY), Double.valueOf(Double.POSITIVE_INFINITY)); assertNotEquals(Double.valueOf(Double.NEGATIVE_INFINITY), Double.valueOf(Double.POSITIVE_INFINITY));
assertEquals(Double.valueOf(Double.NEGATIVE_INFINITY), Double.valueOf(Double.NEGATIVE_INFINITY)); assertEquals(Double.valueOf(Double.NEGATIVE_INFINITY), Double.valueOf(Double.NEGATIVE_INFINITY));
@ -144,4 +145,16 @@ public class DoubleTest {
assertEquals(1, Double.compare(0.0, -0.0)); assertEquals(1, Double.compare(0.0, -0.0));
assertEquals(-1, Double.compare(-0.0, 0.0)); assertEquals(-1, Double.compare(-0.0, 0.0));
} }
@Test
public void testNaN() {
assertTrue(Double.isNaN(OTHER_NAN));
assertTrue(OTHER_NAN != OTHER_NAN);
assertTrue(OTHER_NAN != Double.NaN);
assertEquals(Double.valueOf(Double.NaN), Double.valueOf(Double.NaN));
assertEquals(Double.valueOf(OTHER_NAN), Double.valueOf(Double.NaN));
assertEquals(Double.valueOf(OTHER_NAN), Double.valueOf(OTHER_NAN));
assertNotEquals(Double.doubleToRawLongBits(OTHER_NAN), Double.doubleToRawLongBits(Double.NaN));
assertEquals(Double.doubleToLongBits(OTHER_NAN), Double.doubleToLongBits(Double.NaN));
}
} }

View File

@ -24,6 +24,8 @@ import org.teavm.junit.TeaVMTestRunner;
@RunWith(TeaVMTestRunner.class) @RunWith(TeaVMTestRunner.class)
public class FloatTest { public class FloatTest {
private static final float OTHER_NAN = Float.intBitsToFloat(Float.floatToIntBits(Float.NaN) + 1);
@Test @Test
public void parsed() { public void parsed() {
assertEquals(23, Float.parseFloat("23"), 1E-12F); assertEquals(23, Float.parseFloat("23"), 1E-12F);
@ -58,7 +60,6 @@ public class FloatTest {
public void testEquals() { public void testEquals() {
assertNotEquals(Float.valueOf(-0.0f), Float.valueOf(0.0f)); assertNotEquals(Float.valueOf(-0.0f), Float.valueOf(0.0f));
assertEquals(Float.valueOf(5.0f), Float.valueOf(5.0f)); assertEquals(Float.valueOf(5.0f), Float.valueOf(5.0f));
assertEquals(Float.valueOf(Float.NaN), Float.valueOf(Float.NaN));
assertEquals(Float.valueOf(Float.POSITIVE_INFINITY), Float.valueOf(Float.POSITIVE_INFINITY)); assertEquals(Float.valueOf(Float.POSITIVE_INFINITY), Float.valueOf(Float.POSITIVE_INFINITY));
assertNotEquals(Float.valueOf(Float.NEGATIVE_INFINITY), Float.valueOf(Float.POSITIVE_INFINITY)); assertNotEquals(Float.valueOf(Float.NEGATIVE_INFINITY), Float.valueOf(Float.POSITIVE_INFINITY));
assertEquals(Float.valueOf(Float.NEGATIVE_INFINITY), Float.valueOf(Float.NEGATIVE_INFINITY)); assertEquals(Float.valueOf(Float.NEGATIVE_INFINITY), Float.valueOf(Float.NEGATIVE_INFINITY));
@ -126,4 +127,16 @@ public class FloatTest {
assertEquals(1, Float.compare(0.0f, -0.0f)); assertEquals(1, Float.compare(0.0f, -0.0f));
assertEquals(-1, Float.compare(-0.0f, 0.0f)); assertEquals(-1, Float.compare(-0.0f, 0.0f));
} }
@Test
public void testNaN() {
assertTrue(Float.isNaN(OTHER_NAN));
assertTrue(OTHER_NAN != OTHER_NAN);
assertTrue(OTHER_NAN != Double.NaN);
assertEquals(Float.valueOf(Float.NaN), Float.valueOf(Float.NaN));
assertEquals(Float.valueOf(OTHER_NAN), Float.valueOf(Float.NaN));
assertEquals(Float.valueOf(OTHER_NAN), Float.valueOf(OTHER_NAN));
assertNotEquals(Float.floatToRawIntBits(OTHER_NAN), Float.floatToRawIntBits(Float.NaN));
assertEquals(Float.floatToIntBits(OTHER_NAN), Float.floatToIntBits(Float.NaN));
}
} }

View File

@ -29,6 +29,7 @@ import java.nio.InvalidMarkException;
import java.nio.ReadOnlyBufferException; import java.nio.ReadOnlyBufferException;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.teavm.classlib.java.lang.DoubleTest;
import org.teavm.junit.TeaVMTestRunner; import org.teavm.junit.TeaVMTestRunner;
import org.teavm.junit.WholeClassCompilation; import org.teavm.junit.WholeClassCompilation;
@ -632,6 +633,8 @@ public class ByteBufferTest {
buffer.putDouble(1, 2.0); buffer.putDouble(1, 2.0);
assertArrayEquals(new byte[] { 63, 64, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0 }, array); assertArrayEquals(new byte[] { 63, 64, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0 }, array);
buffer.putDouble(0, DoubleTest.OTHER_NAN);
assertArrayEquals(new byte[] { 127, -8, 0, 0, 0, 0, 0, 1, 0, 55, 0, 0, 0, 0, 0, 0 }, array);
} }
@Test @Test