提交 afc47100 编写于 作者: O olagneau

7050528: Improve performance of java.text.DecimalFormat.format() call stack

Reviewed-by: darcy
上级 7d09db22
......@@ -529,9 +529,25 @@ public class DecimalFormat extends NumberFormat {
@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 @@ public class DecimalFormat extends NumberFormat {
return delegate.getIterator(sb.toString());
}
// ==== Begin fast-path formating logic for double =========================
/* Fast-path formatting will be used for format(double ...) methods iff a
* number of conditions are met (see checkAndSetFastPathStatus()):
* - Only if instance properties meet the right predefined conditions.
* - The abs value of the double to format is <= Integer.MAX_VALUE.
*
* The basic approach is to split the binary to decimal conversion of a
* double value into two phases:
* * The conversion of the integer portion of the double.
* * The conversion of the fractional portion of the double
* (limited to two or three digits).
*
* The isolation and conversion of the integer portion of the double is
* straightforward. The conversion of the fraction is more subtle and relies
* on some rounding properties of double to the decimal precisions in
* question. Using the terminology of BigDecimal, this fast-path algorithm
* is applied when a double value has a magnitude less than Integer.MAX_VALUE
* and rounding is to nearest even and the destination format has two or
* three digits of *scale* (digits after the decimal point).
*
* Under a rounding to nearest even policy, the returned result is a digit
* string of a number in the (in this case decimal) destination format
* closest to the exact numerical value of the (in this case binary) input
* value. If two destination format numbers are equally distant, the one
* with the last digit even is returned. To compute such a correctly rounded
* value, some information about digits beyond the smallest returned digit
* position needs to be consulted.
*
* In general, a guard digit, a round digit, and a sticky *bit* are needed
* beyond the returned digit position. If the discarded portion of the input
* is sufficiently large, the returned digit string is incremented. In round
* to nearest even, this threshold to increment occurs near the half-way
* point between digits. The sticky bit records if there are any remaining
* trailing digits of the exact input value in the new format; the sticky bit
* is consulted only in close to half-way rounding cases.
*
* Given the computation of the digit and bit values, rounding is then
* reduced to a table lookup problem. For decimal, the even/odd cases look
* like this:
*
* Last Round Sticky
* 6 5 0 => 6 // exactly halfway, return even digit.
* 6 5 1 => 7 // a little bit more than halfway, round up.
* 7 5 0 => 8 // exactly halfway, round up to even.
* 7 5 1 => 8 // a little bit more than halfway, round up.
* With analogous entries for other even and odd last-returned digits.
*
* However, decimal negative powers of 5 smaller than 0.5 are *not* exactly
* representable as binary fraction. In particular, 0.005 (the round limit
* for a two-digit scale) and 0.0005 (the round limit for a three-digit
* scale) are not representable. Therefore, for input values near these cases
* the sticky bit is known to be set which reduces the rounding logic to:
*
* Last Round Sticky
* 6 5 1 => 7 // a little bit more than halfway, round up.
* 7 5 1 => 8 // a little bit more than halfway, round up.
*
* In other words, if the round digit is 5, the sticky bit is known to be
* set. If the round digit is something other than 5, the sticky bit is not
* relevant. Therefore, some of the logic about whether or not to increment
* the destination *decimal* value can occur based on tests of *binary*
* computations of the binary input number.
*/
/**
* Check validity of using fast-path for this instance. If fast-path is valid
* for this instance, sets fast-path state as true and initializes fast-path
* utility fields as needed.
*
* This method is supposed to be called rarely, otherwise that will break the
* fast-path performance. That means avoiding frequent changes of the
* properties of the instance, since for most properties, each time a change
* happens, a call to this method is needed at the next format call.
*
* FAST-PATH RULES:
* Similar to the default DecimalFormat instantiation case.
* More precisely:
* - HALF_EVEN rounding mode,
* - isGroupingUsed() is true,
* - groupingSize of 3,
* - multiplier is 1,
* - Decimal separator not mandatory,
* - No use of exponential notation,
* - minimumIntegerDigits is exactly 1 and maximumIntegerDigits at least 10
* - For number of fractional digits, the exact values found in the default case:
* Currency : min = max = 2.
* Decimal : min = 0. max = 3.
*
*/
private void checkAndSetFastPathStatus() {
boolean fastPathWasOn = isFastPath;
if ((roundingMode == RoundingMode.HALF_EVEN) &&
(isGroupingUsed()) &&
(groupingSize == 3) &&
(multiplier == 1) &&
(!decimalSeparatorAlwaysShown) &&
(!useExponentialNotation)) {
// The fast-path algorithm is semi-hardcoded against
// minimumIntegerDigits and maximumIntegerDigits.
isFastPath = ((minimumIntegerDigits == 1) &&
(maximumIntegerDigits >= 10));
// The fast-path algorithm is hardcoded against
// minimumFractionDigits and maximumFractionDigits.
if (isFastPath) {
if (isCurrencyFormat) {
if ((minimumFractionDigits != 2) ||
(maximumFractionDigits != 2))
isFastPath = false;
} else if ((minimumFractionDigits != 0) ||
(maximumFractionDigits != 3))
isFastPath = false;
}
} else
isFastPath = false;
// Since some instance properties may have changed while still falling
// in the fast-path case, we need to reinitialize fastPathData anyway.
if (isFastPath) {
// We need to instantiate fastPathData if not already done.
if (fastPathData == null)
fastPathData = new FastPathData();
// Sets up the locale specific constants used when formatting.
// '0' is our default representation of zero.
fastPathData.zeroDelta = symbols.getZeroDigit() - '0';
fastPathData.groupingChar = symbols.getGroupingSeparator();
// Sets up fractional constants related to currency/decimal pattern.
fastPathData.fractionalMaxIntBound = (isCurrencyFormat) ? 99 : 999;
fastPathData.fractionalScaleFactor = (isCurrencyFormat) ? 100.0d : 1000.0d;
// Records the need for adding prefix or suffix
fastPathData.positiveAffixesRequired =
(positivePrefix.length() != 0) || (positiveSuffix.length() != 0);
fastPathData.negativeAffixesRequired =
(negativePrefix.length() != 0) || (negativeSuffix.length() != 0);
// Creates a cached char container for result, with max possible size.
int maxNbIntegralDigits = 10;
int maxNbGroups = 3;
int containerSize =
Math.max(positivePrefix.length(), negativePrefix.length()) +
maxNbIntegralDigits + maxNbGroups + 1 + maximumFractionDigits +
Math.max(positiveSuffix.length(), negativeSuffix.length());
fastPathData.fastPathContainer = new char[containerSize];
// Sets up prefix and suffix char arrays constants.
fastPathData.charsPositiveSuffix = positiveSuffix.toCharArray();
fastPathData.charsNegativeSuffix = negativeSuffix.toCharArray();
fastPathData.charsPositivePrefix = positivePrefix.toCharArray();
fastPathData.charsNegativePrefix = negativePrefix.toCharArray();
// Sets up fixed index positions for integral and fractional digits.
// Sets up decimal point in cached result container.
int longestPrefixLength =
Math.max(positivePrefix.length(), negativePrefix.length());
int decimalPointIndex =
maxNbIntegralDigits + maxNbGroups + longestPrefixLength;
fastPathData.integralLastIndex = decimalPointIndex - 1;
fastPathData.fractionalFirstIndex = decimalPointIndex + 1;
fastPathData.fastPathContainer[decimalPointIndex] =
isCurrencyFormat ?
symbols.getMonetaryDecimalSeparator() :
symbols.getDecimalSeparator();
} else if (fastPathWasOn) {
// Previous state was fast-path and is no more.
// Resets cached array constants.
fastPathData.fastPathContainer = null;
fastPathData.charsPositiveSuffix = null;
fastPathData.charsNegativeSuffix = null;
fastPathData.charsPositivePrefix = null;
fastPathData.charsNegativePrefix = null;
}
fastPathCheckNeeded = false;
}
/**
* Returns true if rounding-up must be done on {@code scaledFractionalPartAsInt},
* false otherwise.
*
* This is a utility method that takes correct half-even rounding decision on
* passed fractional value at the scaled decimal point (2 digits for currency
* case and 3 for decimal case), when the approximated fractional part after
* scaled decimal point is exactly 0.5d. This is done by means of exact
* calculations on the {@code fractionalPart} floating-point value.
*
* This method is supposed to be called by private {@code fastDoubleFormat}
* method only.
*
* The algorithms used for the exact calculations are :
*
* The <b><i>FastTwoSum</i></b> algorithm, from T.J.Dekker, described in the
* papers "<i>A Floating-Point Technique for Extending the Available
* Precision</i>" by Dekker, and in "<i>Adaptive Precision Floating-Point
* Arithmetic and Fast Robust Geometric Predicates</i>" from J.Shewchuk.
*
* A modified version of <b><i>Sum2S</i></b> cascaded summation described in
* "<i>Accurate Sum and Dot Product</i>" from Takeshi Ogita and All. As
* Ogita says in this paper this is an equivalent of the Kahan-Babuska's
* summation algorithm because we order the terms by magnitude before summing
* them. For this reason we can use the <i>FastTwoSum</i> algorithm rather
* than the more expensive Knuth's <i>TwoSum</i>.
*
* We do this to avoid a more expensive exact "<i>TwoProduct</i>" algorithm,
* like those described in Shewchuk's paper above. See comments in the code
* below.
*
* @param fractionalPart The fractional value on which we take rounding
* decision.
* @param scaledFractionalPartAsInt The integral part of the scaled
* fractional value.
*
* @return the decision that must be taken regarding half-even rounding.
*/
private boolean exactRoundUp(double fractionalPart,
int scaledFractionalPartAsInt) {
/* exactRoundUp() method is called by fastDoubleFormat() only.
* The precondition expected to be verified by the passed parameters is :
* scaledFractionalPartAsInt ==
* (int) (fractionalPart * fastPathData.fractionalScaleFactor).
* This is ensured by fastDoubleFormat() code.
*/
/* We first calculate roundoff error made by fastDoubleFormat() on
* the scaled fractional part. We do this with exact calculation on the
* passed fractionalPart. Rounding decision will then be taken from roundoff.
*/
/* ---- TwoProduct(fractionalPart, scale factor (i.e. 1000.0d or 100.0d)).
*
* The below is an optimized exact "TwoProduct" calculation of passed
* fractional part with scale factor, using Ogita's Sum2S cascaded
* summation adapted as Kahan-Babuska equivalent by using FastTwoSum
* (much faster) rather than Knuth's TwoSum.
*
* We can do this because we order the summation from smallest to
* greatest, so that FastTwoSum can be used without any additional error.
*
* The "TwoProduct" exact calculation needs 17 flops. We replace this by
* a cascaded summation of FastTwoSum calculations, each involving an
* exact multiply by a power of 2.
*
* Doing so saves overall 4 multiplications and 1 addition compared to
* using traditional "TwoProduct".
*
* The scale factor is either 100 (currency case) or 1000 (decimal case).
* - when 1000, we replace it by (1024 - 16 - 8) = 1000.
* - when 100, we replace it by (128 - 32 + 4) = 100.
* Every multiplication by a power of 2 (1024, 128, 32, 16, 8, 4) is exact.
*
*/
double approxMax; // Will always be positive.
double approxMedium; // Will always be negative.
double approxMin;
double fastTwoSumApproximation = 0.0d;
double fastTwoSumRoundOff = 0.0d;
double bVirtual = 0.0d;
if (isCurrencyFormat) {
// Scale is 100 = 128 - 32 + 4.
// Multiply by 2**n is a shift. No roundoff. No error.
approxMax = fractionalPart * 128.00d;
approxMedium = - (fractionalPart * 32.00d);
approxMin = fractionalPart * 4.00d;
} else {
// Scale is 1000 = 1024 - 16 - 8.
// Multiply by 2**n is a shift. No roundoff. No error.
approxMax = fractionalPart * 1024.00d;
approxMedium = - (fractionalPart * 16.00d);
approxMin = - (fractionalPart * 8.00d);
}
// Shewchuk/Dekker's FastTwoSum(approxMedium, approxMin).
assert(-approxMedium >= Math.abs(approxMin));
fastTwoSumApproximation = approxMedium + approxMin;
bVirtual = fastTwoSumApproximation - approxMedium;
fastTwoSumRoundOff = approxMin - bVirtual;
double approxS1 = fastTwoSumApproximation;
double roundoffS1 = fastTwoSumRoundOff;
// Shewchuk/Dekker's FastTwoSum(approxMax, approxS1);
assert(approxMax >= Math.abs(approxS1));
fastTwoSumApproximation = approxMax + approxS1;
bVirtual = fastTwoSumApproximation - approxMax;
fastTwoSumRoundOff = approxS1 - bVirtual;
double roundoff1000 = fastTwoSumRoundOff;
double approx1000 = fastTwoSumApproximation;
double roundoffTotal = roundoffS1 + roundoff1000;
// Shewchuk/Dekker's FastTwoSum(approx1000, roundoffTotal);
assert(approx1000 >= Math.abs(roundoffTotal));
fastTwoSumApproximation = approx1000 + roundoffTotal;
bVirtual = fastTwoSumApproximation - approx1000;
// Now we have got the roundoff for the scaled fractional
double scaledFractionalRoundoff = roundoffTotal - bVirtual;
// ---- TwoProduct(fractionalPart, scale (i.e. 1000.0d or 100.0d)) end.
/* ---- Taking the rounding decision
*
* We take rounding decision based on roundoff and half-even rounding
* rule.
*
* The above TwoProduct gives us the exact roundoff on the approximated
* scaled fractional, and we know that this approximation is exactly
* 0.5d, since that has already been tested by the caller
* (fastDoubleFormat).
*
* Decision comes first from the sign of the calculated exact roundoff.
* - Since being exact roundoff, it cannot be positive with a scaled
* fractional less than 0.5d, as well as negative with a scaled
* fractional greater than 0.5d. That leaves us with following 3 cases.
* - positive, thus scaled fractional == 0.500....0fff ==> round-up.
* - negative, thus scaled fractional == 0.499....9fff ==> don't round-up.
* - is zero, thus scaled fractioanl == 0.5 ==> half-even rounding applies :
* we round-up only if the integral part of the scaled fractional is odd.
*
*/
if (scaledFractionalRoundoff > 0.0) {
return true;
} else if (scaledFractionalRoundoff < 0.0) {
return false;
} else if ((scaledFractionalPartAsInt & 1) != 0) {
return true;
}
return false;
// ---- Taking the rounding decision end
}
/**
* Collects integral digits from passed {@code number}, while setting
* grouping chars as needed. Updates {@code firstUsedIndex} accordingly.
*
* Loops downward starting from {@code backwardIndex} position (inclusive).
*
* @param number The int value from which we collect digits.
* @param digitsBuffer The char array container where digits and grouping chars
* are stored.
* @param backwardIndex the position from which we start storing digits in
* digitsBuffer.
*
*/
private void collectIntegralDigits(int number,
char[] digitsBuffer,
int backwardIndex) {
int index = backwardIndex;
int q;
int r;
while (number > 999) {
// Generates 3 digits per iteration.
q = number / 1000;
r = number - (q << 10) + (q << 4) + (q << 3); // -1024 +16 +8 = 1000.
number = q;
digitsBuffer[index--] = DigitArrays.DigitOnes1000[r];
digitsBuffer[index--] = DigitArrays.DigitTens1000[r];
digitsBuffer[index--] = DigitArrays.DigitHundreds1000[r];
digitsBuffer[index--] = fastPathData.groupingChar;
}
// Collects last 3 or less digits.
digitsBuffer[index] = DigitArrays.DigitOnes1000[number];
if (number > 9) {
digitsBuffer[--index] = DigitArrays.DigitTens1000[number];
if (number > 99)
digitsBuffer[--index] = DigitArrays.DigitHundreds1000[number];
}
fastPathData.firstUsedIndex = index;
}
/**
* Collects the 2 (currency) or 3 (decimal) fractional digits from passed
* {@code number}, starting at {@code startIndex} position
* inclusive. There is no punctuation to set here (no grouping chars).
* Updates {@code fastPathData.lastFreeIndex} accordingly.
*
*
* @param number The int value from which we collect digits.
* @param digitsBuffer The char array container where digits are stored.
* @param startIndex the position from which we start storing digits in
* digitsBuffer.
*
*/
private void collectFractionalDigits(int number,
char[] digitsBuffer,
int startIndex) {
int index = startIndex;
char digitOnes = DigitArrays.DigitOnes1000[number];
char digitTens = DigitArrays.DigitTens1000[number];
if (isCurrencyFormat) {
// Currency case. Always collects fractional digits.
digitsBuffer[index++] = digitTens;
digitsBuffer[index++] = digitOnes;
} else if (number != 0) {
// Decimal case. Hundreds will always be collected
digitsBuffer[index++] = DigitArrays.DigitHundreds1000[number];
// Ending zeros won't be collected.
if (digitOnes != '0') {
digitsBuffer[index++] = digitTens;
digitsBuffer[index++] = digitOnes;
} else if (digitTens != '0')
digitsBuffer[index++] = digitTens;
} else
// This is decimal pattern and fractional part is zero.
// We must remove decimal point from result.
index--;
fastPathData.lastFreeIndex = index;
}
/**
* Internal utility.
* Adds the passed {@code prefix} and {@code suffix} to {@code container}.
*
* @param container Char array container which to prepend/append the
* prefix/suffix.
* @param prefix Char sequence to prepend as a prefix.
* @param suffix Char sequence to append as a suffix.
*
*/
// private void addAffixes(boolean isNegative, char[] container) {
private void addAffixes(char[] container, char[] prefix, char[] suffix) {
// We add affixes only if needed (affix length > 0).
int pl = prefix.length;
int sl = suffix.length;
if (pl != 0) prependPrefix(prefix, pl, container);
if (sl != 0) appendSuffix(suffix, sl, container);
}
/**
* Prepends the passed {@code prefix} chars to given result
* {@code container}. Updates {@code fastPathData.firstUsedIndex}
* accordingly.
*
* @param prefix The prefix characters to prepend to result.
* @param len The number of chars to prepend.
* @param container Char array container which to prepend the prefix
*/
private void prependPrefix(char[] prefix,
int len,
char[] container) {
fastPathData.firstUsedIndex -= len;
int startIndex = fastPathData.firstUsedIndex;
// If prefix to prepend is only 1 char long, just assigns this char.
// If prefix is less or equal 4, we use a dedicated algorithm that
// has shown to run faster than System.arraycopy.
// If more than 4, we use System.arraycopy.
if (len == 1)
container[startIndex] = prefix[0];
else if (len <= 4) {
int dstLower = startIndex;
int dstUpper = dstLower + len - 1;
int srcUpper = len - 1;
container[dstLower] = prefix[0];
container[dstUpper] = prefix[srcUpper];
if (len > 2)
container[++dstLower] = prefix[1];
if (len == 4)
container[--dstUpper] = prefix[2];
} else
System.arraycopy(prefix, 0, container, startIndex, len);
}
/**
* Appends the passed {@code suffix} chars to given result
* {@code container}. Updates {@code fastPathData.lastFreeIndex}
* accordingly.
*
* @param suffix The suffix characters to append to result.
* @param len The number of chars to append.
* @param container Char array container which to append the suffix
*/
private void appendSuffix(char[] suffix,
int len,
char[] container) {
int startIndex = fastPathData.lastFreeIndex;
// If suffix to append is only 1 char long, just assigns this char.
// If suffix is less or equal 4, we use a dedicated algorithm that
// has shown to run faster than System.arraycopy.
// If more than 4, we use System.arraycopy.
if (len == 1)
container[startIndex] = suffix[0];
else if (len <= 4) {
int dstLower = startIndex;
int dstUpper = dstLower + len - 1;
int srcUpper = len - 1;
container[dstLower] = suffix[0];
container[dstUpper] = suffix[srcUpper];
if (len > 2)
container[++dstLower] = suffix[1];
if (len == 4)
container[--dstUpper] = suffix[2];
} else
System.arraycopy(suffix, 0, container, startIndex, len);
fastPathData.lastFreeIndex += len;
}
/**
* Converts digit chars from {@code digitsBuffer} to current locale.
*
* Must be called before adding affixes since we refer to
* {@code fastPathData.firstUsedIndex} and {@code fastPathData.lastFreeIndex},
* and do not support affixes (for speed reason).
*
* We loop backward starting from last used index in {@code fastPathData}.
*
* @param digitsBuffer The char array container where the digits are stored.
*/
private void localizeDigits(char[] digitsBuffer) {
// We will localize only the digits, using the groupingSize,
// and taking into account fractional part.
// First take into account fractional part.
int digitsCounter =
fastPathData.lastFreeIndex - fastPathData.fractionalFirstIndex;
// The case when there is no fractional digits.
if (digitsCounter < 0)
digitsCounter = groupingSize;
// Only the digits remains to localize.
for (int cursor = fastPathData.lastFreeIndex - 1;
cursor >= fastPathData.firstUsedIndex;
cursor--) {
if (digitsCounter != 0) {
// This is a digit char, we must localize it.
digitsBuffer[cursor] += fastPathData.zeroDelta;
digitsCounter--;
} else {
// Decimal separator or grouping char. Reinit counter only.
digitsCounter = groupingSize;
}
}
}
/**
* This is the main entry point for the fast-path format algorithm.
*
* At this point we are sure to be in the expected conditions to run it.
* This algorithm builds the formatted result and puts it in the dedicated
* {@code fastPathData.fastPathContainer}.
*
* @param d the double value to be formatted.
* @param negative Flag precising if {@code d} is negative.
*/
private void fastDoubleFormat(double d,
boolean negative) {
char[] container = fastPathData.fastPathContainer;
/*
* The principle of the algorithm is to :
* - Break the passed double into its integral and fractional parts
* converted into integers.
* - Then decide if rounding up must be applied or not by following
* the half-even rounding rule, first using approximated scaled
* fractional part.
* - For the difficult cases (approximated scaled fractional part
* being exactly 0.5d), we refine the rounding decision by calling
* exactRoundUp utility method that both calculates the exact roundoff
* on the approximation and takes correct rounding decision.
* - We round-up the fractional part if needed, possibly propagating the
* rounding to integral part if we meet a "all-nine" case for the
* scaled fractional part.
* - We then collect digits from the resulting integral and fractional
* parts, also setting the required grouping chars on the fly.
* - Then we localize the collected digits if needed, and
* - Finally prepend/append prefix/suffix if any is needed.
*/
// Exact integral part of d.
int integralPartAsInt = (int) d;
// Exact fractional part of d (since we subtract it's integral part).
double exactFractionalPart = d - (double) integralPartAsInt;
// Approximated scaled fractional part of d (due to multiplication).
double scaledFractional =
exactFractionalPart * fastPathData.fractionalScaleFactor;
// Exact integral part of scaled fractional above.
int fractionalPartAsInt = (int) scaledFractional;
// Exact fractional part of scaled fractional above.
scaledFractional = scaledFractional - (double) fractionalPartAsInt;
// Only when scaledFractional is exactly 0.5d do we have to do exact
// calculations and take fine-grained rounding decision, since
// approximated results above may lead to incorrect decision.
// Otherwise comparing against 0.5d (strictly greater or less) is ok.
boolean roundItUp = false;
if (scaledFractional >= 0.5d) {
if (scaledFractional == 0.5d)
// Rounding need fine-grained decision.
roundItUp = exactRoundUp(exactFractionalPart, fractionalPartAsInt);
else
roundItUp = true;
if (roundItUp) {
// Rounds up both fractional part (and also integral if needed).
if (fractionalPartAsInt < fastPathData.fractionalMaxIntBound) {
fractionalPartAsInt++;
} else {
// Propagates rounding to integral part since "all nines" case.
fractionalPartAsInt = 0;
integralPartAsInt++;
}
}
}
// Collecting digits.
collectFractionalDigits(fractionalPartAsInt, container,
fastPathData.fractionalFirstIndex);
collectIntegralDigits(integralPartAsInt, container,
fastPathData.integralLastIndex);
// Localizing digits.
if (fastPathData.zeroDelta != 0)
localizeDigits(container);
// Adding prefix and suffix.
if (negative) {
if (fastPathData.negativeAffixesRequired)
addAffixes(container,
fastPathData.charsNegativePrefix,
fastPathData.charsNegativeSuffix);
} else if (fastPathData.positiveAffixesRequired)
addAffixes(container,
fastPathData.charsPositivePrefix,
fastPathData.charsPositiveSuffix);
}
/**
* A fast-path shortcut of format(double) to be called by NumberFormat, or by
* format(double, ...) public methods.
*
* If instance can be applied fast-path and passed double is not NaN or
* Infinity, is in the integer range, we call {@code fastDoubleFormat}
* after changing {@code d} to its positive value if necessary.
*
* Otherwise returns null by convention since fast-path can't be exercized.
*
* @param d The double value to be formatted
*
* @return the formatted result for {@code d} as a string.
*/
String fastFormat(double d) {
// (Re-)Evaluates fast-path status if needed.
if (fastPathCheckNeeded)
checkAndSetFastPathStatus();
if (!isFastPath )
// DecimalFormat instance is not in a fast-path state.
return null;
if (!Double.isFinite(d))
// Should not use fast-path for Infinity and NaN.
return null;
// Extracts and records sign of double value, possibly changing it
// to a positive one, before calling fastDoubleFormat().
boolean negative = false;
if (d < 0.0d) {
negative = true;
d = -d;
} else if (d == 0.0d) {
negative = (Math.copySign(1.0d, d) == -1.0d);
d = +0.0d;
}
if (d > MAX_INT_AS_DOUBLE)
// Filters out values that are outside expected fast-path range
return null;
else
fastDoubleFormat(d, negative);
// Returns a new string from updated fastPathContainer.
return new String(fastPathData.fastPathContainer,
fastPathData.firstUsedIndex,
fastPathData.lastFreeIndex - fastPathData.firstUsedIndex);
}
// ======== End fast-path formating logic for double =========================
/**
* Complete the formatting of a finite number. On entry, the digitList must
* be filled in with the correct digits.
......@@ -1168,8 +1898,7 @@ public class DecimalFormat extends NumberFormat {
if (isNegative) {
append(result, negativeSuffix, delegate,
getNegativeSuffixFieldPositions(), Field.SIGN);
}
else {
} else {
append(result, positiveSuffix, delegate,
getPositiveSuffixFieldPositions(), Field.SIGN);
}
......@@ -1557,8 +2286,7 @@ public class DecimalFormat extends NumberFormat {
sawExponent = true;
}
break; // Whether we fail or succeed, we exit this loop
}
else {
} else {
break;
}
}
......@@ -1653,6 +2381,7 @@ public class DecimalFormat extends NumberFormat {
// don't allow multiple references
symbols = (DecimalFormatSymbols) newSymbols.clone();
expandAffixes();
fastPathCheckNeeded = true;
} catch (Exception foo) {
// should never happen
}
......@@ -1674,6 +2403,7 @@ public class DecimalFormat extends NumberFormat {
positivePrefix = newValue;
posPrefixPattern = null;
positivePrefixFieldPositions = null;
fastPathCheckNeeded = true;
}
/**
......@@ -1688,8 +2418,7 @@ public class DecimalFormat extends NumberFormat {
if (positivePrefixFieldPositions == null) {
if (posPrefixPattern != null) {
positivePrefixFieldPositions = expandAffix(posPrefixPattern);
}
else {
} else {
positivePrefixFieldPositions = EmptyFieldPositionArray;
}
}
......@@ -1711,6 +2440,7 @@ public class DecimalFormat extends NumberFormat {
public void setNegativePrefix (String newValue) {
negativePrefix = newValue;
negPrefixPattern = null;
fastPathCheckNeeded = true;
}
/**
......@@ -1725,8 +2455,7 @@ public class DecimalFormat extends NumberFormat {
if (negativePrefixFieldPositions == null) {
if (negPrefixPattern != null) {
negativePrefixFieldPositions = expandAffix(negPrefixPattern);
}
else {
} else {
negativePrefixFieldPositions = EmptyFieldPositionArray;
}
}
......@@ -1748,6 +2477,7 @@ public class DecimalFormat extends NumberFormat {
public void setPositiveSuffix (String newValue) {
positiveSuffix = newValue;
posSuffixPattern = null;
fastPathCheckNeeded = true;
}
/**
......@@ -1762,8 +2492,7 @@ public class DecimalFormat extends NumberFormat {
if (positiveSuffixFieldPositions == null) {
if (posSuffixPattern != null) {
positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
}
else {
} else {
positiveSuffixFieldPositions = EmptyFieldPositionArray;
}
}
......@@ -1785,6 +2514,7 @@ public class DecimalFormat extends NumberFormat {
public void setNegativeSuffix (String newValue) {
negativeSuffix = newValue;
negSuffixPattern = null;
fastPathCheckNeeded = true;
}
/**
......@@ -1799,8 +2529,7 @@ public class DecimalFormat extends NumberFormat {
if (negativeSuffixFieldPositions == null) {
if (negSuffixPattern != null) {
negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
}
else {
} else {
negativeSuffixFieldPositions = EmptyFieldPositionArray;
}
}
......@@ -1834,6 +2563,16 @@ public class DecimalFormat extends NumberFormat {
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 class DecimalFormat extends NumberFormat {
*/
public void setGroupingSize (int newValue) {
groupingSize = (byte)newValue;
fastPathCheckNeeded = true;
}
/**
......@@ -1878,6 +2618,7 @@ public class DecimalFormat extends NumberFormat {
*/
public void setDecimalSeparatorAlwaysShown(boolean newValue) {
decimalSeparatorAlwaysShown = newValue;
fastPathCheckNeeded = true;
}
/**
......@@ -1908,6 +2649,20 @@ public class DecimalFormat extends NumberFormat {
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 @@ public class DecimalFormat extends NumberFormat {
@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 @@ public class DecimalFormat extends NumberFormat {
|| 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 @@ public class DecimalFormat extends NumberFormat {
super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
}
fastPathCheckNeeded = true;
}
/**
......@@ -2714,6 +3471,7 @@ public class DecimalFormat extends NumberFormat {
super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
}
fastPathCheckNeeded = true;
}
/**
......@@ -2734,6 +3492,7 @@ public class DecimalFormat extends NumberFormat {
super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
}
fastPathCheckNeeded = true;
}
/**
......@@ -2754,6 +3513,7 @@ public class DecimalFormat extends NumberFormat {
super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
}
fastPathCheckNeeded = true;
}
/**
......@@ -2843,6 +3603,7 @@ public class DecimalFormat extends NumberFormat {
expandAffixes();
}
}
fastPathCheckNeeded = true;
}
/**
......@@ -2873,6 +3634,7 @@ public class DecimalFormat extends NumberFormat {
this.roundingMode = roundingMode;
digitList.setRoundingMode(roundingMode);
fastPathCheckNeeded = true;
}
/**
......@@ -2924,6 +3686,12 @@ public class DecimalFormat extends NumberFormat {
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 @@ public class DecimalFormat extends NumberFormat {
*/
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 @@ public class DecimalFormat extends NumberFormat {
// 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 = ',';
......
/*
* 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 @@ public abstract class NumberFormat extends Format {
* @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
......
/*
* 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;
}
}
}
/*
* 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
};
}
/*
* 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 },
};
}
/*
* 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).");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册