From 947d88a6477acfb4d60f9c08525052ab6e270d76 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Fri, 4 Jul 2014 18:10:48 +0400 Subject: [PATCH] Fixes some bugs. Adds test case for Double.doubleToLongBits() --- .../java/lang/TAbstractStringBuilder.java | 9 +- .../org/teavm/classlib/java/lang/TDouble.java | 2 +- .../org/teavm/classlib/java/lang/TFloat.java | 2 +- .../teavm/classlib/java/math/TBigDecimal.java | 87 ++++++++----------- .../teavm/classlib/java/lang/DoubleTest.java | 5 ++ .../java/math/BigDecimalConstructorsTest.java | 5 +- .../java/math/BigDecimalConvertTest.java | 56 +----------- 7 files changed, 50 insertions(+), 116 deletions(-) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java index af4fdf755..3648b5382 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java @@ -82,17 +82,14 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ return this; } ensureCapacity(length + string.length()); - if (index < length) { - for (int i = length - 1; i >= index; --i) { - buffer[i + string.length()] = buffer[i]; - } - length += string.length(); + for (int i = length - 1; i >= index; --i) { + buffer[i + string.length()] = buffer[i]; } + length += string.length(); int j = index; for (int i = 0; i < string.length(); ++i) { buffer[j++] = string.charAt(i); } - length = j; return this; } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java index 498292f88..c4c31a5a9 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java @@ -261,7 +261,7 @@ public class TDouble extends TNumber implements TComparable { doubleMantissa = abs * 0x1p1022 * binaryExponent(negExp - 1022); } long mantissa = (long)(doubleMantissa + 0.5) & 0xFFFFFFFFFFFFFL; - return mantissa | ((exp + 1023L) << 52) | ((value < 0 || 1 / value == NEGATIVE_INFINITY) ? (1L << 63) : 0); + return mantissa | ((exp + 1023L) << 52) | (value < 0 || 1 / value == NEGATIVE_INFINITY ? (1L << 63) : 0); } public static double longBitsToDouble(long bits) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java index c2f78ef21..6e226e54b 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java @@ -263,7 +263,7 @@ public class TFloat extends TNumber implements TComparable { doubleMantissa = abs * 0x1p126f * binaryExponent(negExp - 126); } int mantissa = (int)(doubleMantissa + 0.5f) & 0x7FFFFF; - return mantissa | ((exp + 127) << 23) | (value < 0 ? (1 << 31) : 0); + return mantissa | ((exp + 127) << 23) | (value < 0 || 1 / value == NEGATIVE_INFINITY ? (1 << 31) : 0); } public static float intBitsToFloat(int bits) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/math/TBigDecimal.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/math/TBigDecimal.java index e2f3d1e95..0a97fa3cd 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/math/TBigDecimal.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/math/TBigDecimal.java @@ -260,13 +260,13 @@ public class TBigDecimal extends Number implements Comparable, Seri */ private transient int precision = 0; - private TBigDecimal(long smallValue, int scale){ + private TBigDecimal(long smallValue, int scale) { this.smallValue = smallValue; this.scale = scale; this.bitLength = bitLength(smallValue); } - private TBigDecimal(int smallValue, int scale){ + private TBigDecimal(int smallValue, int scale) { this.smallValue = smallValue; this.scale = scale; this.bitLength = bitLength(smallValue); @@ -511,7 +511,7 @@ public class TBigDecimal extends Number implements Comparable, Seri */ public TBigDecimal(double val) { if (Double.isInfinite(val) || Double.isNaN(val)) { - throw new NumberFormatException("Infinity or NaN"); + throw new NumberFormatException("Infinite or NaN"); } long bits = Double.doubleToLongBits(val); // IEEE-754 long mantisa; @@ -519,8 +519,7 @@ public class TBigDecimal extends Number implements Comparable, Seri // Extracting the exponent, note that the bias is 1023 scale = 1075 - (int)((bits >> 52) & 0x7FFL); // Extracting the 52 bits of the mantisa. - mantisa = (scale == 1075) ? (bits & 0xFFFFFFFFFFFFFL) << 1 - : (bits & 0xFFFFFFFFFFFFFL) | 0x10000000000000L; + mantisa = scale == 1075 ? (bits & 0xFFFFFFFFFFFFFL) << 1 : (bits & 0xFFFFFFFFFFFFFL) | 0x10000000000000L; if (mantisa == 0) { scale = 0; precision = 1; @@ -546,8 +545,7 @@ public class TBigDecimal extends Number implements Comparable, Seri scale = 0; } else if (scale > 0) { // m * 2^e = (m * 5^(-e)) * 10^e - if(scale < LONG_FIVE_POW.length - && mantisaBits+LONG_FIVE_POW_BIT_LENGTH[scale] < 64) { + if(scale < LONG_FIVE_POW.length && mantisaBits + LONG_FIVE_POW_BIT_LENGTH[scale] < 64) { smallValue = mantisa * LONG_FIVE_POW[scale]; bitLength = bitLength(smallValue); } else { @@ -832,8 +830,8 @@ public class TBigDecimal extends Number implements Comparable, Seri private static TBigDecimal addAndMult10(TBigDecimal thisValue,TBigDecimal augend, int diffScale) { if(diffScale < LONG_TEN_POW.length && - Math.max(thisValue.bitLength,augend.bitLength+LONG_TEN_POW_BIT_LENGTH[diffScale])+1<64) { - return valueOf(thisValue.smallValue+augend.smallValue*LONG_TEN_POW[diffScale],thisValue.scale); + Math.max(thisValue.bitLength, augend.bitLength + LONG_TEN_POW_BIT_LENGTH[diffScale]) + 1 < 64) { + return valueOf(thisValue.smallValue + augend.smallValue * LONG_TEN_POW[diffScale], thisValue.scale); } return new TBigDecimal(thisValue.getUnscaledValue().add( TMultiplication.multiplyByTenPow(augend.getUnscaledValue(),diffScale)), thisValue.scale); @@ -858,8 +856,7 @@ public class TBigDecimal extends Number implements Comparable, Seri long diffScale = (long)this.scale - augend.scale; int largerSignum; // Some operand is zero or the precision is infinity - if ((augend.isZero()) || (this.isZero()) - || (mc.getPrecision() == 0)) { + if ((augend.isZero()) || (this.isZero()) || (mc.getPrecision() == 0)) { return add(augend).round(mc); } // Cases where there is room for optimizations @@ -879,13 +876,11 @@ public class TBigDecimal extends Number implements Comparable, Seri // Cases where it's unnecessary to add two numbers with very different scales largerSignum = larger.signum(); if (largerSignum == smaller.signum()) { - tempBI = TMultiplication.multiplyByPositiveInt(larger.getUnscaledValue(),10) - .add(TBigInteger.valueOf(largerSignum)); + tempBI = TMultiplication.multiplyByPositiveInt(larger.getUnscaledValue(), 10) + .add(TBigInteger.valueOf(largerSignum)); } else { - tempBI = larger.getUnscaledValue().subtract( - TBigInteger.valueOf(largerSignum)); - tempBI = TMultiplication.multiplyByPositiveInt(tempBI,10) - .add(TBigInteger.valueOf(largerSignum * 9)); + tempBI = larger.getUnscaledValue().subtract(TBigInteger.valueOf(largerSignum)); + tempBI = TMultiplication.multiplyByPositiveInt(tempBI, 10).add(TBigInteger.valueOf(largerSignum * 9)); } // Rounding the improved adding larger = new TBigDecimal(tempBI, larger.scale + 1); @@ -927,19 +922,19 @@ public class TBigDecimal extends Number implements Comparable, Seri } else if (diffScale > 0) { // case s1 > s2 : [ u1 - u2 * 10 ^ (s1 - s2) , s1 ] if(diffScale < LONG_TEN_POW.length && - Math.max(this.bitLength,subtrahend.bitLength+LONG_TEN_POW_BIT_LENGTH[diffScale])+1<64) { - return valueOf(this.smallValue-subtrahend.smallValue*LONG_TEN_POW[diffScale],this.scale); + Math.max(this.bitLength, subtrahend.bitLength + LONG_TEN_POW_BIT_LENGTH[diffScale]) + 1 < 64) { + return valueOf(this.smallValue - subtrahend.smallValue * LONG_TEN_POW[diffScale], this.scale); } return new TBigDecimal(this.getUnscaledValue().subtract( TMultiplication.multiplyByTenPow(subtrahend.getUnscaledValue(),diffScale)), this.scale); } else {// case s2 > s1 : [ u1 * 10 ^ (s2 - s1) - u2 , s2 ] diffScale = -diffScale; if(diffScale < LONG_TEN_POW.length && - Math.max(this.bitLength+LONG_TEN_POW_BIT_LENGTH[diffScale],subtrahend.bitLength)+1<64) { - return valueOf(this.smallValue*LONG_TEN_POW[diffScale]-subtrahend.smallValue,subtrahend.scale); + Math.max(this.bitLength + LONG_TEN_POW_BIT_LENGTH[diffScale], subtrahend.bitLength) + 1 < 64) { + return valueOf(this.smallValue * LONG_TEN_POW[diffScale] - subtrahend.smallValue,subtrahend.scale); } - return new TBigDecimal(TMultiplication.multiplyByTenPow(this.getUnscaledValue(),diffScale) - .subtract(subtrahend.getUnscaledValue()), subtrahend.scale); + return new TBigDecimal(TMultiplication.multiplyByTenPow(this.getUnscaledValue(), diffScale) + .subtract(subtrahend.getUnscaledValue()), subtrahend.scale); } } @@ -961,8 +956,7 @@ public class TBigDecimal extends Number implements Comparable, Seri TBigDecimal leftOperand; // it will be only the left operand (this) TBigInteger tempBI; // Some operand is zero or the precision is infinity - if ((subtrahend.isZero()) || (this.isZero()) - || (mc.getPrecision() == 0)) { + if (subtrahend.isZero() || isZero() || mc.getPrecision() == 0) { return subtract(subtrahend).round(mc); } // Now: this != 0 and subtrahend != 0 @@ -972,11 +966,11 @@ public class TBigDecimal extends Number implements Comparable, Seri thisSignum = this.signum(); if (thisSignum != subtrahend.signum()) { tempBI = TMultiplication.multiplyByPositiveInt(this.getUnscaledValue(), 10) - .add(TBigInteger.valueOf(thisSignum)); + .add(TBigInteger.valueOf(thisSignum)); } else { tempBI = this.getUnscaledValue().subtract(TBigInteger.valueOf(thisSignum)); tempBI = TMultiplication.multiplyByPositiveInt(tempBI, 10) - .add(TBigInteger.valueOf(thisSignum * 9)); + .add(TBigInteger.valueOf(thisSignum * 9)); } // Rounding the improved subtracting leftOperand = new TBigDecimal(tempBI, this.scale + 1); @@ -1001,13 +995,13 @@ public class TBigDecimal extends Number implements Comparable, Seri public TBigDecimal multiply(TBigDecimal multiplicand) { long newScale = (long)this.scale + multiplicand.scale; - if ((this.isZero()) || (multiplicand.isZero())) { + if (isZero() || multiplicand.isZero()) { return zeroScaledBy(newScale); } /* Let be: this = [u1,s1] and multiplicand = [u2,s2] so: * this x multiplicand = [ s1 * s2 , s1 + s2 ] */ if(this.bitLength + multiplicand.bitLength < 64) { - return valueOf(this.smallValue*multiplicand.smallValue,toIntScale(newScale)); + return valueOf(this.smallValue*multiplicand.smallValue, toIntScale(newScale)); } return new TBigDecimal(this.getUnscaledValue().multiply( multiplicand.getUnscaledValue()), toIntScale(newScale)); @@ -1096,10 +1090,7 @@ public class TBigDecimal extends Number implements Comparable, Seri long diffScale = ((long)this.scale - divisor.scale) - scale; if(this.bitLength < 64 && divisor.bitLength < 64 ) { if(diffScale == 0) { - return dividePrimitiveLongs(this.smallValue, - divisor.smallValue, - scale, - roundingMode ); + return dividePrimitiveLongs(this.smallValue, divisor.smallValue, scale, roundingMode); } else if(diffScale > 0) { if(diffScale < LONG_TEN_POW.length && divisor.bitLength + LONG_TEN_POW_BIT_LENGTH[(int)diffScale] < 64) { @@ -1112,11 +1103,8 @@ public class TBigDecimal extends Number implements Comparable, Seri if(-diffScale < LONG_TEN_POW.length && this.bitLength + LONG_TEN_POW_BIT_LENGTH[(int)-diffScale] < 64) { return dividePrimitiveLongs(this.smallValue*LONG_TEN_POW[(int)-diffScale], - divisor.smallValue, - scale, - roundingMode); + divisor.smallValue, scale, roundingMode); } - } } TBigInteger scaledDividend = this.getUnscaledValue(); @@ -1132,8 +1120,8 @@ public class TBigDecimal extends Number implements Comparable, Seri return divideBigIntegers(scaledDividend, scaledDivisor, scale, roundingMode); } - private static TBigDecimal divideBigIntegers(TBigInteger scaledDividend, TBigInteger scaledDivisor, int scale, TRoundingMode roundingMode) { - + private static TBigDecimal divideBigIntegers(TBigInteger scaledDividend, TBigInteger scaledDivisor, int scale, + TRoundingMode roundingMode) { TBigInteger[] quotAndRem = scaledDividend.divideAndRemainder(scaledDivisor); // quotient and remainder // If after division there is a remainder... TBigInteger quotient = quotAndRem[0]; @@ -1154,10 +1142,9 @@ public class TBigDecimal extends Number implements Comparable, Seri } else { // Checking if: remainder * 2 >= scaledDivisor compRem = remainder.abs().shiftLeftOneBit().compareTo(scaledDivisor.abs()); - compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0, - sign * (5 + compRem), roundingMode); + compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0, sign * (5 + compRem), roundingMode); } - if (compRem != 0) { + if (compRem != 0) { if(quotient.bitLength() < 63) { return valueOf(quotient.longValue() + compRem,scale); } @@ -1168,18 +1155,17 @@ public class TBigDecimal extends Number implements Comparable, Seri return new TBigDecimal(quotient, scale); } - private static TBigDecimal dividePrimitiveLongs(long scaledDividend, long scaledDivisor, int scale, TRoundingMode roundingMode) { + private static TBigDecimal dividePrimitiveLongs(long scaledDividend, long scaledDivisor, int scale, + TRoundingMode roundingMode) { long quotient = scaledDividend / scaledDivisor; long remainder = scaledDividend % scaledDivisor; - int sign = Long.signum( scaledDividend ) * Long.signum( scaledDivisor ); + int sign = Long.signum( scaledDividend ) * Long.signum(scaledDivisor); if (remainder != 0) { // Checking if: remainder * 2 >= scaledDivisor int compRem; // 'compare to remainder' - compRem = longCompareTo(Math.abs(remainder) << 1,Math.abs(scaledDivisor)); + compRem = longCompareTo(Math.abs(remainder) << 1, Math.abs(scaledDivisor)); // To look if there is a carry - quotient += roundingBehavior(((int)quotient) & 1, - sign * (5 + compRem), - roundingMode); + quotient += roundingBehavior(((int)quotient) & 1, sign * (5 + compRem), roundingMode); } // Constructing the result with the appropriate unscaled value return valueOf(quotient, scale); @@ -1333,8 +1319,7 @@ public class TBigDecimal extends Number implements Comparable, Seri public TBigDecimal divide(TBigDecimal divisor, TMathContext mc) { /* Calculating how many zeros must be append to 'dividend' * to obtain a quotient with at least 'mc.precision()' digits */ - long traillingZeros = mc.getPrecision() + 2L - + divisor.aproxPrecision() - aproxPrecision(); + long traillingZeros = mc.getPrecision() + 2L + divisor.aproxPrecision() - aproxPrecision(); long diffScale = (long)scale - divisor.scale; long newScale = diffScale; // scale of the final quotient int compRem; // to compare the remainder @@ -2293,7 +2278,7 @@ public class TBigDecimal extends Number implements Comparable, Seri if (exponent >= 0) { result.insert(end - scale, '.'); } else { - result.insert(begin - 1, "0."); //$NON-NLS-1$ + result.insert(begin - 1, "0."); result.insert(begin + 1, CH_ZEROS, 0, -(int)exponent - 1); } } else { diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java index 6c89e7469..36edba86e 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java @@ -54,6 +54,11 @@ public class DoubleTest { assertEquals(0x41E23456789ABCDEL, Double.doubleToLongBits(0x1.23456789ABCDEP+31)); } + @Test + public void longBitsExtracted2() { + assertEquals(0x3FE1C28F5C28F5C3L, TDouble.doubleToLongBits(0.555)); + } + @Test public void subNormalLongBitsExtracted() { assertEquals(0x00000056789ABCDEL, Double.doubleToLongBits(0x0.00056789ABCDEP-1022)); diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/math/BigDecimalConstructorsTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/math/BigDecimalConstructorsTest.java index e85f30f4e..abd1fbe00 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/java/math/BigDecimalConstructorsTest.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/math/BigDecimalConstructorsTest.java @@ -258,8 +258,7 @@ public class BigDecimalConstructorsTest { new BigDecimal(a); fail("NumberFormatException has not been caught"); } catch (NumberFormatException e) { - assertEquals("Improper exception message", "Infinite or NaN", e - .getMessage()); + assertEquals("Improper exception message", "Infinite or NaN", e.getMessage()); } } @@ -342,7 +341,7 @@ public class BigDecimalConstructorsTest { public void testConstrDouble02() { double a = 0.555; int aScale = 53; - BigInteger bA = new BigInteger("55500000000000004884981308350688777863979339599609375"); + TBigInteger bA = new TBigInteger("55500000000000004884981308350688777863979339599609375"); BigDecimal aNumber = new BigDecimal(a); assertEquals("incorrect value", bA, aNumber.unscaledValue()); assertEquals("incorrect scale", aScale, aNumber.scale()); diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/math/BigDecimalConvertTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/math/BigDecimalConvertTest.java index 6f25bfc82..e8c48b236 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/java/math/BigDecimalConvertTest.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/math/BigDecimalConvertTest.java @@ -152,7 +152,7 @@ public class BigDecimalConvertTest { BigDecimal aNumber = new BigDecimal(a); int minusZero = -2147483648; float result = aNumber.floatValue(); - assertTrue("incorrect value", Float.floatToIntBits(result) == minusZero); + assertEquals("incorrect value", Float.floatToIntBits(result), minusZero); } /** @@ -478,7 +478,7 @@ public class BigDecimalConvertTest { String a = "-123.4564563673567380964839238475457356735674573563567890295784902768787678287E-5"; BigDecimal aNumber = new BigDecimal(a); String result = "-0.001234564563673567380964839238475457356735674573563567890295784902768787678287"; - assertTrue("incorrect value", aNumber.toString().equals(result)); + assertEquals("incorrect value", result, aNumber.toString()); } /** @@ -551,58 +551,6 @@ public class BigDecimalConvertTest { assertTrue("incorrect value", aNumber.toString().equals(result)); } - /** - * Create a BigDecimal from a negative double value - */ - @Test - public void testValueOfDoubleNeg() { - double a = -65678765876567576.98788767; - BigDecimal result = BigDecimal.valueOf(a); - String res = "-65678765876567576"; - int resScale = 0; - assertEquals("incorrect value", res, result.toString()); - assertEquals("incorrect scale", resScale, result.scale()); - } - - /** - * Create a BigDecimal from a positive double value - */ - @Test - public void testValueOfDoublePos1() { - double a = 65678765876567576.98788767; - BigDecimal result = BigDecimal.valueOf(a); - String res = "65678765876567576"; - int resScale = 0; - assertEquals("incorrect value", res, result.toString()); - assertEquals("incorrect scale", resScale, result.scale()); - } - - /** - * Create a BigDecimal from a positive double value - */ - @Test - public void testValueOfDoublePos2() { - double a = 12321237576.98788767; - BigDecimal result = BigDecimal.valueOf(a); - String res = "12321237576.987888"; - int resScale = 6; - assertEquals("incorrect value", res, result.toString()); - assertEquals("incorrect scale", resScale, result.scale()); - } - - /** - * Create a BigDecimal from a positive double value - */ - @Test - public void testValueOfDoublePos3() { - double a = 12321237576.9878838; - BigDecimal result = BigDecimal.valueOf(a); - String res = "12321237576.987885"; - int resScale = 6; - assertEquals("incorrect value", res, result.toString()); - assertEquals("incorrect scale", resScale, result.scale()); - } - /** * valueOf(Double.NaN) */