From 603d7f1f887a5162a761ff6cefd2e391f75dfde1 Mon Sep 17 00:00:00 2001 From: Ivan Hetman Date: Mon, 25 Sep 2023 16:56:43 +0300 Subject: [PATCH] classlib: distinguish between +0 and -0 in double stringifier, improve copySign implementation --- .../java/lang/TAbstractStringBuilder.java | 52 ++++++++++--------- .../org/teavm/classlib/java/lang/TMath.java | 20 +++---- .../teavm/classlib/java/lang/MathTest.java | 30 +++++++++++ .../classlib/java/lang/StringBuilderTest.java | 6 ++- 4 files changed, 70 insertions(+), 38 deletions(-) diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java index a5376cda9..4b261f748 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java @@ -194,18 +194,20 @@ class TAbstractStringBuilder implements TSerializable, TCharSequence { protected TAbstractStringBuilder insert(int target, float value) { if (value == 0) { - insertSpace(target, target + 3); - buffer[target++] = '0'; - buffer[target++] = '.'; - buffer[target++] = '0'; - return this; - } else if (value == -0) { - insertSpace(target, target + 4); - buffer[target++] = '-'; - buffer[target++] = '0'; - buffer[target++] = '.'; - buffer[target++] = '0'; - return this; + if (1 / value == Float.POSITIVE_INFINITY) { + insertSpace(target, target + 3); + buffer[target++] = '0'; + buffer[target++] = '.'; + buffer[target++] = '0'; + return this; + } else { + insertSpace(target, target + 4); + buffer[target++] = '-'; + buffer[target++] = '0'; + buffer[target++] = '.'; + buffer[target++] = '0'; + return this; + } } else if (Float.isNaN(value)) { insertSpace(target, target + 3); buffer[target++] = 'N'; @@ -330,18 +332,20 @@ class TAbstractStringBuilder implements TSerializable, TCharSequence { protected TAbstractStringBuilder insert(int target, double value) { if (value == 0) { - insertSpace(target, target + 3); - buffer[target++] = '0'; - buffer[target++] = '.'; - buffer[target++] = '0'; - return this; - } else if (value == -0) { - insertSpace(target, target + 4); - buffer[target++] = '-'; - buffer[target++] = '0'; - buffer[target++] = '.'; - buffer[target++] = '0'; - return this; + if (1 / value == Double.POSITIVE_INFINITY) { + insertSpace(target, target + 3); + buffer[target++] = '0'; + buffer[target++] = '.'; + buffer[target++] = '0'; + return this; + } else { + insertSpace(target, target + 4); + buffer[target++] = '-'; + buffer[target++] = '0'; + buffer[target++] = '.'; + buffer[target++] = '0'; + return this; + } } else if (Double.isNaN(value)) { insertSpace(target, target + 3); buffer[target++] = 'N'; 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 95c7b5977..d693bd410 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 @@ -344,29 +344,25 @@ public final class TMath extends TObject { } public static float copySign(float magnitude, float sign) { - if (sign == 0 || sign == -0) { - return sign; - } - return (sign > 0) == (magnitude > 0) ? magnitude : -magnitude; + return Float.intBitsToFloat((Float.floatToRawIntBits(sign) & Integer.MIN_VALUE) + | (Float.floatToRawIntBits(magnitude) & Integer.MAX_VALUE)); } public static double copySign(double magnitude, double sign) { - if (sign == 0 || sign == -0) { - return sign; - } - return (sign > 0) == (magnitude > 0) ? magnitude : -magnitude; + return Double.longBitsToDouble((Double.doubleToRawLongBits(sign) & Long.MIN_VALUE) + | (Double.doubleToRawLongBits(magnitude) & Long.MAX_VALUE)); } public static int getExponent(double d) { - long bits = TDouble.doubleToLongBits(d); + long bits = TDouble.doubleToRawLongBits(d); int exponent = (int) ((bits >> 52) & 0x7FF); return exponent - 1023; } public static int getExponent(float f) { - int bits = TFloat.floatToIntBits(f); - int exponent = (bits >> 23) & 0xF; - return exponent + 128; + int bits = TFloat.floatToRawIntBits(f); + int exponent = (bits >> 23) & 0xFF; + return exponent - 127; } public static double nextAfter(double start, double direction) { 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 0c15c914f..afab53c09 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 @@ -94,6 +94,20 @@ public class MathTest { assertEquals(Float.valueOf(1), Float.valueOf(Math.signum(Float.POSITIVE_INFINITY))); } + @Test + public void copySignWorks() { + assertEquals(Double.valueOf(1.0), Double.valueOf(Math.copySign(1.0, 0.0))); + assertEquals(Double.valueOf(-1.0), Double.valueOf(Math.copySign(1.0, -0.0))); + assertEquals(Double.valueOf(1.0), Double.valueOf(Math.copySign(1.0, Double.NaN))); + assertEquals(Double.valueOf(Double.NaN), Double.valueOf(Math.copySign(Double.NaN, -1.0))); + assertEquals(Double.valueOf(Double.POSITIVE_INFINITY), Double.valueOf(Math.copySign(Double.NEGATIVE_INFINITY, 1.0))); + assertEquals(Float.valueOf(1.0f), Float.valueOf(Math.copySign(1.0f, 0.0f))); + assertEquals(Float.valueOf(-1.0f), Float.valueOf(Math.copySign(1.0f, -0.0f))); + assertEquals(Float.valueOf(1.0f), Float.valueOf(Math.copySign(1.0f, Float.NaN))); + assertEquals(Float.valueOf(Float.NaN), Float.valueOf(Math.copySign(Float.NaN, -1.0f))); + assertEquals(Float.valueOf(Float.POSITIVE_INFINITY), Float.valueOf(Math.copySign(Float.NEGATIVE_INFINITY, 1.0f))); + } + @Test public void roundWorks() { assertEquals(1, Math.round(1.3)); @@ -133,4 +147,20 @@ public class MathTest { assertEquals(Double.valueOf(Double.longBitsToDouble(Double.doubleToLongBits(Double.NEGATIVE_INFINITY) - 1)), Double.valueOf(Math.nextUp(Double.NEGATIVE_INFINITY))); } + + @Test + public void exponentWorks() { + assertEquals(0, Math.getExponent(1.0f)); + assertEquals(-127, Math.getExponent(Float.MIN_VALUE)); + assertEquals(127, Math.getExponent(Float.MAX_VALUE)); + assertEquals(128, Math.getExponent(Float.POSITIVE_INFINITY)); + assertEquals(128, Math.getExponent(Float.NEGATIVE_INFINITY)); + assertEquals(128, Math.getExponent(Float.NaN)); + assertEquals(0, Math.getExponent(1.0)); + assertEquals(-1023, Math.getExponent(Double.MIN_VALUE)); + assertEquals(1023, Math.getExponent(Double.MAX_VALUE)); + assertEquals(1024, Math.getExponent(Double.POSITIVE_INFINITY)); + assertEquals(1024, Math.getExponent(Double.NEGATIVE_INFINITY)); + assertEquals(1024, Math.getExponent(Double.NaN)); + } } diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java index f2710dc81..266ef4725 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java @@ -78,13 +78,14 @@ public class StringBuilderTest { .append(" ").append(1200f) .append(" ").append(0.023f) .append(" ").append(0f) + .append(" ").append(-0.0f) .append(" ").append(1f) .append(" ").append(Float.NaN) .append(" ").append(Float.POSITIVE_INFINITY) .append(" ").append(Float.NEGATIVE_INFINITY); assertEquals("1.234E25 9.8765E30 -1.234E25 -9.8765E30 3.402823E38" + " 1.234E-25 9.8764E-30 -1.234E-25 -9.8764E-30 1.17549E-38" - + " 1200.0 0.023 0.0 1.0 NaN Infinity -Infinity", sb.toString()); + + " 1200.0 0.023 0.0 -0.0 1.0 NaN Infinity -Infinity", sb.toString()); } @Test @@ -107,6 +108,7 @@ public class StringBuilderTest { .append(" ").append(1200.0) .append(" ").append(0.023) .append(" ").append(0.0) + .append(" ").append(-0.0) .append(" ").append(1.0) .append(" ").append(Double.NaN) .append(" ").append(Double.POSITIVE_INFINITY) @@ -114,7 +116,7 @@ public class StringBuilderTest { assertEquals("1.23456789E150 10.0 20.0 100.0 1000.0 0.1 0.01 1.0E20 2.0E20 1.0E-12" + " -1.23456789E150 1.23456789E-150 1.79769313486231E308 3.0E-308" + " 1200.0 0.023" - + " 0.0 1.0 NaN Infinity -Infinity", sb.toString()); + + " 0.0 -0.0 1.0 NaN Infinity -Infinity", sb.toString()); } @Test