Fixes some bugs. Adds test case for Double.doubleToLongBits()

This commit is contained in:
konsoletyper 2014-07-04 18:10:48 +04:00
parent fb4ec191d9
commit 947d88a647
7 changed files with 50 additions and 116 deletions

View File

@ -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();
}
int j = index;
for (int i = 0; i < string.length(); ++i) {
buffer[j++] = string.charAt(i);
}
length = j;
return this;
}

View File

@ -261,7 +261,7 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
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) {

View File

@ -263,7 +263,7 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
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) {

View File

@ -260,13 +260,13 @@ public class TBigDecimal extends Number implements Comparable<TBigDecimal>, 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<TBigDecimal>, 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<TBigDecimal>, 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<TBigDecimal>, 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<TBigDecimal>, 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<TBigDecimal>, 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<TBigDecimal>, 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)
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,18 +922,18 @@ public class TBigDecimal extends Number implements Comparable<TBigDecimal>, 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)
return new TBigDecimal(TMultiplication.multiplyByTenPow(this.getUnscaledValue(), diffScale)
.subtract(subtrahend.getUnscaledValue()), subtrahend.scale);
}
}
@ -961,8 +956,7 @@ public class TBigDecimal extends Number implements Comparable<TBigDecimal>, 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
@ -1001,13 +995,13 @@ public class TBigDecimal extends Number implements Comparable<TBigDecimal>, 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<TBigDecimal>, 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<TBigDecimal>, 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<TBigDecimal>, 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,8 +1142,7 @@ public class TBigDecimal extends Number implements Comparable<TBigDecimal>, 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(quotient.bitLength() < 63) {
@ -1168,18 +1155,17 @@ public class TBigDecimal extends Number implements Comparable<TBigDecimal>, 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<TBigDecimal>, 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<TBigDecimal>, 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 {

View File

@ -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));

View File

@ -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());

View File

@ -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)
*/