6813240: Remove dead code in sun.misc.FormattedFloatingDecimal class

Remove unused methods from FormattedFloatingDecimal that were originally copied from FloatingDecimal

Reviewed-by: darcy
This commit is contained in:
Mandy Chung 2009-03-12 10:32:58 -07:00
parent 0a64902056
commit 2f06b83dfc

View File

@ -978,15 +978,6 @@ public class FormattedFloatingDecimal{
return new String(result);
}
// This method should only ever be called if this object is constructed
// without Form.DECIMAL_FLOAT because the perThreadBuffer is not large
// enough to handle floating-point numbers of large precision.
public String toJavaFormatString() {
char result[] = (char[])(perThreadBuffer.get());
int i = getChars(result);
return new String(result, 0, i);
}
// returns the exponent before rounding
public int getExponent() {
return decExponent - 1;
@ -1157,265 +1148,6 @@ public class FormattedFloatingDecimal{
}
};
// This method should only ever be called if this object is constructed
// without Form.DECIMAL_FLOAT because the perThreadBuffer is not large
// enough to handle floating-point numbers of large precision.
public void appendTo(Appendable buf) {
char result[] = (char[])(perThreadBuffer.get());
int i = getChars(result);
if (buf instanceof StringBuilder)
((StringBuilder) buf).append(result, 0, i);
else if (buf instanceof StringBuffer)
((StringBuffer) buf).append(result, 0, i);
else
assert false;
}
public static FormattedFloatingDecimal
readJavaFormatString( String in ) throws NumberFormatException {
boolean isNegative = false;
boolean signSeen = false;
int decExp;
char c;
parseNumber:
try{
in = in.trim(); // don't fool around with white space.
// throws NullPointerException if null
int l = in.length();
if ( l == 0 ) throw new NumberFormatException("empty String");
int i = 0;
switch ( c = in.charAt( i ) ){
case '-':
isNegative = true;
//FALLTHROUGH
case '+':
i++;
signSeen = true;
}
// Check for NaN and Infinity strings
c = in.charAt(i);
if(c == 'N' || c == 'I') { // possible NaN or infinity
boolean potentialNaN = false;
char targetChars[] = null; // char arrary of "NaN" or "Infinity"
if(c == 'N') {
targetChars = notANumber;
potentialNaN = true;
} else {
targetChars = infinity;
}
// compare Input string to "NaN" or "Infinity"
int j = 0;
while(i < l && j < targetChars.length) {
if(in.charAt(i) == targetChars[j]) {
i++; j++;
}
else // something is amiss, throw exception
break parseNumber;
}
// For the candidate string to be a NaN or infinity,
// all characters in input string and target char[]
// must be matched ==> j must equal targetChars.length
// and i must equal l
if( (j == targetChars.length) && (i == l) ) { // return NaN or infinity
return (potentialNaN ? new FormattedFloatingDecimal(Double.NaN) // NaN has no sign
: new FormattedFloatingDecimal(isNegative?
Double.NEGATIVE_INFINITY:
Double.POSITIVE_INFINITY)) ;
}
else { // something went wrong, throw exception
break parseNumber;
}
} else if (c == '0') { // check for hexadecimal floating-point number
if (l > i+1 ) {
char ch = in.charAt(i+1);
if (ch == 'x' || ch == 'X' ) // possible hex string
return parseHexString(in);
}
} // look for and process decimal floating-point string
char[] digits = new char[ l ];
int nDigits= 0;
boolean decSeen = false;
int decPt = 0;
int nLeadZero = 0;
int nTrailZero= 0;
digitLoop:
while ( i < l ){
switch ( c = in.charAt( i ) ){
case '0':
if ( nDigits > 0 ){
nTrailZero += 1;
} else {
nLeadZero += 1;
}
break; // out of switch.
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
while ( nTrailZero > 0 ){
digits[nDigits++] = '0';
nTrailZero -= 1;
}
digits[nDigits++] = c;
break; // out of switch.
case '.':
if ( decSeen ){
// already saw one ., this is the 2nd.
throw new NumberFormatException("multiple points");
}
decPt = i;
if ( signSeen ){
decPt -= 1;
}
decSeen = true;
break; // out of switch.
default:
break digitLoop;
}
i++;
}
/*
* At this point, we've scanned all the digits and decimal
* point we're going to see. Trim off leading and trailing
* zeros, which will just confuse us later, and adjust
* our initial decimal exponent accordingly.
* To review:
* we have seen i total characters.
* nLeadZero of them were zeros before any other digits.
* nTrailZero of them were zeros after any other digits.
* if ( decSeen ), then a . was seen after decPt characters
* ( including leading zeros which have been discarded )
* nDigits characters were neither lead nor trailing
* zeros, nor point
*/
/*
* special hack: if we saw no non-zero digits, then the
* answer is zero!
* Unfortunately, we feel honor-bound to keep parsing!
*/
if ( nDigits == 0 ){
digits = zero;
nDigits = 1;
if ( nLeadZero == 0 ){
// we saw NO DIGITS AT ALL,
// not even a crummy 0!
// this is not allowed.
break parseNumber; // go throw exception
}
}
/* Our initial exponent is decPt, adjusted by the number of
* discarded zeros. Or, if there was no decPt,
* then its just nDigits adjusted by discarded trailing zeros.
*/
if ( decSeen ){
decExp = decPt - nLeadZero;
} else {
decExp = nDigits+nTrailZero;
}
/*
* Look for 'e' or 'E' and an optionally signed integer.
*/
if ( (i < l) && (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
int expSign = 1;
int expVal = 0;
int reallyBig = Integer.MAX_VALUE / 10;
boolean expOverflow = false;
switch( in.charAt(++i) ){
case '-':
expSign = -1;
//FALLTHROUGH
case '+':
i++;
}
int expAt = i;
expLoop:
while ( i < l ){
if ( expVal >= reallyBig ){
// the next character will cause integer
// overflow.
expOverflow = true;
}
switch ( c = in.charAt(i++) ){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
expVal = expVal*10 + ( (int)c - (int)'0' );
continue;
default:
i--; // back up.
break expLoop; // stop parsing exponent.
}
}
int expLimit = bigDecimalExponent+nDigits+nTrailZero;
if ( expOverflow || ( expVal > expLimit ) ){
//
// The intent here is to end up with
// infinity or zero, as appropriate.
// The reason for yielding such a small decExponent,
// rather than something intuitive such as
// expSign*Integer.MAX_VALUE, is that this value
// is subject to further manipulation in
// doubleValue() and floatValue(), and I don't want
// it to be able to cause overflow there!
// (The only way we can get into trouble here is for
// really outrageous nDigits+nTrailZero, such as 2 billion. )
//
decExp = expSign*expLimit;
} else {
// this should not overflow, since we tested
// for expVal > (MAX+N), where N >= abs(decExp)
decExp = decExp + expSign*expVal;
}
// if we saw something not a digit ( or end of string )
// after the [Ee][+-], without seeing any digits at all
// this is certainly an error. If we saw some digits,
// but then some trailing garbage, that might be ok.
// so we just fall through in that case.
// HUMBUG
if ( i == expAt )
break parseNumber; // certainly bad
}
/*
* We parsed everything we could.
* If there are leftovers, then this is not good input!
*/
if ( i < l &&
((i != l - 1) ||
(in.charAt(i) != 'f' &&
in.charAt(i) != 'F' &&
in.charAt(i) != 'd' &&
in.charAt(i) != 'D'))) {
break parseNumber; // go throw exception
}
return new FormattedFloatingDecimal( isNegative, decExp, digits, nDigits, false, Integer.MAX_VALUE, Form.COMPATIBLE );
} catch ( StringIndexOutOfBoundsException e ){ }
throw new NumberFormatException("For input string: \"" + in + "\"");
}
/*
* Take a FormattedFloatingDecimal, which we presumably just scanned in,
* and find out what its value is, as a double.
@ -2035,548 +1767,4 @@ public class FormattedFloatingDecimal{
private static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
private static final char notANumber[] = { 'N', 'a', 'N' };
private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' };
/*
* Grammar is compatible with hexadecimal floating-point constants
* described in section 6.4.4.2 of the C99 specification.
*/
private static Pattern hexFloatPattern = Pattern.compile(
//1 234 56 7 8 9
"([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
);
/*
* Convert string s to a suitable floating decimal; uses the
* double constructor and set the roundDir variable appropriately
* in case the value is later converted to a float.
*/
static FormattedFloatingDecimal parseHexString(String s) {
// Verify string is a member of the hexadecimal floating-point
// string language.
Matcher m = hexFloatPattern.matcher(s);
boolean validInput = m.matches();
if (!validInput) {
// Input does not match pattern
throw new NumberFormatException("For input string: \"" + s + "\"");
} else { // validInput
/*
* We must isolate the sign, significand, and exponent
* fields. The sign value is straightforward. Since
* floating-point numbers are stored with a normalized
* representation, the significand and exponent are
* interrelated.
*
* After extracting the sign, we normalized the
* significand as a hexadecimal value, calculating an
* exponent adjust for any shifts made during
* normalization. If the significand is zero, the
* exponent doesn't need to be examined since the output
* will be zero.
*
* Next the exponent in the input string is extracted.
* Afterwards, the significand is normalized as a *binary*
* value and the input value's normalized exponent can be
* computed. The significand bits are copied into a
* double significand; if the string has more logical bits
* than can fit in a double, the extra bits affect the
* round and sticky bits which are used to round the final
* value.
*/
// Extract significand sign
String group1 = m.group(1);
double sign = (( group1 == null ) || group1.equals("+"))? 1.0 : -1.0;
// Extract Significand magnitude
/*
* Based on the form of the significand, calculate how the
* binary exponent needs to be adjusted to create a
* normalized *hexadecimal* floating-point number; that
* is, a number where there is one nonzero hex digit to
* the left of the (hexa)decimal point. Since we are
* adjusting a binary, not hexadecimal exponent, the
* exponent is adjusted by a multiple of 4.
*
* There are a number of significand scenarios to consider;
* letters are used in indicate nonzero digits:
*
* 1. 000xxxx => x.xxx normalized
* increase exponent by (number of x's - 1)*4
*
* 2. 000xxx.yyyy => x.xxyyyy normalized
* increase exponent by (number of x's - 1)*4
*
* 3. .000yyy => y.yy normalized
* decrease exponent by (number of zeros + 1)*4
*
* 4. 000.00000yyy => y.yy normalized
* decrease exponent by (number of zeros to right of point + 1)*4
*
* If the significand is exactly zero, return a properly
* signed zero.
*/
String significandString =null;
int signifLength = 0;
int exponentAdjust = 0;
{
int leftDigits = 0; // number of meaningful digits to
// left of "decimal" point
// (leading zeros stripped)
int rightDigits = 0; // number of digits to right of
// "decimal" point; leading zeros
// must always be accounted for
/*
* The significand is made up of either
*
* 1. group 4 entirely (integer portion only)
*
* OR
*
* 2. the fractional portion from group 7 plus any
* (optional) integer portions from group 6.
*/
String group4;
if( (group4 = m.group(4)) != null) { // Integer-only significand
// Leading zeros never matter on the integer portion
significandString = stripLeadingZeros(group4);
leftDigits = significandString.length();
}
else {
// Group 6 is the optional integer; leading zeros
// never matter on the integer portion
String group6 = stripLeadingZeros(m.group(6));
leftDigits = group6.length();
// fraction
String group7 = m.group(7);
rightDigits = group7.length();
// Turn "integer.fraction" into "integer"+"fraction"
significandString =
((group6 == null)?"":group6) + // is the null
// check necessary?
group7;
}
significandString = stripLeadingZeros(significandString);
signifLength = significandString.length();
/*
* Adjust exponent as described above
*/
if (leftDigits >= 1) { // Cases 1 and 2
exponentAdjust = 4*(leftDigits - 1);
} else { // Cases 3 and 4
exponentAdjust = -4*( rightDigits - signifLength + 1);
}
// If the significand is zero, the exponent doesn't
// matter; return a properly signed zero.
if (signifLength == 0) { // Only zeros in input
return new FormattedFloatingDecimal(sign * 0.0);
}
}
// Extract Exponent
/*
* Use an int to read in the exponent value; this should
* provide more than sufficient range for non-contrived
* inputs. If reading the exponent in as an int does
* overflow, examine the sign of the exponent and
* significand to determine what to do.
*/
String group8 = m.group(8);
boolean positiveExponent = ( group8 == null ) || group8.equals("+");
long unsignedRawExponent;
try {
unsignedRawExponent = Integer.parseInt(m.group(9));
}
catch (NumberFormatException e) {
// At this point, we know the exponent is
// syntactically well-formed as a sequence of
// digits. Therefore, if an NumberFormatException
// is thrown, it must be due to overflowing int's
// range. Also, at this point, we have already
// checked for a zero significand. Thus the signs
// of the exponent and significand determine the
// final result:
//
// significand
// + -
// exponent + +infinity -infinity
// - +0.0 -0.0
return new FormattedFloatingDecimal(sign * (positiveExponent ?
Double.POSITIVE_INFINITY : 0.0));
}
long rawExponent =
(positiveExponent ? 1L : -1L) * // exponent sign
unsignedRawExponent; // exponent magnitude
// Calculate partially adjusted exponent
long exponent = rawExponent + exponentAdjust ;
// Starting copying non-zero bits into proper position in
// a long; copy explicit bit too; this will be masked
// later for normal values.
boolean round = false;
boolean sticky = false;
int bitsCopied=0;
int nextShift=0;
long significand=0L;
// First iteration is different, since we only copy
// from the leading significand bit; one more exponent
// adjust will be needed...
// IMPORTANT: make leadingDigit a long to avoid
// surprising shift semantics!
long leadingDigit = getHexDigit(significandString, 0);
/*
* Left shift the leading digit (53 - (bit position of
* leading 1 in digit)); this sets the top bit of the
* significand to 1. The nextShift value is adjusted
* to take into account the number of bit positions of
* the leadingDigit actually used. Finally, the
* exponent is adjusted to normalize the significand
* as a binary value, not just a hex value.
*/
if (leadingDigit == 1) {
significand |= leadingDigit << 52;
nextShift = 52 - 4;
/* exponent += 0 */ }
else if (leadingDigit <= 3) { // [2, 3]
significand |= leadingDigit << 51;
nextShift = 52 - 5;
exponent += 1;
}
else if (leadingDigit <= 7) { // [4, 7]
significand |= leadingDigit << 50;
nextShift = 52 - 6;
exponent += 2;
}
else if (leadingDigit <= 15) { // [8, f]
significand |= leadingDigit << 49;
nextShift = 52 - 7;
exponent += 3;
} else {
throw new AssertionError("Result from digit converstion too large!");
}
// The preceding if-else could be replaced by a single
// code block based on the high-order bit set in
// leadingDigit. Given leadingOnePosition,
// significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition);
// nextShift = 52 - (3 + leadingOnePosition);
// exponent += (leadingOnePosition-1);
/*
* Now the exponent variable is equal to the normalized
* binary exponent. Code below will make representation
* adjustments if the exponent is incremented after
* rounding (includes overflows to infinity) or if the
* result is subnormal.
*/
// Copy digit into significand until the significand can't
// hold another full hex digit or there are no more input
// hex digits.
int i = 0;
for(i = 1;
i < signifLength && nextShift >= 0;
i++) {
long currentDigit = getHexDigit(significandString, i);
significand |= (currentDigit << nextShift);
nextShift-=4;
}
// After the above loop, the bulk of the string is copied.
// Now, we must copy any partial hex digits into the
// significand AND compute the round bit and start computing
// sticky bit.
if ( i < signifLength ) { // at least one hex input digit exists
long currentDigit = getHexDigit(significandString, i);
// from nextShift, figure out how many bits need
// to be copied, if any
switch(nextShift) { // must be negative
case -1:
// three bits need to be copied in; can
// set round bit
significand |= ((currentDigit & 0xEL) >> 1);
round = (currentDigit & 0x1L) != 0L;
break;
case -2:
// two bits need to be copied in; can
// set round and start sticky
significand |= ((currentDigit & 0xCL) >> 2);
round = (currentDigit &0x2L) != 0L;
sticky = (currentDigit & 0x1L) != 0;
break;
case -3:
// one bit needs to be copied in
significand |= ((currentDigit & 0x8L)>>3);
// Now set round and start sticky, if possible
round = (currentDigit &0x4L) != 0L;
sticky = (currentDigit & 0x3L) != 0;
break;
case -4:
// all bits copied into significand; set
// round and start sticky
round = ((currentDigit & 0x8L) != 0); // is top bit set?
// nonzeros in three low order bits?
sticky = (currentDigit & 0x7L) != 0;
break;
default:
throw new AssertionError("Unexpected shift distance remainder.");
// break;
}
// Round is set; sticky might be set.
// For the sticky bit, it suffices to check the
// current digit and test for any nonzero digits in
// the remaining unprocessed input.
i++;
while(i < signifLength && !sticky) {
currentDigit = getHexDigit(significandString,i);
sticky = sticky || (currentDigit != 0);
i++;
}
}
// else all of string was seen, round and sticky are
// correct as false.
// Check for overflow and update exponent accordingly.
if (exponent > DoubleConsts.MAX_EXPONENT) { // Infinite result
// overflow to properly signed infinity
return new FormattedFloatingDecimal(sign * Double.POSITIVE_INFINITY);
} else { // Finite return value
if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result
exponent >= DoubleConsts.MIN_EXPONENT) {
// The result returned in this block cannot be a
// zero or subnormal; however after the
// significand is adjusted from rounding, we could
// still overflow in infinity.
// AND exponent bits into significand; if the
// significand is incremented and overflows from
// rounding, this combination will update the
// exponent correctly, even in the case of
// Double.MAX_VALUE overflowing to infinity.
significand = (( ((long)exponent +
(long)DoubleConsts.EXP_BIAS) <<
(DoubleConsts.SIGNIFICAND_WIDTH-1))
& DoubleConsts.EXP_BIT_MASK) |
(DoubleConsts.SIGNIF_BIT_MASK & significand);
} else { // Subnormal or zero
// (exponent < DoubleConsts.MIN_EXPONENT)
if (exponent < (DoubleConsts.MIN_SUB_EXPONENT -1 )) {
// No way to round back to nonzero value
// regardless of significand if the exponent is
// less than -1075.
return new FormattedFloatingDecimal(sign * 0.0);
} else { // -1075 <= exponent <= MIN_EXPONENT -1 = -1023
/*
* Find bit position to round to; recompute
* round and sticky bits, and shift
* significand right appropriately.
*/
sticky = sticky || round;
round = false;
// Number of bits of significand to preserve is
// exponent - abs_min_exp +1
// check:
// -1075 +1074 + 1 = 0
// -1023 +1074 + 1 = 52
int bitsDiscarded = 53 -
((int)exponent - DoubleConsts.MIN_SUB_EXPONENT + 1);
assert bitsDiscarded >= 1 && bitsDiscarded <= 53;
// What to do here:
// First, isolate the new round bit
round = (significand & (1L << (bitsDiscarded -1))) != 0L;
if (bitsDiscarded > 1) {
// create mask to update sticky bits; low
// order bitsDiscarded bits should be 1
long mask = ~((~0L) << (bitsDiscarded -1));
sticky = sticky || ((significand & mask) != 0L ) ;
}
// Now, discard the bits
significand = significand >> bitsDiscarded;
significand = (( ((long)(DoubleConsts.MIN_EXPONENT -1) + // subnorm exp.
(long)DoubleConsts.EXP_BIAS) <<
(DoubleConsts.SIGNIFICAND_WIDTH-1))
& DoubleConsts.EXP_BIT_MASK) |
(DoubleConsts.SIGNIF_BIT_MASK & significand);
}
}
// The significand variable now contains the currently
// appropriate exponent bits too.
/*
* Determine if significand should be incremented;
* making this determination depends on the least
* significant bit and the round and sticky bits.
*
* Round to nearest even rounding table, adapted from
* table 4.7 in "Computer Arithmetic" by IsraelKoren.
* The digit to the left of the "decimal" point is the
* least significant bit, the digits to the right of
* the point are the round and sticky bits
*
* Number Round(x)
* x0.00 x0.
* x0.01 x0.
* x0.10 x0.
* x0.11 x1. = x0. +1
* x1.00 x1.
* x1.01 x1.
* x1.10 x1. + 1
* x1.11 x1. + 1
*/
boolean incremented = false;
boolean leastZero = ((significand & 1L) == 0L);
if( ( leastZero && round && sticky ) ||
((!leastZero) && round )) {
incremented = true;
significand++;
}
FormattedFloatingDecimal fd = new FormattedFloatingDecimal(FpUtils.rawCopySign(
Double.longBitsToDouble(significand),
sign));
/*
* Set roundingDir variable field of fd properly so
* that the input string can be properly rounded to a
* float value. There are two cases to consider:
*
* 1. rounding to double discards sticky bit
* information that would change the result of a float
* rounding (near halfway case between two floats)
*
* 2. rounding to double rounds up when rounding up
* would not occur when rounding to float.
*
* For former case only needs to be considered when
* the bits rounded away when casting to float are all
* zero; otherwise, float round bit is properly set
* and sticky will already be true.
*
* The lower exponent bound for the code below is the
* minimum (normalized) subnormal exponent - 1 since a
* value with that exponent can round up to the
* minimum subnormal value and the sticky bit
* information must be preserved (i.e. case 1).
*/
if ((exponent >= FloatConsts.MIN_SUB_EXPONENT-1) &&
(exponent <= FloatConsts.MAX_EXPONENT ) ){
// Outside above exponent range, the float value
// will be zero or infinity.
/*
* If the low-order 28 bits of a rounded double
* significand are 0, the double could be a
* half-way case for a rounding to float. If the
* double value is a half-way case, the double
* significand may have to be modified to round
* the the right float value (see the stickyRound
* method). If the rounding to double has lost
* what would be float sticky bit information, the
* double significand must be incremented. If the
* double value's significand was itself
* incremented, the float value may end up too
* large so the increment should be undone.
*/
if ((significand & 0xfffffffL) == 0x0L) {
// For negative values, the sign of the
// roundDir is the same as for positive values
// since adding 1 increasing the significand's
// magnitude and subtracting 1 decreases the
// significand's magnitude. If neither round
// nor sticky is true, the double value is
// exact and no adjustment is required for a
// proper float rounding.
if( round || sticky) {
if (leastZero) { // prerounding lsb is 0
// If round and sticky were both true,
// and the least significant
// significand bit were 0, the rounded
// significand would not have its
// low-order bits be zero. Therefore,
// we only need to adjust the
// significand if round XOR sticky is
// true.
if (round ^ sticky) {
fd.roundDir = 1;
}
}
else { // prerounding lsb is 1
// If the prerounding lsb is 1 and the
// resulting significand has its
// low-order bits zero, the significand
// was incremented. Here, we undo the
// increment, which will ensure the
// right guard and sticky bits for the
// float rounding.
if (round)
fd.roundDir = -1;
}
}
}
}
fd.fromHex = true;
return fd;
}
}
}
/**
* Return <code>s</code> with any leading zeros removed.
*/
static String stripLeadingZeros(String s) {
return s.replaceFirst("^0+", "");
}
/**
* Extract a hexadecimal digit from position <code>position</code>
* of string <code>s</code>.
*/
static int getHexDigit(String s, int position) {
int value = Character.digit(s.charAt(position), 16);
if (value <= -1 || value >= 16) {
throw new AssertionError("Unxpected failure of digit converstion of " +
s.charAt(position));
}
return value;
}
}