diff --git a/.gitattributes b/.gitattributes
index 9f033a9abf4..159c81d2153 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -245,6 +245,8 @@ icu4j/main/classes/core/.project -text
icu4j/main/classes/core/.settings/org.eclipse.core.resources.prefs -text
icu4j/main/classes/core/.settings/org.eclipse.jdt.core.prefs -text
icu4j/main/classes/core/manifest.stub -text
+icu4j/main/classes/core/src/com/ibm/icu/text/CompactDecimalFormat.java -text
+icu4j/main/classes/core/src/com/ibm/icu/text/CompactDecimalFormatData.java -text
icu4j/main/classes/currdata/.externalToolBuilders/copy-data-currdata.launch -text
icu4j/main/classes/currdata/.settings/org.eclipse.core.resources.prefs -text
icu4j/main/classes/currdata/.settings/org.eclipse.jdt.core.prefs -text
@@ -304,6 +306,7 @@ icu4j/main/tests/core/manifest.stub -text
icu4j/main/tests/core/src/com/ibm/icu/dev/data/rbbi/english.dict -text
icu4j/main/tests/core/src/com/ibm/icu/dev/data/resources/testmessages.properties -text
icu4j/main/tests/core/src/com/ibm/icu/dev/data/thai6.ucs -text
+icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/CompactDecimalFormatTest.java -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.impl.OlsonTimeZone.dat -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.impl.TimeZoneAdapter.dat -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.math.BigDecimal.dat -text
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/CompactDecimalFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/CompactDecimalFormat.java
new file mode 100644
index 00000000000..887a5050bb9
--- /dev/null
+++ b/icu4j/main/classes/core/src/com/ibm/icu/text/CompactDecimalFormat.java
@@ -0,0 +1,240 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2012, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+package com.ibm.icu.text;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.ibm.icu.util.ULocale;
+
+/**
+ * The CompactDecimalFormat produces abbreviated numbers, suitable for display in environments will limited real estate.
+ * For example, 'Hits: 1.2B' instead of 'Hits: 1,200,000,000'. The format will be appropriate for the given language,
+ * such as "1,2 Mrd." for German.
+ *
+ * For numbers under 1000 trillion (under 10^15, such as 123,456,789,012,345), the result will be short for supported
+ * languages. However, the result may sometimes exceed 7 characters, such as when there are combining marks or thin
+ * characters. In such cases, the visual width in fonts should still be short.
+ *
+ * By default, there are 2 significant digits. After creation, if more than three significant digits are set (with
+ * setMaximumSignificantDigits), or if a fixed number of digits are set (with setMaximumIntegerDigits or
+ * setMaximumFractionDigits), then result may be wider.
+ *
+ * At this time, negative numbers and parsing are not supported, and will produce an UnsupportedOperationException.
+ * Resetting the pattern prefixes or suffixes is not supported; the method calls are ignored.
+ *
+ * Note that important methods, like setting the number of decimals, will be moved up from DecimalFormat to
+ * NumberFormat.
+ *
+ * @author markdavis
+ * @internal
+ */
+public class CompactDecimalFormat extends DecimalFormat {
+ private static final long serialVersionUID = 4716293295276629682L;
+
+ private static final int MINIMUM_ARRAY_LENGTH = 15;
+ private static final int POSITIVE_PREFIX = 0, POSITIVE_SUFFIX = 1, AFFIX_SIZE = 2;
+
+ private final String[] prefix;
+ private final String[] suffix;
+ private final long[] divisor;
+ private final String[] currencyAffixes;
+
+ /**
+ * The normal mechanism is to use NumberFormat.getCompactDecimalInstance(). This is intended only for testing.
+ *
+ * @param locale
+ * the desired locale
+ * @param style
+ * the compact style
+ * @internal
+ */
+ public CompactDecimalFormat(ULocale locale, CompactStyle style) {
+ DecimalFormat format = (DecimalFormat) NumberFormat.getInstance(locale);
+ Data data;
+ while (true) {
+ data = localeToData.get(locale);
+ if (data != null) {
+ break;
+ }
+ locale = locale.equals(zhTW) ? ULocale.TRADITIONAL_CHINESE : locale.getFallback();
+ }
+ this.prefix = data.prefixes;
+ this.suffix = data.suffixes;
+ this.divisor = data.divisors;
+ applyPattern(format.toPattern());
+ setDecimalFormatSymbols(format.getDecimalFormatSymbols());
+ setMaximumSignificantDigits(2); // default significant digits
+ setSignificantDigitsUsed(true);
+ setGroupingUsed(false);
+
+ DecimalFormat currencyFormat = (DecimalFormat) NumberFormat.getCurrencyInstance(locale);
+ currencyAffixes = new String[AFFIX_SIZE];
+ currencyAffixes[CompactDecimalFormat.POSITIVE_PREFIX] = currencyFormat.getPositivePrefix();
+ currencyAffixes[CompactDecimalFormat.POSITIVE_SUFFIX] = currencyFormat.getPositiveSuffix();
+ // TODO fix to get right symbol for the count
+ }
+
+ /**
+ * Create a short number "from scratch". Intended for internal use. The prefix, suffix, and divisor arrays are
+ * parallel, and provide the information for each power of 10. When formatting a value, the correct power of 10 is
+ * found, then the value is divided by the divisor, and the prefix and suffix are set (using
+ * setPositivePrefix/Suffix).
+ *
+ * @param pattern
+ * A number format pattern. Note that the prefix and suffix are discarded, and the decimals are
+ * overridden by default.
+ * @param formatSymbols
+ * Decimal format symbols, typically from a locale.
+ * @param prefix
+ * An array of prefix values, one for each power of 10 from 0 to 14
+ * @param suffix
+ * An array of prefix values, one for each power of 10 from 0 to 14
+ * @param divisor
+ * An array of prefix values, one for each power of 10 from 0 to 14
+ * @param debugCreationErrors
+ * A collection of strings for debugging. If null on input, then any errors found will be added to that
+ * collection instead of throwing exceptions.
+ * @internal
+ */
+ public CompactDecimalFormat(String pattern, DecimalFormatSymbols formatSymbols, String[] prefix, String[] suffix,
+ long[] divisor, Collection debugCreationErrors, CompactStyle style, String[] currencyAffixes) {
+ if (prefix.length < MINIMUM_ARRAY_LENGTH) {
+ recordError(debugCreationErrors, "Must have at least " + MINIMUM_ARRAY_LENGTH + " prefix items.");
+ }
+ if (prefix.length != suffix.length || prefix.length != divisor.length) {
+ recordError(debugCreationErrors, "Prefix, suffix, and divisor arrays must have the same length.");
+ }
+ long oldDivisor = 0;
+ Map seen = new HashMap();
+ for (int i = 0; i < prefix.length; ++i) {
+ if (prefix[i] == null || suffix[i] == null) {
+ recordError(debugCreationErrors, "Prefix or suffix is null for " + i);
+ }
+
+ // divisor must be a power of 10, and must be less than or equal to 10^i
+ int log = (int) Math.log10(divisor[i]);
+ if (log > i) {
+ recordError(debugCreationErrors, "Divisor[" + i + "] must be less than or equal to 10^" + i
+ + ", but is: " + divisor[i]);
+ }
+ long roundTrip = (long) Math.pow(10.0d, log);
+ if (roundTrip != divisor[i]) {
+ recordError(debugCreationErrors, "Divisor[" + i + "] must be a power of 10, but is: " + divisor[i]);
+ }
+
+ // we can't have two different indexes with the same display
+ String key = prefix[i] + "\uFFFF" + suffix[i] + "\uFFFF" + (i - log);
+ Integer old = seen.get(key);
+ if (old != null) {
+ recordError(debugCreationErrors, "Collision between values for " + i + " and " + old
+ + " for [prefix/suffix/index-log(divisor)" + key.replace('\uFFFF', ';'));
+ } else {
+ seen.put(key, i);
+ }
+ if (divisor[i] < oldDivisor) {
+ recordError(debugCreationErrors, "Bad divisor, the divisor for 10E" + i + "(" + divisor[i]
+ + ") is less than the divisor for the divisor for 10E" + (i - 1) + "(" + oldDivisor + ")");
+ }
+ oldDivisor = divisor[i];
+ }
+
+ this.prefix = prefix.clone();
+ this.suffix = suffix.clone();
+ this.divisor = divisor.clone();
+ applyPattern(pattern);
+ setDecimalFormatSymbols(formatSymbols);
+ setMaximumSignificantDigits(2); // default significant digits
+ setSignificantDigitsUsed(true);
+ setGroupingUsed(false);
+ this.currencyAffixes = currencyAffixes.clone();
+ }
+
+ @Override
+ public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
+ if (number < 0.0d) {
+ throw new UnsupportedOperationException("CompactDecimalFormat doesn't handle negative numbers yet.");
+ }
+ int integerCount = (int) Math.log10(number);
+ int base = integerCount > 14 ? 14 : integerCount;
+ number = number / divisor[base];
+ setPositivePrefix(prefix[base]);
+ setPositiveSuffix(suffix[base]);
+ setCurrency(null);
+ return super.format(number, toAppendTo, pos);
+ }
+
+ @Override
+ public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
+ return format((double) number, toAppendTo, pos);
+ }
+
+ @Override
+ public StringBuffer format(BigInteger number, StringBuffer toAppendTo, FieldPosition pos) {
+ return format(number.doubleValue(), toAppendTo, pos);
+ }
+
+ @Override
+ public StringBuffer format(BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
+ return format(number.doubleValue(), toAppendTo, pos);
+ }
+
+ @Override
+ public StringBuffer format(com.ibm.icu.math.BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
+ return format(number.doubleValue(), toAppendTo, pos);
+ }
+
+ /**
+ * Parsing is currently unsupported, and throws an UnsupportedOperationException.
+ */
+ @Override
+ public Number parse(String text, ParsePosition parsePosition) {
+ throw new UnsupportedOperationException();
+ }
+
+ /* INTERNALS */
+
+ private static ULocale zhTW = new ULocale("zh_TW");
+
+ private void recordError(Collection creationErrors, String errorMessage) {
+ if (creationErrors == null) {
+ throw new IllegalArgumentException(errorMessage);
+ }
+ creationErrors.add(errorMessage);
+ }
+
+ /** JUST FOR DEVELOPMENT */
+ // For use with the hard-coded data
+ static class Data {
+ public Data(long[] divisors, String[] prefixes, String[] suffixes) {
+ this.divisors = divisors;
+ this.prefixes = prefixes;
+ this.suffixes = suffixes;
+ }
+
+ long[] divisors;
+ String[] prefixes;
+ String[] suffixes;
+ }
+
+ static Map localeToData = new HashMap();
+
+ static void add(String locale, long[] ls, String[] prefixes, String[] suffixes) {
+ localeToData.put(new ULocale(locale), new Data(ls, prefixes, suffixes));
+ }
+
+ static {
+ CompactDecimalFormatData.load();
+ }
+
+}
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/CompactDecimalFormatData.java b/icu4j/main/classes/core/src/com/ibm/icu/text/CompactDecimalFormatData.java
new file mode 100644
index 00000000000..a71e9842074
--- /dev/null
+++ b/icu4j/main/classes/core/src/com/ibm/icu/text/CompactDecimalFormatData.java
@@ -0,0 +1,234 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2012, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+package com.ibm.icu.text;
+
+/**
+ * Only until we access the data from CLDR.
+ */
+class CompactDecimalFormatData {
+ static void load() {
+ CompactDecimalFormat.add("af",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " mil", " mil", " mil", " mjd", " mjd", " mjd", " bil", " bil", " bil"});
+ CompactDecimalFormat.add("am",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "ኪባ", " ሜትር", " ሜትር", " ሜትር", "G", "G", "G", "T", "T", "T"});
+ CompactDecimalFormat.add("ar",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("bg",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " Х", " Х", " Х", " М", " М", " М", " Б", " Б", " Б", " Т", " Т", " Т"});
+ CompactDecimalFormat.add("bn",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("ca",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " M", " M", " M", " M", "k M", "k M", " B", " B", " B"});
+ CompactDecimalFormat.add("cs",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " tis.", " tis.", " tis.", " mil.", " mil.", " mil.", " mld.", " mld.", " mld.", " bil.", " bil.", " bil."});
+ CompactDecimalFormat.add("da",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " mio", " mio", " mio", " mia", " mia", " mia", " bill", " bill", " bill"});
+ CompactDecimalFormat.add("de",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " Mio", " Mio", " Mio", " Mrd", " Mrd", " Mrd", " B", " B", " B"});
+ CompactDecimalFormat.add("el",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " χιλ.", " χιλ.", " χιλ.", " εκ.", " εκ.", " εκ.", " δις", " δις", " δις", " τρις", " τρις", " τρις"});
+ CompactDecimalFormat.add("en",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("es",
+ new long[]{1L, 1L, 1L, 1L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "k", "k", " M", " M", " M", " M", "k M", "k M", " B", " B", " B"});
+ CompactDecimalFormat.add("et",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " tuh", " tuh", " tuh", " mln", " mln", " mln", " mld", " mld", " mld", " trl", " trl", " trl"});
+ CompactDecimalFormat.add("eu",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " M", " M", " M", " M", "k M", "k M", " B", " B", " B"});
+ CompactDecimalFormat.add("fa",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("fi",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " t", " t", " t", " ml", " ml", " ml", " mr", " mr", " mr", " b", " b", " b"});
+ CompactDecimalFormat.add("fil",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("fr",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " M", " M", " M", " Md", " Mds", " Mds", " Bn", " Bn", " Bn"});
+ CompactDecimalFormat.add("gl",
+ new long[]{1L, 1L, 1L, 1L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "k", "k", " M", " M", " M", " M", "k M", "k M", " B", " B", " B"});
+ CompactDecimalFormat.add("gu",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("he",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("hi",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("hr",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " mil.", " mil.", " mil.", " mlr", " mlr", " mlr", " bil.", " bil.", " bil."});
+ CompactDecimalFormat.add("hu",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " e", " e", " e", " m", " m", " m", " mrd", " mrd", " mrd", " b", " b", " b"});
+ CompactDecimalFormat.add("id",
+ new long[]{1L, 1L, 1L, 1L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", " rb", " rb", " jt", " jt", " jt", " M", " M", " M", " T", " T", " T"});
+ CompactDecimalFormat.add("is",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " þ.", " þ.", " þ.", " m.", " m.", " m.", " ma.", " ma.", " ma.", " tr.", " tr.", " tr."});
+ CompactDecimalFormat.add("it",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " M", " M", " M", " Md", " Md", " Md", " B", " B", " B"});
+ CompactDecimalFormat.add("ja",
+ new long[]{1L, 1L, 1L, 1L, 10000L, 10000L, 10000L, 10000L, 100000000L, 100000000L, 100000000L, 100000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "万", "万", "万", "万", "億", "億", "億", "億", "兆", "兆", "兆"});
+ CompactDecimalFormat.add("kn",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("ko",
+ new long[]{1L, 1L, 1L, 1L, 10000L, 10000L, 10000L, 10000L, 100000000L, 100000000L, 100000000L, 100000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "만", "만", "만", "만", "억", "억", "억", "억", "조", "조", "조"});
+ CompactDecimalFormat.add("lt",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " K", " K", " K", " M", " M", " M", " G", " G", " G", " T", " T", " T"});
+ CompactDecimalFormat.add("lv",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " K", " K", " K", " M", " M", " M", " G", " G", " G", " T", " T", " T"});
+ CompactDecimalFormat.add("ml",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("mr",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("ms",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("nb",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " mill", " mill", " mill", " mrd", " mrd", " mrd", " bill", " bill", " bill"});
+ CompactDecimalFormat.add("nl",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " mln", " mln", " mln", " mld", " mld", " mld", " bilj", " bilj", " bilj"});
+ CompactDecimalFormat.add("pl",
+ new long[]{1L, 1L, 1L, 1L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", " tys.", " tys.", " mln", " mln", " mln", " mld", " mld", " mld", " bln", " bln", " bln"});
+ CompactDecimalFormat.add("pt",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " mil", " mil", " mil", " mi", " mi", " mi", " bi", " bi", " bi", " tri", " tri", " tri"});
+ CompactDecimalFormat.add("ro",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " mii", " mii", " mii", " mil.", " mil.", " mil.", " mld.", " mld.", " mld.", " bln.", " bln.", " bln."});
+ CompactDecimalFormat.add("ru",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " тыс.", " тыс.", " тыс.", " млн", " млн", " млн", " млрд", " млрд", " млрд", " трлн", " трлн", " трлн"});
+ CompactDecimalFormat.add("sk",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " tis.", " tis.", " tis.", " mil.", " mil.", " mil.", " mld.", " mld.", " mld.", " bil.", " bil.", " bil."});
+ CompactDecimalFormat.add("sl",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " tis.", " tis.", " tis.", " mio.", " mio.", " mio.", " mrd.", " mrd.", " mrd.", " bil.", " bil.", " bil."});
+ CompactDecimalFormat.add("sr",
+ new long[]{1L, 1L, 1L, 1L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", " хиљ", " хиљ", " мил", " мил", " мил", " млрд", " млрд", " млрд", " бил", " бил", " бил"});
+ CompactDecimalFormat.add("sv",
+ new long[]{1L, 1L, 1L, 1L, 1L, 1L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "", "", " mjn", " mjn", " mjn", " mjd", " mjd", " mjd", " trl", " trl", " trl"});
+ CompactDecimalFormat.add("sw",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 100000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "elfu ", "elfu ", "laki", "M", "M", "M", "B", "B", "B", "T", "T", "T"},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""});
+ CompactDecimalFormat.add("ta",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("te",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("th",
+ new long[]{1L, 1L, 1L, 1000L, 10000L, 100000L, 1000000L, 1000000L, 1000000L, 1000000000L, 10000000000L, 100000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " พัน", "หมื่น", "แสน", " ล้าน", " ล้าน", " ล.", " พ.ล.", " ม.ล.", " ส.ล.", " ล.ล.", " ล.ล", " ล.ล."});
+ CompactDecimalFormat.add("tr",
+ new long[]{1L, 1L, 1L, 1L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", " B", " B", " Mn", " Mn", " Mn", " Mr", " Mr", " Mr", " T", " T", " T"});
+ CompactDecimalFormat.add("uk",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " тис", " тис", " тис", " млн", " млн", " млн", " млрд", " млрд", " млрд", " трлн", " трлн", " трлн"});
+ CompactDecimalFormat.add("ur",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "K", "K", "K", "M", "M", "M", "B", "B", "B", "T", "T", "T"});
+ CompactDecimalFormat.add("vi",
+ new long[]{1L, 1L, 1L, 1000L, 1000L, 1000L, 1000000L, 1000000L, 1000000L, 1000000000L, 1000000000L, 1000000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", " N", " N", " N", " Tr", " Tr", " Tr", " Tỷ", " Tỷ", " Tỷ", " NT", " NT", " NT"});
+ CompactDecimalFormat.add("zh",
+ new long[]{1L, 1L, 1L, 1L, 10000L, 10000L, 10000L, 10000L, 100000000L, 100000000L, 100000000L, 100000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "万", "万", "万", "万", "亿", "亿", "亿", "亿", "兆", "兆", "兆"});
+ CompactDecimalFormat.add("zh_Hant",
+ new long[]{1L, 1L, 1L, 1L, 10000L, 10000L, 10000L, 10000L, 100000000L, 100000000L, 100000000L, 100000000L, 1000000000000L, 1000000000000L, 1000000000000L},
+ new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
+ new String[]{"", "", "", "", "萬", "萬", "萬", "萬", "億", "億", "億", "億", "兆", "兆", "兆"});
+}}
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/NumberFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/NumberFormat.java
index e2c870e17d1..15817d9aaea 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/text/NumberFormat.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/text/NumberFormat.java
@@ -713,6 +713,46 @@ public abstract class NumberFormat extends UFormat {
return getInstance(inLocale, SCIENTIFICSTYLE);
}
+ /**
+ * Style parameter for CompactDecimalFormat.
+ * @internal
+ */
+ public enum CompactStyle {
+ /**
+ * Short version, like "1.2T"
+ */
+ SHORT,
+ /**
+ * Longer version, like "1.2 trillion", if available. May return same result as SHORT if not.
+ */
+ LONG
+ }
+
+ /**
+ * Create a CompactDecimalFormat appropriate for a locale (Mockup for what would be in NumberFormat). The result may
+ * be affected by the number system in the locale, such as ar-u-nu-latn.
+ *
+ * @param locale the desired locale
+ * @param style the compact style
+ * @internal
+ */
+ public static final CompactDecimalFormat getCompactDecimalInstance(ULocale locale, CompactStyle style) {
+ return new CompactDecimalFormat(locale, style);
+ }
+
+ /**
+ * Create a CompactDecimalFormat appropriate for a locale (Mockup for what would be in NumberFormat). The result may
+ * be affected by the number system in the locale, such as ar-u-nu-latn.
+ *
+ * @param locale the desired locale
+ * @param style the compact style
+ * @internal
+ */
+ public static final CompactDecimalFormat getCompactDecimalInstance(Locale locale, CompactStyle style) {
+ return new CompactDecimalFormat(ULocale.forLocale(locale), style);
+ }
+
+
// ===== Factory stuff =====
/**
* A NumberFormatFactory is used to register new number formats. The factory
@@ -1796,4 +1836,4 @@ public abstract class NumberFormat extends UFormat {
throw new InvalidObjectException("An invalid object.");
}
}
-}
+}
\ No newline at end of file
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/CompactDecimalFormatTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/CompactDecimalFormatTest.java
new file mode 100644
index 00000000000..5f4102a9d42
--- /dev/null
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/CompactDecimalFormatTest.java
@@ -0,0 +1,71 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2012, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.test.format;
+
+import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.text.CompactDecimalFormat;
+import com.ibm.icu.text.NumberFormat;
+import com.ibm.icu.text.NumberFormat.CompactStyle;
+import com.ibm.icu.util.ULocale;
+
+public class CompactDecimalFormatTest extends TestFmwk {
+
+ public static void main(String[] args) {
+ new CompactDecimalFormatTest().run(args);
+ }
+
+ Object[][] EnglishTestData = {
+ // default is 2 digits of accuracy
+ {1234, "1.2K"},
+ {12345, "12K"},
+ {123456, "120K"},
+ {1234567, "1.2M"},
+ {12345678, "12M"},
+ {123456789, "120M"},
+ {1234567890, "1.2B"},
+ {12345678901f, "12B"},
+ {123456789012f, "120B"},
+ {1234567890123f, "1.2T"},
+ {12345678901234f, "12T"},
+ {123456789012345f, "120T"},
+ };
+
+ Object[][] JapaneseTestData = {
+ {1234, "1200"},
+ {12345, "1.2万"},
+ {123456, "12万"},
+ {1234567, "120万"},
+ {12345678, "1200万"},
+ {123456789, "1.2億"},
+ {1234567890, "12億"},
+ {12345678901f, "120億"},
+ {123456789012f, "1200億"},
+ {1234567890123f, "1.2兆"},
+ {12345678901234f, "12兆"},
+ {123456789012345f, "120兆"},
+ };
+
+ public void TestEnglish() {
+ checkLocale(ULocale.ENGLISH, EnglishTestData);
+ }
+
+ public void TestJapanese() {
+ checkLocale(ULocale.JAPANESE, JapaneseTestData);
+ }
+
+ public void TestJapaneseGermany() {
+ // check fallback.
+ checkLocale(ULocale.forLanguageTag("ja-DE"), JapaneseTestData);
+ }
+
+ public void checkLocale(ULocale locale, Object[][] testData) {
+ CompactDecimalFormat cdf = NumberFormat.getCompactDecimalInstance(locale, CompactStyle.SHORT);
+ for (Object[] row : testData) {
+ assertEquals(locale + " (" + locale.getDisplayName(locale) + ")", row[1], cdf.format((Number) row[0]));
+ }
+ }
+}
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/Relation.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/Relation.java
index 8f88327e515..05cdb347675 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/Relation.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/Relation.java
@@ -1,6 +1,6 @@
/*
**********************************************************************
- * Copyright (c) 2002-2011, International Business Machines
+ * Copyright (c) 2002-2012, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Mark Davis
@@ -199,9 +199,12 @@ public class Relation implements Freezable { // TODO: add , Map values() {
- Set result = newSet();
- for (K key : data.keySet()) {
- result.addAll(data.get(key));
+ return values(new LinkedHashSet());
+ }
+
+ public > C values(C result) {
+ for (Entry> keyValue : data.entrySet()) {
+ result.addAll(keyValue.getValue());
}
return result;
}