]> granicus.if.org Git - icu/commitdiff
ICU-20974 Correctly handle extreme values of double.
authorShane Carr <shane@unicode.org>
Sat, 15 Feb 2020 02:24:14 +0000 (18:24 -0800)
committerShane F. Carr <shane@unicode.org>
Thu, 5 Mar 2020 21:40:59 +0000 (13:40 -0800)
icu4c/source/i18n/number_decimalquantity.cpp
icu4c/source/test/intltest/numbertest_api.cpp
icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java

index 2c584a40f257802993dc3bdc521479a4126f0547..482e93dc7a1a360dcfc2663bf6e7da888ea183d6 100644 (file)
@@ -439,9 +439,6 @@ void DecimalQuantity::_setToDoubleFast(double n) {
     // TODO: Make a fast path for other types of doubles.
     if (!std::numeric_limits<double>::is_iec559) {
         convertToAccurateDouble();
-        // Turn off the approximate double flag, since the value is now exact.
-        isApproximate = false;
-        origDouble = 0.0;
         return;
     }
 
@@ -456,8 +453,14 @@ void DecimalQuantity::_setToDoubleFast(double n) {
         return;
     }
 
+    if (exponent == -1023 || exponent == 1024) {
+        // The extreme values of exponent are special; use slow path.
+        convertToAccurateDouble();
+        return;
+    }
+
     // 3.3219... is log2(10)
-    auto fracLength = static_cast<int32_t> ((52 - exponent) / 3.32192809489);
+    auto fracLength = static_cast<int32_t> ((52 - exponent) / 3.32192809488736234787031942948939017586);
     if (fracLength >= 0) {
         int32_t i = fracLength;
         // 1e22 is the largest exact double.
index 98c8ceb46e0547cdfd815f59abe99ac3b9d5cbc4..01494ff8ab99ff382b137307c9dbf7e16c3f3864 100644 (file)
@@ -1391,6 +1391,30 @@ void NumberFormatterApiTest::roundingOther() {
             u"1",
             u"1",
             u"0");
+
+    assertFormatSingle(
+            u"ICU-20974 Double.MIN_NORMAL",
+            u"scientific",
+            u"E0",
+            NumberFormatter::with().notation(Notation::scientific()),
+            Locale::getEnglish(),
+            DBL_MIN,
+            u"2.225074E-308");
+
+#ifndef DBL_TRUE_MIN
+#define DBL_TRUE_MIN 4.9E-324
+#endif
+
+    // Note: this behavior is intentionally different from Java; see
+    // https://github.com/google/double-conversion/issues/126
+    assertFormatSingle(
+            u"ICU-20974 Double.MIN_VALUE",
+            u"scientific",
+            u"E0",
+            NumberFormatter::with().notation(Notation::scientific()),
+            Locale::getEnglish(),
+            DBL_TRUE_MIN,
+            u"5E-324");
 }
 
 void NumberFormatterApiTest::grouping() {
index 5873bab9e3cc2eb346881a1dc4e4ae1aefbe3abc..b1ead768c7c1549f6d87ffcfd767a7bc2f2c1d2b 100644 (file)
@@ -488,8 +488,14 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
             return;
         }
 
+        if (exponent == -1023 || exponent == 1024) {
+            // The extreme values of exponent are special; use slow path.
+            convertToAccurateDouble();
+            return;
+        }
+
         // 3.3219... is log2(10)
-        int fracLength = (int) ((52 - exponent) / 3.32192809489);
+        int fracLength = (int) ((52 - exponent) / 3.32192809488736234787031942948939017586);
         if (fracLength >= 0) {
             int i = fracLength;
             // 1e22 is the largest exact double.
index 4188068b8474575eeef9b6dcd036ec15460cbac4..2512b1fc7aac5e56a41073baacf90e980468e8cb 100644 (file)
@@ -1350,6 +1350,24 @@ public class NumberFormatterApiTest {
                 "1",
                 "1",
                 "0");
+
+        assertFormatSingle(
+                "ICU-20974 Double.MIN_NORMAL",
+                "scientific",
+                "E0",
+                NumberFormatter.with().notation(Notation.scientific()),
+                ULocale.ENGLISH,
+                Double.MIN_NORMAL,
+                "2.225074E-308");
+
+        assertFormatSingle(
+                "ICU-20974 Double.MIN_VALUE",
+                "scientific",
+                "E0",
+                NumberFormatter.with().notation(Notation.scientific()),
+                ULocale.ENGLISH,
+                Double.MIN_VALUE,
+                "4.9E-324");
     }
 
     @Test