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:
parent
0a64902056
commit
2f06b83dfc
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user