// formatting
//-----------------------------------------------------------------------
+ private static final long MAX_INT64_IN_DOUBLE = 0x1FFFFFFFFFFFFFL;
+
/**
* Performs a mathematical operation on the number, formats it using
* either ruleSet or decimalFormat, and inserts the result into
* position to determine exactly where to insert the new text)
*/
public void doSubstitution(long number, StringBuilder toInsertInto, int position, int recursionCount) {
- // perform a transformation on the number that is dependent
- // on the type of substitution this is, then just call its
- // rule set's format() method to format the result
- long numberToFormat = transformNumber(number);
-
if (ruleSet != null) {
+ // Perform a transformation on the number that is dependent
+ // on the type of substitution this is, then just call its
+ // rule set's format() method to format the result
+ long numberToFormat = transformNumber(number);
+
ruleSet.format(numberToFormat, toInsertInto, position + pos, recursionCount);
} else {
- toInsertInto.insert(position + pos, numberFormat.format(numberToFormat));
+ if (number <= MAX_INT64_IN_DOUBLE) {
+ // or perform the transformation on the number (preserving
+ // the result's fractional part if the formatter it set
+ // to show it), then use that formatter's format() method
+ // to format the result
+ double numberToFormat = transformNumber((double) number);
+ if (numberFormat.getMaximumFractionDigits() == 0) {
+ numberToFormat = Math.floor(numberToFormat);
+ }
+
+ toInsertInto.insert(position + pos, numberFormat.format(numberToFormat));
+ }
+ else {
+ // We have gone beyond double precision. Something has to give.
+ // We're favoring accuracy of the large number over potential rules
+ // that round like a CompactDecimalFormat, which is not a common use case.
+ //
+ // Perform a transformation on the number that is dependent
+ // on the type of substitution this is, then just call its
+ // rule set's format() method to format the result
+ long numberToFormat = transformNumber(number);
+ toInsertInto.insert(position + pos, numberFormat.format(numberToFormat));
+ }
}
}
@Test
public void TestRuleSetDisplayName() {
- /**
+ /*
* Spellout rules for U.K. English.
- * I borrow the rule sets for TestRuleSetDisplayName()
+ * This was borrowed from the rule sets for TestRuleSetDisplayName()
*/
final String ukEnglish =
"%simplified:\n"
rbnf.getRuleSetDisplayName("", new ULocale("en_US"));
errln("RuleBasedNumberFormat.getRuleSetDisplayName(String ruleSetName, ULocale loc) " +
"was suppose to have an exception.");
- } catch(Exception e){}
+ } catch(Exception ignored){}
try{
rbnf.getRuleSetDisplayName("dummy", new ULocale("en_US"));
errln("RuleBasedNumberFormat.getRuleSetDisplayName(String ruleSetName, ULocale loc) " +
"was suppose to have an exception.");
- } catch(Exception e){}
+ } catch(Exception ignored){}
}
/* Test the method
RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(ULocale.US, RuleBasedNumberFormat.SPELLOUT);
String[][] enTestFullData = {
+ {"-9007199254740991", "minus nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-one"}, // Maximum precision in both a double and a long
+ {"9007199254740991", "nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-one"}, // Maximum precision in both a double and a long
+ {"-9007199254740992", "minus nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-two"}, // Only precisely contained in a long
+ {"9007199254740992", "nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-two"}, // Only precisely contained in a long
{"9999999999999998", "nine quadrillion nine hundred ninety-nine trillion nine hundred ninety-nine billion nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-eight"},
{"9999999999999999", "nine quadrillion nine hundred ninety-nine trillion nine hundred ninety-nine billion nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-nine"},
{"999999999999999999", "nine hundred ninety-nine quadrillion nine hundred ninety-nine trillion nine hundred ninety-nine billion nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-nine"},
{"9223372036854775000", "9,223,372,036,854,775,000"}, // Below 64-bit precision
{"9223372036854775806", "9,223,372,036,854,775,806"}, // Maximum 64-bit precision - 1
{"9223372036854775807", "9,223,372,036,854,775,807"}, // Maximum 64-bit precision
- {"9223372036854775808", "9,223,372,036,854,775,808"}, // We've gone beyond 64-bit precision
+ {"9223372036854775808", "9,223,372,036,854,775,808"}, // We've gone beyond 64-bit precision. This can only be represented with BigDecimal.
+ };
+ doTest(rbnf, enTestFullData, false);
+ }
+
+ @Test
+ public void testCompactDecimalFormatStyle() {
+ // This is not a common use case, but we're testing it anyway.
+ final String numberPattern = "=###0.#####=;"
+ + "1000: <###0.00< K;"
+ + "1000000: <###0.00< M;"
+ + "1000000000: <###0.00< B;"
+ + "1000000000000: <###0.00< T;"
+ + "1000000000000000: <###0.00< Q;";
+ RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(numberPattern, ULocale.US);
+
+ String[][] enTestFullData = {
+ {"1000", "1.00 K"},
+ {"1234", "1.23 K"},
+ {"999994", "999.99 K"},
+ {"999995", "1000.00 K"},
+ {"1000000", "1.00 M"},
+ {"1200000", "1.20 M"},
+ {"1200000000", "1.20 B"},
+ {"1200000000000", "1.20 T"},
+ {"1200000000000000", "1.20 Q"},
+ {"4503599627370495", "4.50 Q"},
+ {"4503599627370496", "4.50 Q"},
+ {"8990000000000000", "8.99 Q"},
+ {"9008000000000000", "9.00 Q"}, // Number doesn't precisely fit into a double
+ {"9456000000000000", "9.00 Q"}, // Number doesn't precisely fit into a double
+ {"10000000000000000", "10.00 Q"}, // Number doesn't precisely fit into a double
+ {"9223372036854775807", "9223.00 Q"}, // Maximum 64-bit precision
+ {"9223372036854775808", "9,223,372,036,854,775,808"}, // We've gone beyond 64-bit precision. This can only be represented with BigDecimal.
};
doTest(rbnf, enTestFullData, false);
}