ICU-20974 Correctly handle extreme values of double.
diff --git a/icu4c/source/i18n/number_decimalquantity.cpp b/icu4c/source/i18n/number_decimalquantity.cpp
index 2c584a4..482e93d 100644
--- a/icu4c/source/i18n/number_decimalquantity.cpp
+++ b/icu4c/source/i18n/number_decimalquantity.cpp
@@ -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.
diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp
index 98c8ceb..01494ff 100644
--- a/icu4c/source/test/intltest/numbertest_api.cpp
+++ b/icu4c/source/test/intltest/numbertest_api.cpp
@@ -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() {
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java
index 5873bab..b1ead76 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java
@@ -488,8 +488,14 @@ private void _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)
- 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.
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
index 4188068..2512b1f 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
@@ -1350,6 +1350,24 @@ public void roundingOther() {
"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