ICU-20974 Correctly handle extreme values of double.

This commit is contained in:
Shane Carr 2020-02-14 18:24:14 -08:00 committed by Shane F. Carr
parent be3ee4cc63
commit 0b7f6b1864
4 changed files with 56 additions and 5 deletions

View 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.

View 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() {

View 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.

View 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