ICU-21675 Allow NaN and Infinity to appear in DecNum strings

See #1871
This commit is contained in:
Shane F. Carr 2021-09-21 20:09:45 +00:00
parent f39cf84d62
commit 469456604a
8 changed files with 38 additions and 10 deletions

View file

@ -539,7 +539,11 @@ void DecimalQuantity::_setToDecNum(const DecNum& decnum, UErrorCode& status) {
if (decnum.isNegative()) {
flags |= NEGATIVE_FLAG;
}
if (!decnum.isZero()) {
if (decnum.isNaN()) {
flags |= NAN_FLAG;
} else if (decnum.isInfinity()) {
flags |= INFINITY_FLAG;
} else if (!decnum.isZero()) {
readDecNumberToBcd(decnum);
compact();
}

View file

@ -56,6 +56,13 @@ class U_I18N_API DecNum : public UMemory {
bool isZero() const;
/** Is infinity or NaN */
bool isSpecial() const;
bool isInfinity() const;
bool isNaN() const;
void toString(ByteSink& output, UErrorCode& status) const;
inline CharString toCharString(UErrorCode& status) const {

View file

@ -13,6 +13,7 @@
#include "double-conversion.h"
#include "number_roundingutils.h"
#include "number_skeletons.h"
#include "number_decnum.h"
#include "putilimp.h"
#include "string_segment.h"
@ -35,8 +36,10 @@ void number::impl::parseIncrementOption(const StringSegment &segment,
// Utilize DecimalQuantity/decNumber to parse this for us.
DecimalQuantity dq;
UErrorCode localStatus = U_ZERO_ERROR;
dq.setToDecNumber({buffer.data(), buffer.length()}, localStatus);
if (U_FAILURE(localStatus)) {
DecNum decnum;
decnum.setTo({buffer.data(), buffer.length()}, localStatus);
dq.setToDecNum(decnum, localStatus);
if (U_FAILURE(localStatus) || decnum.isSpecial()) {
// throw new SkeletonSyntaxException("Invalid rounding increment", segment, e);
status = U_NUMBER_SKELETON_SYNTAX_ERROR;
return;

View file

@ -1493,7 +1493,7 @@ void blueprint_helpers::parseScaleOption(const StringSegment& segment, MacroProp
LocalPointer<DecNum> decnum(new DecNum(), status);
if (U_FAILURE(status)) { return; }
decnum->setTo({buffer.data(), buffer.length()}, status);
if (U_FAILURE(status)) {
if (U_FAILURE(status) || decnum->isSpecial()) {
// This is a skeleton syntax error; don't let the low-level decnum error bubble up
status = U_NUMBER_SKELETON_SYNTAX_ERROR;
return;

View file

@ -180,12 +180,6 @@ void DecNum::_setTo(const char* str, int32_t maxDigits, UErrorCode& status) {
status = U_UNSUPPORTED_ERROR;
return;
}
// For consistency with Java BigDecimal, no support for DecNum that is NaN or Infinity!
if (decNumberIsSpecial(fData.getAlias())) {
status = U_UNSUPPORTED_ERROR;
return;
}
}
void
@ -252,6 +246,18 @@ bool DecNum::isZero() const {
return decNumberIsZero(fData.getAlias());
}
bool DecNum::isSpecial() const {
return decNumberIsSpecial(fData.getAlias());
}
bool DecNum::isInfinity() const {
return decNumberIsInfinite(fData.getAlias());
}
bool DecNum::isNaN() const {
return decNumberIsNaN(fData.getAlias());
}
void DecNum::toString(ByteSink& output, UErrorCode& status) const {
if (U_FAILURE(status)) {
return;

View file

@ -677,6 +677,8 @@ void NumberRangeFormatterTest::testNaNInfinity() {
auto result4 = lnf.formatFormattableRange(uprv_getNaN(), 0, status);
auto result5 = lnf.formatFormattableRange(0, uprv_getNaN(), status);
auto result6 = lnf.formatFormattableRange(uprv_getNaN(), uprv_getNaN(), status);
auto result7 = lnf.formatFormattableRange({"1000", status}, {"Infinity", status}, status);
auto result8 = lnf.formatFormattableRange({"-Infinity", status}, {"NaN", status}, status);
assertEquals("0 - inf", u"-∞ 0", result1.toTempString(status));
assertEquals("-inf - 0", u"0", result2.toTempString(status));
@ -684,6 +686,8 @@ void NumberRangeFormatterTest::testNaNInfinity() {
assertEquals("NaN - 0", u"NaN0", result4.toTempString(status));
assertEquals("0 - NaN", u"0NaN", result5.toTempString(status));
assertEquals("NaN - NaN", u"~NaN", result6.toTempString(status));
assertEquals("1000 - inf", u"1,000", result7.toTempString(status));
assertEquals("-inf - NaN", u"-∞ NaN", result8.toTempString(status));
}
void NumberRangeFormatterTest::testPlurals() {

View file

@ -184,9 +184,11 @@ void NumberSkeletonTest::invalidTokens() {
u"scientific/ee",
u"precision-increment/xxx",
u"precision-increment/NaN",
u"precision-increment/Infinity",
u"precision-increment/0.1.2",
u"scale/xxx",
u"scale/NaN",
u"scale/Infinity",
u"scale/0.1.2",
u"scale/français", // non-invariant characters for C++
u"currency/dummy",

View file

@ -167,9 +167,11 @@ public class NumberSkeletonTest {
"scientific/ee",
"precision-increment/xxx",
"precision-increment/NaN",
"precision-increment/Infinity",
"precision-increment/0.1.2",
"scale/xxx",
"scale/NaN",
"scale/Infinity",
"scale/0.1.2",
"scale/français", // non-invariant characters for C++
"currency/dummy",