7032154: Performance tuning of sun.misc.FloatingDecimal/FormattedFloatingDecimal

Performance improvements for double/float -> String and decimal/hex String -> double/float conversions.

Co-authored-by: Sergey Kuksenko <sergey.kuksenko@oracle.com>
Co-authored-by: Dmitry Nadezhin <dmitry.nadezhin@oracle.com>
Co-authored-by: Olivier Lagneau <olivier.lagneau@oracle.com>
Reviewed-by: martin, iris
This commit is contained in:
Brian Burkhalter 2013-06-05 21:01:02 -07:00
parent 854a6b898f
commit a1fe63768f
11 changed files with 5737 additions and 3938 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -689,7 +689,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @return a reference to this object.
*/
public AbstractStringBuilder append(float f) {
new FloatingDecimal(f).appendTo(this);
FloatingDecimal.appendTo(f,this);
return this;
}
@ -706,7 +706,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @return a reference to this object.
*/
public AbstractStringBuilder append(double d) {
new FloatingDecimal(d).appendTo(this);
FloatingDecimal.appendTo(d,this);
return this;
}

View File

@ -201,7 +201,7 @@ public final class Double extends Number implements Comparable<Double> {
* @return a string representation of the argument.
*/
public static String toString(double d) {
return new FloatingDecimal(d).toJavaFormatString();
return FloatingDecimal.toJavaFormatString(d);
}
/**
@ -509,7 +509,7 @@ public final class Double extends Number implements Comparable<Double> {
* parsable number.
*/
public static Double valueOf(String s) throws NumberFormatException {
return new Double(FloatingDecimal.readJavaFormatString(s).doubleValue());
return new Double(parseDouble(s));
}
/**
@ -545,7 +545,7 @@ public final class Double extends Number implements Comparable<Double> {
* @since 1.2
*/
public static double parseDouble(String s) throws NumberFormatException {
return FloatingDecimal.readJavaFormatString(s).doubleValue();
return FloatingDecimal.parseDouble(s);
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -203,7 +203,7 @@ public final class Float extends Number implements Comparable<Float> {
* @return a string representation of the argument.
*/
public static String toString(float f) {
return new FloatingDecimal(f).toJavaFormatString();
return FloatingDecimal.toJavaFormatString(f);
}
/**
@ -421,7 +421,7 @@ public final class Float extends Number implements Comparable<Float> {
* parsable number.
*/
public static Float valueOf(String s) throws NumberFormatException {
return new Float(FloatingDecimal.readJavaFormatString(s).floatValue());
return new Float(parseFloat(s));
}
/**
@ -456,7 +456,7 @@ public final class Float extends Number implements Comparable<Float> {
* @since 1.2
*/
public static float parseFloat(String s) throws NumberFormatException {
return FloatingDecimal.readJavaFormatString(s).floatValue();
return FloatingDecimal.parseFloat(s);
}
/**

View File

@ -271,7 +271,7 @@ final class DigitList implements Cloneable {
* @param maximumFractionDigits The most fractional digits which should
* be converted.
*/
public final void set(boolean isNegative, double source, int maximumFractionDigits) {
final void set(boolean isNegative, double source, int maximumFractionDigits) {
set(isNegative, source, maximumFractionDigits, true);
}
@ -288,10 +288,11 @@ final class DigitList implements Cloneable {
*/
final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
FloatingDecimal fd = new FloatingDecimal(source);
boolean hasBeenRoundedUp = fd.digitsRoundedUp();
boolean allDecimalDigits = fd.decimalDigitsExact();
String digitsString = fd.toJavaFormatString();
FloatingDecimal.BinaryToASCIIConverter fdConverter = FloatingDecimal.getBinaryToASCIIConverter(source);
boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp();
boolean allDecimalDigits = fdConverter.decimalDigitsExact();
assert !fdConverter.isExceptional();
String digitsString = fdConverter.toJavaFormatString();
set(isNegative, digitsString,
hasBeenRoundedUp, allDecimalDigits,
@ -305,9 +306,9 @@ final class DigitList implements Cloneable {
* @param allDecimalDigits Boolean value indicating if the digits in s are
* an exact decimal representation of the double that was passed.
*/
final void set(boolean isNegative, String s,
boolean roundedUp, boolean allDecimalDigits,
int maximumDigits, boolean fixedPoint) {
private void set(boolean isNegative, String s,
boolean roundedUp, boolean allDecimalDigits,
int maximumDigits, boolean fixedPoint) {
this.isNegative = isNegative;
int len = s.length();
char[] source = getDataChars(len);
@ -607,7 +608,7 @@ final class DigitList implements Cloneable {
/**
* Utility routine to set the value of the digit list from a long
*/
public final void set(boolean isNegative, long source) {
final void set(boolean isNegative, long source) {
set(isNegative, source, 0);
}
@ -620,7 +621,7 @@ final class DigitList implements Cloneable {
* If maximumDigits is lower than the number of significant digits
* in source, the representation will be rounded. Ignored if <= 0.
*/
public final void set(boolean isNegative, long source, int maximumDigits) {
final void set(boolean isNegative, long source, int maximumDigits) {
this.isNegative = isNegative;
// This method does not expect a negative number. However,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -2807,10 +2807,10 @@ public final class Formatter implements Closeable, Flushable {
cal = Calendar.getInstance(l == null ? Locale.US : l);
cal.setTime((Date)arg);
} else if (arg instanceof Calendar) {
cal = (Calendar) ((Calendar)arg).clone();
cal = (Calendar) ((Calendar) arg).clone();
cal.setLenient(true);
} else if (arg instanceof TemporalAccessor) {
print((TemporalAccessor)arg, c, l);
print((TemporalAccessor) arg, c, l);
return;
} else {
failConversion(c, arg);
@ -3242,13 +3242,10 @@ public final class Formatter implements Closeable, Flushable {
int prec = (precision == -1 ? 6 : precision);
FormattedFloatingDecimal fd
= new FormattedFloatingDecimal(value, prec,
FormattedFloatingDecimal.Form.SCIENTIFIC);
= FormattedFloatingDecimal.valueOf(value, prec,
FormattedFloatingDecimal.Form.SCIENTIFIC);
char[] v = new char[MAX_FD_CHARS];
int len = fd.getChars(v);
char[] mant = addZeros(mantissa(v, len), prec);
char[] mant = addZeros(fd.getMantissa(), prec);
// If the precision is zero and the '#' flag is set, add the
// requested decimal point.
@ -3256,7 +3253,7 @@ public final class Formatter implements Closeable, Flushable {
mant = addDot(mant);
char[] exp = (value == 0.0)
? new char[] {'+','0','0'} : exponent(v, len);
? new char[] {'+','0','0'} : fd.getExponent();
int newW = width;
if (width != -1)
@ -3279,15 +3276,10 @@ public final class Formatter implements Closeable, Flushable {
int prec = (precision == -1 ? 6 : precision);
FormattedFloatingDecimal fd
= new FormattedFloatingDecimal(value, prec,
FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
= FormattedFloatingDecimal.valueOf(value, prec,
FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
// MAX_FD_CHARS + 1 (round?)
char[] v = new char[MAX_FD_CHARS + 1
+ Math.abs(fd.getExponent())];
int len = fd.getChars(v);
char[] mant = addZeros(mantissa(v, len), prec);
char[] mant = addZeros(fd.getMantissa(), prec);
// If the precision is zero and the '#' flag is set, add the
// requested decimal point.
@ -3306,22 +3298,17 @@ public final class Formatter implements Closeable, Flushable {
prec = 1;
FormattedFloatingDecimal fd
= new FormattedFloatingDecimal(value, prec,
FormattedFloatingDecimal.Form.GENERAL);
= FormattedFloatingDecimal.valueOf(value, prec,
FormattedFloatingDecimal.Form.GENERAL);
// MAX_FD_CHARS + 1 (round?)
char[] v = new char[MAX_FD_CHARS + 1
+ Math.abs(fd.getExponent())];
int len = fd.getChars(v);
char[] exp = exponent(v, len);
char[] exp = fd.getExponent();
if (exp != null) {
prec -= 1;
} else {
prec = prec - (value == 0 ? 0 : fd.getExponentRounded()) - 1;
}
char[] mant = addZeros(mantissa(v, len), prec);
char[] mant = addZeros(fd.getMantissa(), prec);
// If the precision is zero and the '#' flag is set, add the
// requested decimal point.
if (f.contains(Flags.ALTERNATE) && (prec == 0))
@ -3380,30 +3367,6 @@ public final class Formatter implements Closeable, Flushable {
}
}
private char[] mantissa(char[] v, int len) {
int i;
for (i = 0; i < len; i++) {
if (v[i] == 'e')
break;
}
char[] tmp = new char[i];
System.arraycopy(v, 0, tmp, 0, i);
return tmp;
}
private char[] exponent(char[] v, int len) {
int i;
for (i = len - 1; i >= 0; i--) {
if (v[i] == 'e')
break;
}
if (i == -1)
return null;
char[] tmp = new char[len - i - 1];
System.arraycopy(v, i + 1, tmp, 0, len - i - 1);
return tmp;
}
// Add zeros to the requested precision.
private char[] addZeros(char[] v, int prec) {
// Look for the dot. If we don't find one, the we'll need to add

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,7 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -23,41 +21,41 @@
* questions.
*/
package sun.misc;
//package sun.misc;
/*
* A really, really simple bigint package
* tailored to the needs of floating base conversion.
*/
class FDBigInt {
class OldFDBigIntForTest {
int nWords; // number of words used
int data[]; // value: data[0] is least significant
public FDBigInt( int v ){
public OldFDBigIntForTest( int v ){
nWords = 1;
data = new int[1];
data[0] = v;
}
public FDBigInt( long v ){
public OldFDBigIntForTest( long v ){
data = new int[2];
data[0] = (int)v;
data[1] = (int)(v>>>32);
nWords = (data[1]==0) ? 1 : 2;
}
public FDBigInt( FDBigInt other ){
public OldFDBigIntForTest( OldFDBigIntForTest other ){
data = new int[nWords = other.nWords];
System.arraycopy( other.data, 0, data, 0, nWords );
}
private FDBigInt( int [] d, int n ){
private OldFDBigIntForTest( int [] d, int n ){
data = d;
nWords = n;
}
public FDBigInt( long seed, char digit[], int nd0, int nd ){
public OldFDBigIntForTest( long seed, char digit[], int nd0, int nd ){
int n= (nd+8)/9; // estimate size needed.
if ( n < 2 ) n = 2;
data = new int[n]; // allocate enough space
@ -189,10 +187,10 @@ class FDBigInt {
}
/*
* Multiply a FDBigInt by an int.
* Result is a new FDBigInt.
* Multiply a OldFDBigIntForTest by an int.
* Result is a new OldFDBigIntForTest.
*/
public FDBigInt
public OldFDBigIntForTest
mult( int iv ) {
long v = iv;
int r[];
@ -207,15 +205,15 @@ class FDBigInt {
p >>>= 32;
}
if ( p == 0L){
return new FDBigInt( r, nWords );
return new OldFDBigIntForTest( r, nWords );
} else {
r[nWords] = (int)p;
return new FDBigInt( r, nWords+1 );
return new OldFDBigIntForTest( r, nWords+1 );
}
}
/*
* Multiply a FDBigInt by an int and add another int.
* Multiply a OldFDBigIntForTest by an int and add another int.
* Result is computed in place.
* Hope it fits!
*/
@ -240,11 +238,11 @@ class FDBigInt {
}
/*
* Multiply a FDBigInt by another FDBigInt.
* Result is a new FDBigInt.
* Multiply a OldFDBigIntForTest by another OldFDBigIntForTest.
* Result is a new OldFDBigIntForTest.
*/
public FDBigInt
mult( FDBigInt other ){
public OldFDBigIntForTest
mult( OldFDBigIntForTest other ){
// crudely guess adequate size for r
int r[] = new int[ nWords + other.nWords ];
int i;
@ -265,14 +263,14 @@ class FDBigInt {
for ( i = r.length-1; i> 0; i--)
if ( r[i] != 0 )
break;
return new FDBigInt( r, i+1 );
return new OldFDBigIntForTest( r, i+1 );
}
/*
* Add one FDBigInt to another. Return a FDBigInt
* Add one OldFDBigIntForTest to another. Return a OldFDBigIntForTest
*/
public FDBigInt
add( FDBigInt other ){
public OldFDBigIntForTest
add( OldFDBigIntForTest other ){
int i;
int a[], b[];
int n, m;
@ -304,17 +302,17 @@ class FDBigInt {
int s[] = new int[ r.length+1 ];
System.arraycopy( r, 0, s, 0, r.length );
s[i++] = (int)c;
return new FDBigInt( s, i );
return new OldFDBigIntForTest( s, i );
}
return new FDBigInt( r, i );
return new OldFDBigIntForTest( r, i );
}
/*
* Subtract one FDBigInt from another. Return a FDBigInt
* Subtract one OldFDBigIntForTest from another. Return a OldFDBigIntForTest
* Assert that the result is positive.
*/
public FDBigInt
sub( FDBigInt other ){
public OldFDBigIntForTest
sub( OldFDBigIntForTest other ){
int r[] = new int[ this.nWords ];
int i;
int n = this.nWords;
@ -334,10 +332,10 @@ class FDBigInt {
}
assert c == 0L : c; // borrow out of subtract
assert dataInRangeIsZero(i, m, other); // negative result of subtract
return new FDBigInt( r, n-nzeros );
return new OldFDBigIntForTest( r, n-nzeros );
}
private static boolean dataInRangeIsZero(int i, int m, FDBigInt other) {
private static boolean dataInRangeIsZero(int i, int m, OldFDBigIntForTest other) {
while ( i < m )
if (other.data[i++] != 0)
return false;
@ -345,13 +343,13 @@ class FDBigInt {
}
/*
* Compare FDBigInt with another FDBigInt. Return an integer
* Compare OldFDBigIntForTest with another OldFDBigIntForTest. Return an integer
* >0: this > other
* 0: this == other
* <0: this < other
*/
public int
cmp( FDBigInt other ){
cmp( OldFDBigIntForTest other ){
int i;
if ( this.nWords > other.nWords ){
// if any of my high-order words is non-zero,
@ -405,7 +403,7 @@ class FDBigInt {
* as an integer, 0 <= q < 10.
*/
public int
quoRemIteration( FDBigInt S )throws IllegalArgumentException {
quoRemIteration( OldFDBigIntForTest S )throws IllegalArgumentException {
// ensure that this and S have the same number of
// digits. If S is properly normalized and q < 10 then
// this must be so.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,426 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.math.BigInteger;
import java.util.Random;
import sun.misc.FDBigInteger;
/**
* @test
* @bug 7032154
* @summary unit testys of sun.misc.FDBigInteger
* @author Dmitry Nadezhin
*/
public class TestFDBigInteger {
private static final int MAX_P5 = 413;
private static final int MAX_P2 = 65;
private static final long LONG_SIGN_MASK = (1L << 63);
private static final BigInteger FIVE = BigInteger.valueOf(5);
private static final FDBigInteger MUTABLE_ZERO = FDBigInteger.valueOfPow52(0, 0).leftInplaceSub(FDBigInteger.valueOfPow52(0, 0));
private static final FDBigInteger IMMUTABLE_ZERO = FDBigInteger.valueOfPow52(0, 0).leftInplaceSub(FDBigInteger.valueOfPow52(0, 0));
private static final FDBigInteger IMMUTABLE_MILLION = genMillion1();
private static final FDBigInteger IMMUTABLE_BILLION = genBillion1();
private static final FDBigInteger IMMUTABLE_TEN18 = genTen18();
static {
IMMUTABLE_ZERO.makeImmutable();
IMMUTABLE_MILLION.makeImmutable();
IMMUTABLE_BILLION.makeImmutable();
IMMUTABLE_TEN18.makeImmutable();
}
private static FDBigInteger mutable(String hex, int offset) {
char[] chars = new BigInteger(hex, 16).toString().toCharArray();
return new FDBigInteger(0, chars, 0, chars.length).multByPow52(0, offset * 32);
}
private static FDBigInteger immutable(String hex, int offset) {
FDBigInteger fd = mutable(hex, offset);
fd.makeImmutable();
return fd;
}
private static BigInteger biPow52(int p5, int p2) {
return FIVE.pow(p5).shiftLeft(p2);
}
// data.length == 1, nWords == 1, offset == 0
private static FDBigInteger genMillion1() {
return FDBigInteger.valueOfPow52(6, 0).leftShift(6);
}
// data.length == 2, nWords == 1, offset == 0
private static FDBigInteger genMillion2() {
return FDBigInteger.valueOfMulPow52(1000000L, 0, 0);
}
// data.length == 1, nWords == 1, offset == 0
private static FDBigInteger genBillion1() {
return FDBigInteger.valueOfPow52(9, 0).leftShift(9);
}
// data.length == 2, nWords == 2, offset == 0
private static FDBigInteger genTen18() {
return FDBigInteger.valueOfPow52(18, 0).leftShift(18);
}
private static void check(BigInteger expected, FDBigInteger actual, String message) throws Exception {
if (!expected.equals(actual.toBigInteger())) {
throw new Exception(message + " result " + actual.toHexString() + " expected " + expected.toString(16));
}
}
private static void testValueOfPow52(int p5, int p2) throws Exception {
check(biPow52(p5, p2), FDBigInteger.valueOfPow52(p5, p2),
"valueOfPow52(" + p5 + "," + p2 + ")");
}
private static void testValueOfPow52() throws Exception {
for (int p5 = 0; p5 <= MAX_P5; p5++) {
for (int p2 = 0; p2 <= MAX_P2; p2++) {
testValueOfPow52(p5, p2);
}
}
}
private static void testValueOfMulPow52(long value, int p5, int p2) throws Exception {
BigInteger bi = BigInteger.valueOf(value & ~LONG_SIGN_MASK);
if (value < 0) {
bi = bi.setBit(63);
}
check(biPow52(p5, p2).multiply(bi), FDBigInteger.valueOfMulPow52(value, p5, p2),
"valueOfMulPow52(" + Long.toHexString(value) + "." + p5 + "," + p2 + ")");
}
private static void testValueOfMulPow52(long value, int p5) throws Exception {
testValueOfMulPow52(value, p5, 0);
testValueOfMulPow52(value, p5, 1);
testValueOfMulPow52(value, p5, 30);
testValueOfMulPow52(value, p5, 31);
testValueOfMulPow52(value, p5, 33);
testValueOfMulPow52(value, p5, 63);
}
private static void testValueOfMulPow52() throws Exception {
for (int p5 = 0; p5 <= MAX_P5; p5++) {
testValueOfMulPow52(0xFFFFFFFFL, p5);
testValueOfMulPow52(0x123456789AL, p5);
testValueOfMulPow52(0x7FFFFFFFFFFFFFFFL, p5);
testValueOfMulPow52(0xFFFFFFFFFFF54321L, p5);
}
}
private static void testLeftShift(FDBigInteger t, int shift, boolean isImmutable) throws Exception {
BigInteger bt = t.toBigInteger();
FDBigInteger r = t.leftShift(shift);
if ((bt.signum() == 0 || shift == 0 || !isImmutable) && r != t) {
throw new Exception("leftShift doesn't reuse its argument");
}
if (isImmutable) {
check(bt, t, "leftShift corrupts its argument");
}
check(bt.shiftLeft(shift), r, "leftShift returns wrong result");
}
private static void testLeftShift() throws Exception {
testLeftShift(IMMUTABLE_ZERO, 0, true);
testLeftShift(IMMUTABLE_ZERO, 10, true);
testLeftShift(MUTABLE_ZERO, 0, false);
testLeftShift(MUTABLE_ZERO, 10, false);
testLeftShift(IMMUTABLE_MILLION, 0, true);
testLeftShift(IMMUTABLE_MILLION, 1, true);
testLeftShift(IMMUTABLE_MILLION, 12, true);
testLeftShift(IMMUTABLE_MILLION, 13, true);
testLeftShift(IMMUTABLE_MILLION, 32, true);
testLeftShift(IMMUTABLE_MILLION, 33, true);
testLeftShift(IMMUTABLE_MILLION, 44, true);
testLeftShift(IMMUTABLE_MILLION, 45, true);
testLeftShift(genMillion1(), 0, false);
testLeftShift(genMillion1(), 1, false);
testLeftShift(genMillion1(), 12, false);
testLeftShift(genMillion1(), 13, false);
testLeftShift(genMillion1(), 25, false);
testLeftShift(genMillion1(), 26, false);
testLeftShift(genMillion1(), 32, false);
testLeftShift(genMillion1(), 33, false);
testLeftShift(genMillion1(), 44, false);
testLeftShift(genMillion1(), 45, false);
testLeftShift(genMillion2(), 0, false);
testLeftShift(genMillion2(), 1, false);
testLeftShift(genMillion2(), 12, false);
testLeftShift(genMillion2(), 13, false);
testLeftShift(genMillion2(), 25, false);
testLeftShift(genMillion2(), 26, false);
testLeftShift(genMillion2(), 32, false);
testLeftShift(genMillion2(), 33, false);
testLeftShift(genMillion2(), 44, false);
testLeftShift(genMillion2(), 45, false);
}
private static void testQuoRemIteration(FDBigInteger t, FDBigInteger s) throws Exception {
BigInteger bt = t.toBigInteger();
BigInteger bs = s.toBigInteger();
int q = t.quoRemIteration(s);
BigInteger[] qr = bt.divideAndRemainder(bs);
if (!BigInteger.valueOf(q).equals(qr[0])) {
throw new Exception("quoRemIteration returns incorrect quo");
}
check(qr[1].multiply(BigInteger.TEN), t, "quoRemIteration returns incorrect rem");
}
private static void testQuoRemIteration() throws Exception {
// IMMUTABLE_TEN18 == 0de0b6b3a7640000
// q = 0
testQuoRemIteration(mutable("00000001", 0), IMMUTABLE_TEN18);
testQuoRemIteration(mutable("00000001", 1), IMMUTABLE_TEN18);
testQuoRemIteration(mutable("0de0b6b2", 1), IMMUTABLE_TEN18);
// q = 1 -> q = 0
testQuoRemIteration(mutable("0de0b6b3", 1), IMMUTABLE_TEN18);
testQuoRemIteration(mutable("0de0b6b3a763FFFF", 0), IMMUTABLE_TEN18);
// q = 1
testQuoRemIteration(mutable("0de0b6b3a7640000", 0), IMMUTABLE_TEN18);
testQuoRemIteration(mutable("0de0b6b3FFFFFFFF", 0), IMMUTABLE_TEN18);
testQuoRemIteration(mutable("8ac72304", 1), IMMUTABLE_TEN18);
testQuoRemIteration(mutable("0de0b6b400000000", 0), IMMUTABLE_TEN18);
testQuoRemIteration(mutable("8ac72305", 1), IMMUTABLE_TEN18);
// q = 18
testQuoRemIteration(mutable("FFFFFFFF", 1), IMMUTABLE_TEN18);
}
private static void testCmp(FDBigInteger t, FDBigInteger o) throws Exception {
BigInteger bt = t.toBigInteger();
BigInteger bo = o.toBigInteger();
int cmp = t.cmp(o);
int bcmp = bt.compareTo(bo);
if (bcmp != cmp) {
throw new Exception("cmp returns " + cmp + " expected " + bcmp);
}
check(bt, t, "cmp corrupts this");
check(bo, o, "cmp corrupts other");
if (o.cmp(t) != -cmp) {
throw new Exception("asymmetrical cmp");
}
check(bt, t, "cmp corrupts this");
check(bo, o, "cmp corrupts other");
}
private static void testCmp() throws Exception {
testCmp(mutable("FFFFFFFF", 0), mutable("100000000", 0));
testCmp(mutable("FFFFFFFF", 0), mutable("1", 1));
testCmp(mutable("5", 0), mutable("6", 0));
testCmp(mutable("5", 0), mutable("5", 0));
testCmp(mutable("5000000001", 0), mutable("500000001", 0));
testCmp(mutable("5000000001", 0), mutable("6", 1));
testCmp(mutable("5000000001", 0), mutable("5", 1));
testCmp(mutable("5000000000", 0), mutable("5", 1));
}
private static void testCmpPow52(FDBigInteger t, int p5, int p2) throws Exception {
FDBigInteger o = FDBigInteger.valueOfPow52(p5, p2);
BigInteger bt = t.toBigInteger();
BigInteger bo = biPow52(p5, p2);
int cmp = t.cmp(o);
int bcmp = bt.compareTo(bo);
if (bcmp != cmp) {
throw new Exception("cmpPow52 returns " + cmp + " expected " + bcmp);
}
check(bt, t, "cmpPow52 corrupts this");
check(bo, o, "cmpPow5 corrupts other");
}
private static void testCmpPow52() throws Exception {
testCmpPow52(mutable("00000002", 1), 0, 31);
testCmpPow52(mutable("00000002", 1), 0, 32);
testCmpPow52(mutable("00000002", 1), 0, 33);
testCmpPow52(mutable("00000002", 1), 0, 34);
testCmpPow52(mutable("00000002", 1), 0, 64);
testCmpPow52(mutable("00000003", 1), 0, 32);
testCmpPow52(mutable("00000003", 1), 0, 33);
testCmpPow52(mutable("00000003", 1), 0, 34);
}
private static void testAddAndCmp(FDBigInteger t, FDBigInteger x, FDBigInteger y) throws Exception {
BigInteger bt = t.toBigInteger();
BigInteger bx = x.toBigInteger();
BigInteger by = y.toBigInteger();
int cmp = t.addAndCmp(x, y);
int bcmp = bt.compareTo(bx.add(by));
if (bcmp != cmp) {
throw new Exception("addAndCmp returns " + cmp + " expected " + bcmp);
}
check(bt, t, "addAndCmp corrupts this");
check(bx, x, "addAndCmp corrupts x");
check(by, y, "addAndCmp corrupts y");
}
private static void testAddAndCmp() throws Exception {
testAddAndCmp(MUTABLE_ZERO, MUTABLE_ZERO, MUTABLE_ZERO);
testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, MUTABLE_ZERO);
testAddAndCmp(mutable("00000001", 0), mutable("00000001", 0), MUTABLE_ZERO);
testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, mutable("00000001", 0));
testAddAndCmp(mutable("00000001", 0), mutable("00000002", 0), MUTABLE_ZERO);
testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, mutable("00000002", 0));
testAddAndCmp(mutable("00000001", 2), mutable("FFFFFFFF", 0), mutable("FFFFFFFF", 0));
testAddAndCmp(mutable("00000001", 0), mutable("00000001", 1), mutable("00000001", 0));
testAddAndCmp(mutable("00000001", 2), mutable("0F0F0F0F80000000", 1), mutable("F0F0F0F080000000", 1));
testAddAndCmp(mutable("00000001", 2), mutable("0F0F0F0E80000000", 1), mutable("F0F0F0F080000000", 1));
testAddAndCmp(mutable("00000002", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
testAddAndCmp(mutable("00000003", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
testAddAndCmp(mutable("00000004", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
testAddAndCmp(mutable("00000005", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
testAddAndCmp(mutable("00000001", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
testAddAndCmp(mutable("00000001", 2), mutable("8000000000000000", 0), mutable("8000000000000001", 0));
testAddAndCmp(mutable("00000002", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
testAddAndCmp(mutable("00000003", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
}
private static void testMultBy10(FDBigInteger t, boolean isImmutable) throws Exception {
BigInteger bt = t.toBigInteger();
FDBigInteger r = t.multBy10();
if ((bt.signum() == 0 || !isImmutable) && r != t) {
throw new Exception("multBy10 of doesn't reuse its argument");
}
if (isImmutable) {
check(bt, t, "multBy10 corrupts its argument");
}
check(bt.multiply(BigInteger.TEN), r, "multBy10 returns wrong result");
}
private static void testMultBy10() throws Exception {
for (int p5 = 0; p5 <= MAX_P5; p5++) {
for (int p2 = 0; p2 <= MAX_P2; p2++) {
// This strange way of creating a value ensures that it is mutable.
FDBigInteger value = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
testMultBy10(value, false);
value.makeImmutable();
testMultBy10(value, true);
}
}
}
private static void testMultByPow52(FDBigInteger t, int p5, int p2) throws Exception {
BigInteger bt = t.toBigInteger();
FDBigInteger r = t.multByPow52(p5, p2);
if (bt.signum() == 0 && r != t) {
throw new Exception("multByPow52 of doesn't reuse its argument");
}
check(bt.multiply(biPow52(p5, p2)), r, "multByPow52 returns wrong result");
}
private static void testMultByPow52() throws Exception {
for (int p5 = 0; p5 <= MAX_P5; p5++) {
for (int p2 = 0; p2 <= MAX_P2; p2++) {
// This strange way of creating a value ensures that it is mutable.
FDBigInteger value = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
testMultByPow52(value, p5, p2);
}
}
}
private static void testLeftInplaceSub(FDBigInteger left, FDBigInteger right, boolean isImmutable) throws Exception {
BigInteger biLeft = left.toBigInteger();
BigInteger biRight = right.toBigInteger();
FDBigInteger diff = left.leftInplaceSub(right);
if (!isImmutable && diff != left) {
throw new Exception("leftInplaceSub of doesn't reuse its argument");
}
check(biLeft.subtract(biRight), diff, "leftInplaceSub returns wrong result");
}
private static void testLeftInplaceSub() throws Exception {
for (int p5 = 0; p5 <= MAX_P5; p5++) {
for (int p2 = 0; p2 <= MAX_P2; p2++) {
// for (int p5r = 0; p5r <= p5; p5r += 10) {
// for (int p2r = 0; p2r <= p2; p2r += 10) {
for (int p5r = 0; p5r <= p5; p5r++) {
for (int p2r = 0; p2r <= p2; p2r++) {
// This strange way of creating a value ensures that it is mutable.
FDBigInteger left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
FDBigInteger right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
testLeftInplaceSub(left, right, false);
left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
left.makeImmutable();
testLeftInplaceSub(left, right, true);
}
}
}
}
}
private static void testRightInplaceSub(FDBigInteger left, FDBigInteger right, boolean isImmutable) throws Exception {
BigInteger biLeft = left.toBigInteger();
BigInteger biRight = right.toBigInteger();
FDBigInteger diff = left.rightInplaceSub(right);
if (!isImmutable && diff != right) {
throw new Exception("rightInplaceSub of doesn't reuse its argument");
}
try {
check(biLeft.subtract(biRight), diff, "rightInplaceSub returns wrong result");
} catch (Exception e) {
System.out.println(biLeft+" - "+biRight+" = "+biLeft.subtract(biRight));
throw e;
}
}
private static void testRightInplaceSub() throws Exception {
for (int p5 = 0; p5 <= MAX_P5; p5++) {
for (int p2 = 0; p2 <= MAX_P2; p2++) {
// for (int p5r = 0; p5r <= p5; p5r += 10) {
// for (int p2r = 0; p2r <= p2; p2r += 10) {
for (int p5r = 0; p5r <= p5; p5r++) {
for (int p2r = 0; p2r <= p2; p2r++) {
// This strange way of creating a value ensures that it is mutable.
FDBigInteger left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
FDBigInteger right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
testRightInplaceSub(left, right, false);
right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
right.makeImmutable();
testRightInplaceSub(left, right, true);
}
}
}
}
}
public static void main(String[] args) throws Exception {
testValueOfPow52();
testValueOfMulPow52();
testLeftShift();
testQuoRemIteration();
testCmp();
testCmpPow52();
testAddAndCmp();
// Uncomment the following for more comprehensize but slow testing.
// testLeftInplaceSub();
// testMultBy10();
// testMultByPow52();
// testRightInplaceSub();
}
}

View File

@ -0,0 +1,324 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Random;
import sun.misc.FloatingDecimal;
/*
OldFloatingDecimalForTest
public class OldFloatingDecimalForTest {
public boolean digitsRoundedUp();
public OldFloatingDecimalForTest(double);
public OldFloatingDecimalForTest(float);
public boolean decimalDigitsExact();
public java.lang.String toString();
public java.lang.String toJavaFormatString();
public void appendTo(java.lang.Appendable);
public static OldFloatingDecimalForTest readJavaFormatString(java.lang.String) throws java.lang.NumberFormatException;
public strictfp double doubleValue();
public strictfp float floatValue();
}
sun.misc.FloatingDecimal
public class sun.misc.FloatingDecimal {
public sun.misc.FloatingDecimal();
public static java.lang.String toJavaFormatString(double);
public static java.lang.String toJavaFormatString(float);
public static void appendTo(double, java.lang.Appendable);
public static void appendTo(float, java.lang.Appendable);
public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
public static sun.misc.FloatingDecimal$AbstractD2ABuffer getD2ABuffer(double);
}
*/
/**
* @test
* @bug 7032154
* @summary unit tests of sun.misc.FloatingDecimal
* @author Brian Burkhalter
*/
public class TestFloatingDecimal {
private static enum ResultType {
RESULT_EXCEPTION,
RESULT_PRINT
}
private static final ResultType RESULT_TYPE = ResultType.RESULT_PRINT;
private static final int NUM_RANDOM_TESTS = 100000;
private static final Random RANDOM = new Random();
private static void result(String message) {
switch (RESULT_TYPE) {
case RESULT_EXCEPTION:
throw new RuntimeException(message);
case RESULT_PRINT:
System.err.println(message);
break;
default:
assert false;
}
}
private static int check(String test, Object expected, Object actual) {
int failures = 0;
if(!actual.equals(expected)) {
failures++;
result("Test "+test+" expected "+expected+" but obtained "+actual);
}
return failures;
}
private static int testAppendToDouble() {
System.out.println(" testAppendToDouble");
int failures = 0;
for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
double[] d = new double[] {
RANDOM.nextLong(),
RANDOM.nextGaussian(),
RANDOM.nextDouble()*Double.MAX_VALUE
};
for(int j = 0; j < d.length; j++) {
OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
StringBuilder sb = new StringBuilder();
ofd.appendTo(sb);
String oldString = sb.toString();
sb = new StringBuilder();
FloatingDecimal.appendTo(d[j], sb);
String newString = sb.toString();
failures += check("testAppendToDouble", oldString, newString);
}
}
return failures;
}
private static int testAppendToFloat() {
System.out.println(" testAppendToFloat");
int failures = 0;
for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
float[] f = new float[] {
RANDOM.nextLong(),
(float)RANDOM.nextGaussian(),
RANDOM.nextFloat()*Float.MAX_VALUE
};
for(int j = 0; j < f.length; j++) {
OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
StringBuilder sb = new StringBuilder();
ofd.appendTo(sb);
String oldString = sb.toString();
sb = new StringBuilder();
FloatingDecimal.appendTo(f[j], sb);
String newString = sb.toString();
failures += check("testAppendToFloat", oldString, newString);
}
}
return failures;
}
private static int testAppendTo() {
System.out.println("testAppendTo");
int failures = 0;
failures += testAppendToDouble();
failures += testAppendToFloat();
return failures;
}
private static int testParseDouble() {
System.out.println(" testParseDouble");
int failures = 0;
for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
double[] d = new double[] {
RANDOM.nextLong(),
RANDOM.nextGaussian(),
RANDOM.nextDouble()*Double.MAX_VALUE
};
for(int j = 0; j < d.length; j++) {
OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
String javaFormatString = ofd.toJavaFormatString();
ofd = OldFloatingDecimalForTest.readJavaFormatString(javaFormatString);
double oldDouble = ofd.doubleValue();
double newDouble = FloatingDecimal.parseDouble(javaFormatString);
failures += check("testParseDouble", oldDouble, newDouble);
}
}
return failures;
}
private static int testParseFloat() {
System.out.println(" testParseFloat");
int failures = 0;
for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
float[] f = new float[] {
RANDOM.nextInt(),
(float)RANDOM.nextGaussian(),
RANDOM.nextFloat()*Float.MAX_VALUE
};
for(int j = 0; j < f.length; j++) {
OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
String javaFormatString = ofd.toJavaFormatString();
ofd = OldFloatingDecimalForTest.readJavaFormatString(javaFormatString);
float oldFloat = ofd.floatValue();
float newFloat = FloatingDecimal.parseFloat(javaFormatString);
failures += check("testParseFloat", oldFloat, newFloat);
}
}
return failures;
}
private static int testParse() {
System.out.println("testParse");
int failures = 0;
failures += testParseDouble();
failures += testParseFloat();
return failures;
}
private static int testToJavaFormatStringDoubleFixed() {
System.out.println(" testToJavaFormatStringDoubleFixed");
int failures = 0;
double[] d = new double [] {
-5.9522650387500933e18, // dtoa() fast path
0.872989018674569, // dtoa() fast iterative - long
1.1317400099603851e308 // dtoa() slow iterative
};
for(int i = 0; i < d.length; i++) {
OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[i]);
failures += check("testToJavaFormatStringDoubleFixed", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(d[i]));
}
return failures;
}
private static int testToJavaFormatStringDoubleRandom() {
System.out.println(" testToJavaFormatStringDoubleRandom");
int failures = 0;
for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
double[] d = new double[] {
RANDOM.nextLong(),
RANDOM.nextGaussian(),
RANDOM.nextDouble()*Double.MAX_VALUE
};
for(int j = 0; j < d.length; j++) {
OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
failures += check("testToJavaFormatStringDoubleRandom", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(d[j]));
}
}
return failures;
}
private static int testToJavaFormatStringDouble() {
System.out.println(" testToJavaFormatStringDouble");
int failures = 0;
failures += testToJavaFormatStringDoubleFixed();
failures += testToJavaFormatStringDoubleRandom();
return failures;
}
private static int testToJavaFormatStringFloatFixed() {
System.out.println(" testToJavaFormatStringFloatFixed");
int failures = 0;
float[] f = new float[] {
-9.8784166e8f, // dtoa() fast path
0.70443946f, // dtoa() fast iterative - int
1.8254228e37f // dtoa() slow iterative
};
for(int i = 0; i < f.length; i++) {
OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[i]);
failures += check("testToJavaFormatStringFloatFixed", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(f[i]));
}
return failures;
}
private static int testToJavaFormatStringFloatRandom() {
System.out.println(" testToJavaFormatStringFloatRandom");
int failures = 0;
for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
float[] f = new float[] {
RANDOM.nextInt(),
(float)RANDOM.nextGaussian(),
RANDOM.nextFloat()*Float.MAX_VALUE
};
for(int j = 0; j < f.length; j++) {
OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
failures += check("testToJavaFormatStringFloatRandom", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(f[j]));
}
}
return failures;
}
private static int testToJavaFormatStringFloat() {
System.out.println(" testToJavaFormatStringFloat");
int failures = 0;
failures += testToJavaFormatStringFloatFixed();
failures += testToJavaFormatStringFloatRandom();
return failures;
}
private static int testToJavaFormatString() {
System.out.println("testToJavaFormatString");
int failures = 0;
failures += testToJavaFormatStringDouble();
failures += testToJavaFormatStringFloat();
return failures;
}
public static void main(String[] args) {
int failures = 0;
failures += testAppendTo();
failures += testParse();
failures += testToJavaFormatString();
if (failures != 0) {
throw new RuntimeException("" + failures + " failures while testing FloatingDecimal");
}
}
}