# HG changeset patch
# User olagneau
# Date 1349169117 -3600
# Node ID f771d5fb3b2700461572ea03da6ea45623dbe291
# Parent da3648e13e67dfc24d764be467c33289cd095f8c
7050528: Improve performance of java.text.DecimalFormat.format() call stack
Reviewed-by: darcy
diff -r da3648e13e67 -r f771d5fb3b27 jdk/src/share/classes/java/text/DecimalFormat.java
--- 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 FastTwoSum algorithm, from T.J.Dekker, described in the
+ * papers "A Floating-Point Technique for Extending the Available
+ * Precision" by Dekker, and in "Adaptive Precision Floating-Point
+ * Arithmetic and Fast Robust Geometric Predicates" from J.Shewchuk.
+ *
+ * A modified version of Sum2S cascaded summation described in
+ * "Accurate Sum and Dot Product" 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 FastTwoSum algorithm rather
+ * than the more expensive Knuth's TwoSum.
+ *
+ * We do this to avoid a more expensive exact "TwoProduct" 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 = ',';
diff -r da3648e13e67 -r f771d5fb3b27 jdk/src/share/classes/java/text/NumberFormat.java
--- 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
diff -r da3648e13e67 -r f771d5fb3b27 jdk/test/java/text/Format/DecimalFormat/FormatMicroBenchmark.java
--- /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;
+ }
+ }
+
+}
diff -r da3648e13e67 -r f771d5fb3b27 jdk/test/java/text/Format/DecimalFormat/GoldenDoubleValues.java
--- /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
+ };
+}
diff -r da3648e13e67 -r f771d5fb3b27 jdk/test/java/text/Format/DecimalFormat/GoldenFormattedValues.java
--- /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 },
+ };
+
+}
diff -r da3648e13e67 -r f771d5fb3b27 jdk/test/java/text/Format/DecimalFormat/RoundingAndPropertyTest.java
--- /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).");
+ }
+ }
+}