author | olagneau |
Tue, 02 Oct 2012 10:11:57 +0100 | |
changeset 14015 | f771d5fb3b27 |
parent 14014 | da3648e13e67 |
child 14016 | 56be5085fc31 |
--- a/jdk/src/share/classes/java/text/DecimalFormat.java Mon Oct 01 15:36:57 2012 +0100 +++ b/jdk/src/share/classes/java/text/DecimalFormat.java Tue Oct 02 10:11:57 2012 +0100 @@ -529,9 +529,25 @@ @Override public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) { - fieldPosition.setBeginIndex(0); - fieldPosition.setEndIndex(0); - + // If fieldPosition is a DontCareFieldPosition instance we can + // try to go to fast-path code. + boolean tryFastPath = false; + if (fieldPosition == DontCareFieldPosition.INSTANCE) + tryFastPath = true; + else { + fieldPosition.setBeginIndex(0); + fieldPosition.setEndIndex(0); + } + + if (tryFastPath) { + String tempResult = fastFormat(number); + if (tempResult != null) { + result.append(tempResult); + return result; + } + } + + // if fast-path could not work, we fallback to standard code. return format(number, result, fieldPosition.getFieldDelegate()); } @@ -869,6 +885,720 @@ return delegate.getIterator(sb.toString()); } + // ==== Begin fast-path formating logic for double ========================= + + /* Fast-path formatting will be used for format(double ...) methods iff a + * number of conditions are met (see checkAndSetFastPathStatus()): + * - Only if instance properties meet the right predefined conditions. + * - The abs value of the double to format is <= Integer.MAX_VALUE. + * + * The basic approach is to split the binary to decimal conversion of a + * double value into two phases: + * * The conversion of the integer portion of the double. + * * The conversion of the fractional portion of the double + * (limited to two or three digits). + * + * The isolation and conversion of the integer portion of the double is + * straightforward. The conversion of the fraction is more subtle and relies + * on some rounding properties of double to the decimal precisions in + * question. Using the terminology of BigDecimal, this fast-path algorithm + * is applied when a double value has a magnitude less than Integer.MAX_VALUE + * and rounding is to nearest even and the destination format has two or + * three digits of *scale* (digits after the decimal point). + * + * Under a rounding to nearest even policy, the returned result is a digit + * string of a number in the (in this case decimal) destination format + * closest to the exact numerical value of the (in this case binary) input + * value. If two destination format numbers are equally distant, the one + * with the last digit even is returned. To compute such a correctly rounded + * value, some information about digits beyond the smallest returned digit + * position needs to be consulted. + * + * In general, a guard digit, a round digit, and a sticky *bit* are needed + * beyond the returned digit position. If the discarded portion of the input + * is sufficiently large, the returned digit string is incremented. In round + * to nearest even, this threshold to increment occurs near the half-way + * point between digits. The sticky bit records if there are any remaining + * trailing digits of the exact input value in the new format; the sticky bit + * is consulted only in close to half-way rounding cases. + * + * Given the computation of the digit and bit values, rounding is then + * reduced to a table lookup problem. For decimal, the even/odd cases look + * like this: + * + * Last Round Sticky + * 6 5 0 => 6 // exactly halfway, return even digit. + * 6 5 1 => 7 // a little bit more than halfway, round up. + * 7 5 0 => 8 // exactly halfway, round up to even. + * 7 5 1 => 8 // a little bit more than halfway, round up. + * With analogous entries for other even and odd last-returned digits. + * + * However, decimal negative powers of 5 smaller than 0.5 are *not* exactly + * representable as binary fraction. In particular, 0.005 (the round limit + * for a two-digit scale) and 0.0005 (the round limit for a three-digit + * scale) are not representable. Therefore, for input values near these cases + * the sticky bit is known to be set which reduces the rounding logic to: + * + * Last Round Sticky + * 6 5 1 => 7 // a little bit more than halfway, round up. + * 7 5 1 => 8 // a little bit more than halfway, round up. + * + * In other words, if the round digit is 5, the sticky bit is known to be + * set. If the round digit is something other than 5, the sticky bit is not + * relevant. Therefore, some of the logic about whether or not to increment + * the destination *decimal* value can occur based on tests of *binary* + * computations of the binary input number. + */ + + /** + * Check validity of using fast-path for this instance. If fast-path is valid + * for this instance, sets fast-path state as true and initializes fast-path + * utility fields as needed. + * + * This method is supposed to be called rarely, otherwise that will break the + * fast-path performance. That means avoiding frequent changes of the + * properties of the instance, since for most properties, each time a change + * happens, a call to this method is needed at the next format call. + * + * FAST-PATH RULES: + * Similar to the default DecimalFormat instantiation case. + * More precisely: + * - HALF_EVEN rounding mode, + * - isGroupingUsed() is true, + * - groupingSize of 3, + * - multiplier is 1, + * - Decimal separator not mandatory, + * - No use of exponential notation, + * - minimumIntegerDigits is exactly 1 and maximumIntegerDigits at least 10 + * - For number of fractional digits, the exact values found in the default case: + * Currency : min = max = 2. + * Decimal : min = 0. max = 3. + * + */ + private void checkAndSetFastPathStatus() { + + boolean fastPathWasOn = isFastPath; + + if ((roundingMode == RoundingMode.HALF_EVEN) && + (isGroupingUsed()) && + (groupingSize == 3) && + (multiplier == 1) && + (!decimalSeparatorAlwaysShown) && + (!useExponentialNotation)) { + + // The fast-path algorithm is semi-hardcoded against + // minimumIntegerDigits and maximumIntegerDigits. + isFastPath = ((minimumIntegerDigits == 1) && + (maximumIntegerDigits >= 10)); + + // The fast-path algorithm is hardcoded against + // minimumFractionDigits and maximumFractionDigits. + if (isFastPath) { + if (isCurrencyFormat) { + if ((minimumFractionDigits != 2) || + (maximumFractionDigits != 2)) + isFastPath = false; + } else if ((minimumFractionDigits != 0) || + (maximumFractionDigits != 3)) + isFastPath = false; + } + } else + isFastPath = false; + + // Since some instance properties may have changed while still falling + // in the fast-path case, we need to reinitialize fastPathData anyway. + if (isFastPath) { + // We need to instantiate fastPathData if not already done. + if (fastPathData == null) + fastPathData = new FastPathData(); + + // Sets up the locale specific constants used when formatting. + // '0' is our default representation of zero. + fastPathData.zeroDelta = symbols.getZeroDigit() - '0'; + fastPathData.groupingChar = symbols.getGroupingSeparator(); + + // Sets up fractional constants related to currency/decimal pattern. + fastPathData.fractionalMaxIntBound = (isCurrencyFormat) ? 99 : 999; + fastPathData.fractionalScaleFactor = (isCurrencyFormat) ? 100.0d : 1000.0d; + + // Records the need for adding prefix or suffix + fastPathData.positiveAffixesRequired = + (positivePrefix.length() != 0) || (positiveSuffix.length() != 0); + fastPathData.negativeAffixesRequired = + (negativePrefix.length() != 0) || (negativeSuffix.length() != 0); + + // Creates a cached char container for result, with max possible size. + int maxNbIntegralDigits = 10; + int maxNbGroups = 3; + int containerSize = + Math.max(positivePrefix.length(), negativePrefix.length()) + + maxNbIntegralDigits + maxNbGroups + 1 + maximumFractionDigits + + Math.max(positiveSuffix.length(), negativeSuffix.length()); + + fastPathData.fastPathContainer = new char[containerSize]; + + // Sets up prefix and suffix char arrays constants. + fastPathData.charsPositiveSuffix = positiveSuffix.toCharArray(); + fastPathData.charsNegativeSuffix = negativeSuffix.toCharArray(); + fastPathData.charsPositivePrefix = positivePrefix.toCharArray(); + fastPathData.charsNegativePrefix = negativePrefix.toCharArray(); + + // Sets up fixed index positions for integral and fractional digits. + // Sets up decimal point in cached result container. + int longestPrefixLength = + Math.max(positivePrefix.length(), negativePrefix.length()); + int decimalPointIndex = + maxNbIntegralDigits + maxNbGroups + longestPrefixLength; + + fastPathData.integralLastIndex = decimalPointIndex - 1; + fastPathData.fractionalFirstIndex = decimalPointIndex + 1; + fastPathData.fastPathContainer[decimalPointIndex] = + isCurrencyFormat ? + symbols.getMonetaryDecimalSeparator() : + symbols.getDecimalSeparator(); + + } else if (fastPathWasOn) { + // Previous state was fast-path and is no more. + // Resets cached array constants. + fastPathData.fastPathContainer = null; + fastPathData.charsPositiveSuffix = null; + fastPathData.charsNegativeSuffix = null; + fastPathData.charsPositivePrefix = null; + fastPathData.charsNegativePrefix = null; + } + + fastPathCheckNeeded = false; + } + + /** + * Returns true if rounding-up must be done on {@code scaledFractionalPartAsInt}, + * false otherwise. + * + * This is a utility method that takes correct half-even rounding decision on + * passed fractional value at the scaled decimal point (2 digits for currency + * case and 3 for decimal case), when the approximated fractional part after + * scaled decimal point is exactly 0.5d. This is done by means of exact + * calculations on the {@code fractionalPart} floating-point value. + * + * This method is supposed to be called by private {@code fastDoubleFormat} + * method only. + * + * The algorithms used for the exact calculations are : + * + * The <b><i>FastTwoSum</i></b> algorithm, from T.J.Dekker, described in the + * papers "<i>A Floating-Point Technique for Extending the Available + * Precision</i>" by Dekker, and in "<i>Adaptive Precision Floating-Point + * Arithmetic and Fast Robust Geometric Predicates</i>" from J.Shewchuk. + * + * A modified version of <b><i>Sum2S</i></b> cascaded summation described in + * "<i>Accurate Sum and Dot Product</i>" from Takeshi Ogita and All. As + * Ogita says in this paper this is an equivalent of the Kahan-Babuska's + * summation algorithm because we order the terms by magnitude before summing + * them. For this reason we can use the <i>FastTwoSum</i> algorithm rather + * than the more expensive Knuth's <i>TwoSum</i>. + * + * We do this to avoid a more expensive exact "<i>TwoProduct</i>" algorithm, + * like those described in Shewchuk's paper above. See comments in the code + * below. + * + * @param fractionalPart The fractional value on which we take rounding + * decision. + * @param scaledFractionalPartAsInt The integral part of the scaled + * fractional value. + * + * @return the decision that must be taken regarding half-even rounding. + */ + private boolean exactRoundUp(double fractionalPart, + int scaledFractionalPartAsInt) { + + /* exactRoundUp() method is called by fastDoubleFormat() only. + * The precondition expected to be verified by the passed parameters is : + * scaledFractionalPartAsInt == + * (int) (fractionalPart * fastPathData.fractionalScaleFactor). + * This is ensured by fastDoubleFormat() code. + */ + + /* We first calculate roundoff error made by fastDoubleFormat() on + * the scaled fractional part. We do this with exact calculation on the + * passed fractionalPart. Rounding decision will then be taken from roundoff. + */ + + /* ---- TwoProduct(fractionalPart, scale factor (i.e. 1000.0d or 100.0d)). + * + * The below is an optimized exact "TwoProduct" calculation of passed + * fractional part with scale factor, using Ogita's Sum2S cascaded + * summation adapted as Kahan-Babuska equivalent by using FastTwoSum + * (much faster) rather than Knuth's TwoSum. + * + * We can do this because we order the summation from smallest to + * greatest, so that FastTwoSum can be used without any additional error. + * + * The "TwoProduct" exact calculation needs 17 flops. We replace this by + * a cascaded summation of FastTwoSum calculations, each involving an + * exact multiply by a power of 2. + * + * Doing so saves overall 4 multiplications and 1 addition compared to + * using traditional "TwoProduct". + * + * The scale factor is either 100 (currency case) or 1000 (decimal case). + * - when 1000, we replace it by (1024 - 16 - 8) = 1000. + * - when 100, we replace it by (128 - 32 + 4) = 100. + * Every multiplication by a power of 2 (1024, 128, 32, 16, 8, 4) is exact. + * + */ + double approxMax; // Will always be positive. + double approxMedium; // Will always be negative. + double approxMin; + + double fastTwoSumApproximation = 0.0d; + double fastTwoSumRoundOff = 0.0d; + double bVirtual = 0.0d; + + if (isCurrencyFormat) { + // Scale is 100 = 128 - 32 + 4. + // Multiply by 2**n is a shift. No roundoff. No error. + approxMax = fractionalPart * 128.00d; + approxMedium = - (fractionalPart * 32.00d); + approxMin = fractionalPart * 4.00d; + } else { + // Scale is 1000 = 1024 - 16 - 8. + // Multiply by 2**n is a shift. No roundoff. No error. + approxMax = fractionalPart * 1024.00d; + approxMedium = - (fractionalPart * 16.00d); + approxMin = - (fractionalPart * 8.00d); + } + + // Shewchuk/Dekker's FastTwoSum(approxMedium, approxMin). + assert(-approxMedium >= Math.abs(approxMin)); + fastTwoSumApproximation = approxMedium + approxMin; + bVirtual = fastTwoSumApproximation - approxMedium; + fastTwoSumRoundOff = approxMin - bVirtual; + double approxS1 = fastTwoSumApproximation; + double roundoffS1 = fastTwoSumRoundOff; + + // Shewchuk/Dekker's FastTwoSum(approxMax, approxS1); + assert(approxMax >= Math.abs(approxS1)); + fastTwoSumApproximation = approxMax + approxS1; + bVirtual = fastTwoSumApproximation - approxMax; + fastTwoSumRoundOff = approxS1 - bVirtual; + double roundoff1000 = fastTwoSumRoundOff; + double approx1000 = fastTwoSumApproximation; + double roundoffTotal = roundoffS1 + roundoff1000; + + // Shewchuk/Dekker's FastTwoSum(approx1000, roundoffTotal); + assert(approx1000 >= Math.abs(roundoffTotal)); + fastTwoSumApproximation = approx1000 + roundoffTotal; + bVirtual = fastTwoSumApproximation - approx1000; + + // Now we have got the roundoff for the scaled fractional + double scaledFractionalRoundoff = roundoffTotal - bVirtual; + + // ---- TwoProduct(fractionalPart, scale (i.e. 1000.0d or 100.0d)) end. + + /* ---- Taking the rounding decision + * + * We take rounding decision based on roundoff and half-even rounding + * rule. + * + * The above TwoProduct gives us the exact roundoff on the approximated + * scaled fractional, and we know that this approximation is exactly + * 0.5d, since that has already been tested by the caller + * (fastDoubleFormat). + * + * Decision comes first from the sign of the calculated exact roundoff. + * - Since being exact roundoff, it cannot be positive with a scaled + * fractional less than 0.5d, as well as negative with a scaled + * fractional greater than 0.5d. That leaves us with following 3 cases. + * - positive, thus scaled fractional == 0.500....0fff ==> round-up. + * - negative, thus scaled fractional == 0.499....9fff ==> don't round-up. + * - is zero, thus scaled fractioanl == 0.5 ==> half-even rounding applies : + * we round-up only if the integral part of the scaled fractional is odd. + * + */ + if (scaledFractionalRoundoff > 0.0) { + return true; + } else if (scaledFractionalRoundoff < 0.0) { + return false; + } else if ((scaledFractionalPartAsInt & 1) != 0) { + return true; + } + + return false; + + // ---- Taking the rounding decision end + } + + /** + * Collects integral digits from passed {@code number}, while setting + * grouping chars as needed. Updates {@code firstUsedIndex} accordingly. + * + * Loops downward starting from {@code backwardIndex} position (inclusive). + * + * @param number The int value from which we collect digits. + * @param digitsBuffer The char array container where digits and grouping chars + * are stored. + * @param backwardIndex the position from which we start storing digits in + * digitsBuffer. + * + */ + private void collectIntegralDigits(int number, + char[] digitsBuffer, + int backwardIndex) { + int index = backwardIndex; + int q; + int r; + while (number > 999) { + // Generates 3 digits per iteration. + q = number / 1000; + r = number - (q << 10) + (q << 4) + (q << 3); // -1024 +16 +8 = 1000. + number = q; + + digitsBuffer[index--] = DigitArrays.DigitOnes1000[r]; + digitsBuffer[index--] = DigitArrays.DigitTens1000[r]; + digitsBuffer[index--] = DigitArrays.DigitHundreds1000[r]; + digitsBuffer[index--] = fastPathData.groupingChar; + } + + // Collects last 3 or less digits. + digitsBuffer[index] = DigitArrays.DigitOnes1000[number]; + if (number > 9) { + digitsBuffer[--index] = DigitArrays.DigitTens1000[number]; + if (number > 99) + digitsBuffer[--index] = DigitArrays.DigitHundreds1000[number]; + } + + fastPathData.firstUsedIndex = index; + } + + /** + * Collects the 2 (currency) or 3 (decimal) fractional digits from passed + * {@code number}, starting at {@code startIndex} position + * inclusive. There is no punctuation to set here (no grouping chars). + * Updates {@code fastPathData.lastFreeIndex} accordingly. + * + * + * @param number The int value from which we collect digits. + * @param digitsBuffer The char array container where digits are stored. + * @param startIndex the position from which we start storing digits in + * digitsBuffer. + * + */ + private void collectFractionalDigits(int number, + char[] digitsBuffer, + int startIndex) { + int index = startIndex; + + char digitOnes = DigitArrays.DigitOnes1000[number]; + char digitTens = DigitArrays.DigitTens1000[number]; + + if (isCurrencyFormat) { + // Currency case. Always collects fractional digits. + digitsBuffer[index++] = digitTens; + digitsBuffer[index++] = digitOnes; + } else if (number != 0) { + // Decimal case. Hundreds will always be collected + digitsBuffer[index++] = DigitArrays.DigitHundreds1000[number]; + + // Ending zeros won't be collected. + if (digitOnes != '0') { + digitsBuffer[index++] = digitTens; + digitsBuffer[index++] = digitOnes; + } else if (digitTens != '0') + digitsBuffer[index++] = digitTens; + + } else + // This is decimal pattern and fractional part is zero. + // We must remove decimal point from result. + index--; + + fastPathData.lastFreeIndex = index; + } + + /** + * Internal utility. + * Adds the passed {@code prefix} and {@code suffix} to {@code container}. + * + * @param container Char array container which to prepend/append the + * prefix/suffix. + * @param prefix Char sequence to prepend as a prefix. + * @param suffix Char sequence to append as a suffix. + * + */ + // private void addAffixes(boolean isNegative, char[] container) { + private void addAffixes(char[] container, char[] prefix, char[] suffix) { + + // We add affixes only if needed (affix length > 0). + int pl = prefix.length; + int sl = suffix.length; + if (pl != 0) prependPrefix(prefix, pl, container); + if (sl != 0) appendSuffix(suffix, sl, container); + + } + + /** + * Prepends the passed {@code prefix} chars to given result + * {@code container}. Updates {@code fastPathData.firstUsedIndex} + * accordingly. + * + * @param prefix The prefix characters to prepend to result. + * @param len The number of chars to prepend. + * @param container Char array container which to prepend the prefix + */ + private void prependPrefix(char[] prefix, + int len, + char[] container) { + + fastPathData.firstUsedIndex -= len; + int startIndex = fastPathData.firstUsedIndex; + + // If prefix to prepend is only 1 char long, just assigns this char. + // If prefix is less or equal 4, we use a dedicated algorithm that + // has shown to run faster than System.arraycopy. + // If more than 4, we use System.arraycopy. + if (len == 1) + container[startIndex] = prefix[0]; + else if (len <= 4) { + int dstLower = startIndex; + int dstUpper = dstLower + len - 1; + int srcUpper = len - 1; + container[dstLower] = prefix[0]; + container[dstUpper] = prefix[srcUpper]; + + if (len > 2) + container[++dstLower] = prefix[1]; + if (len == 4) + container[--dstUpper] = prefix[2]; + } else + System.arraycopy(prefix, 0, container, startIndex, len); + } + + /** + * Appends the passed {@code suffix} chars to given result + * {@code container}. Updates {@code fastPathData.lastFreeIndex} + * accordingly. + * + * @param suffix The suffix characters to append to result. + * @param len The number of chars to append. + * @param container Char array container which to append the suffix + */ + private void appendSuffix(char[] suffix, + int len, + char[] container) { + + int startIndex = fastPathData.lastFreeIndex; + + // If suffix to append is only 1 char long, just assigns this char. + // If suffix is less or equal 4, we use a dedicated algorithm that + // has shown to run faster than System.arraycopy. + // If more than 4, we use System.arraycopy. + if (len == 1) + container[startIndex] = suffix[0]; + else if (len <= 4) { + int dstLower = startIndex; + int dstUpper = dstLower + len - 1; + int srcUpper = len - 1; + container[dstLower] = suffix[0]; + container[dstUpper] = suffix[srcUpper]; + + if (len > 2) + container[++dstLower] = suffix[1]; + if (len == 4) + container[--dstUpper] = suffix[2]; + } else + System.arraycopy(suffix, 0, container, startIndex, len); + + fastPathData.lastFreeIndex += len; + } + + /** + * Converts digit chars from {@code digitsBuffer} to current locale. + * + * Must be called before adding affixes since we refer to + * {@code fastPathData.firstUsedIndex} and {@code fastPathData.lastFreeIndex}, + * and do not support affixes (for speed reason). + * + * We loop backward starting from last used index in {@code fastPathData}. + * + * @param digitsBuffer The char array container where the digits are stored. + */ + private void localizeDigits(char[] digitsBuffer) { + + // We will localize only the digits, using the groupingSize, + // and taking into account fractional part. + + // First take into account fractional part. + int digitsCounter = + fastPathData.lastFreeIndex - fastPathData.fractionalFirstIndex; + + // The case when there is no fractional digits. + if (digitsCounter < 0) + digitsCounter = groupingSize; + + // Only the digits remains to localize. + for (int cursor = fastPathData.lastFreeIndex - 1; + cursor >= fastPathData.firstUsedIndex; + cursor--) { + if (digitsCounter != 0) { + // This is a digit char, we must localize it. + digitsBuffer[cursor] += fastPathData.zeroDelta; + digitsCounter--; + } else { + // Decimal separator or grouping char. Reinit counter only. + digitsCounter = groupingSize; + } + } + } + + /** + * This is the main entry point for the fast-path format algorithm. + * + * At this point we are sure to be in the expected conditions to run it. + * This algorithm builds the formatted result and puts it in the dedicated + * {@code fastPathData.fastPathContainer}. + * + * @param d the double value to be formatted. + * @param negative Flag precising if {@code d} is negative. + */ + private void fastDoubleFormat(double d, + boolean negative) { + + char[] container = fastPathData.fastPathContainer; + + /* + * The principle of the algorithm is to : + * - Break the passed double into its integral and fractional parts + * converted into integers. + * - Then decide if rounding up must be applied or not by following + * the half-even rounding rule, first using approximated scaled + * fractional part. + * - For the difficult cases (approximated scaled fractional part + * being exactly 0.5d), we refine the rounding decision by calling + * exactRoundUp utility method that both calculates the exact roundoff + * on the approximation and takes correct rounding decision. + * - We round-up the fractional part if needed, possibly propagating the + * rounding to integral part if we meet a "all-nine" case for the + * scaled fractional part. + * - We then collect digits from the resulting integral and fractional + * parts, also setting the required grouping chars on the fly. + * - Then we localize the collected digits if needed, and + * - Finally prepend/append prefix/suffix if any is needed. + */ + + // Exact integral part of d. + int integralPartAsInt = (int) d; + + // Exact fractional part of d (since we subtract it's integral part). + double exactFractionalPart = d - (double) integralPartAsInt; + + // Approximated scaled fractional part of d (due to multiplication). + double scaledFractional = + exactFractionalPart * fastPathData.fractionalScaleFactor; + + // Exact integral part of scaled fractional above. + int fractionalPartAsInt = (int) scaledFractional; + + // Exact fractional part of scaled fractional above. + scaledFractional = scaledFractional - (double) fractionalPartAsInt; + + // Only when scaledFractional is exactly 0.5d do we have to do exact + // calculations and take fine-grained rounding decision, since + // approximated results above may lead to incorrect decision. + // Otherwise comparing against 0.5d (strictly greater or less) is ok. + boolean roundItUp = false; + if (scaledFractional >= 0.5d) { + if (scaledFractional == 0.5d) + // Rounding need fine-grained decision. + roundItUp = exactRoundUp(exactFractionalPart, fractionalPartAsInt); + else + roundItUp = true; + + if (roundItUp) { + // Rounds up both fractional part (and also integral if needed). + if (fractionalPartAsInt < fastPathData.fractionalMaxIntBound) { + fractionalPartAsInt++; + } else { + // Propagates rounding to integral part since "all nines" case. + fractionalPartAsInt = 0; + integralPartAsInt++; + } + } + } + + // Collecting digits. + collectFractionalDigits(fractionalPartAsInt, container, + fastPathData.fractionalFirstIndex); + collectIntegralDigits(integralPartAsInt, container, + fastPathData.integralLastIndex); + + // Localizing digits. + if (fastPathData.zeroDelta != 0) + localizeDigits(container); + + // Adding prefix and suffix. + if (negative) { + if (fastPathData.negativeAffixesRequired) + addAffixes(container, + fastPathData.charsNegativePrefix, + fastPathData.charsNegativeSuffix); + } else if (fastPathData.positiveAffixesRequired) + addAffixes(container, + fastPathData.charsPositivePrefix, + fastPathData.charsPositiveSuffix); + } + + /** + * A fast-path shortcut of format(double) to be called by NumberFormat, or by + * format(double, ...) public methods. + * + * If instance can be applied fast-path and passed double is not NaN or + * Infinity, is in the integer range, we call {@code fastDoubleFormat} + * after changing {@code d} to its positive value if necessary. + * + * Otherwise returns null by convention since fast-path can't be exercized. + * + * @param d The double value to be formatted + * + * @return the formatted result for {@code d} as a string. + */ + String fastFormat(double d) { + // (Re-)Evaluates fast-path status if needed. + if (fastPathCheckNeeded) + checkAndSetFastPathStatus(); + + if (!isFastPath ) + // DecimalFormat instance is not in a fast-path state. + return null; + + if (!Double.isFinite(d)) + // Should not use fast-path for Infinity and NaN. + return null; + + // Extracts and records sign of double value, possibly changing it + // to a positive one, before calling fastDoubleFormat(). + boolean negative = false; + if (d < 0.0d) { + negative = true; + d = -d; + } else if (d == 0.0d) { + negative = (Math.copySign(1.0d, d) == -1.0d); + d = +0.0d; + } + + if (d > MAX_INT_AS_DOUBLE) + // Filters out values that are outside expected fast-path range + return null; + else + fastDoubleFormat(d, negative); + + // Returns a new string from updated fastPathContainer. + return new String(fastPathData.fastPathContainer, + fastPathData.firstUsedIndex, + fastPathData.lastFreeIndex - fastPathData.firstUsedIndex); + + } + + // ======== End fast-path formating logic for double ========================= + /** * Complete the formatting of a finite number. On entry, the digitList must * be filled in with the correct digits. @@ -1168,8 +1898,7 @@ if (isNegative) { append(result, negativeSuffix, delegate, getNegativeSuffixFieldPositions(), Field.SIGN); - } - else { + } else { append(result, positiveSuffix, delegate, getPositiveSuffixFieldPositions(), Field.SIGN); } @@ -1557,8 +2286,7 @@ sawExponent = true; } break; // Whether we fail or succeed, we exit this loop - } - else { + } else { break; } } @@ -1653,6 +2381,7 @@ // don't allow multiple references symbols = (DecimalFormatSymbols) newSymbols.clone(); expandAffixes(); + fastPathCheckNeeded = true; } catch (Exception foo) { // should never happen } @@ -1674,6 +2403,7 @@ positivePrefix = newValue; posPrefixPattern = null; positivePrefixFieldPositions = null; + fastPathCheckNeeded = true; } /** @@ -1688,8 +2418,7 @@ if (positivePrefixFieldPositions == null) { if (posPrefixPattern != null) { positivePrefixFieldPositions = expandAffix(posPrefixPattern); - } - else { + } else { positivePrefixFieldPositions = EmptyFieldPositionArray; } } @@ -1711,6 +2440,7 @@ public void setNegativePrefix (String newValue) { negativePrefix = newValue; negPrefixPattern = null; + fastPathCheckNeeded = true; } /** @@ -1725,8 +2455,7 @@ if (negativePrefixFieldPositions == null) { if (negPrefixPattern != null) { negativePrefixFieldPositions = expandAffix(negPrefixPattern); - } - else { + } else { negativePrefixFieldPositions = EmptyFieldPositionArray; } } @@ -1748,6 +2477,7 @@ public void setPositiveSuffix (String newValue) { positiveSuffix = newValue; posSuffixPattern = null; + fastPathCheckNeeded = true; } /** @@ -1762,8 +2492,7 @@ if (positiveSuffixFieldPositions == null) { if (posSuffixPattern != null) { positiveSuffixFieldPositions = expandAffix(posSuffixPattern); - } - else { + } else { positiveSuffixFieldPositions = EmptyFieldPositionArray; } } @@ -1785,6 +2514,7 @@ public void setNegativeSuffix (String newValue) { negativeSuffix = newValue; negSuffixPattern = null; + fastPathCheckNeeded = true; } /** @@ -1799,8 +2529,7 @@ if (negativeSuffixFieldPositions == null) { if (negSuffixPattern != null) { negativeSuffixFieldPositions = expandAffix(negSuffixPattern); - } - else { + } else { negativeSuffixFieldPositions = EmptyFieldPositionArray; } } @@ -1834,6 +2563,16 @@ multiplier = newValue; bigDecimalMultiplier = null; bigIntegerMultiplier = null; + fastPathCheckNeeded = true; + } + + /** + * {@inheritDoc} + */ + @Override + public void setGroupingUsed(boolean newValue) { + super.setGroupingUsed(newValue); + fastPathCheckNeeded = true; } /** @@ -1860,6 +2599,7 @@ */ public void setGroupingSize (int newValue) { groupingSize = (byte)newValue; + fastPathCheckNeeded = true; } /** @@ -1878,6 +2618,7 @@ */ public void setDecimalSeparatorAlwaysShown(boolean newValue) { decimalSeparatorAlwaysShown = newValue; + fastPathCheckNeeded = true; } /** @@ -1908,6 +2649,20 @@ DecimalFormat other = (DecimalFormat) super.clone(); other.symbols = (DecimalFormatSymbols) symbols.clone(); other.digitList = (DigitList) digitList.clone(); + + // Fast-path is almost stateless algorithm. The only logical state is the + // isFastPath flag. In addition fastPathCheckNeeded is a sentinel flag + // that forces recalculation of all fast-path fields when set to true. + // + // There is thus no need to clone all the fast-path fields. + // We just only need to set fastPathCheckNeeded to true when cloning, + // and init fastPathData to null as if it were a truly new instance. + // Every fast-path field will be recalculated (only once) at next usage of + // fast-path algorithm. + other.fastPathCheckNeeded = true; + other.isFastPath = false; + other.fastPathData = null; + return other; } @@ -1917,8 +2672,10 @@ @Override public boolean equals(Object obj) { - if (obj == null) return false; - if (!super.equals(obj)) return false; // super does class check + if (obj == null) + return false; + if (!super.equals(obj)) + return false; // super does class check DecimalFormat other = (DecimalFormat) obj; return ((posPrefixPattern == other.posPrefixPattern && positivePrefix.equals(other.positivePrefix)) @@ -2206,8 +2963,7 @@ || affix.indexOf(symbols.getPatternSeparator()) >= 0 || affix.indexOf(symbols.getMinusSign()) >= 0 || affix.indexOf(CURRENCY_SIGN) >= 0; - } - else { + } else { needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0 || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0 || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0 @@ -2694,6 +3450,7 @@ super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); } + fastPathCheckNeeded = true; } /** @@ -2714,6 +3471,7 @@ super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); } + fastPathCheckNeeded = true; } /** @@ -2734,6 +3492,7 @@ super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? DOUBLE_FRACTION_DIGITS : minimumFractionDigits); } + fastPathCheckNeeded = true; } /** @@ -2754,6 +3513,7 @@ super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? DOUBLE_FRACTION_DIGITS : maximumFractionDigits); } + fastPathCheckNeeded = true; } /** @@ -2843,6 +3603,7 @@ expandAffixes(); } } + fastPathCheckNeeded = true; } /** @@ -2873,6 +3634,7 @@ this.roundingMode = roundingMode; digitList.setRoundingMode(roundingMode); + fastPathCheckNeeded = true; } /** @@ -2924,6 +3686,12 @@ stream.defaultReadObject(); digitList = new DigitList(); + // We force complete fast-path reinitialization when the instance is + // deserialized. See clone() comment on fastPathCheckNeeded. + fastPathCheckNeeded = true; + isFastPath = false; + fastPathData = null; + if (serialVersionOnStream < 4) { setRoundingMode(RoundingMode.HALF_EVEN); } @@ -3195,6 +3963,77 @@ */ private RoundingMode roundingMode = RoundingMode.HALF_EVEN; + // ------ DecimalFormat fields for fast-path for double algorithm ------ + + /** + * Helper inner utility class for storing the data used in the fast-path + * algorithm. Almost all fields related to fast-path are encapsulated in + * this class. + * + * Any {@code DecimalFormat} instance has a {@code fastPathData} + * reference field that is null unless both the properties of the instance + * are such that the instance is in the "fast-path" state, and a format call + * has been done at least once while in this state. + * + * Almost all fields are related to the "fast-path" state only and don't + * change until one of the instance properties is changed. + * + * {@code firstUsedIndex} and {@code lastFreeIndex} are the only + * two fields that are used and modified while inside a call to + * {@code fastDoubleFormat}. + * + */ + private static class FastPathData { + // --- Temporary fields used in fast-path, shared by several methods. + + /** The first unused index at the end of the formatted result. */ + int lastFreeIndex; + + /** The first used index at the beginning of the formatted result */ + int firstUsedIndex; + + // --- State fields related to fast-path status. Changes due to a + // property change only. Set by checkAndSetFastPathStatus() only. + + /** Difference between locale zero and default zero representation. */ + int zeroDelta; + + /** Locale char for grouping separator. */ + char groupingChar; + + /** Fixed index position of last integral digit of formatted result */ + int integralLastIndex; + + /** Fixed index position of first fractional digit of formatted result */ + int fractionalFirstIndex; + + /** Fractional constants depending on decimal|currency state */ + double fractionalScaleFactor; + int fractionalMaxIntBound; + + + /** The char array buffer that will contain the formatted result */ + char[] fastPathContainer; + + /** Suffixes recorded as char array for efficiency. */ + char[] charsPositivePrefix; + char[] charsNegativePrefix; + char[] charsPositiveSuffix; + char[] charsNegativeSuffix; + boolean positiveAffixesRequired = true; + boolean negativeAffixesRequired = true; + } + + /** The format fast-path status of the instance. Logical state. */ + private transient boolean isFastPath = false; + + /** Flag stating need of check and reinit fast-path status on next format call. */ + private transient boolean fastPathCheckNeeded = true; + + /** DecimalFormat reference to its FastPathData */ + private transient FastPathData fastPathData; + + //---------------------------------------------------------------------- static final int currentSerialVersion = 4; @@ -3228,6 +4067,54 @@ // CONSTANTS //---------------------------------------------------------------------- + // ------ Fast-Path for double Constants ------ + + /** Maximum valid integer value for applying fast-path algorithm */ + private static final double MAX_INT_AS_DOUBLE = (double) Integer.MAX_VALUE; + + /** + * The digit arrays used in the fast-path methods for collecting digits. + * Using 3 constants arrays of chars ensures a very fast collection of digits + */ + private static class DigitArrays { + static final char[] DigitOnes1000 = new char[1000]; + static final char[] DigitTens1000 = new char[1000]; + static final char[] DigitHundreds1000 = new char[1000]; + + // initialize on demand holder class idiom for arrays of digits + static { + int tenIndex = 0; + int hundredIndex = 0; + char digitOne = '0'; + char digitTen = '0'; + char digitHundred = '0'; + for (int i = 0; i < 1000; i++ ) { + + DigitOnes1000[i] = digitOne; + if (digitOne == '9') + digitOne = '0'; + else + digitOne++; + + DigitTens1000[i] = digitTen; + if (i == (tenIndex + 9)) { + tenIndex += 10; + if (digitTen == '9') + digitTen = '0'; + else + digitTen++; + } + + DigitHundreds1000[i] = digitHundred; + if (i == (hundredIndex + 99)) { + digitHundred++; + hundredIndex += 100; + } + } + } + } + // ------ Fast-Path for double Constants end ------ + // Constants for characters used in programmatic (unlocalized) patterns. private static final char PATTERN_ZERO_DIGIT = '0'; private static final char PATTERN_GROUPING_SEPARATOR = ',';
--- a/jdk/src/share/classes/java/text/NumberFormat.java Mon Oct 01 15:36:57 2012 +0100 +++ b/jdk/src/share/classes/java/text/NumberFormat.java Tue Oct 02 10:11:57 2012 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2012, 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 @@ -286,10 +286,21 @@ * @see java.text.Format#format */ public final String format(double number) { + // Use fast-path for double result if that works + String result = fastFormat(number); + if (result != null) + return result; + return format(number, new StringBuffer(), DontCareFieldPosition.INSTANCE).toString(); } + /* + * fastFormat() is supposed to be implemented in concrete subclasses only. + * Default implem always returns null. + */ + String fastFormat(double number) { return null; } + /** * Specialization of format. * @exception ArithmeticException if rounding is needed with rounding
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/text/Format/DecimalFormat/FormatMicroBenchmark.java Tue Oct 02 10:11:57 2012 +0100 @@ -0,0 +1,926 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* + * @test + * @bug 7050528 + * @summary Set of micro-benchmarks testing throughput of java.text.DecimalFormat.format() + * @author Olivier Lagneau + * @run main FormatMicroBenchmark + */ + +/* This is a set of micro-benchmarks testing throughput of java.text.DecimalFormat.format(). + * It never fails. + * + * Usage and arguments: + * - Run with no argument skips the whole benchmark and exits. + * - Run with "-help" as first argument calls the usage() method and exits. + * - Run with "-doit" runs the benchmark with summary details. + * - Run with "-verbose" provides additional details on the run. + * + * Example run : + * java -Xms500m -Xmx500m -XX:NewSize=400m FormatMicroBenchmark -doit -verbose + * + * Running with jtreg: + * The jtreg header "run" tag options+args must be changed to avoid skipping + * the execution. here is an example of run options: + * "main/othervm -Xms500m -Xmx500m -XX:NewSize=400m FormatMicroBenchmark -doit" + * + * Note: + * - Vm options -Xms, -Xmx, -XX:NewSize must be set correctly for + * getting reliable numbers. Otherwise GC activity may corrupt results. + * As of jdk80b48 using "-Xms500m -Xmx500m -XX:NewSize=400m" covers + * all cases. + * - Optionally using "-XX:+printGC" option provides information that + * helps checking any GC activity while benches are run. + * + * Vm Options: + * - Vm options to use (as of jdk80b48): + * fast-path case : -Xms128m -Xmx128m -XX:NewSize=100m + * non fast-path case: -Xms500m -Xmx500m -XX:NewSize=400m + * or use worst case (non fast-path above) with both types of algorithm. + * + * - use -XX:+PrintGC to verify memory consumption of the benchmarks. + * (See "Checking Memory Consumption" below). + * + * Description: + * + * Fast-path algorithm for format(double...) call stack is very different of + * the standard call stack. Where the standard algorithm for formating double + * uses internal class sun.misc.FloatingDecimal and its dtoa(double) method to + * provide digits, fast-path embeds its own algorithm for binary to decimal + * string conversion. + * + * FloatingDecimal always converts completely the passed double to a string. + * Fast-path converts only to the needed digits since it follows constraints + * on both the pattern rule, the DecimalFormat instance properties, and the + * passed double. + * + * Micro benchmarks below measure the throughput for formating double values + * using NumberFormat.format(double) call stack. The standard DecimalFormat + * call stack as well as the fast-path algorithm implementation are sensitive + * to the nature of the passed double values regarding throughput performance. + * + * These benchmarks are useful both for measuring the global performance gain + * of fast-path and to check that any modification done on fast-path algorithm + * does not bring any regression in the performance boost of fast-path. + * + * Note that these benchmarks will provide numbers without any knowledge of + * the implementation of DecimalFormat class. So to check regression any run + * should be compared to another reference run with a previous JDK, wether or + * not this previous reference JDK contains fast-path implementation. + * + * The eight benchmarks below are dedicated to measure throughput on different + * kinds of double that all fall in the fast-path case (all in Integer range): + * + * - Integer case : used double values are all "integer-like" (ex: -12345.0). + * This is the benchFormatInteger micro-benchmark. + * + * - Fractional case : double values are "fractional" (ex: -0.12345). + * This is the benchFormatFractional micro-benchmark. + * + * - Small integral case : like Integer case but double values are all limited + * in their magnitude, from -500.0 to 500.0 if the number of iterations N is + * set to 500000. + * This is the benchFormatSmallIntegral micro-benchmark. + * + * - Fractional All Nines : doubles values have fractional part that is very + * close to "999" (decimal pattern), or "99" (currency pattern), + * or "0000...". + * This is the benchFormatFractionalAllNines micro-benchmark. + * + * - All Nines : double values are such that both integral and fractional + * part consist only of '9' digits. None of these values are rounded up. + * This is the benchFormatAllNines micro-benchmark. + * + * - Fair simple case : calling J the loop variable and iterating over + * the N number of iterations, used double values are computed as + * d = (double) J + J*seed + * where seed is a very small value that adds a fractional part and adds a + * small number to integral part. Provides fairly distributed double values. + * This is the benchFormatFairSimple micro-benchmark. + * + * - Fair case : this is a combination of small integral case and fair simple + * case. Double values are limited in their magnitude but follow a parabolic + * curve y = x**2 / K, keeping large magnitude only for large values of J. + * The intent is trying to reproduce a distribution of double values as could + * be found in a business application, with most values in either the low + * range or the high range. + * This is the benchFormatFair micro-benchmark. + * + * - Tie cases: values are very close to a tie case (iii...ii.fff5) + * That is the worst situation that can happen for Fast-path algorithm when + * considering throughput. + * This is the benchFormatTie micro-benchmark. + * + * For all of the micro-benchmarks, the throughput load of the eventual + * additional computations inside the loop is calculated prior to running the + * benchmark, and provided in the output. That may be useful since this load + * may vary for each architecture or machine configuration. + * + * The "-verbose" flag, when set, provides the throughput load numbers, the + * time spent for each run of a benchmark, as well as an estimation of the + * memory consumed by the runs. Beware of incremental GCs, see "Checking + * Memory Consumption" section below. Every run should be done with correct + * ms, mx, and NewSize vm options to get fully reliable numbers. + * + * The output provides the mean time needed for a benchmark after the server + * jit compiler has done its optimization work if any. Thus only the last but + * first three runs are taken into account in the time measurement (server jit + * compiler shows to have done full optimization in most cases after the + * second run, given a base number of iterations set to 500000). + * + * The program cleans up memory (stabilizeMemory() method) between each run of + * the benchmarks to make sure that no garbage collection activity happens in + * measurements. However that does not preclude incremental GCs activity that + * may happen during the micro-benchmark if -Xms, -Xmx, and NewSize options + * have not been tuned and set correctly. + * + * Checking Memory Consumption: + * + * For getting confidence in the throughput numbers, there must not give any + * GC activity during the benchmark runs. That means that specific VM options + * related to memory must be tuned for any given implementation of the JDK. + * + * Running with "-verbose" arguments will provide clues of the memory consumed + * but is not enough, since any unexpected incremental GC may lower + * artificially the estimation of the memory consumption. + * + * Options to set are -Xms, -Xmx, -XX:NewSize, plus -XX:+PrintGC to evaluate + * correctly the values of these options. When running "-verbose", varying + * numbers reported for memory consumption may indicate bad choices for these + * options. + * + * For jdk80b25, fast-path shows a consuption of ~60Mbs for 500000 iterations + * while a jdk without fast-path will consume ~260Mbs for each benchmark run. + * Indeed these values will vary depending on the jdk used. + * + * Correct option settings found jdk80b48 were : + * fast-path : -Xms128m -Xmx128m -XX:NewSize=100m + * non fast-path : -Xms500m -Xmx500m -XX:NewSize=400m + * Greater values can be provided safely but not smaller ones. + * ---------------------------------------------------------------------- + */ + +import java.util.*; +import java.text.NumberFormat; +import java.text.DecimalFormat; + +public class FormatMicroBenchmark { + + // The number of times the bench method will be run (must be at least 4). + private static final int NB_RUNS = 20; + + // The bench* methods below all iterates over [-MAX_RANGE , +MAX_RANGE] integer values. + private static final int MAX_RANGE = 500000; + + // Flag for more details on each bench run (default is no). + private static boolean Verbose = false; + + // Should we really execute the benches ? (no by default). + private static boolean DoIt = false; + + // Prints out a message describing how to run the program. + private static void usage() { + System.out.println( + "This is a set of micro-benchmarks testing throughput of " + + "java.text.DecimalFormat.format(). It never fails.\n\n" + + "Usage and arguments:\n" + + " - Run with no argument skips the whole benchmark and exits.\n" + + " - Run with \"-help\" as first argument prints this message and exits.\n" + + " - Run with \"-doit\" runs the benchmark with summary details.\n" + + " - Run with \"-verbose\" provides additional details on the run.\n\n" + + "Example run :\n" + + " java -Xms500m -Xmx500m -XX:NewSize=400m FormatMicroBenchmark -doit -verbose\n\n" + + "Note: \n" + + " - Vm options -Xms, -Xmx, -XX:NewSize must be set correctly for \n" + + " getting reliable numbers. Otherwise GC activity may corrupt results.\n" + + " As of jdk80b48 using \"-Xms500m -Xmx500m -XX:NewSize=400m\" covers \n" + + " all cases.\n" + + " - Optionally using \"-XX:+printGC\" option provides information that \n" + + " helps checking any GC activity while benches are run.\n\n" + + "Look at the heading comments and description in source code for " + + "detailed information.\n"); + } + + /* We will call stabilizeMemory before each call of benchFormat***(). + * This in turn tries to clean up as much memory as possible. + * As a safe bound we limit number of System.gc() calls to 10, + * but most of the time two calls to System.gc() will be enough. + * If memory reporting is asked for, the method returns the difference + * of free memory between entering an leaving the method. + */ + private static long stabilizeMemory(boolean reportConsumedMemory) { + final long oneMegabyte = 1024L * 1024L; + + long refMemory = 0; + long initialMemoryLeft = Runtime.getRuntime().freeMemory(); + long currMemoryLeft = initialMemoryLeft; + int nbGCCalls = 0; + + do { + nbGCCalls++; + + refMemory = currMemoryLeft; + System.gc(); + currMemoryLeft = Runtime.getRuntime().freeMemory(); + + } while ((Math.abs(currMemoryLeft - refMemory) > oneMegabyte) && + (nbGCCalls < 10)); + + if (Verbose && + reportConsumedMemory) + System.out.println("Memory consumed by previous run : " + + (currMemoryLeft - initialMemoryLeft)/oneMegabyte + "Mbs."); + + return currMemoryLeft; + } + + + // ---------- Integer only based bench -------------------- + private static final String INTEGER_BENCH = "benchFormatInteger"; + private static String benchFormatInteger(NumberFormat nf) { + String str = ""; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) + str = nf.format((double) j); + return str; + } + + // This reproduces the throughput load added in benchFormatInteger + static double integerThroughputLoad() { + double d = 0.0d; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + d = (double) j; + } + return d; + } + + // Runs integerThroughputLoad and calculate its mean load + static void calculateIntegerThroughputLoad() { + int nbRuns = NB_RUNS; + long elapsedTime = 0; + double foo; + + for (int i = 1; i <= nbRuns; i++) { + + long startTime = System.nanoTime(); + foo = integerThroughputLoad(); + long estimatedTime = System.nanoTime() - startTime; + if (i > 3) elapsedTime += estimatedTime / 1000; + } + + + if (Verbose) + System.out.println( + "calculated throughput load for " + INTEGER_BENCH + + " bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds"); + } + + // ---------- Fractional only based bench -------------------- + private static final String FRACTIONAL_BENCH = "benchFormatFractional"; + private static String benchFormatFractional(NumberFormat nf) { + String str = ""; + double floatingN = 1.0d / (double) MAX_RANGE; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) + str = nf.format(floatingN * (double) j); + return str; + } + + // This reproduces the throughput load added in benchFormatFractional + static double fractionalThroughputLoad() { + double d = 0.0d; + double floatingN = 1.0d / (double) MAX_RANGE; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + d = floatingN * (double) j; + } + return d; + } + + // Runs fractionalThroughputLoad and calculate its mean load + static void calculateFractionalThroughputLoad() { + int nbRuns = NB_RUNS; + long elapsedTime = 0; + double foo; + + for (int i = 1; i <= nbRuns; i++) { + + long startTime = System.nanoTime(); + foo = fractionalThroughputLoad(); + long estimatedTime = System.nanoTime() - startTime; + if (i > 3) elapsedTime += estimatedTime / 1000; + } + + if (Verbose) + System.out.println( + "calculated throughput load for " + FRACTIONAL_BENCH + + " bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds"); + } + + // ---------- An Small Integral bench -------------------- + // that limits the magnitude of tested double values + private static final String SMALL_INTEGRAL_BENCH = "benchFormatSmallIntegral"; + private static String benchFormatSmallIntegral(NumberFormat nf) { + String str = ""; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) + str = nf.format(((double) j) / 1000.0d); + return str; + } + + // This reproduces the throughput load added in benchFormatSmallIntegral + static double smallIntegralThroughputLoad() { + double d = 0.0d; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + d = (double) j / 1000.0d; + } + return d; + } + + // Runs small_integralThroughputLoad and calculate its mean load + static void calculateSmallIntegralThroughputLoad() { + int nbRuns = NB_RUNS; + long elapsedTime = 0; + double foo; + + for (int i = 1; i <= nbRuns; i++) { + + long startTime = System.nanoTime(); + foo = smallIntegralThroughputLoad(); + long estimatedTime = System.nanoTime() - startTime; + if (i > 3) elapsedTime += estimatedTime / 1000; + } + + if (Verbose) + System.out.println( + "calculated throughput load for " + SMALL_INTEGRAL_BENCH + + " bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds"); + } + + // ---------- A fair and simple bench -------------------- + private static final String FAIR_SIMPLE_BENCH = "benchFormatFairSimple"; + private static String benchFormatFairSimple(NumberFormat nf, boolean isCurrency) { + String str = ""; + double seed = isCurrency ? 0.0010203040506070809 : 0.00010203040506070809; + double d = (double) -MAX_RANGE; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + d = d + 1.0d + seed; + str = nf.format(d); + } + return str; + } + + // This reproduces the throughput load added in benchFormatFairSimple + static double fairSimpleThroughputLoad() { + double seed = 0.00010203040506070809; + double delta = 0.0d; + double d = (double) -MAX_RANGE; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + d = d + 1.0d + seed; + } + return d; + } + + // Runs fairThroughputLoad and calculate its mean load + static void calculateFairSimpleThroughputLoad() { + int nbRuns = NB_RUNS; + long elapsedTime = 0; + double foo; + + for (int i = 1; i <= nbRuns; i++) { + + long startTime = System.nanoTime(); + foo = fairSimpleThroughputLoad(); + long estimatedTime = System.nanoTime() - startTime; + if (i > 3) elapsedTime += estimatedTime / 1000; + } + + if (Verbose) + System.out.println( + "calculated throughput load for " + FAIR_SIMPLE_BENCH + + " bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds"); + } + + // ---------- Fractional part is only made of nines bench -------------- + private static final String FRACTIONAL_ALL_NINES_BENCH = "benchFormatFractionalAllNines"; + private static String benchFormatFractionalAllNines(NumberFormat nf, boolean isCurrency) { + String str = ""; + double fractionalEven = isCurrency ? 0.993000001 : 0.99930000001; + double fractionalOdd = isCurrency ? 0.996000001 : 0.99960000001; + double fractional; + double d; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + if ((j & 1) == 0) + fractional = fractionalEven; + else + fractional = fractionalOdd; + if ( j >= 0) + d = (double ) j + fractional; + else d = (double) j - fractional; + str = nf.format(d); + } + return str; + } + + // This reproduces the throughput load added in benchFormatFractionalAllNines + static double fractionalAllNinesThroughputLoad() { + double fractionalEven = 0.99930000001; + double fractionalOdd = 0.99960000001; + double fractional; + double d = 0.0d; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + if ((j & 1) == 0) + fractional = fractionalEven; + else fractional = fractionalOdd; + if ( j >= 0) + d = (double ) j + fractional; + else d = (double) j - fractional; + } + return d; + } + + // Runs fractionalAllNinesThroughputLoad and calculate its mean load + static void calculateFractionalAllNinesThroughputLoad() { + int nbRuns = NB_RUNS; + long elapsedTime = 0; + double foo; + + for (int i = 1; i <= nbRuns; i++) { + + long startTime = System.nanoTime(); + foo = fractionalAllNinesThroughputLoad(); + long estimatedTime = System.nanoTime() - startTime; + if (i > 3) elapsedTime += estimatedTime / 1000; + } + + if (Verbose) + System.out.println( + "calculated throughput load for " + FRACTIONAL_ALL_NINES_BENCH + + " bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds"); + } + + // ---------- Number is only made of nines bench -------------- + private static final String ALL_NINES_BENCH = "benchFormatAllNines"; + private static String benchFormatAllNines(NumberFormat nf, boolean isCurrency) { + String str = ""; + double[] decimaAllNines = + {9.9993, 99.9993, 999.9993, 9999.9993, 99999.9993, + 999999.9993, 9999999.9993, 99999999.9993, 999999999.9993}; + double[] currencyAllNines = + {9.993, 99.993, 999.993, 9999.993, 99999.993, + 999999.993, 9999999.993, 99999999.993, 999999999.993}; + double[] valuesArray = (isCurrency) ? currencyAllNines : decimaAllNines; + double seed = 1.0 / (double) MAX_RANGE; + double d; + int id; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + id = (j >= 0) ? j % 9 : -j % 9; + if ((j & 1) == 0) + d = valuesArray[id] + id * seed; + else + d = valuesArray[id] - id * seed; + str = nf.format(d); + } + return str; + } + + // This reproduces the throughput load added in benchFormatAllNines + static double allNinesThroughputLoad() { + double[] decimaAllNines = + {9.9993, 99.9993, 999.9993, 9999.9993, 99999.9993, + 999999.9993, 9999999.9993, 99999999.9993, 999999999.9993}; + double[] valuesArray = decimaAllNines; + double seed = 1.0 / (double) MAX_RANGE; + double d = 0.0d; + int id; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + id = (j >= 0) ? j % 9 : -j % 9; + if ((j & 1) == 0) + d = valuesArray[id] + id * seed; + else + d = valuesArray[id] - id * seed; + } + return d; + } + + // Runs allNinesThroughputLoad and calculate its mean load + static void calculateAllNinesThroughputLoad() { + int nbRuns = NB_RUNS; + long elapsedTime = 0; + double foo; + + for (int i = 1; i <= nbRuns; i++) { + + long startTime = System.nanoTime(); + foo = allNinesThroughputLoad(); + long estimatedTime = System.nanoTime() - startTime; + if (i > 3) elapsedTime += estimatedTime / 1000; + } + + if (Verbose) + System.out.println( + "calculated throughput load for " + ALL_NINES_BENCH + + " bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds"); + } + + + + // --- A fair bench trying (hopefully) to reproduce business applicatons --- + + /* benchFormatFair uses the following formula : + * y = F(x) = sign(x) * x**2 * ((1000/MAX_RANGE)**2). + * + * which converts in the loop as (if j is the loop index) : + * x = double(j) + * k = 1000.0d * double(MAX_RANGE) + * y = sign(j) * x**2 * k**2 + * + * This is a flattened parabolic curve where only the j values + * in [-1000, 1000] will provide y results in [-1, +1] interval, + * and for abs(j) >= 1000 the result y will be greater than 1. + * + * The difference with benchFormatSmallIntegral is that since y results + * follow a parabolic curve the magnitude of y grows much more rapidly + * and closer to j values when abs(j) >= 1000: + * - for |j| < 1000, SmallIntegral(j) < 1.0 and fair(j) < 1.0 + * - for j in [1000, 10000[ + * SmallIntegral(j) is in [1, 10[ + * Fair(j) is in [4, 400[ + * - for j in [10000,100000[ + * SmallIntegral(j) is in [10, 100[ + * Fair(j) is in [400,40000[ + * - for j in [100000,1000000[ + * SmallIntegral(j) is in [100, 1000[ + * Fair(j) is in [40000, 4000000[ + * + * Since double values for j less than 100000 provide only 4 digits in the + * integral, values greater than 250000 provide at least 6 digits, and 500000 + * computes to 1000000, the distribution is roughly half with less than 5 + * digits and half with at least 6 digits in the integral part. + * + * Compared to FairSimple bench, this represents an application where 20% of + * the double values to format are less than 40000.0 absolute value. + * + * Fair(j) is close to the magnitude of j when j > 100000 and is hopefully + * more representative of what may be found in general in business apps. + * (assumption : there will be mainly either small or large values, and + * less values in middle range). + * + * We could get even more precise distribution of values using formula : + * y = sign(x) * abs(x)**n * ((1000 / MAX_RANGE)**n) where n > 2, + * or even well-known statistics function to fine target such distribution, + * but we have considred that the throughput load for calculating y would + * then be too high. We thus restrain the use of a power of 2 formula. + */ + + private static final String FAIR_BENCH = "benchFormatFair"; + private static String benchFormatFair(NumberFormat nf) { + String str = ""; + double k = 1000.0d / (double) MAX_RANGE; + k *= k; + + double d; + double absj; + double jPowerOf2; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + absj = (double) j; + jPowerOf2 = absj * absj; + d = k * jPowerOf2; + if (j < 0) d = -d; + str = nf.format(d); + } + return str; + } + + // This is the exact throughput load added in benchFormatFair + static double fairThroughputLoad() { + double k = 1000.0d / (double) MAX_RANGE; + k *= k; + + double d = 0.0d; + double absj; + double jPowerOf2; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + absj = (double) j; + jPowerOf2 = absj * absj; + d = k * jPowerOf2; + if (j < 0) d = -d; + } + return d; + } + + // Runs fairThroughputLoad and calculate its mean load + static void calculateFairThroughputLoad() { + int nbRuns = NB_RUNS; + long elapsedTime = 0; + double foo; + + for (int i = 1; i <= nbRuns; i++) { + + long startTime = System.nanoTime(); + foo = fairThroughputLoad(); + long estimatedTime = System.nanoTime() - startTime; + if (i > 3) elapsedTime += estimatedTime / 1000; + } + + if (Verbose) + System.out.println( + "calculated throughput load for " + FAIR_BENCH + + " bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds"); + } + + // ---------- All double values are very close to a tie -------------------- + // i.e. like 123.1235 (for decimal case) or 123.125 (for currency case). + + private static final String TIE_BENCH = "benchFormatTie"; + private static String benchFormatTie(NumberFormat nf, boolean isCurrency) { + double d; + String str = ""; + double fractionaScaling = (isCurrency) ? 1000.0d : 10000.0d; + int fixedFractionalPart = (isCurrency) ? 125 : 1235; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + d = (((double) j * fractionaScaling) + + (double) fixedFractionalPart) / fractionaScaling; + str = nf.format(d); + } + return str; + } + + // This is the exact throughput load added in benchFormatTie + static double tieThroughputLoad(boolean isCurrency) { + double d = 0.0d; + double fractionaScaling = (isCurrency) ? 1000.0d : 10000.0d; + int fixedFractionalPart = (isCurrency) ? 125 : 1235; + for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) { + d = (((double) j * fractionaScaling) + + (double) fixedFractionalPart) / fractionaScaling; + } + return d; + } + + // Runs tieThroughputLoad and calculate its mean load + static void calculateTieThroughputLoad(boolean isCurrency) { + int nbRuns = NB_RUNS; + long elapsedTime = 0; + double foo; + + for (int i = 1; i <= nbRuns; i++) { + + long startTime = System.nanoTime(); + foo = tieThroughputLoad(isCurrency); + long estimatedTime = System.nanoTime() - startTime; + if (i > 3) elapsedTime += estimatedTime / 1000; + } + + if (Verbose) + System.out.println( + "calculated throughput load for " + TIE_BENCH + + " bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds"); + } + + + // Print statistics for passed times results of benchName. + static void printPerfResults(long[] times, String benchName) { + int nbBenches = times.length; + + long totalTimeSpent = 0; + long meanTimeSpent; + + double variance = 0; + double standardDeviation = 0; + + // Calculates mean spent time + for (int i = 1; i <= nbBenches; i++) + totalTimeSpent += times[i-1]; + meanTimeSpent = totalTimeSpent / nbBenches; + + // Calculates standard deviation + for (int j = 1; j <= nbBenches; j++) + variance += Math.pow(((double)times[j-1] - (double)meanTimeSpent), 2); + variance = variance / (double) times.length; + standardDeviation = Math.sqrt(variance) / meanTimeSpent; + + // Print result and statistics for benchName + System.out.println( + "Statistics (starting at 4th bench) for bench " + benchName + + "\n for last " + nbBenches + + " runs out of " + NB_RUNS + + " , each with 2x" + MAX_RANGE + " format(double) calls : " + + "\n mean exec time = " + meanTimeSpent + " microseconds" + + "\n standard deviation = " + String.format("%.3f", standardDeviation) + "% \n"); + } + + public static void main(String[] args) { + + if (args.length >= 1) { + // Parse args, just checks expected ones. Ignore others or dups. + if (args[0].equals("-help")) { + usage(); + return; + } + + for (String s : args) { + if (s.equals("-doit")) + DoIt = true; + else if (s.equals("-verbose")) + Verbose = true; + } + } else { + // No arguments, skips the benchmarks and exits. + System.out.println( + "Test skipped with success by default. See -help for details."); + return; + } + + if (!DoIt) { + if (Verbose) + usage(); + System.out.println( + "Test skipped and considered successful."); + return; + } + + System.out.println("Single Threaded micro benchmark evaluating " + + "the throughput of java.text.DecimalFormat.format() call stack.\n"); + + String fooString = ""; + + // Run benches for decimal instance + DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(Locale.US); + System.out.println("Running with a decimal instance of DecimalFormat."); + + calculateIntegerThroughputLoad(); + fooString = + BenchType.INTEGER_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false); + + calculateFractionalThroughputLoad(); + fooString = + BenchType.FRACTIONAL_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false); + + calculateSmallIntegralThroughputLoad(); + fooString = + BenchType.SMALL_INTEGRAL_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false); + + calculateFractionalAllNinesThroughputLoad(); + fooString = + BenchType.FRACTIONAL_ALL_NINES_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false); + + calculateAllNinesThroughputLoad(); + fooString = + BenchType.ALL_NINES_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false); + + calculateFairSimpleThroughputLoad(); + fooString = + BenchType.FAIR_SIMPLE_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false); + + calculateFairThroughputLoad(); + fooString = + BenchType.FAIR_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false); + + calculateTieThroughputLoad(false); + fooString = + BenchType.TIE_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false); + + // Run benches for currency instance + DecimalFormat cf = (DecimalFormat) NumberFormat.getCurrencyInstance(Locale.US); + System.out.println("Running with a currency instance of DecimalFormat."); + + calculateIntegerThroughputLoad(); + fooString = + BenchType.INTEGER_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false); + + calculateFractionalThroughputLoad(); + fooString = + BenchType.FRACTIONAL_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false); + + calculateSmallIntegralThroughputLoad(); + fooString = + BenchType.SMALL_INTEGRAL_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false); + + calculateFractionalAllNinesThroughputLoad(); + fooString = + BenchType.FRACTIONAL_ALL_NINES_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false); + + calculateAllNinesThroughputLoad(); + fooString = + BenchType.ALL_NINES_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false); + + calculateFairSimpleThroughputLoad(); + fooString = + BenchType.FAIR_SIMPLE_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false); + + calculateFairThroughputLoad(); + fooString = + BenchType.FAIR_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false); + + calculateTieThroughputLoad(false); + fooString = + BenchType.TIE_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false); + + } + + // This class to factorise what would be duplicated otherwise. + static enum BenchType { + + INTEGER_BENCH("benchFormatInteger"), + FRACTIONAL_BENCH("benchFormatFractional"), + SMALL_INTEGRAL_BENCH("benchFormatSmallIntegral"), + FAIR_SIMPLE_BENCH("benchFormatFairSimple"), + FRACTIONAL_ALL_NINES_BENCH("benchFormatFractionalAllNines"), + ALL_NINES_BENCH("benchFormatAllNines"), + FAIR_BENCH("benchFormatFair"), + TIE_BENCH("benchFormatTie"); + + private final String name; + + BenchType(String name) { + this.name = name; + } + + String runBenchAndPrintStatistics(int nbRuns, + NumberFormat nf, + boolean isCurrency) { + + // We eliminate the first 3 runs in the time measurements + // to let C2 do complete compilation and optimization work. + long[] elapsedTimes = new long[nbRuns - 3]; + + System.out.println("Now running " + nbRuns + " times bench " + name); + + String str = ""; + for (int i = 1; i <= nbRuns; i++) { + + stabilizeMemory(false); + long startTime = System.nanoTime(); + + switch(this) { + case INTEGER_BENCH : + str = benchFormatInteger(nf); + break; + case FRACTIONAL_BENCH : + str = benchFormatFractional(nf); + break; + case SMALL_INTEGRAL_BENCH : + str = benchFormatSmallIntegral(nf); + break; + case FRACTIONAL_ALL_NINES_BENCH : + str = benchFormatFractionalAllNines(nf, isCurrency); + break; + case ALL_NINES_BENCH : + str = benchFormatAllNines(nf, isCurrency); + break; + case FAIR_SIMPLE_BENCH : + str = benchFormatFairSimple(nf, isCurrency); + break; + case FAIR_BENCH : + str = benchFormatFair(nf); + break; + case TIE_BENCH : + str = benchFormatTie(nf, isCurrency); + break; + + default: + } + + + long estimatedTime = System.nanoTime() - startTime; + if (i > 3) + elapsedTimes[i-4] = estimatedTime / 1000; + + if (Verbose) + System.out.println( + "calculated time for " + name + + " bench " + i + " is = " + + (estimatedTime / 1000) + " microseconds"); + else System.out.print("."); + + stabilizeMemory(true); + } + + System.out.println(name + " Done."); + + printPerfResults(elapsedTimes, name); + + return str; + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/text/Format/DecimalFormat/GoldenDoubleValues.java Tue Oct 02 10:11:57 2012 +0100 @@ -0,0 +1,965 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* Set of constants and values used in RoundingAndPropertyTest.java. + * + * There are 5 different information in this class: + * - TestLocale is the locale used by RoundingAndPropertyTest regression test + * when calling DecimalFormat.format() on either the set of DecimalGoldenValues + * or CurrencyGoldenValues. + * See main method of RoundingAndPropertyTest. + * + * - FullLocalizationTestLocale is the locale used by RoundingAndPropertyTest + * regression test when calling DecimalFormat.format() on the set of values + * (DecimalLocalizationValues) used to test that localization of digits + * happens correctly when needed. + * See main method of RoundingAndPropertyTest. + * + * - DecimalLocalizationValues is an array containing all the double values used + * to check that localization of digits happens correctly when needed. + * See RoundingAndPropertyTest.testLocalizationValues() method. + * + * - DecimalGoldenValues and CurrencyGoldenValues are arrays containing all the + * double values that will be used as input when checking correctness of + * results returned by DecimalFormat.format(). + * 2 arrays are needed since decimal and currency formatting patterns require + * a different number of digits after decimal point. + * See RoundingAndPropertyTest.testGoldenValues() method. + * + * - PROPERTY_CHECK_POSITIVE_VALUE and PROPERTY_CHECK_NEGATIVE_VALUE are the + * double values used for testing the validity of the property changes call + * in the fast-path case. The locale used in that case is TestLocale. + * See RoundingAndPropertyTest.testSettersAndFastPath() method. + */ + +import java.util.*; + +class GoldenDoubleValues { + + // TestLocale is the testing locale used by RoundingAndPropertyTest test, + // when testing the golden double values + static final Locale TestLocale = new Locale("en", "US"); + + + // FullTestLocale is the testing locale used by RoundingAndPropertyTest test, + // when testing full localization of double values. + static final Locale FullLocalizationTestLocale = new Locale("hi", "IN"); + + + /* Below are the two double values used for exercising the changes of + * of DecimalFormat properties and symbols. These values are also used + * as golden values (see golden arrays below). + */ + + /* PROPERTY_CHECK_NEGATIVE_VALUE is the negative double value used for + * testing the validity of the property changes for fast-path. + * See testSettersAndFastPath() in RoundingAndPropertyTest test. + */ + static final double PROPERTY_CHECK_NEGATIVE_VALUE = -2147483646.2334997d; + + /* PROPERTY_CHECK_POSITIVE_VALUE is the positive double value used for + * testing the validity of the property changes for fast-path. + * See testSettersAndFastPath() in RoundingAndPropertyTest test. + */ + static final double PROPERTY_CHECK_POSITIVE_VALUE = 2147483646.2335003d; + + /* --- Array of double values to test localization ------------------------ + * + * For most locales, effective localization does not happen on digits, i.e. + * the digits are not changed due to localization. In order to check that + * fast-path localize correctly digits in such a case, the array of double + * values below deals with all the case of localization that may happen on + * digits + */ + static final double[] DecimalLocalizationValues = { + 1.123, + 12.123, + 123.123, + 1234.123, + 12345.123, + 123456.123, + 1234567.123, + 12345678.123, + 123456789.123, + 1234567890.123, + 1234.0, + 1234.9, + 1234.99, + 1234.999 + }; + + + /* --- Arrays of golden double values ---------------------------------- + * + * The GoldenValues arrays are used as input values for checking the + * correctness of the DecimalFormat.format() call results done in + * RoundingAndPropertyTest regression test. The results are compared to the + * expected ones found in GoldenFormattedValues. For each value in the + * arrays there is a corresponding expected string result found, + * represented as an array of unicode values, at the same index in the + * related GoldenFormattedValues array. The string returned by the format + * call and the found in GoldenFormattedValues array must be equal for the + * result to be considered valid. + * See RoundingAndPropertyTest.testGoldenValues() method. + * + * We need 2 such GoldenValues arrays since the decimal and currency + * formatting rules require different number of digits after decimal point. + * + * Thus we have two different arrays of golden values: + * - DecimalGoldenValues for the decimal case. + * - CurrencyGoldenValues for the currency case. + * + * They are associated to related GoldenFormattedValues arrays, generated by + * running RoundingAndPropertyTest with a "gengold" argument: + * - DecimalGoldenFormattedValues for the decimal case. + * - CurrencyGoldenFormattedValues for the currency case. + * These two generated arrays are found in GoldenFormattedValues.java file. + * + * The impact of the formatting rules is as follows, because the pattern + * rule for the fractional part is different for decimal and currency + * patterns: + * - in decimal case one must output the first non-zero 3 digits of + * fractional part 1.1232 => "1.123" and 1.12016789 => "1.12" + * - in currency case the first 2 fractional digits are always output + * 1.1232 => "1.12" and 1.0016789 => "1.00" + * + * Thus we need a different number of fractional digits when we specify + * below the golden double values to check, and most of the decimal and + * currency golden values differ only in the number of fractional digits. + * + * The list below exercises almost all code pathes of the fast-path + * algorithm except localization of digits. + */ + + // --- The set of golden values for the Decimal formatting case -------- + static final double[] DecimalGoldenValues = { + // Testing of specific values + +0.0, + -0.0, + Double.MIN_VALUE, + Double.MIN_NORMAL, + PROPERTY_CHECK_NEGATIVE_VALUE, + PROPERTY_CHECK_POSITIVE_VALUE, + -2147483647.9996, + 2147483647.9996, + -1999999999.9994997, + 1999999999.9995003, + // Testing fast-path range checks (all outside bounds) + Double.NaN, + Double.POSITIVE_INFINITY, + Double.NEGATIVE_INFINITY, + Double.MAX_VALUE, + -9876543210.9876543, + 9876543210.9876543, + -1234567890.1234567E128, + 1234567890.1234567E128, + // Testing of integral string size + 1.123, + 12.123, + 123.123, + 1234.123, + 12345.123, + 123456.123, + 1234567.123, + 12345678.123, + 123456789.123, + 1234567890.123, + -1.123, + -12.123, + -123.123, + -1234.123, + -12345.123, + -123456.123, + -1234567.123, + -12345678.123, + -123456789.123, + -1234567890.123, + // Testing of fractional string size + 0.1, + 0.12, + 0.123, + 0.1234, + 10.1, + 10.12, + 10.123, + 10.1234, + 100.1, + 100.12, + 100.123, + 100.1234, + 1000.1, + 1000.12, + 1000.123, + 1000.1234, + 10000.1, + 10000.12, + 10000.123, + 10000.1234, + 100000.1, + 100000.12, + 100000.123, + 100000.1234, + 1000000.1, + 1000000.12, + 1000000.123, + 1000000.1234, + 10000000.1, + 10000000.12, + 10000000.123, + 10000000.1234, + 100000000.1, + 100000000.12, + 100000000.123, + 100000000.1234, + 1000000000.1, + 1000000000.12, + 1000000000.123, + 1000000000.1234, + -0.1, + -0.12, + -0.123, + -0.1234, + -10.1, + -10.12, + -10.123, + -10.1234, + -100.1, + -100.12, + -100.123, + -100.1234, + -1000.1, + -1000.12, + -1000.123, + -1000.1234, + -10000.1, + -10000.12, + -10000.123, + -10000.1234, + -100000.1, + -100000.12, + -100000.123, + -100000.1234, + -1000000.1, + -1000000.12, + -1000000.123, + -1000000.1234, + -10000000.1, + -10000000.12, + -10000000.123, + -10000000.1234, + -100000000.1, + -100000000.12, + -100000000.123, + -100000000.1234, + -1000000000.1, + -1000000000.12, + -1000000000.123, + -1000000000.1234, + // Testing of special rounding cases + 1.9993, + 12.9993, + 123.9993, + 1234.9993, + 12345.9993, + 123456.9993, + 1234567.9993, + 12345678.9993, + 123456789.9993, + 1234567890.9993, + 1.9996, + 12.9996, + 123.9996, + 1234.9996, + 12345.9996, + 123456.9996, + 1234567.9996, + 12345678.9996, + 123456789.9996, + 1234567890.9996, + -1.9993, + -12.9993, + -123.9993, + -1234.9993, + -12345.9993, + -123456.9993, + -1234567.9993, + -12345678.9993, + -123456789.9993, + -1234567890.9993, + -1.9996, + -12.9996, + -123.9996, + -1234.9996, + -12345.9996, + -123456.9996, + -1234567.9996, + -12345678.9996, + -123456789.9996, + -1234567890.9996, + 109.9996, + 1099.9996, + 10999.9996, + 109999.9996, + 1099999.9996, + 10999999.9996, + 109999999.9996, + 1099999999.9996, + -109.9996, + -1099.9996, + -10999.9996, + -109999.9996, + -1099999.9996, + -10999999.9996, + -109999999.9996, + -1099999999.9996, + 1.9996, + 19.9996, + 199.9996, + 1999.9996, + 19999.9996, + 199999.9996, + 1999999.9996, + 19999999.9996, + 199999999.9996, + 1999999999.9996, + -1.9996, + -19.9996, + -199.9996, + -1999.9996, + -19999.9996, + -199999.9996, + -1999999.9996, + -19999999.9996, + -199999999.9996, + -1999999999.9996, + // Testing for all nines cases + 9.9996, + 99.9996, + 999.9996, + 9999.9996, + 99999.9996, + 999999.9996, + 9999999.9996, + 99999999.9996, + 999999999.9996, + 9.999, + 99.999, + 999.999, + 9999.999, + 99999.999, + 999999.999, + 9999999.999, + 99999999.999, + 999999999.999, + -9.9996, + -99.9996, + -999.9996, + -9999.9996, + -99999.9996, + -999999.9996, + -9999999.9996, + -99999999.9996, + -999999999.9996, + -9.999, + -99.999, + -999.999, + -9999.999, + -99999.999, + -999999.999, + -9999999.999, + -99999999.999, + -999999999.999, + // Testing for no Fractional part cases + 1.0, + 12.0, + 123.0, + 1234.0, + 12345.0, + 123456.0, + 1234567.0, + 12345678.0, + 123456789.0, + 1234567890.0, + -1.0, + -12.0, + -123.0, + -1234.0, + -12345.0, + -123456.0, + -1234567.0, + -12345678.0, + -123456789.0, + -1234567890.0, + // Testing of tricky cases + -2599.399999990123, + -2599.339999990123, + -2599.333999990123, + 1.000099999999818, + 1.000199999999818, + 1.000299999999818, + 1.000399999999818, + 1.000499999999818, + 1.000599999999818, + 1.000699999999818, + 1.000799999999818, + 1.000899999999818, + 1.000999999999818, + 1.2224999999999980, + 1.2224999999999981, + 1.2224999999999982, + 1.2224999999999983, + 1.2224999999999984, + 1.2224999999999985, + 1.2224999999999986, + 1.2224999999999987, + 1.2224999999999988, + 1.2224999999999989, + 1.2224999999999990, + 1.2224999999999991, + 1.2224999999999992, + 1.2224999999999993, + 1.2224999999999994, + 1.2224999999999995, + 1.2224999999999996, + 1.2224999999999997, + 1.2224999999999998, + // 1.2225 and 1.2224999999999999 have the same double approximation + 1.2225, + 1.2225000000000001, + 1.2225000000000002, + 1.2225000000000003, + 1.2225000000000004, + 1.2225000000000005, + 1.2225000000000006, + 1.2225000000000007, + 1.2225000000000008, + 1.2225000000000009, + 1.2225000000000010, + 1.2225000000000011, + 1.2225000000000012, + 1.2225000000000013, + 1.2225000000000014, + 1.2225000000000015, + 1.2225000000000016, + 1.2225000000000017, + 1.2225000000000018, + 1.2225000000000019, + // Tricky rounding cases around tie values + 100913.67050000005, + 199999.99895901306, + 251846.3465, + 253243.8825000001, + 365045.85349999997, + 314734.9615, + 541133.9755, + 858372.1225, + 1000999.9995000001, + 1347505.7825, + 3358844.1975, + 9997979.4085, + 9993743.1585, + 9938671.9085, + 3385302.5465, + 3404642.6605, + 3431280.0865, + 3438756.4754999997, + 3446053.7874999996, + 3457917.5125, + 3465393.9014999997, + 3484734.0154999997, + 3492031.3274999997, + 3503895.0525, + 3511371.4414999997, + 3518668.7534999996, + 3530532.4785, + 3538008.8674999997, + 3545306.1794999996, + 3557169.9045, + 3557348.9814999998, + 3564646.2934999997, + 3583986.4074999997, + 3591283.7194999997, + 3603147.4445, + 3610623.8334999997, + 3617921.1454999996, + 3629784.8705, + 3637261.2594999997, + 3656422.2965, + 3656601.3734999998, + 3663898.6854999997, + 3675762.4105, + 3683238.7994999997, + 3690536.1114999996, + 3702399.8365, + 3709876.2254999997, + 3717173.5374999996, + 3729037.2625, + 3736513.6514999997, + 3755853.7654999997, + 3763151.0774999997, + 3775014.8025, + 3782491.1914999997, + 3789788.5034999996, + 3801652.2285, + 3809128.6174999997, + 3816425.9294999996, + 3828289.6545, + 3828468.7314999998, + 3835766.0434999997, + 3855106.1574999997, + 3862403.4694999997, + 3874267.1945, + 3881743.5834999997, + 3889040.8954999996, + 3900904.6205, + 3908381.0094999997, + 3927542.0465, + 3927721.1234999998, + 3935018.4354999997, + 3946882.1605, + 3954358.5494999997, + 3961655.8614999996, + 3973519.5865, + 3980995.9754999997, + 3988293.2874999996, + 4000157.0125, + 4007633.4014999997, + 4026973.5154999997, + 4034270.8274999997, + 4046134.5525, + 4053610.9414999997, + 4060908.2534999996, + 4072771.9785, + 4080248.3674999997, + 4087545.6794999996, + 4099409.4045, + 4099588.4814999998, + 4106885.7934999997, + 4126225.9074999997, + 4133523.2194999997, + 4145386.9445, + 4152863.3334999997, + 4160160.6454999996, + 4172024.3705, + 4179500.7594999997, + 4198661.7965, + 4203407.2865, + 4210704.5985, + 4213435.4975 + }; + + // --- The set of golden values for the currency formatting case -------- + static final double[] CurrencyGoldenValues = { + // Testing of specific values + +0.0, + -0.0, + Double.MIN_VALUE, + Double.MIN_NORMAL, + PROPERTY_CHECK_NEGATIVE_VALUE, + PROPERTY_CHECK_POSITIVE_VALUE, + -2147483647.996, + 2147483647.996, + -1999999999.9949997, + 1999999999.9950003, + // Testing fast-path range checks (all outside bounds) + Double.NaN, + Double.POSITIVE_INFINITY, + Double.NEGATIVE_INFINITY, + Double.MAX_VALUE, + -9876543210.9876543, + 9876543210.9876543, + -1234567890.1234567E128, + 1234567890.1234567E128, + // Testing of integral string size + 1.12, + 12.12, + 123.12, + 1234.12, + 12345.12, + 123456.12, + 1234567.12, + 12345678.12, + 123456789.12, + 1234567890.12, + -1.12, + -12.12, + -123.12, + -1234.12, + -12345.12, + -123456.12, + -1234567.12, + -12345678.12, + -123456789.12, + -1234567890.12, + // Testing of fractional string size + 0.1, + 0.12, + 0.123, + 10.1, + 10.12, + 10.123, + 100.1, + 100.12, + 100.123, + 1000.1, + 1000.12, + 1000.123, + 10000.1, + 10000.12, + 10000.123, + 100000.1, + 100000.12, + 100000.123, + 1000000.1, + 1000000.12, + 1000000.123, + 10000000.1, + 10000000.12, + 10000000.123, + 100000000.1, + 100000000.12, + 100000000.123, + 1000000000.1, + 1000000000.12, + 1000000000.123, + -0.1, + -0.12, + -0.123, + -10.1, + -10.12, + -10.123, + -100.1, + -100.12, + -100.123, + -1000.1, + -1000.12, + -1000.123, + -10000.1, + -10000.12, + -10000.123, + -100000.1, + -100000.12, + -100000.123, + -1000000.1, + -1000000.12, + -1000000.123, + -10000000.1, + -10000000.12, + -10000000.123, + -100000000.1, + -100000000.12, + -100000000.123, + -1000000000.1, + -1000000000.12, + -1000000000.123, + // Testing of special rounding cases + 1.993, + 12.993, + 123.993, + 1234.993, + 12345.993, + 123456.993, + 1234567.993, + 12345678.993, + 123456789.993, + 1234567890.993, + 1.996, + 12.996, + 123.996, + 1234.996, + 12345.996, + 123456.996, + 1234567.996, + 12345678.996, + 123456789.996, + 1234567890.996, + -1.993, + -12.993, + -123.993, + -1234.993, + -12345.993, + -123456.993, + -1234567.993, + -12345678.993, + -123456789.993, + -1234567890.993, + -1.996, + -12.996, + -123.996, + -1234.996, + -12345.996, + -123456.996, + -1234567.996, + -12345678.996, + -123456789.996, + -1234567890.996, + 109.996, + 1099.996, + 10999.996, + 109999.996, + 1099999.996, + 10999999.996, + 109999999.996, + 1099999999.996, + -109.996, + -1099.996, + -10999.996, + -109999.996, + -1099999.996, + -10999999.996, + -109999999.996, + -1099999999.996, + 1.996, + 19.996, + 199.996, + 1999.996, + 19999.996, + 199999.996, + 1999999.996, + 19999999.996, + 199999999.996, + 1999999999.996, + -1.996, + -19.996, + -199.996, + -1999.996, + -19999.996, + -199999.996, + -1999999.996, + -19999999.996, + -199999999.996, + -1999999999.996, + // Testing of all nines cases + 9.996, + 99.996, + 999.996, + 9999.996, + 99999.996, + 999999.996, + 9999999.996, + 99999999.996, + 999999999.996, + 9.99, + 99.99, + 999.99, + 9999.99, + 99999.99, + 999999.99, + 9999999.99, + 99999999.99, + 999999999.99, + -9.996, + -99.996, + -999.996, + -9999.996, + -99999.996, + -999999.996, + -9999999.996, + -99999999.996, + -999999999.996, + -9.99, + -99.99, + -999.99, + -9999.99, + -99999.99, + -999999.99, + -9999999.99, + -99999999.99, + -999999999.99, + // Testing of no Fractional part cases + 1.0, + 12.0, + 123.0, + 1234.0, + 12345.0, + 123456.0, + 1234567.0, + 12345678.0, + 123456789.0, + 1234567890.0, + -1.0, + -12.0, + -123.0, + -1234.0, + -12345.0, + -123456.0, + -1234567.0, + -12345678.0, + -123456789.0, + -1234567890.0, + // Testing of tricky cases + -2599.399999990123, + -2599.339999990123, + -2599.333999990123, + 1.000999999999818, + 1.001999999999818, + 1.002999999999818, + 1.003999999999818, + 1.004999999999818, + 1.005999999999818, + 1.006999999999818, + 1.007999999999818, + 1.008999999999818, + 1.009999999999818, + 1.224999999999980, + 1.224999999999981, + 1.224999999999982, + 1.224999999999983, + 1.224999999999984, + 1.224999999999985, + 1.224999999999986, + 1.224999999999987, + 1.224999999999988, + 1.224999999999989, + 1.224999999999990, + 1.224999999999991, + 1.224999999999992, + 1.224999999999993, + 1.224999999999994, + 1.224999999999995, + 1.224999999999996, + 1.224999999999997, + 1.224999999999998, + 1.224999999999999, + 1.225, + 1.225000000000001, + 1.225000000000002, + 1.225000000000003, + 1.225000000000004, + 1.225000000000005, + 1.225000000000006, + 1.225000000000007, + 1.225000000000008, + 1.225000000000009, + 1.225000000000010, + 1.225000000000011, + 1.225000000000012, + 1.225000000000013, + 1.225000000000014, + 1.225000000000015, + 1.225000000000016, + 1.225000000000017, + 1.225000000000018, + 1.225000000000019, + // Tricky rounding cases around tie values + 1009136.7050000005, + 2518463.465, + 2532438.825000001, + 3650458.5349999997, + 3147349.615, + 5411339.755, + 8583721.225, + 13475057.825, + 33588441.975, + 99979794.085, + 99937431.585, + 99386719.085, + 33853025.465, + 34046426.605, + 34312800.865, + 34387564.754999997, + 34460537.874999996, + 34579175.125, + 34653939.014999997, + 34847340.154999997, + 34920313.274999997, + 35038950.525, + 35113714.414999997, + 35186687.534999996, + 35305324.785, + 35380088.674999997, + 35453061.794999996, + 35571699.045, + 35573489.814999998, + 35646462.934999997, + 35839864.074999997, + 35912837.194999997, + 36031474.445, + 36106238.334999997, + 36179211.454999996, + 36297848.705, + 36372612.594999997, + 36564222.965, + 36566013.734999998, + 36638986.854999997, + 36757624.105, + 36832387.994999997, + 36905361.114999996, + 37023998.365, + 37098762.254999997, + 37171735.374999996, + 37290372.625, + 37365136.514999997, + 37558537.654999997, + 37631510.774999997, + 37750148.025, + 37824911.914999997, + 37897885.034999996, + 38016522.285, + 38091286.174999997, + 38164259.294999996, + 38282896.545, + 38284687.314999998, + 38357660.434999997, + 38551061.574999997, + 38624034.694999997, + 38742671.945, + 38817435.834999997, + 38890408.954999996, + 39009046.205, + 39083810.094999997, + 39275420.465, + 39277211.234999998, + 39350184.354999997, + 39468821.605, + 39543585.494999997, + 39616558.614999996, + 39735195.865, + 39809959.754999997, + 39882932.874999996, + 40001570.125, + 40076334.014999997, + 40269735.154999997, + 40342708.274999997, + 40461345.525, + 40536109.414999997, + 40609082.534999996, + 40727719.785, + 40802483.674999997, + 40875456.794999996, + 40994094.045, + 40995884.814999998, + 41068857.934999997, + 41262259.074999997, + 41335232.194999997, + 41453869.445, + 41528633.334999997, + 41601606.454999996, + 41720243.705, + 41795007.594999997, + 41986617.965, + 42034072.865, + 42107045.985, + 42134354.975 + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/text/Format/DecimalFormat/GoldenFormattedValues.java Tue Oct 02 10:11:57 2012 +0100 @@ -0,0 +1,868 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* This is a machine generated file - Please DO NOT EDIT ! + * Change RoundingAndPropertyTest instead, + * and run with "-gengold" argument to regenerate (without copyright header). + */ + +/* This file contains the set of result Strings expected from calling inside + * RoundingAndPropertyTest the method NumberFormat.format() upon the set of + * double values provided in GoldenDoubleValues.java. It contains three arrays, + * each containing arrays of unicode values representing the expected string + * result when calling format() on the corresponding (i.e. same index) double + * value found in GoldenDoubleValues arrays : + * - DecimalDigitsLocalizedFormattedValues corresponds to DecimalLocalizationValues, + * when using FullLocalizationTestLocale to format. + * - DecimalGoldenFormattedValues corresponds to DecimalGoldenValues, when used + * in the decimal pattern case together with TestLocale. + * - CurrencyGoldenFormattedValues corresponds to CurrencyGoldenValues. when used + * in the currency pattern case together with TestLocale. + * Please see documentation in RoundingAndPropertyTest.java for more details. + * + * This file generated by running RoundingAndPropertyTest with "-gengold" argument. + */ + +class GoldenFormattedValues { + + // The formatted values below were generated from golden values + // listed in GoldenDoubleValues.java, using the following jvm version : + // Oracle Corporation Java HotSpot(TM) Server VM 1.8.0-ea + // locale for golden double values : en_US + // locale for testing digit localization : hi_IN + + // The array of int[] unicode values storing the expected results + // when experiencing full localization of digits on DecimalLocalizationValues. + static int[][] DecimalDigitsLocalizedFormattedValues = { + { 2407, 46, 2407, 2408, 2409 }, + { 2407, 2408, 46, 2407, 2408, 2409 }, + { 2407, 2408, 2409, 46, 2407, 2408, 2409 }, + { 2407, 44, 2408, 2409, 2410, 46, 2407, 2408, 2409 }, + { 2407, 2408, 44, 2409, 2410, 2411, 46, 2407, 2408, 2409 }, + { 2407, 2408, 2409, 44, 2410, 2411, 2412, 46, 2407, 2408, 2409 }, + { 2407, 44, 2408, 2409, 2410, 44, 2411, 2412, 2413, 46, 2407, 2408, 2409 }, + { 2407, 2408, 44, 2409, 2410, 2411, 44, 2412, 2413, 2414, 46, 2407, 2408, 2409 }, + { 2407, 2408, 2409, 44, 2410, 2411, 2412, 44, 2413, 2414, 2415, 46, 2407, 2408, 2409 }, + { 2407, 44, 2408, 2409, 2410, 44, 2411, 2412, 2413, 44, 2414, 2415, 2406, 46, 2407, 2408, 2409 }, + { 2407, 44, 2408, 2409, 2410 }, + { 2407, 44, 2408, 2409, 2410, 46, 2415 }, + { 2407, 44, 2408, 2409, 2410, 46, 2415, 2415 }, + { 2407, 44, 2408, 2409, 2410, 46, 2415, 2415, 2415 }, + }; + + // The array of int[] unicode values storing the expected results + // when calling Decimal.format(double) on the decimal GoldenDoubleValues. + static int[][] DecimalGoldenFormattedValues = { + { 48 }, + { 45, 48 }, + { 48 }, + { 48 }, + { 45, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 54, 46, 50, 51, 51 }, + { 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 54, 46, 50, 51, 52 }, + { 45, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 56 }, + { 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 56 }, + { 45, 49, 44, 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 65533 }, + { 8734 }, + { 45, 8734 }, + { 49, 55, 57, 44, 55, 54, 57, 44, 51, 49, 51, 44, 52, 56, 54, 44, 50, 51, 49, 44, 53, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 57, 44, 56, 55, 54, 44, 53, 52, 51, 44, 50, 49, 48, 46, 57, 56, 56 }, + { 57, 44, 56, 55, 54, 44, 53, 52, 51, 44, 50, 49, 48, 46, 57, 56, 56 }, + { 45, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 44, 48, 49, 50, 44, 51, 52, 53, 44, 54, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 44, 48, 49, 50, 44, 51, 52, 53, 44, 54, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 49, 46, 49, 50, 51 }, + { 49, 50, 46, 49, 50, 51 }, + { 49, 50, 51, 46, 49, 50, 51 }, + { 49, 44, 50, 51, 52, 46, 49, 50, 51 }, + { 49, 50, 44, 51, 52, 53, 46, 49, 50, 51 }, + { 49, 50, 51, 44, 52, 53, 54, 46, 49, 50, 51 }, + { 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 49, 50, 51 }, + { 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 49, 50, 51 }, + { 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 49, 50, 51 }, + { 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 49, 50, 51 }, + { 45, 49, 46, 49, 50, 51 }, + { 45, 49, 50, 46, 49, 50, 51 }, + { 45, 49, 50, 51, 46, 49, 50, 51 }, + { 45, 49, 44, 50, 51, 52, 46, 49, 50, 51 }, + { 45, 49, 50, 44, 51, 52, 53, 46, 49, 50, 51 }, + { 45, 49, 50, 51, 44, 52, 53, 54, 46, 49, 50, 51 }, + { 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 49, 50, 51 }, + { 45, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 49, 50, 51 }, + { 45, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 49, 50, 51 }, + { 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 49, 50, 51 }, + { 48, 46, 49 }, + { 48, 46, 49, 50 }, + { 48, 46, 49, 50, 51 }, + { 48, 46, 49, 50, 51 }, + { 49, 48, 46, 49 }, + { 49, 48, 46, 49, 50 }, + { 49, 48, 46, 49, 50, 51 }, + { 49, 48, 46, 49, 50, 51 }, + { 49, 48, 48, 46, 49 }, + { 49, 48, 48, 46, 49, 50 }, + { 49, 48, 48, 46, 49, 50, 51 }, + { 49, 48, 48, 46, 49, 50, 51 }, + { 49, 44, 48, 48, 48, 46, 49 }, + { 49, 44, 48, 48, 48, 46, 49, 50 }, + { 49, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 48, 44, 48, 48, 48, 46, 49 }, + { 49, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 49, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 48, 48, 44, 48, 48, 48, 46, 49 }, + { 49, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 49, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 }, + { 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 }, + { 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 }, + { 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 }, + { 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 48, 46, 49 }, + { 45, 48, 46, 49, 50 }, + { 45, 48, 46, 49, 50, 51 }, + { 45, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 46, 49 }, + { 45, 49, 48, 46, 49, 50 }, + { 45, 49, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 48, 46, 49 }, + { 45, 49, 48, 48, 46, 49, 50 }, + { 45, 49, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 44, 48, 48, 48, 46, 49 }, + { 45, 49, 44, 48, 48, 48, 46, 49, 50 }, + { 45, 49, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 44, 48, 48, 48, 46, 49 }, + { 45, 49, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 45, 49, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 48, 44, 48, 48, 48, 46, 49 }, + { 45, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 45, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 }, + { 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 }, + { 45, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 45, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 }, + { 45, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 45, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 }, + { 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 }, + { 49, 46, 57, 57, 57 }, + { 49, 50, 46, 57, 57, 57 }, + { 49, 50, 51, 46, 57, 57, 57 }, + { 49, 44, 50, 51, 52, 46, 57, 57, 57 }, + { 49, 50, 44, 51, 52, 53, 46, 57, 57, 57 }, + { 49, 50, 51, 44, 52, 53, 54, 46, 57, 57, 57 }, + { 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 57, 57, 57 }, + { 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 57, 57, 57 }, + { 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 57, 57, 57 }, + { 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 57, 57, 57 }, + { 50 }, + { 49, 51 }, + { 49, 50, 52 }, + { 49, 44, 50, 51, 53 }, + { 49, 50, 44, 51, 52, 54 }, + { 49, 50, 51, 44, 52, 53, 55 }, + { 49, 44, 50, 51, 52, 44, 53, 54, 56 }, + { 49, 50, 44, 51, 52, 53, 44, 54, 55, 57 }, + { 49, 50, 51, 44, 52, 53, 54, 44, 55, 57, 48 }, + { 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 49 }, + { 45, 49, 46, 57, 57, 57 }, + { 45, 49, 50, 46, 57, 57, 57 }, + { 45, 49, 50, 51, 46, 57, 57, 57 }, + { 45, 49, 44, 50, 51, 52, 46, 57, 57, 57 }, + { 45, 49, 50, 44, 51, 52, 53, 46, 57, 57, 57 }, + { 45, 49, 50, 51, 44, 52, 53, 54, 46, 57, 57, 57 }, + { 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 57, 57, 57 }, + { 45, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 57, 57, 57 }, + { 45, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 57, 57, 57 }, + { 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 57, 57, 57 }, + { 45, 50 }, + { 45, 49, 51 }, + { 45, 49, 50, 52 }, + { 45, 49, 44, 50, 51, 53 }, + { 45, 49, 50, 44, 51, 52, 54 }, + { 45, 49, 50, 51, 44, 52, 53, 55 }, + { 45, 49, 44, 50, 51, 52, 44, 53, 54, 56 }, + { 45, 49, 50, 44, 51, 52, 53, 44, 54, 55, 57 }, + { 45, 49, 50, 51, 44, 52, 53, 54, 44, 55, 57, 48 }, + { 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 49 }, + { 49, 49, 48 }, + { 49, 44, 49, 48, 48 }, + { 49, 49, 44, 48, 48, 48 }, + { 49, 49, 48, 44, 48, 48, 48 }, + { 49, 44, 49, 48, 48, 44, 48, 48, 48 }, + { 49, 49, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 49, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 49, 44, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 49, 49, 48 }, + { 45, 49, 44, 49, 48, 48 }, + { 45, 49, 49, 44, 48, 48, 48 }, + { 45, 49, 49, 48, 44, 48, 48, 48 }, + { 45, 49, 44, 49, 48, 48, 44, 48, 48, 48 }, + { 45, 49, 49, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 49, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 49, 44, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 50 }, + { 50, 48 }, + { 50, 48, 48 }, + { 50, 44, 48, 48, 48 }, + { 50, 48, 44, 48, 48, 48 }, + { 50, 48, 48, 44, 48, 48, 48 }, + { 50, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 50, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 50, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 50 }, + { 45, 50, 48 }, + { 45, 50, 48, 48 }, + { 45, 50, 44, 48, 48, 48 }, + { 45, 50, 48, 44, 48, 48, 48 }, + { 45, 50, 48, 48, 44, 48, 48, 48 }, + { 45, 50, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 50, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 50, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 49, 48 }, + { 49, 48, 48 }, + { 49, 44, 48, 48, 48 }, + { 49, 48, 44, 48, 48, 48 }, + { 49, 48, 48, 44, 48, 48, 48 }, + { 49, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 49, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 57, 46, 57, 57, 57 }, + { 57, 57, 46, 57, 57, 57 }, + { 57, 57, 57, 46, 57, 57, 57 }, + { 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 45, 49, 48 }, + { 45, 49, 48, 48 }, + { 45, 49, 44, 48, 48, 48 }, + { 45, 49, 48, 44, 48, 48, 48 }, + { 45, 49, 48, 48, 44, 48, 48, 48 }, + { 45, 49, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 }, + { 45, 57, 46, 57, 57, 57 }, + { 45, 57, 57, 46, 57, 57, 57 }, + { 45, 57, 57, 57, 46, 57, 57, 57 }, + { 45, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 45, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 45, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 45, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 45, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 45, 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 49 }, + { 49, 50 }, + { 49, 50, 51 }, + { 49, 44, 50, 51, 52 }, + { 49, 50, 44, 51, 52, 53 }, + { 49, 50, 51, 44, 52, 53, 54 }, + { 49, 44, 50, 51, 52, 44, 53, 54, 55 }, + { 49, 50, 44, 51, 52, 53, 44, 54, 55, 56 }, + { 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57 }, + { 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48 }, + { 45, 49 }, + { 45, 49, 50 }, + { 45, 49, 50, 51 }, + { 45, 49, 44, 50, 51, 52 }, + { 45, 49, 50, 44, 51, 52, 53 }, + { 45, 49, 50, 51, 44, 52, 53, 54 }, + { 45, 49, 44, 50, 51, 52, 44, 53, 54, 55 }, + { 45, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56 }, + { 45, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57 }, + { 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48 }, + { 45, 50, 44, 53, 57, 57, 46, 52 }, + { 45, 50, 44, 53, 57, 57, 46, 51, 52 }, + { 45, 50, 44, 53, 57, 57, 46, 51, 51, 52 }, + { 49 }, + { 49 }, + { 49 }, + { 49 }, + { 49 }, + { 49, 46, 48, 48, 49 }, + { 49, 46, 48, 48, 49 }, + { 49, 46, 48, 48, 49 }, + { 49, 46, 48, 48, 49 }, + { 49, 46, 48, 48, 49 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 50 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 46, 50, 50, 51 }, + { 49, 48, 48, 44, 57, 49, 51, 46, 54, 55, 49 }, + { 49, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 }, + { 50, 53, 49, 44, 56, 52, 54, 46, 51, 52, 55 }, + { 50, 53, 51, 44, 50, 52, 51, 46, 56, 56, 51 }, + { 51, 54, 53, 44, 48, 52, 53, 46, 56, 53, 51 }, + { 51, 49, 52, 44, 55, 51, 52, 46, 57, 54, 49 }, + { 53, 52, 49, 44, 49, 51, 51, 46, 57, 55, 53 }, + { 56, 53, 56, 44, 51, 55, 50, 46, 49, 50, 51 }, + { 49, 44, 48, 48, 49, 44, 48, 48, 48 }, + { 49, 44, 51, 52, 55, 44, 53, 48, 53, 46, 55, 56, 50 }, + { 51, 44, 51, 53, 56, 44, 56, 52, 52, 46, 49, 57, 55 }, + { 57, 44, 57, 57, 55, 44, 57, 55, 57, 46, 52, 48, 57 }, + { 57, 44, 57, 57, 51, 44, 55, 52, 51, 46, 49, 53, 57 }, + { 57, 44, 57, 51, 56, 44, 54, 55, 49, 46, 57, 48, 57 }, + { 51, 44, 51, 56, 53, 44, 51, 48, 50, 46, 53, 52, 55 }, + { 51, 44, 52, 48, 52, 44, 54, 52, 50, 46, 54, 54, 49 }, + { 51, 44, 52, 51, 49, 44, 50, 56, 48, 46, 48, 56, 55 }, + { 51, 44, 52, 51, 56, 44, 55, 53, 54, 46, 52, 55, 53 }, + { 51, 44, 52, 52, 54, 44, 48, 53, 51, 46, 55, 56, 55 }, + { 51, 44, 52, 53, 55, 44, 57, 49, 55, 46, 53, 49, 51 }, + { 51, 44, 52, 54, 53, 44, 51, 57, 51, 46, 57, 48, 49 }, + { 51, 44, 52, 56, 52, 44, 55, 51, 52, 46, 48, 49, 53 }, + { 51, 44, 52, 57, 50, 44, 48, 51, 49, 46, 51, 50, 55 }, + { 51, 44, 53, 48, 51, 44, 56, 57, 53, 46, 48, 53, 51 }, + { 51, 44, 53, 49, 49, 44, 51, 55, 49, 46, 52, 52, 49 }, + { 51, 44, 53, 49, 56, 44, 54, 54, 56, 46, 55, 53, 51 }, + { 51, 44, 53, 51, 48, 44, 53, 51, 50, 46, 52, 55, 57 }, + { 51, 44, 53, 51, 56, 44, 48, 48, 56, 46, 56, 54, 55 }, + { 51, 44, 53, 52, 53, 44, 51, 48, 54, 46, 49, 55, 57 }, + { 51, 44, 53, 53, 55, 44, 49, 54, 57, 46, 57, 48, 53 }, + { 51, 44, 53, 53, 55, 44, 51, 52, 56, 46, 57, 56, 49 }, + { 51, 44, 53, 54, 52, 44, 54, 52, 54, 46, 50, 57, 51 }, + { 51, 44, 53, 56, 51, 44, 57, 56, 54, 46, 52, 48, 55 }, + { 51, 44, 53, 57, 49, 44, 50, 56, 51, 46, 55, 49, 57 }, + { 51, 44, 54, 48, 51, 44, 49, 52, 55, 46, 52, 52, 53 }, + { 51, 44, 54, 49, 48, 44, 54, 50, 51, 46, 56, 51, 51 }, + { 51, 44, 54, 49, 55, 44, 57, 50, 49, 46, 49, 52, 53 }, + { 51, 44, 54, 50, 57, 44, 55, 56, 52, 46, 56, 55, 49 }, + { 51, 44, 54, 51, 55, 44, 50, 54, 49, 46, 50, 53, 57 }, + { 51, 44, 54, 53, 54, 44, 52, 50, 50, 46, 50, 57, 55 }, + { 51, 44, 54, 53, 54, 44, 54, 48, 49, 46, 51, 55, 51 }, + { 51, 44, 54, 54, 51, 44, 56, 57, 56, 46, 54, 56, 53 }, + { 51, 44, 54, 55, 53, 44, 55, 54, 50, 46, 52, 49, 49 }, + { 51, 44, 54, 56, 51, 44, 50, 51, 56, 46, 55, 57, 57 }, + { 51, 44, 54, 57, 48, 44, 53, 51, 54, 46, 49, 49, 49 }, + { 51, 44, 55, 48, 50, 44, 51, 57, 57, 46, 56, 51, 55 }, + { 51, 44, 55, 48, 57, 44, 56, 55, 54, 46, 50, 50, 53 }, + { 51, 44, 55, 49, 55, 44, 49, 55, 51, 46, 53, 51, 55 }, + { 51, 44, 55, 50, 57, 44, 48, 51, 55, 46, 50, 54, 51 }, + { 51, 44, 55, 51, 54, 44, 53, 49, 51, 46, 54, 53, 49 }, + { 51, 44, 55, 53, 53, 44, 56, 53, 51, 46, 55, 54, 53 }, + { 51, 44, 55, 54, 51, 44, 49, 53, 49, 46, 48, 55, 55 }, + { 51, 44, 55, 55, 53, 44, 48, 49, 52, 46, 56, 48, 51 }, + { 51, 44, 55, 56, 50, 44, 52, 57, 49, 46, 49, 57, 49 }, + { 51, 44, 55, 56, 57, 44, 55, 56, 56, 46, 53, 48, 51 }, + { 51, 44, 56, 48, 49, 44, 54, 53, 50, 46, 50, 50, 57 }, + { 51, 44, 56, 48, 57, 44, 49, 50, 56, 46, 54, 49, 55 }, + { 51, 44, 56, 49, 54, 44, 52, 50, 53, 46, 57, 50, 57 }, + { 51, 44, 56, 50, 56, 44, 50, 56, 57, 46, 54, 53, 53 }, + { 51, 44, 56, 50, 56, 44, 52, 54, 56, 46, 55, 51, 49 }, + { 51, 44, 56, 51, 53, 44, 55, 54, 54, 46, 48, 52, 51 }, + { 51, 44, 56, 53, 53, 44, 49, 48, 54, 46, 49, 53, 55 }, + { 51, 44, 56, 54, 50, 44, 52, 48, 51, 46, 52, 54, 57 }, + { 51, 44, 56, 55, 52, 44, 50, 54, 55, 46, 49, 57, 53 }, + { 51, 44, 56, 56, 49, 44, 55, 52, 51, 46, 53, 56, 51 }, + { 51, 44, 56, 56, 57, 44, 48, 52, 48, 46, 56, 57, 53 }, + { 51, 44, 57, 48, 48, 44, 57, 48, 52, 46, 54, 50, 49 }, + { 51, 44, 57, 48, 56, 44, 51, 56, 49, 46, 48, 48, 57 }, + { 51, 44, 57, 50, 55, 44, 53, 52, 50, 46, 48, 52, 55 }, + { 51, 44, 57, 50, 55, 44, 55, 50, 49, 46, 49, 50, 51 }, + { 51, 44, 57, 51, 53, 44, 48, 49, 56, 46, 52, 51, 53 }, + { 51, 44, 57, 52, 54, 44, 56, 56, 50, 46, 49, 54, 49 }, + { 51, 44, 57, 53, 52, 44, 51, 53, 56, 46, 53, 52, 57 }, + { 51, 44, 57, 54, 49, 44, 54, 53, 53, 46, 56, 54, 49 }, + { 51, 44, 57, 55, 51, 44, 53, 49, 57, 46, 53, 56, 55 }, + { 51, 44, 57, 56, 48, 44, 57, 57, 53, 46, 57, 55, 53 }, + { 51, 44, 57, 56, 56, 44, 50, 57, 51, 46, 50, 56, 55 }, + { 52, 44, 48, 48, 48, 44, 49, 53, 55, 46, 48, 49, 51 }, + { 52, 44, 48, 48, 55, 44, 54, 51, 51, 46, 52, 48, 49 }, + { 52, 44, 48, 50, 54, 44, 57, 55, 51, 46, 53, 49, 53 }, + { 52, 44, 48, 51, 52, 44, 50, 55, 48, 46, 56, 50, 55 }, + { 52, 44, 48, 52, 54, 44, 49, 51, 52, 46, 53, 53, 51 }, + { 52, 44, 48, 53, 51, 44, 54, 49, 48, 46, 57, 52, 49 }, + { 52, 44, 48, 54, 48, 44, 57, 48, 56, 46, 50, 53, 51 }, + { 52, 44, 48, 55, 50, 44, 55, 55, 49, 46, 57, 55, 57 }, + { 52, 44, 48, 56, 48, 44, 50, 52, 56, 46, 51, 54, 55 }, + { 52, 44, 48, 56, 55, 44, 53, 52, 53, 46, 54, 55, 57 }, + { 52, 44, 48, 57, 57, 44, 52, 48, 57, 46, 52, 48, 53 }, + { 52, 44, 48, 57, 57, 44, 53, 56, 56, 46, 52, 56, 49 }, + { 52, 44, 49, 48, 54, 44, 56, 56, 53, 46, 55, 57, 51 }, + { 52, 44, 49, 50, 54, 44, 50, 50, 53, 46, 57, 48, 55 }, + { 52, 44, 49, 51, 51, 44, 53, 50, 51, 46, 50, 49, 57 }, + { 52, 44, 49, 52, 53, 44, 51, 56, 54, 46, 57, 52, 53 }, + { 52, 44, 49, 53, 50, 44, 56, 54, 51, 46, 51, 51, 51 }, + { 52, 44, 49, 54, 48, 44, 49, 54, 48, 46, 54, 52, 53 }, + { 52, 44, 49, 55, 50, 44, 48, 50, 52, 46, 51, 55, 49 }, + { 52, 44, 49, 55, 57, 44, 53, 48, 48, 46, 55, 53, 57 }, + { 52, 44, 49, 57, 56, 44, 54, 54, 49, 46, 55, 57, 55 }, + { 52, 44, 50, 48, 51, 44, 52, 48, 55, 46, 50, 56, 55 }, + { 52, 44, 50, 49, 48, 44, 55, 48, 52, 46, 53, 57, 57 }, + { 52, 44, 50, 49, 51, 44, 52, 51, 53, 46, 52, 57, 55 }, + }; + + // The array of int[] unicode values storing the expected results + // when calling Decimal.format(double) on the currency GoldenDoubleValues. + static int[][] CurrencyGoldenFormattedValues = { + { 36, 48, 46, 48, 48 }, + { 40, 36, 48, 46, 48, 48, 41 }, + { 36, 48, 46, 48, 48 }, + { 36, 48, 46, 48, 48 }, + { 40, 36, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 54, 46, 50, 51, 41 }, + { 36, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 54, 46, 50, 51 }, + { 40, 36, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 56, 46, 48, 48, 41 }, + { 36, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 56, 46, 48, 48 }, + { 40, 36, 49, 44, 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 41 }, + { 36, 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 65533 }, + { 36, 8734 }, + { 40, 36, 8734, 41 }, + { 36, 49, 55, 57, 44, 55, 54, 57, 44, 51, 49, 51, 44, 52, 56, 54, 44, 50, 51, 49, 44, 53, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 40, 36, 57, 44, 56, 55, 54, 44, 53, 52, 51, 44, 50, 49, 48, 46, 57, 57, 41 }, + { 36, 57, 44, 56, 55, 54, 44, 53, 52, 51, 44, 50, 49, 48, 46, 57, 57 }, + { 40, 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 44, 48, 49, 50, 44, 51, 52, 53, 44, 54, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 44, 48, 49, 50, 44, 51, 52, 53, 44, 54, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 46, 49, 50 }, + { 36, 49, 50, 46, 49, 50 }, + { 36, 49, 50, 51, 46, 49, 50 }, + { 36, 49, 44, 50, 51, 52, 46, 49, 50 }, + { 36, 49, 50, 44, 51, 52, 53, 46, 49, 50 }, + { 36, 49, 50, 51, 44, 52, 53, 54, 46, 49, 50 }, + { 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 49, 50 }, + { 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 49, 50 }, + { 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 49, 50 }, + { 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 49, 50 }, + { 40, 36, 49, 46, 49, 50, 41 }, + { 40, 36, 49, 50, 46, 49, 50, 41 }, + { 40, 36, 49, 50, 51, 46, 49, 50, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 46, 49, 50, 41 }, + { 40, 36, 49, 50, 44, 51, 52, 53, 46, 49, 50, 41 }, + { 40, 36, 49, 50, 51, 44, 52, 53, 54, 46, 49, 50, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 49, 50, 41 }, + { 40, 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 49, 50, 41 }, + { 40, 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 49, 50, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 49, 50, 41 }, + { 36, 48, 46, 49, 48 }, + { 36, 48, 46, 49, 50 }, + { 36, 48, 46, 49, 50 }, + { 36, 49, 48, 46, 49, 48 }, + { 36, 49, 48, 46, 49, 50 }, + { 36, 49, 48, 46, 49, 50 }, + { 36, 49, 48, 48, 46, 49, 48 }, + { 36, 49, 48, 48, 46, 49, 50 }, + { 36, 49, 48, 48, 46, 49, 50 }, + { 36, 49, 44, 48, 48, 48, 46, 49, 48 }, + { 36, 49, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 48, 44, 48, 48, 48, 46, 49, 48 }, + { 36, 49, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 48 }, + { 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 }, + { 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 }, + { 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 }, + { 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 }, + { 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 }, + { 40, 36, 48, 46, 49, 48, 41 }, + { 40, 36, 48, 46, 49, 50, 41 }, + { 40, 36, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 46, 49, 48, 41 }, + { 40, 36, 49, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 48, 46, 49, 48, 41 }, + { 40, 36, 49, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 46, 49, 48, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 44, 48, 48, 48, 46, 49, 48, 41 }, + { 40, 36, 49, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 48, 41 }, + { 40, 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48, 41 }, + { 40, 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48, 41 }, + { 40, 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 41 }, + { 36, 49, 46, 57, 57 }, + { 36, 49, 50, 46, 57, 57 }, + { 36, 49, 50, 51, 46, 57, 57 }, + { 36, 49, 44, 50, 51, 52, 46, 57, 57 }, + { 36, 49, 50, 44, 51, 52, 53, 46, 57, 57 }, + { 36, 49, 50, 51, 44, 52, 53, 54, 46, 57, 57 }, + { 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 57, 57 }, + { 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 57, 57 }, + { 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 57, 57 }, + { 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 57, 57 }, + { 36, 50, 46, 48, 48 }, + { 36, 49, 51, 46, 48, 48 }, + { 36, 49, 50, 52, 46, 48, 48 }, + { 36, 49, 44, 50, 51, 53, 46, 48, 48 }, + { 36, 49, 50, 44, 51, 52, 54, 46, 48, 48 }, + { 36, 49, 50, 51, 44, 52, 53, 55, 46, 48, 48 }, + { 36, 49, 44, 50, 51, 52, 44, 53, 54, 56, 46, 48, 48 }, + { 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 57, 46, 48, 48 }, + { 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 57, 48, 46, 48, 48 }, + { 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 49, 46, 48, 48 }, + { 40, 36, 49, 46, 57, 57, 41 }, + { 40, 36, 49, 50, 46, 57, 57, 41 }, + { 40, 36, 49, 50, 51, 46, 57, 57, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 46, 57, 57, 41 }, + { 40, 36, 49, 50, 44, 51, 52, 53, 46, 57, 57, 41 }, + { 40, 36, 49, 50, 51, 44, 52, 53, 54, 46, 57, 57, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 57, 57, 41 }, + { 40, 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 57, 57, 41 }, + { 40, 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 57, 57, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 57, 57, 41 }, + { 40, 36, 50, 46, 48, 48, 41 }, + { 40, 36, 49, 51, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 52, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 50, 51, 53, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 44, 51, 52, 54, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 51, 44, 52, 53, 55, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 44, 53, 54, 56, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 57, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 57, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 49, 46, 48, 48, 41 }, + { 36, 49, 49, 48, 46, 48, 48 }, + { 36, 49, 44, 49, 48, 48, 46, 48, 48 }, + { 36, 49, 49, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 49, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 44, 49, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 44, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 40, 36, 49, 49, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 49, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 49, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 49, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 49, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 36, 50, 46, 48, 48 }, + { 36, 50, 48, 46, 48, 48 }, + { 36, 50, 48, 48, 46, 48, 48 }, + { 36, 50, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 50, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 50, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 50, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 50, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 50, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 40, 36, 50, 46, 48, 48, 41 }, + { 40, 36, 50, 48, 46, 48, 48, 41 }, + { 40, 36, 50, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 50, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 50, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 50, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 50, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 50, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 50, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 36, 49, 48, 46, 48, 48 }, + { 36, 49, 48, 48, 46, 48, 48 }, + { 36, 49, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 }, + { 36, 57, 46, 57, 57 }, + { 36, 57, 57, 46, 57, 57 }, + { 36, 57, 57, 57, 46, 57, 57 }, + { 36, 57, 44, 57, 57, 57, 46, 57, 57 }, + { 36, 57, 57, 44, 57, 57, 57, 46, 57, 57 }, + { 36, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 }, + { 36, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 }, + { 36, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 }, + { 36, 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 }, + { 40, 36, 49, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48, 41 }, + { 40, 36, 57, 46, 57, 57, 41 }, + { 40, 36, 57, 57, 46, 57, 57, 41 }, + { 40, 36, 57, 57, 57, 46, 57, 57, 41 }, + { 40, 36, 57, 44, 57, 57, 57, 46, 57, 57, 41 }, + { 40, 36, 57, 57, 44, 57, 57, 57, 46, 57, 57, 41 }, + { 40, 36, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 41 }, + { 40, 36, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 41 }, + { 40, 36, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 41 }, + { 40, 36, 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 41 }, + { 36, 49, 46, 48, 48 }, + { 36, 49, 50, 46, 48, 48 }, + { 36, 49, 50, 51, 46, 48, 48 }, + { 36, 49, 44, 50, 51, 52, 46, 48, 48 }, + { 36, 49, 50, 44, 51, 52, 53, 46, 48, 48 }, + { 36, 49, 50, 51, 44, 52, 53, 54, 46, 48, 48 }, + { 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 48, 48 }, + { 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 48, 48 }, + { 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 48, 48 }, + { 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 48, 48 }, + { 40, 36, 49, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 51, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 44, 51, 52, 53, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 51, 44, 52, 53, 54, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 48, 48, 41 }, + { 40, 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 48, 48, 41 }, + { 40, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 48, 48, 41 }, + { 40, 36, 50, 44, 53, 57, 57, 46, 52, 48, 41 }, + { 40, 36, 50, 44, 53, 57, 57, 46, 51, 52, 41 }, + { 40, 36, 50, 44, 53, 57, 57, 46, 51, 51, 41 }, + { 36, 49, 46, 48, 48 }, + { 36, 49, 46, 48, 48 }, + { 36, 49, 46, 48, 48 }, + { 36, 49, 46, 48, 48 }, + { 36, 49, 46, 48, 48 }, + { 36, 49, 46, 48, 49 }, + { 36, 49, 46, 48, 49 }, + { 36, 49, 46, 48, 49 }, + { 36, 49, 46, 48, 49 }, + { 36, 49, 46, 48, 49 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 50 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 46, 50, 51 }, + { 36, 49, 44, 48, 48, 57, 44, 49, 51, 54, 46, 55, 49 }, + { 36, 50, 44, 53, 49, 56, 44, 52, 54, 51, 46, 52, 54 }, + { 36, 50, 44, 53, 51, 50, 44, 52, 51, 56, 46, 56, 51 }, + { 36, 51, 44, 54, 53, 48, 44, 52, 53, 56, 46, 53, 51 }, + { 36, 51, 44, 49, 52, 55, 44, 51, 52, 57, 46, 54, 50 }, + { 36, 53, 44, 52, 49, 49, 44, 51, 51, 57, 46, 55, 53 }, + { 36, 56, 44, 53, 56, 51, 44, 55, 50, 49, 46, 50, 50 }, + { 36, 49, 51, 44, 52, 55, 53, 44, 48, 53, 55, 46, 56, 50 }, + { 36, 51, 51, 44, 53, 56, 56, 44, 52, 52, 49, 46, 57, 56 }, + { 36, 57, 57, 44, 57, 55, 57, 44, 55, 57, 52, 46, 48, 56 }, + { 36, 57, 57, 44, 57, 51, 55, 44, 52, 51, 49, 46, 53, 56 }, + { 36, 57, 57, 44, 51, 56, 54, 44, 55, 49, 57, 46, 48, 56 }, + { 36, 51, 51, 44, 56, 53, 51, 44, 48, 50, 53, 46, 52, 55 }, + { 36, 51, 52, 44, 48, 52, 54, 44, 52, 50, 54, 46, 54, 48 }, + { 36, 51, 52, 44, 51, 49, 50, 44, 56, 48, 48, 46, 56, 55 }, + { 36, 51, 52, 44, 51, 56, 55, 44, 53, 54, 52, 46, 55, 53 }, + { 36, 51, 52, 44, 52, 54, 48, 44, 53, 51, 55, 46, 56, 55 }, + { 36, 51, 52, 44, 53, 55, 57, 44, 49, 55, 53, 46, 49, 50 }, + { 36, 51, 52, 44, 54, 53, 51, 44, 57, 51, 57, 46, 48, 50 }, + { 36, 51, 52, 44, 56, 52, 55, 44, 51, 52, 48, 46, 49, 53 }, + { 36, 51, 52, 44, 57, 50, 48, 44, 51, 49, 51, 46, 50, 55 }, + { 36, 51, 53, 44, 48, 51, 56, 44, 57, 53, 48, 46, 53, 50 }, + { 36, 51, 53, 44, 49, 49, 51, 44, 55, 49, 52, 46, 52, 49 }, + { 36, 51, 53, 44, 49, 56, 54, 44, 54, 56, 55, 46, 53, 51 }, + { 36, 51, 53, 44, 51, 48, 53, 44, 51, 50, 52, 46, 55, 56 }, + { 36, 51, 53, 44, 51, 56, 48, 44, 48, 56, 56, 46, 54, 55 }, + { 36, 51, 53, 44, 52, 53, 51, 44, 48, 54, 49, 46, 55, 57 }, + { 36, 51, 53, 44, 53, 55, 49, 44, 54, 57, 57, 46, 48, 53 }, + { 36, 51, 53, 44, 53, 55, 51, 44, 52, 56, 57, 46, 56, 49 }, + { 36, 51, 53, 44, 54, 52, 54, 44, 52, 54, 50, 46, 57, 51 }, + { 36, 51, 53, 44, 56, 51, 57, 44, 56, 54, 52, 46, 48, 55 }, + { 36, 51, 53, 44, 57, 49, 50, 44, 56, 51, 55, 46, 50, 48 }, + { 36, 51, 54, 44, 48, 51, 49, 44, 52, 55, 52, 46, 52, 53 }, + { 36, 51, 54, 44, 49, 48, 54, 44, 50, 51, 56, 46, 51, 51 }, + { 36, 51, 54, 44, 49, 55, 57, 44, 50, 49, 49, 46, 52, 53 }, + { 36, 51, 54, 44, 50, 57, 55, 44, 56, 52, 56, 46, 55, 48 }, + { 36, 51, 54, 44, 51, 55, 50, 44, 54, 49, 50, 46, 53, 57 }, + { 36, 51, 54, 44, 53, 54, 52, 44, 50, 50, 50, 46, 57, 55 }, + { 36, 51, 54, 44, 53, 54, 54, 44, 48, 49, 51, 46, 55, 51 }, + { 36, 51, 54, 44, 54, 51, 56, 44, 57, 56, 54, 46, 56, 53 }, + { 36, 51, 54, 44, 55, 53, 55, 44, 54, 50, 52, 46, 49, 48 }, + { 36, 51, 54, 44, 56, 51, 50, 44, 51, 56, 55, 46, 57, 57 }, + { 36, 51, 54, 44, 57, 48, 53, 44, 51, 54, 49, 46, 49, 49 }, + { 36, 51, 55, 44, 48, 50, 51, 44, 57, 57, 56, 46, 51, 55 }, + { 36, 51, 55, 44, 48, 57, 56, 44, 55, 54, 50, 46, 50, 53 }, + { 36, 51, 55, 44, 49, 55, 49, 44, 55, 51, 53, 46, 51, 55 }, + { 36, 51, 55, 44, 50, 57, 48, 44, 51, 55, 50, 46, 54, 50 }, + { 36, 51, 55, 44, 51, 54, 53, 44, 49, 51, 54, 46, 53, 50 }, + { 36, 51, 55, 44, 53, 53, 56, 44, 53, 51, 55, 46, 54, 53 }, + { 36, 51, 55, 44, 54, 51, 49, 44, 53, 49, 48, 46, 55, 55 }, + { 36, 51, 55, 44, 55, 53, 48, 44, 49, 52, 56, 46, 48, 50 }, + { 36, 51, 55, 44, 56, 50, 52, 44, 57, 49, 49, 46, 57, 49 }, + { 36, 51, 55, 44, 56, 57, 55, 44, 56, 56, 53, 46, 48, 51 }, + { 36, 51, 56, 44, 48, 49, 54, 44, 53, 50, 50, 46, 50, 56 }, + { 36, 51, 56, 44, 48, 57, 49, 44, 50, 56, 54, 46, 49, 55 }, + { 36, 51, 56, 44, 49, 54, 52, 44, 50, 53, 57, 46, 50, 57 }, + { 36, 51, 56, 44, 50, 56, 50, 44, 56, 57, 54, 46, 53, 53 }, + { 36, 51, 56, 44, 50, 56, 52, 44, 54, 56, 55, 46, 51, 49 }, + { 36, 51, 56, 44, 51, 53, 55, 44, 54, 54, 48, 46, 52, 51 }, + { 36, 51, 56, 44, 53, 53, 49, 44, 48, 54, 49, 46, 53, 55 }, + { 36, 51, 56, 44, 54, 50, 52, 44, 48, 51, 52, 46, 55, 48 }, + { 36, 51, 56, 44, 55, 52, 50, 44, 54, 55, 49, 46, 57, 53 }, + { 36, 51, 56, 44, 56, 49, 55, 44, 52, 51, 53, 46, 56, 51 }, + { 36, 51, 56, 44, 56, 57, 48, 44, 52, 48, 56, 46, 57, 53 }, + { 36, 51, 57, 44, 48, 48, 57, 44, 48, 52, 54, 46, 50, 48 }, + { 36, 51, 57, 44, 48, 56, 51, 44, 56, 49, 48, 46, 48, 57 }, + { 36, 51, 57, 44, 50, 55, 53, 44, 52, 50, 48, 46, 52, 55 }, + { 36, 51, 57, 44, 50, 55, 55, 44, 50, 49, 49, 46, 50, 51 }, + { 36, 51, 57, 44, 51, 53, 48, 44, 49, 56, 52, 46, 51, 53 }, + { 36, 51, 57, 44, 52, 54, 56, 44, 56, 50, 49, 46, 54, 48 }, + { 36, 51, 57, 44, 53, 52, 51, 44, 53, 56, 53, 46, 52, 57 }, + { 36, 51, 57, 44, 54, 49, 54, 44, 53, 53, 56, 46, 54, 49 }, + { 36, 51, 57, 44, 55, 51, 53, 44, 49, 57, 53, 46, 56, 55 }, + { 36, 51, 57, 44, 56, 48, 57, 44, 57, 53, 57, 46, 55, 53 }, + { 36, 51, 57, 44, 56, 56, 50, 44, 57, 51, 50, 46, 56, 55 }, + { 36, 52, 48, 44, 48, 48, 49, 44, 53, 55, 48, 46, 49, 50 }, + { 36, 52, 48, 44, 48, 55, 54, 44, 51, 51, 52, 46, 48, 50 }, + { 36, 52, 48, 44, 50, 54, 57, 44, 55, 51, 53, 46, 49, 53 }, + { 36, 52, 48, 44, 51, 52, 50, 44, 55, 48, 56, 46, 50, 55 }, + { 36, 52, 48, 44, 52, 54, 49, 44, 51, 52, 53, 46, 53, 50 }, + { 36, 52, 48, 44, 53, 51, 54, 44, 49, 48, 57, 46, 52, 49 }, + { 36, 52, 48, 44, 54, 48, 57, 44, 48, 56, 50, 46, 53, 51 }, + { 36, 52, 48, 44, 55, 50, 55, 44, 55, 49, 57, 46, 55, 56 }, + { 36, 52, 48, 44, 56, 48, 50, 44, 52, 56, 51, 46, 54, 55 }, + { 36, 52, 48, 44, 56, 55, 53, 44, 52, 53, 54, 46, 55, 57 }, + { 36, 52, 48, 44, 57, 57, 52, 44, 48, 57, 52, 46, 48, 53 }, + { 36, 52, 48, 44, 57, 57, 53, 44, 56, 56, 52, 46, 56, 49 }, + { 36, 52, 49, 44, 48, 54, 56, 44, 56, 53, 55, 46, 57, 51 }, + { 36, 52, 49, 44, 50, 54, 50, 44, 50, 53, 57, 46, 48, 55 }, + { 36, 52, 49, 44, 51, 51, 53, 44, 50, 51, 50, 46, 50, 48 }, + { 36, 52, 49, 44, 52, 53, 51, 44, 56, 54, 57, 46, 52, 53 }, + { 36, 52, 49, 44, 53, 50, 56, 44, 54, 51, 51, 46, 51, 51 }, + { 36, 52, 49, 44, 54, 48, 49, 44, 54, 48, 54, 46, 52, 53 }, + { 36, 52, 49, 44, 55, 50, 48, 44, 50, 52, 51, 46, 55, 48 }, + { 36, 52, 49, 44, 55, 57, 53, 44, 48, 48, 55, 46, 53, 57 }, + { 36, 52, 49, 44, 57, 56, 54, 44, 54, 49, 55, 46, 57, 55 }, + { 36, 52, 50, 44, 48, 51, 52, 44, 48, 55, 50, 46, 56, 55 }, + { 36, 52, 50, 44, 49, 48, 55, 44, 48, 52, 53, 46, 57, 56 }, + { 36, 52, 50, 44, 49, 51, 52, 44, 51, 53, 52, 46, 57, 56 }, + }; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/text/Format/DecimalFormat/RoundingAndPropertyTest.java Tue Oct 02 10:11:57 2012 +0100 @@ -0,0 +1,795 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* @test + * @bug 7050528 + * @summary Test java.text.DecimalFormat fast-path for format(double...) + * @author Olivier Lagneau + * @run main RoundingAndPropertyTest + * + */ + +/* ----------------------------------------------------------------------------- + * Note : + * Since fast-path algorithm does not modify any feature of DecimalFormat, + * some tests or values in this program may have to be adapted/added/removed + * when any change has been done in the fast-path source code, because the + * conditions for exercising fast-path may change. + * + * This is specially true if the set of constraints to fall in the fast-path + * case is relaxed in any manner. + * + * Usage : + * - Run main without any argument to test against a set of golden values and + * associated results hard-coded in the source code. That will do the tests + * described below + * See below comment section named "Description". + * + * or + * + * - Run main with string argument "-gengold" to output source code of + * GoldenFormattedValues.java class file with the jdk version used while + * generating the code. + * See below comment section named : "Modifying Golden Values". + * + * In case of error while running the test, a Runtime exception is generated + * providing the numbers of errors detected (format of golden values checks and + * property changes checks), and the program exit. + * + * Description : + * + * This test first checks that localization of digits is done correctly when + * calling DecimalFormat.format() on the array of values DecimalLocalizationValues + * found in GoldenDoubleValues, using the locale FullLocalizationTestLocale + * (from GoldenDoubleValues) that implies localization of digits. it checks the + * the results against expected returned string. In case of formatting error, + * it provides a message informing which value was wrongly formatted. + * + * Then it checks the results of calling NumberFormat.format(double) on a set + * of predefined golden values and checks results against expected returned + * string. It does this both for the decimal case, with an instance returned + * NumberFormat.getInstance() call and for the currency case, with an instance + * returned by NumberFormat.getCurrencyInstance(). Almost all the tested double + * values satisfy the constraints assumed by the fast-path algorithm for + * format(double ...). Some are voluntarily outside the scope of fast-path to + * check that the algorithm correctly eliminate them. In case of formatting + * error a message provides information on the golden value raising the error + * (value, exact decimal value (using BidDecimal), expected result, formatted result). + * + * Last the test checks the status and behavior of a DecimalFormat instance + * when changing properties that make this instance satisfy/invalidate its + * fast-path status, depending on the predefined set of fast-path constraints. + * + * The golden results are predefined arrays of int[] containing the unicode + * ints of the chars in the expected formatted string, when using locale + * provided in GoldenDoubleValues class. The results are those obtained by + * using a reference jdk version (for example one that does not contains the + * DecimalFormat fast-path algorithm, like jdk80-b25). + * + * The double values from which we get golden results are stored inside two + * arrays of double values: + * - DecimalGoldenValues for testing NumberFormat.getInstance(). + * - CurrencyGoldenValues for testing NumberFormat.getCurrencyInstance(). + * These arrays are located in GoldenDoubleValues.java source file. + * + * For each double value in the arrays above, there is an associated golden + * result. These results are stored in arrays of int[]: + * - DecimalGoldenFormattedValues for expected decimal golden results. + * - CurrencyGoldenFormattedValues for expected currency golden results. + * - DecimalDigitsLocalizedFormattedValues for expected localized digit results. + * + * We store the results in int[] arrays containing the expected unicode values + * because the compiler that will compile the containing java file may use a + * different locale than the one registered in GoldenDoubleValues.java. These + * arrays are located in a separate GoldenFormattedValues.java source file + * that is generated by RoundingAndPropertyTest using "-gengold" parameter. + * See below "Modifying Golden Values". + * + * The golden value arrays can be expanded, modified ... to test additional + * or different double values. In that case, the source file of class + * GoldenFormattedValues must be regenerated to replace the existing one.. + * + * Modifying Golden Values : + * + * In order to ease further modification of the list of double values checked + * and associated golden results, the test includes the method + * generatesGoldenFormattedValuesClass() that writes on standard output stream + * the source code for GoldenFormattedValues class that includes the expected + * results arrays. + * + * Here are the steps to follow for updating/modifying golden values and results: + * 1- Edit GoldenDoubleValues.java to add/remove/modify golden or localization + * values. + * 2- Run main with "-gengold" string argument with a target jdk. + * (at the creation of this test file, the target jdk used was jdk1.8.0-ea). + * 2- Copy this java code that has been writen on standard output and replace + * GoldenFormattedValues.java contents by the generated output. + * 3- Check that this updated code compiles. + * [4]- If needed replaces existing GoldenDoubleValues and GoldenFormattedValues + * files in jdk/test section, respectively by the one modified at step 1 and + * generated at step 2. + * ----------------------------------------------------------------------------- + */ + +import java.util.*; +import java.text.NumberFormat; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.math.RoundingMode; +import java.math.BigDecimal; + + +public class RoundingAndPropertyTest { + + + // Prints on standard output stream the unicode values of chars as a + // comma-separated list of int values + private static void printUnicodeValuesArray(char[] chars) { + for (int i = 0; i < chars.length; i++) { + System.out.print((int) chars[i]); + if (i != (chars.length - 1)) + System.out.print(", "); + } + } + + // Converts given array of unicode values as an array of chars. + // Returns this converted array. + private static char[] getCharsFromUnicodeArray(int[] unicodeValues) { + char[] chars = new char[unicodeValues.length]; + + for (int i = 0; i < unicodeValues.length; i++) { + chars[i] = (char) unicodeValues[i]; + } + return chars; + } + + /* Prints on standard output stream the java code of resulting + * GoldenFormattedValues class for the golden values found in + * class GoldenDoubleValues. + */ + private static void generatesGoldenFormattedValuesClass() { + + String fourWhiteSpaces = " "; + String eightWhiteSpaces = " "; + + // Prints header without Copyright header. + System.out.println("/* This is a machine generated file - Please DO NOT EDIT !"); + System.out.println(" * Change RoundingAndPropertyTest instead,"); + System.out.println(" * and run with \"-gengold\" argument to regenerate (without copyright header)."); + System.out.println(" */"); + System.out.println(); + + System.out.println("/* This file contains the set of result Strings expected from calling inside"); + System.out.println(" * RoundingAndPropertyTest the method NumberFormat.format() upon the set of"); + System.out.println(" * double values provided in GoldenDoubleValues.java. It contains three arrays,"); + System.out.println(" * each containing arrays of unicode values representing the expected string"); + System.out.println(" * result when calling format() on the corresponding (i.e. same index) double"); + System.out.println(" * value found in GoldenDoubleValues arrays :"); + System.out.println(" * - DecimalDigitsLocalizedFormattedValues corresponds to DecimalLocalizationValues,"); + System.out.println(" * when using FullLocalizationTestLocale to format."); + System.out.println(" * - DecimalGoldenFormattedValues corresponds to DecimalGoldenValues, when used"); + System.out.println(" * in the decimal pattern case together with TestLocale."); + System.out.println(" * - CurrencyGoldenFormattedValues corresponds to CurrencyGoldenValues. when used"); + System.out.println(" * in the currency pattern case together with TestLocale."); + System.out.println(" * Please see documentation in RoundingAndPropertyTest.java for more details."); + System.out.println(" *"); + System.out.println(" * This file generated by running RoundingAndPropertyTest with \"-gengold\" argument."); + System.out.println(" */"); + System.out.println(); + + // Prints beginning of class GoldenFormattedValues. + System.out.println("class GoldenFormattedValues {"); + System.out.println(); + System.out.println( + fourWhiteSpaces + + "// The formatted values below were generated from golden values"); + System.out.print( + fourWhiteSpaces + + "// listed in GoldenDoubleValues.java,"); + System.out.println(" using the following jvm version :"); + System.out.println( + fourWhiteSpaces + "// " + + System.getProperty("java.vendor") + + " " + + System.getProperty("java.vm.name") + + " " + + System.getProperty("java.version")); + System.out.println( + fourWhiteSpaces + + "// locale for golden double values : " + GoldenDoubleValues.TestLocale); + System.out.println( + fourWhiteSpaces + + "// locale for testing digit localization : " + GoldenDoubleValues.FullLocalizationTestLocale); + System.out.println(); + + // Prints the expected results when digit localization happens + System.out.println( + fourWhiteSpaces + + "// The array of int[] unicode values storing the expected results"); + System.out.print( + fourWhiteSpaces + + "// when experiencing full localization of digits"); + System.out.println(" on DecimalLocalizationValues."); + System.out.println( + fourWhiteSpaces + + "static int[][] DecimalDigitsLocalizedFormattedValues = {"); + NumberFormat df = + NumberFormat.getInstance(GoldenDoubleValues.FullLocalizationTestLocale); + for (int i = 0; + i < GoldenDoubleValues.DecimalLocalizationValues.length; + i++) { + double d = GoldenDoubleValues.DecimalLocalizationValues[i]; + String formatted = df.format(d); + char[] decFmtChars = formatted.toCharArray(); + + System.out.print(eightWhiteSpaces + "{ "); + printUnicodeValuesArray(decFmtChars); + System.out.println(" },"); + } + System.out.println(fourWhiteSpaces + "};"); + System.out.println(); + + // Prints the golden expected results for the decimal pattern case + System.out.println( + fourWhiteSpaces + + "// The array of int[] unicode values storing the expected results"); + System.out.print( + fourWhiteSpaces + + "// when calling Decimal.format(double)"); + System.out.println(" on the decimal GoldenDoubleValues."); + System.out.println( + fourWhiteSpaces + + "static int[][] DecimalGoldenFormattedValues = {"); + df = NumberFormat.getInstance(GoldenDoubleValues.TestLocale); + for (int i = 0; + i < GoldenDoubleValues.DecimalGoldenValues.length; + i++) { + double d = GoldenDoubleValues.DecimalGoldenValues[i]; + String formatted = df.format(d); + char[] decFmtChars = formatted.toCharArray(); + + System.out.print(eightWhiteSpaces + "{ "); + printUnicodeValuesArray(decFmtChars); + System.out.println(" },"); + } + System.out.println(fourWhiteSpaces + "};"); + System.out.println(); + + // Prints the golden expected results for the currency pattern case + System.out.println( + fourWhiteSpaces + + "// The array of int[] unicode values storing the expected results"); + System.out.print( + fourWhiteSpaces + + "// when calling Decimal.format(double)"); + System.out.println(" on the currency GoldenDoubleValues."); + System.out.println( + fourWhiteSpaces + + "static int[][] CurrencyGoldenFormattedValues = {"); + NumberFormat cf = + NumberFormat.getCurrencyInstance(GoldenDoubleValues.TestLocale); + for (int i = 0; + i < GoldenDoubleValues.CurrencyGoldenValues.length; + i++) { + double d = GoldenDoubleValues.CurrencyGoldenValues[i]; + String formatted = cf.format(d); + char[] decFmtChars = formatted.toCharArray(); + + System.out.print(eightWhiteSpaces + "{ "); + printUnicodeValuesArray(decFmtChars); + System.out.println(" },"); + } + System.out.println(fourWhiteSpaces + "};"); + System.out.println(); + + // Prints end of GoldenFormattedValues class. + System.out.println("}"); + } + + private static int testLocalizationValues() { + + DecimalFormat df = (DecimalFormat) + NumberFormat.getInstance(GoldenDoubleValues.FullLocalizationTestLocale); + + double[] localizationValues = GoldenDoubleValues.DecimalLocalizationValues; + int size = localizationValues.length; + int successCounter = 0; + int failureCounter = 0; + for (int i = 0; i < size; i++) { + + double d = localizationValues[i]; + String formatted = df.format(d); + + char[] expectedUnicodeArray = + getCharsFromUnicodeArray( + GoldenFormattedValues.DecimalDigitsLocalizedFormattedValues[i]); + String expected = new String(expectedUnicodeArray); + + if (!formatted.equals(expected)) { + failureCounter++; + System.out.println( + "--- Localization error for value d = " + d + + ". Exact value = " + new BigDecimal(d).toString() + + ". Expected result = " + expected + + ". Output result = " + formatted); + } else successCounter++; + } + System.out.println("Checked positively " + successCounter + + " golden decimal values out of " + size + + " tests. There were " + failureCounter + + " format failure"); + + return failureCounter; + } + + private static int testGoldenValues(java.text.DecimalFormat df, + java.text.DecimalFormat cf) { + + double[] goldenDecimalValues = GoldenDoubleValues.DecimalGoldenValues; + int decimalSize = goldenDecimalValues.length; + int decimalSuccessCounter = 0; + int decimalFailureCounter = 0; + for (int i = 0; i < decimalSize; i++) { + + double d = goldenDecimalValues[i]; + String formatted = df.format(d); + + char[] expectedUnicodeArray = + getCharsFromUnicodeArray( + GoldenFormattedValues.DecimalGoldenFormattedValues[i]); + String expected = new String(expectedUnicodeArray); + + if (!formatted.equals(expected)) { + decimalFailureCounter++; + System.out.println( + "--- Error for golden value d = " + d + + ". Exact value = " + new BigDecimal(d).toString() + + ". Expected result = " + expected + + ". Output result = " + formatted); + } else decimalSuccessCounter++; + } + System.out.println("Checked positively " + decimalSuccessCounter + + " golden decimal values out of " + decimalSize + + " tests. There were " + decimalFailureCounter + + " format failure"); + + double[] goldenCurrencyValues = GoldenDoubleValues.CurrencyGoldenValues; + int currencySize = goldenCurrencyValues.length; + int currencySuccessCounter = 0; + int currencyFailureCounter = 0; + for (int i = 0; i < currencySize; i++) { + double d = goldenCurrencyValues[i]; + String formatted = cf.format(d); + + char[] expectedUnicodeArray = + getCharsFromUnicodeArray( + GoldenFormattedValues.CurrencyGoldenFormattedValues[i]); + String expected = new String(expectedUnicodeArray); + + if (!formatted.equals(expected)) { + currencyFailureCounter++; + System.out.println( + "--- Error for golden value d = " + d + + ". Exact value = " + new BigDecimal(d).toString() + + ". Expected result = " + expected + + ". Output result = " + formatted); + } else currencySuccessCounter++; + } + System.out.println("Checked positively " + currencySuccessCounter + + " golden currency values out of " + currencySize + + " tests. There were " + currencyFailureCounter + + " format failure"); + + return (decimalFailureCounter + currencyFailureCounter); + } + + // Checks that the two passed s1 and s2 string are equal, and prints + // out message in case of error. + private static boolean resultsEqual(String propertyName, + String s1, + String s2) { + + boolean equality = s1.equals(s2); + if (!equality) + System.out.println( + "\n*** Error while reverting to default " + + propertyName + " property.\n" + + " initial output = " + s1 + + ". reverted output = " + s2 + "."); + else System.out.println(" Test passed."); + + return equality; + + } + + /* This methods checks the behaviour of the management of properties + * of a DecimalFormat instance that satisfies fast-path constraints. + * + * It does this by comparing the results of the format(double) output + * obtained from initial fast-path state with the output provided by + * the same instance that has been pushed and exercised outside + * fast-path rules and finally "reverted" to its initial fast-path state. + * + * The schema of actions is this : + * - Call format(double) on a known DecimalFormat fast-path instance, + * and store this result. + * - Record the current state of a given property. + * - Change the property to invalidate the fast-path state. + * - Call again format(double) on the instance. + * - Revert state of property to validate again fast-path context. + * - Call format(double) again. + * - Check that first and last call to format(double) provide same result + * - Record failure if any. + * - Do the same for another property with the same instance. + * So all the property changes are chained one after the other on only the + * same instance. + * + * Some properties that currently do not influence the fast-path state + * are also tested. This is not useful with current fast-path source + * but is here for testing the whole set of properties. This is the case + * for prefixes and suffixes, and parseBigDecimal properties. + */ + private static int testSettersAndFastPath(DecimalFormat df, + boolean isCurrency) { + + final double d1 = GoldenDoubleValues.PROPERTY_CHECK_POSITIVE_VALUE; + final double d2 = GoldenDoubleValues.PROPERTY_CHECK_NEGATIVE_VALUE; + + int errors = 0; + boolean testSucceeded = false; + String firstFormatResult; + String secondFormatResult; + String propertyName; + + // ---- positivePrefix property test ---- + testSucceeded = false; + propertyName = "positivePrefix"; + System.out.print("Checking " + propertyName + " property."); + String initialPrefix = df.getPositivePrefix(); + firstFormatResult = df.format(d1); + df.setPositivePrefix("positivePrefix:"); + df.format(d1); + df.setPositivePrefix(initialPrefix); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- positiveSuffix property test ---- + testSucceeded = false; + propertyName = "positiveSuffix"; + System.out.print("Checking " + propertyName + " property."); + String initialSuffix = df.getPositiveSuffix(); + firstFormatResult = df.format(d1); + df.setPositiveSuffix("positiveSuffix:"); + df.format(d1); + df.setPositiveSuffix(initialSuffix); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName,firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- negativePrefix property test ---- + testSucceeded = false; + propertyName = "negativePrefix"; + System.out.print("Checking " + propertyName + " property."); + initialPrefix = df.getNegativePrefix(); + firstFormatResult = df.format(d1); + df.setNegativePrefix("negativePrefix:"); + df.format(d1); + df.setNegativePrefix(initialPrefix); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- negativeSuffix property test ---- + testSucceeded = false; + propertyName = "negativeSuffix"; + System.out.print("Checking " + propertyName + " property."); + initialSuffix = df.getNegativeSuffix(); + firstFormatResult = df.format(d1); + df.setNegativeSuffix("negativeSuffix:"); + df.format(d1); + df.setNegativeSuffix(initialSuffix); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- multiplier property test ---- + testSucceeded = false; + propertyName = "multiplier"; + System.out.print("Checking " + propertyName + " property."); + int initialMultiplier = df.getMultiplier(); + firstFormatResult = df.format(d1); + df.setMultiplier(10); + df.format(d1); + df.setMultiplier(initialMultiplier); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- groupingUsed property test ---- + testSucceeded = false; + propertyName = "groupingUsed"; + System.out.print("Checking " + propertyName + " property."); + boolean initialGroupingUsed = df.isGroupingUsed(); + firstFormatResult = df.format(d1); + df.setGroupingUsed(!initialGroupingUsed); + df.format(d1); + df.setGroupingUsed(initialGroupingUsed); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- groupingSize property test ---- + testSucceeded = false; + propertyName = "groupingSize"; + System.out.print("Checking " + propertyName + " property."); + int initialGroupingSize = df.getGroupingSize(); + firstFormatResult = df.format(d1); + df.setGroupingSize(initialGroupingSize + 1); + df.format(d1); + df.setGroupingSize(initialGroupingSize); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- decimalSeparatorAlwaysShown property test ---- + testSucceeded = false; + propertyName = "decimalSeparatorAlwaysShown"; + System.out.print("Checking " + propertyName + " property."); + boolean initialDSShown = df.isDecimalSeparatorAlwaysShown(); + firstFormatResult = df.format(d1); + df.setDecimalSeparatorAlwaysShown(!initialDSShown); + df.format(d1); + df.setDecimalSeparatorAlwaysShown(initialDSShown); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- parseBigDecimal property test ---- + testSucceeded = false; + propertyName = "parseBigDecimal"; + System.out.print("Checking " + propertyName + " property."); + boolean initialParseBigdecimal = df.isParseBigDecimal(); + firstFormatResult = df.format(d1); + df.setParseBigDecimal(!initialParseBigdecimal); + df.format(d1); + df.setParseBigDecimal(initialParseBigdecimal); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- maximumIntegerDigits property test ---- + testSucceeded = false; + propertyName = "maximumIntegerDigits"; + System.out.print("Checking " + propertyName + " property."); + int initialMaxIDs = df.getMaximumIntegerDigits(); + firstFormatResult = df.format(d1); + df.setMaximumIntegerDigits(8); + df.format(d1); + df.setMaximumIntegerDigits(initialMaxIDs); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- minimumIntegerDigits property test ---- + testSucceeded = false; + propertyName = "minimumIntegerDigits"; + System.out.print("Checking " + propertyName + " property."); + int initialMinIDs = df.getMinimumIntegerDigits(); + firstFormatResult = df.format(d1); + df.setMinimumIntegerDigits(2); + df.format(d1); + df.setMinimumIntegerDigits(initialMinIDs); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- maximumFractionDigits property test ---- + testSucceeded = false; + propertyName = "maximumFractionDigits"; + System.out.print("Checking " + propertyName + " property."); + firstFormatResult = df.format(d1); + df.setMaximumFractionDigits(8); + df.format(d1); + if (isCurrency) { + df.setMinimumFractionDigits(2); + df.setMaximumFractionDigits(2); + } else { + df.setMinimumFractionDigits(0); + df.setMaximumFractionDigits(3); + } + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- minimumFractionDigits property test ---- + testSucceeded = false; + propertyName = "minimumFractionDigits"; + System.out.print("Checking " + propertyName + " property."); + firstFormatResult = df.format(d1); + df.setMinimumFractionDigits(1); + df.format(d1); + if (isCurrency) { + df.setMinimumFractionDigits(2); + df.setMaximumFractionDigits(2); + } else { + df.setMinimumFractionDigits(0); + df.setMaximumFractionDigits(3); + } + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- currency property test ---- + testSucceeded = false; + propertyName = "currency"; + System.out.print("Checking " + propertyName + " property."); + Currency initialCurrency = df.getCurrency(); + Currency japanCur = java.util.Currency.getInstance(Locale.JAPAN); + firstFormatResult = df.format(d1); + df.setCurrency(japanCur); + df.format(d1); + df.setCurrency(initialCurrency); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- roundingMode property test ---- + testSucceeded = false; + propertyName = "roundingMode"; + System.out.print("Checking " + propertyName + " property."); + RoundingMode initialRMode = df.getRoundingMode(); + firstFormatResult = df.format(d1); + df.setRoundingMode(RoundingMode.HALF_UP); + df.format(d1); + df.setRoundingMode(RoundingMode.HALF_EVEN); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + // ---- decimalFormatSymbols property test ---- + testSucceeded = false; + propertyName = "decimalFormatSymbols"; + System.out.print("Checking " + propertyName + " property."); + DecimalFormatSymbols initialDecimalFormatSymbols = df.getDecimalFormatSymbols(); + firstFormatResult = df.format(d1); + Locale bizarreLocale = new Locale("fr", "FR"); + DecimalFormatSymbols unusualSymbols = new DecimalFormatSymbols(bizarreLocale); + unusualSymbols.setDecimalSeparator('@'); + unusualSymbols.setGroupingSeparator('|'); + df.setDecimalFormatSymbols(unusualSymbols); + df.format(d1); + df.setDecimalFormatSymbols(initialDecimalFormatSymbols); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + testSucceeded = false; + System.out.print("Checking " + propertyName + " property."); + initialDecimalFormatSymbols = df.getDecimalFormatSymbols(); + firstFormatResult = df.format(d1); + Locale japanLocale = Locale.JAPAN; + unusualSymbols = new DecimalFormatSymbols(japanLocale); + unusualSymbols.setDecimalSeparator('9'); + unusualSymbols.setGroupingSeparator('0'); + df.setDecimalFormatSymbols(unusualSymbols); + df.format(d1); + df.setDecimalFormatSymbols(initialDecimalFormatSymbols); + secondFormatResult = df.format(d1); + testSucceeded = + resultsEqual(propertyName, firstFormatResult, secondFormatResult); + if (!testSucceeded) + errors++; + + return errors; + } + + // Main for RoundingAndPropertyTest. We test first the golden values, + // and then the property setters and getters. + public static void main(String[] args) { + + if ((args.length >= 1) && + (args[0].equals("-gengold"))) + generatesGoldenFormattedValuesClass(); + else { + System.out.println("\nChecking correctness of formatting with digit localization."); + System.out.println("============================================================="); + int localizationErrors = testLocalizationValues(); + if (localizationErrors != 0) + System.out.println("*** Failure in localization tests : " + + localizationErrors + " errors detected "); + else System.out.println(" Tests for full localization of digits all passed."); + + DecimalFormat df = (DecimalFormat) + NumberFormat.getInstance(GoldenDoubleValues.TestLocale); + DecimalFormat cf = (DecimalFormat) + NumberFormat.getCurrencyInstance(GoldenDoubleValues.TestLocale); + + System.out.println("\nChecking correctness of formating for golden values."); + System.out.println("============================================================="); + int goldenValuesErrors = testGoldenValues(df,cf); + if (goldenValuesErrors != 0) + System.out.println("*** Failure in goldenValues tests : " + + goldenValuesErrors + " errors detected "); + else System.out.println(" Tests for golden values all passed."); + + System.out.println("\nChecking behavior of property changes for decimal case."); + System.out.println("============================================================="); + int decimalTestsErrors = testSettersAndFastPath(df, false); + if (decimalTestsErrors != 0) + System.out.println("*** Failure in decimal property changes tests : " + + decimalTestsErrors + " errors detected "); + else System.out.println(" Tests for decimal property changes all passed."); + + System.out.println("\nChecking behavior of property changes for currency case."); + System.out.println("============================================================="); + int currencyTestsErrors = testSettersAndFastPath(cf, true); + if (currencyTestsErrors != 0) + System.out.println("*** Failure in currency property changes tests : " + + currencyTestsErrors + " errors detected "); + else System.out.println(" Tests for currency property chamges all passed."); + + if ((localizationErrors > 0) || + (goldenValuesErrors > 0) || + (decimalTestsErrors > 0) || + (currencyTestsErrors > 0)) + throw new RuntimeException( + "Failed with " + + (localizationErrors + goldenValuesErrors + + decimalTestsErrors + currencyTestsErrors) + + " error(s)."); + } + } +}