From 2f06b83dfcf601211b83b31d99b95b368f266493 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Thu, 12 Mar 2009 10:32:58 -0700 Subject: [PATCH] 6813240: Remove dead code in sun.misc.FormattedFloatingDecimal class Remove unused methods from FormattedFloatingDecimal that were originally copied from FloatingDecimal Reviewed-by: darcy --- .../sun/misc/FormattedFloatingDecimal.java | 812 ------------------ 1 file changed, 812 deletions(-) diff --git a/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java b/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java index a1a658a3e6f..99ba5224950 100644 --- a/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java +++ b/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java @@ -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 s with any leading zeros removed. - */ - static String stripLeadingZeros(String s) { - return s.replaceFirst("^0+", ""); - } - - /** - * Extract a hexadecimal digit from position position - * of string s. - */ - 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; - } - - }