]> granicus.if.org Git - icu/commitdiff
ICU-10374 integrate branch
authorMark Davis <mark@macchiato.com>
Tue, 11 Mar 2014 17:25:36 +0000 (17:25 +0000)
committerMark Davis <mark@macchiato.com>
Tue, 11 Mar 2014 17:25:36 +0000 (17:25 +0000)
X-SVN-Rev: 35403

icu4j/main/classes/core/src/com/ibm/icu/text/PluralRules.java
icu4j/main/classes/core/src/com/ibm/icu/util/LocaleMatcher.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/LocaleMatcherTest.java

index 384ff40e2f576ec9d32c2c0bd00756ebe58c8384..c83c51a92a7164cee50cd1e1b5097c196d2ad7f0 100644 (file)
@@ -547,6 +547,8 @@ public class PluralRules implements Serializable {
             return baseFactor;
         }
 
+        static final long MAX = (long)1E18;
+
         /**
          * @internal
          * @deprecated This API is ICU internal only.
@@ -561,7 +563,9 @@ public class PluralRules implements Serializable {
             source = isNegative ? -n : n;
             visibleDecimalDigitCount = v;
             decimalDigits = f;
-            integerValue = (long)n;
+            integerValue = n > MAX 
+                    ? MAX 
+                            : (long)n;
             hasIntegerValue = source == integerValue;
             // check values. TODO make into unit test.
             //            
@@ -605,6 +609,9 @@ public class PluralRules implements Serializable {
             if (v == 0) {
                 return 0;
             } else {
+                if (n < 0) {
+                    n = -n;
+                }
                 int baseFactor = (int) Math.pow(10, v);
                 long scaled = Math.round(n * baseFactor);
                 return (int) (scaled % baseFactor);
@@ -629,15 +636,49 @@ public class PluralRules implements Serializable {
             this(n,0);
         }
 
+        private static final long MAX_INTEGER_PART = 1000000000;
         /**
+         * Return a guess as to the number of decimals that would be displayed. This is only a guess; callers should
+         * always supply the decimals explicitly if possible. Currently, it is up to 6 decimals (without trailing zeros).
+         * Returns 0 for infinities and nans.
          * @internal
          * @deprecated This API is ICU internal only.
+         * 
          */
         @Deprecated
         public static int decimals(double n) {
             // Ugly...
-            String temp = String.valueOf(n);
-            return temp.endsWith(".0") ? 0 : temp.length() - temp.indexOf('.') - 1;
+            if (Double.isInfinite(n) || Double.isNaN(n)) {
+                return 0;
+            }
+            if (n < 0) {
+                n = -n;
+            }
+            if (n < MAX_INTEGER_PART) {
+                long temp = (long)(n * 1000000) % 1000000; // get 6 decimals
+                for (int mask = 10, digits = 6; digits > 0; mask *= 10, --digits) {
+                    if ((temp % mask) != 0) {
+                        return digits;
+                    }
+                }
+                return 0;
+            } else {
+                String buf = String.format(Locale.ENGLISH, "%1.15e", n);
+                int ePos = buf.lastIndexOf('e');
+                String exponentStr = buf.substring(ePos+1);
+                int exponent = Integer.parseInt(exponentStr);
+                int numFractionDigits = ePos - 2 - exponent;
+                if (numFractionDigits < 0) {
+                    return 0;
+                }
+                for (int i=ePos-1; numFractionDigits > 0; --i) {
+                    if (buf.charAt(i) != '0') {
+                        break;
+                    }
+                    --numFractionDigits; 
+                }
+                return numFractionDigits;
+            }
         }
 
         /**
@@ -796,7 +837,7 @@ public class PluralRules implements Serializable {
         @Deprecated
         @Override
         public double doubleValue() {
-            return source;
+            return isNegative ? -source : source;
         }
 
         /**
@@ -1643,11 +1684,10 @@ public class PluralRules implements Serializable {
         }
 
         public String select(FixedDecimal n) {
+            if (Double.isInfinite(n.source) || Double.isNaN(n.source)) {
+                return KEYWORD_OTHER;
+            }
             Rule r = selectRule(n);
-            // since we have explict 'other', we don't need this.
-            //            if (r == null) {
-            //                return KEYWORD_OTHER;
-            //            }
             return r.getKeyword();
         }
 
index 7eb375bb3cefa8c1e32b5a7bc787725ab2f639b7..ef801e9ef19262a40002ee7007138df7ea294f05 100644 (file)
@@ -46,7 +46,7 @@ import com.ibm.icu.impl.Row.R3;
  */
 public class LocaleMatcher {
     
-    private static boolean DEBUG = false;
+    private static boolean DEBUG = true;
 
     private static final ULocale UNKNOWN_LOCALE = new ULocale("und");
 
@@ -112,7 +112,7 @@ public class LocaleMatcher {
      */
     @Deprecated
     public LocaleMatcher(LocalePriorityList languagePriorityList, LanguageMatcherData matcherData, double threshold) {
-        this.matcherData = matcherData;
+        this.matcherData = matcherData == null ? defaultWritten : matcherData;
         for (final ULocale language : languagePriorityList) {
             add(language, languagePriorityList.getWeight(language));
         }
index 2f3a8f3969ab724a483ff7fbe86fb1e285ffdb14..ea94ad09ca8703b340bda284b48667e09f9b1444 100644 (file)
@@ -58,6 +58,38 @@ public class PluralRulesTest extends TestFmwk {
         new PluralRulesTest().run(args);
     }
 
+    public void testOverUnderflow() {
+        logln(String.valueOf(Long.MAX_VALUE + 1d));
+        for (double[] testDouble : new double[][]{
+                {1E18, 0, 0, 1E18}, // check overflow
+                {10000000000000.1d, 1, 1, 10000000000000d},
+                {-0.00001d, 1, 5, 0},
+                {1d, 0, 0, 1},
+                {1.1d, 1, 1, 1},
+                {12345d, 0, 0, 12345},
+                {12345.678912d, 678912, 6, 12345},
+                {12345.6789123d, 678912, 6, 12345}, // we only go out 6 digits
+                {1E18, 0, 0, 1E18}, // check overflow
+                {1E19, 0, 0, 1E18}, // check overflow
+        }) {
+            FixedDecimal fd = new FixedDecimal(testDouble[0]);
+            assertEquals(testDouble[0] + "=doubleValue()", testDouble[0], fd.doubleValue());
+            assertEquals(testDouble[0] + " decimalDigits", (int)testDouble[1], fd.decimalDigits);
+            assertEquals(testDouble[0] + " visibleDecimalDigitCount", (int)testDouble[2], fd.visibleDecimalDigitCount);
+            assertEquals(testDouble[0] + " decimalDigitsWithoutTrailingZeros", (int)testDouble[1], fd.decimalDigitsWithoutTrailingZeros);
+            assertEquals(testDouble[0] + " visibleDecimalDigitCountWithoutTrailingZeros", (int)testDouble[2], fd.visibleDecimalDigitCountWithoutTrailingZeros);            
+            assertEquals(testDouble[0] + " integerValue", (long)testDouble[3], fd.integerValue);            
+        }
+
+        for (ULocale locale : new ULocale[]{ULocale.ENGLISH, new ULocale("cy"), new ULocale("ar")}) {
+            PluralRules rules = factory.forLocale(locale);
+
+            assertEquals(locale + " NaN", "other", rules.select(Double.NaN));
+            assertEquals(locale + " ∞", "other", rules.select(Double.POSITIVE_INFINITY));
+            assertEquals(locale + " -∞", "other", rules.select(Double.NEGATIVE_INFINITY));
+        }
+    }
+
     public void testSyntaxRestrictions() {
         Object[][] shouldFail = {
                 {"a:n in 3..10,13..19"},
@@ -81,7 +113,7 @@ public class PluralRulesTest extends TestFmwk {
                 {"a: n = 1 .. 3"},
                 {"a: n != 1 .. 3"},
                 {"a: n ! = 1 .. 3"},
-                
+
                 // more complicated
                 {"a:n in 3 .. 10 , 13 .. 19"},
 
@@ -91,7 +123,7 @@ public class PluralRulesTest extends TestFmwk {
                 {"a: n not is 1", ParseException.class}, // hacked to fail
                 {"a: n in 1"},
                 {"a: n not in 1"},
-                
+
                 // multiples also have special exceptions
                 // TODO enable the following once there is an update to CLDR
                 // {"a: n is 1,3", ParseException.class},
@@ -721,7 +753,7 @@ public class PluralRulesTest extends TestFmwk {
                 nf.setMinimumFractionDigits(minFracDigits);
                 String expectedFormat = row[2];
                 String expectedKeyword = row[3];
-                
+
                 UFieldPosition pos = new UFieldPosition();
                 String formatted = nf.format(1.0, new StringBuffer(), pos).toString();
                 int countVisibleFractionDigits = pos.getCountVisibleFractionDigits();
@@ -1019,7 +1051,7 @@ public class PluralRulesTest extends TestFmwk {
         }
         logln("max \tsize:\t" + max);
     }
-    
+
     public static class FixedDecimalHandler implements SerializableTest.Handler
     {
         public Object[] getTestObjects()
index ae4dc8fed9c0403e7fdde5bf577680a4e3de15be..a2d5038b6e95f21b378b479533c5a6768e6b1310 100644 (file)
@@ -27,6 +27,20 @@ public class LocaleMatcherTest extends TestFmwk {
         new LocaleMatcherTest().run(args);
     }
 
+    public void testChinese() {
+        LocaleMatcher matcher = new LocaleMatcher("zh_CN, zh_TW, iw");
+        ULocale taiwanChinese = new ULocale("zh_TW");
+        ULocale chinaChinese = new ULocale("zh_CN");
+//        assertEquals("zh_CN, zh_TW, iw;", taiwanChinese, matcher.getBestMatch("zh_Hant_TW"));
+//        assertEquals("zh_CN, zh_TW, iw;", taiwanChinese, matcher.getBestMatch("zh_Hant"));
+//        assertEquals("zh_CN, zh_TW, iw;", taiwanChinese, matcher.getBestMatch("zh_TW"));
+//        assertEquals("zh_CN, zh_TW, iw;", chinaChinese, matcher.getBestMatch("zh_Hans_CN"));
+//        assertEquals("zh_CN, zh_TW, iw;", chinaChinese, matcher.getBestMatch("zh_CN"));
+//        assertEquals("zh_CN, zh_TW, iw;", chinaChinese, matcher.getBestMatch("zh"));
+        
+        assertEquals("zh_CN, zh_TW, iw;", taiwanChinese, matcher.getBestMatch("zh_Hant_HK")); 
+    }
+
     public void testenGB() {
         final LocaleMatcher matcher = new LocaleMatcher("fr, en, en_GB, es_MX, es_419, es");
         assertEquals("en_GB", matcher.getBestMatch("en_NZ").toString());
@@ -36,10 +50,9 @@ public class LocaleMatcherTest extends TestFmwk {
     }
 
     public void testFallbacks() {
-        final LocaleMatcher matcher = new LocaleMatcher("en, hi");
-        if (!logKnownIssue("10705", "Need new data from CLDR for languageMatching")) {
-            assertEquals("hi", matcher.getBestMatch("sa").toString());
-        }
+        LocalePriorityList lpl = LocalePriorityList.add("en, hi").build();
+        final LocaleMatcher matcher = new LocaleMatcher(lpl, null, 0.09);
+        assertEquals("hi", matcher.getBestMatch("sa").toString());
     }
 
     public void testOverrideData() {