ICU-13634 Formatting section of data-driven test file is passing.

X-SVN-Rev: 41120
This commit is contained in:
Shane Carr 2018-03-17 07:23:08 +00:00
parent 4fad01c342
commit 2edb4ec82a
14 changed files with 101 additions and 55 deletions

View file

@ -287,7 +287,7 @@ void DecimalFormat::setGroupingUsed(UBool enabled) {
if (enabled) {
// Set to a reasonable default value
fProperties->groupingSize = 3;
fProperties->secondaryGroupingSize = 3;
fProperties->secondaryGroupingSize = -1;
} else {
fProperties->groupingSize = 0;
fProperties->secondaryGroupingSize = 0;

View file

@ -161,7 +161,7 @@ uint64_t DecimalQuantity::getPositionFingerprint() const {
}
void DecimalQuantity::roundToIncrement(double roundingIncrement, RoundingMode roundingMode,
int32_t minMaxFrac, UErrorCode& status) {
int32_t maxFrac, UErrorCode& status) {
// TODO: This is innefficient. Improve?
// TODO: Should we convert to decNumber instead?
double temp = toDouble();
@ -173,7 +173,8 @@ void DecimalQuantity::roundToIncrement(double roundingIncrement, RoundingMode ro
setToDouble(temp);
// Since we reset the value to a double, we need to specify the rounding boundary
// in order to get the DecimalQuantity out of approximation mode.
roundToMagnitude(-minMaxFrac, roundingMode, status);
// NOTE: In Java, we have minMaxFrac, but in C++, the two are differentiated.
roundToMagnitude(-maxFrac, roundingMode, status);
}
void DecimalQuantity::multiplyBy(int32_t multiplicand) {
@ -454,6 +455,7 @@ int64_t DecimalQuantity::toLong() const {
for (int32_t magnitude = scale + precision - 1; magnitude >= 0; magnitude--) {
result = result * 10 + getDigitPos(magnitude - scale);
}
if (isNegative()) { result = -result; }
return result;
}
@ -485,15 +487,15 @@ bool DecimalQuantity::fitsInLong() const {
// The largest int64 is: 9,223,372,036,854,775,807
for (int p = 0; p < precision; p++) {
int8_t digit = getDigit(18 - p);
static int8_t INT64_BCD[] = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 7 };
static int8_t INT64_BCD[] = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 };
if (digit < INT64_BCD[p]) {
return true;
} else if (digit > INT64_BCD[p]) {
return false;
}
}
// Exactly equal to max long.
return true;
// Exactly equal to max long plus one.
return isNegative();
}
double DecimalQuantity::toDouble() const {
@ -725,8 +727,8 @@ UnicodeString DecimalQuantity::toPlainString() const {
sb.append(u'-');
}
for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
if (m == -1) { sb.append(u'.'); }
sb.append(getDigit(m) + u'0');
if (m == 0) { sb.append(u'.'); }
}
return sb;
}
@ -1046,12 +1048,13 @@ UnicodeString DecimalQuantity::toString() const {
snprintf(
buffer8,
sizeof(buffer8),
"<DecimalQuantity %d:%d:%d:%d %s %s%s%d>",
"<DecimalQuantity %d:%d:%d:%d %s %s%s%s%d>",
(lOptPos > 999 ? 999 : lOptPos),
lReqPos,
rReqPos,
(rOptPos < -999 ? -999 : rOptPos),
(usingBytes ? "bytes" : "long"),
(isNegative() ? "-" : ""),
(precision == 0 ? "0" : digits.getAlias()),
"E",
scale);

View file

@ -71,7 +71,7 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory {
* @param mathContext The {@link RoundingMode} to use if rounding is necessary.
*/
void roundToIncrement(double roundingIncrement, RoundingMode roundingMode,
int32_t minMaxFrac, UErrorCode& status);
int32_t maxFrac, UErrorCode& status);
/**
* Rounds the number to a specified magnitude (power of ten).
@ -130,7 +130,6 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory {
/**
* Returns whether or not a Long can fully represent the value stored in this DecimalQuantity.
* Assumes that the DecimalQuantity is positive.
*/
bool fitsInLong() const;

View file

@ -14,6 +14,7 @@
#include "number_patternstring.h"
#include "unicode/utf16.h"
#include "number_utils.h"
#include "number_roundingutils.h"
using namespace icu;
using namespace icu::number;
@ -706,11 +707,11 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP
}
} else if (roundingInterval != 0.0) {
// Rounding Interval.
digitsStringScale = minFrac;
digitsStringScale = -roundingutils::doubleFractionLength(roundingInterval);
// TODO: Check for DoS here?
DecimalQuantity incrementQuantity;
incrementQuantity.setToDouble(roundingInterval);
incrementQuantity.adjustMagnitude(minFrac);
incrementQuantity.adjustMagnitude(-digitsStringScale);
incrementQuantity.roundToMagnitude(0, kDefaultMode, status);
UnicodeString str = incrementQuantity.toPlainString();
if (str.charAt(0) == u'-') {
@ -809,7 +810,7 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP
sb.append(AffixUtils::escape(UnicodeStringCharSequence(np)));
// Copy the positive digit format into the negative.
// This is optional; the pattern is the same as if '#' were appended here instead.
sb.append(sb, afterPrefixPos, beforeSuffixPos);
sb.append(sb, afterPrefixPos, beforeSuffixPos - afterPrefixPos);
if (!nsp.isBogus()) {
sb.append(nsp);
}

View file

@ -9,11 +9,16 @@
#include "unicode/numberformatter.h"
#include "number_types.h"
#include "number_decimalquantity.h"
#include "double-conversion.h"
#include "number_roundingutils.h"
using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;
using double_conversion::DoubleToStringConverter;
namespace {
int32_t getRoundingMagnitudeFraction(int maxFrac) {
@ -46,6 +51,26 @@ int32_t getDisplayMagnitudeSignificant(const DecimalQuantity &value, int minSig)
}
digits_t roundingutils::doubleFractionLength(double input) {
char buffer[DoubleToStringConverter::kBase10MaximalLength + 1];
bool sign; // unused; always positive
int32_t length;
int32_t point;
DoubleToStringConverter::DoubleToAscii(
input,
DoubleToStringConverter::DtoaMode::SHORTEST,
0,
buffer,
sizeof(buffer),
&sign,
&length,
&point
);
return static_cast<digits_t>(length - point);
}
Rounder Rounder::unlimited() {
return Rounder(RND_NONE, {}, kDefaultMode);
}
@ -225,6 +250,8 @@ IncrementRounder Rounder::constructIncrement(double increment, int32_t minFrac)
IncrementSettings settings;
settings.fIncrement = increment;
settings.fMinFrac = static_cast<digits_t>(minFrac);
// One of the few pre-computed quantities:
settings.fMaxFrac = roundingutils::doubleFractionLength(increment);
RounderUnion union_;
union_.increment = settings;
return {RND_INCREMENT, union_, kDefaultMode};
@ -335,8 +362,11 @@ void Rounder::apply(impl::DecimalQuantity &value, UErrorCode& status) const {
case RND_INCREMENT:
value.roundToIncrement(
fUnion.increment.fIncrement, fRoundingMode, fUnion.increment.fMinFrac, status);
value.setFractionLength(fUnion.increment.fMinFrac, fUnion.increment.fMinFrac);
fUnion.increment.fIncrement,
fRoundingMode,
fUnion.increment.fMaxFrac,
status);
value.setFractionLength(fUnion.increment.fMinFrac, INT32_MAX);
break;
case RND_CURRENCY:

View file

@ -131,6 +131,12 @@ inline bool roundsAtMidpoint(int roundingMode) {
}
}
/**
* Computes the number of fraction digits in a double. Used for computing maxFrac for an increment.
* Calls into the DoubleToStringConverter library to do so.
*/
digits_t doubleFractionLength(double input);
} // namespace roundingutils
} // namespace impl
} // namespace number

View file

@ -116,6 +116,9 @@ void ScientificHandler::processQuantity(DecimalQuantity &quantity, MicroProps &m
ScientificModifier &mod = micros.helpers.scientificModifier;
mod.set(exponent, this);
micros.modInner = &mod;
// We already performed rounding. Do not perform it again.
micros.rounding = Rounder::constructPassThrough();
}
int32_t ScientificHandler::getMultiplier(int32_t magnitude) const {

View file

@ -70,7 +70,7 @@ double ParsedNumber::getDouble() const {
return l;
}
// TODO: MIN_LONG
// TODO: MIN_LONG. It is supported in quantity.toLong() if quantity had the negative flag.
double d = quantity.toDouble();
if (0 != (flags & FLAG_NEGATIVE)) {
d *= -1;

View file

@ -50,6 +50,7 @@ void PatternStringTest::testToPatternSimple() {
{u"0.##", u"0.##"},
{u"0.00", u"0.00"},
{u"0.00#", u"0.00#"},
{u"0.05", u"0.05"},
{u"#E0", u"#E0"},
{u"0E0", u"0E0"},
{u"#00E00", u"#00E00"},
@ -57,6 +58,7 @@ void PatternStringTest::testToPatternSimple() {
{u"#;#", u"0;0"},
// ignore a negative prefix pattern of '-' since that is the default:
{u"#;-#", u"0"},
{u"pp#,000;(#)", u"pp#,000;(#,000)"},
{u"**##0", u"**##0"},
{u"*'x'##0", u"*x##0"},
{u"a''b0", u"a''b0"},

View file

@ -318,8 +318,8 @@ minIntegerDigits maxIntegerDigits minFractionDigits maxFractionDigits output bre
1 1 0 0 3E8
// JDK gives E0 instead of allowing for unlimited precision
0 0 0 0 2.99792458E8 K
// JDK gives .299792E9; Q gives 2.99792E8
0 1 0 5 2.9979E8 KQ
// J gives 2.9979E8
0 1 0 5 2.99792E8 J
// JDK gives 300E6
0 3 0 0 299.792458E6 K
// JDK gives 299.8E6 (maybe maxInt + maxFrac instead of minInt + maxFrac)?
@ -335,8 +335,8 @@ minIntegerDigits maxIntegerDigits minFractionDigits maxFractionDigits output bre
0 0 1 5 .29979E9
// JDK gives E0
0 0 1 0 2.99792458E8 K
// JDK and Q give .2998E9
0 0 0 4 2.998E8 KQ
// J gives 2.998E8
0 0 0 4 .29979E9 J
// According to the spec, if maxInt>minInt and minInt>1, then set
// Context: #13289
2 8 1 6 2.9979246E8 K
@ -382,12 +382,12 @@ begin
format maxIntegerDigits output breaks
123 1 3
0 0 0
// Q ignores max integer if it is less than zero and prints "123"
123 -2147483648 0 Q
// C and Q ignore max integer if it is less than zero and prints "123"
123 -2147483648 0 CQ
12345 1 5
12345 -2147483648 0 Q
12345 -2147483648 0 CQ
5.3 1 5.3
5.3 -2147483648 .3 Q
5.3 -2147483648 .3 CQ
test patterns with zero
set locale en
@ -550,12 +550,12 @@ currency currencyUsage toPattern breaks
// These work in J, but it prepends an extra hash sign to the pattern.
// C does not print the currency rounding information in the pattern.
// K does not support this feature.
USD standard 0.00 CJK
CHF standard 0.00 CJK
CZK standard 0.00 CJK
USD cash 0.00 CJK
CHF cash 0.05 CJK
CZK cash 0 CJK
USD standard 0.00 JK
CHF standard 0.00 JK
CZK standard 0.00 JK
USD cash 0.00 JK
CHF cash 0.05 JK
CZK cash 0 JK
test currency rounding
set locale en
@ -637,8 +637,8 @@ begin
format output breaks
Inf [\u221e]
-Inf (\u221e) K
// Q prints the affixes
NaN NaN KQ
// J does not print the affixes
NaN [NaN] J
test nan and infinity with multiplication
set locale en
@ -652,18 +652,18 @@ NaN NaN K
test nan and infinity with padding
set locale en_US
set pattern $$$0.00$
set formatWidth 7
set formatWidth 8
begin
format padPosition output breaks
Inf beforePrefix $$$\u221e$ K
Inf afterPrefix $$$ \u221e$ K
Inf beforeSuffix $$$\u221e $ K
Inf afterSuffix $$$\u221e$ K
// Q gets $$$NaN$
NaN beforePrefix NaN KQ
NaN afterPrefix NaN KQ
NaN beforeSuffix NaN KQ
NaN afterSuffix NaN KQ
Inf beforePrefix $$$\u221e$ K
Inf afterPrefix $$$ \u221e$ K
Inf beforeSuffix $$$\u221e $ K
Inf afterSuffix $$$\u221e$ K
// J does not print the affixes
NaN beforePrefix $$$NaN$ J
NaN afterPrefix $$$ NaN$ J
NaN beforeSuffix $$$NaN $ J
NaN afterSuffix $$$NaN$ J
test apply formerly localized patterns
begin
@ -689,25 +689,25 @@ test toPattern
set locale en
begin
pattern toPattern breaks
// All of the "S" failures in this section are because of functionally equivalent patterns
// All of the C and S failures in this section are because of functionally equivalent patterns
// JDK doesn't support any patterns with padding or both negative prefix and suffix
// Breaks ICU4J See ticket 11671
**0,000 **0,000 JK
**##0,000 **##0,000 K
**###0,000 **###0,000 K
**####0,000 **#,##0,000 KS
**####0,000 **#,##0,000 CKS
###,000. #,000.
0,000 #0,000 S
0,000 #0,000 CS
.00 #.00
000 #000 S
000,000 #,000,000 S
000 #000 CS
000,000 #,000,000 CS
pp#,000 pp#,000
00.## #00.## S
00.## #00.## CS
#,#00.025 #,#00.025
// No secondary grouping in JDK
#,##,###.02500 #,##,###.02500 K
pp#,000;(#) pp#,000;(#,000) K
**####,##,##0.0##;(#) **#,##,##,##0.0##;**(##,##,##0.0##) KS
**####,##,##0.0##;(#) **#,##,##,##0.0##;**(##,##,##0.0##) CKS
// No significant digits in JDK
@@### @@### K
@,@#,### @,@#,### K

View file

@ -585,11 +585,10 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
return result;
}
static final byte[] INT64_BCD = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 7 };
static final byte[] INT64_BCD = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 };
/**
* Returns whether or not a Long can fully represent the value stored in this DecimalQuantity.
* Assumes that the DecimalQuantity is positive.
*/
public boolean fitsInLong() {
if (isZero()) {
@ -615,8 +614,8 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
return false;
}
}
// Exactly equal to max long.
return true;
// Exactly equal to max long plus one.
return isNegative();
}
/**

View file

@ -415,12 +415,13 @@ public final class DecimalQuantity_DualStorageBCD extends DecimalQuantity_Abstra
@Override
public String toString() {
return String.format("<DecimalQuantity %s:%d:%d:%s %s %s>",
return String.format("<DecimalQuantity %s:%d:%d:%s %s %s%s>",
(lOptPos > 1000 ? "999" : String.valueOf(lOptPos)),
lReqPos,
rReqPos,
(rOptPos < -1000 ? "-999" : String.valueOf(rOptPos)),
(usingBytes ? "bytes" : "long"),
(isNegative() ? "-" : ""),
toNumberString());
}

View file

@ -1869,7 +1869,7 @@ public class DecimalFormat extends NumberFormat {
if (enabled) {
// Set to a reasonable default value
properties.setGroupingSize(3);
properties.setSecondaryGroupingSize(3);
properties.setSecondaryGroupingSize(-1);
} else {
properties.setGroupingSize(0);
properties.setSecondaryGroupingSize(0);

View file

@ -42,12 +42,14 @@ public class PatternStringTest {
{ "0.##", "0.##" },
{ "0.00", "0.00" },
{ "0.00#", "0.00#" },
{ "0.05", "0.05" },
{ "#E0", "#E0" },
{ "0E0", "0E0" },
{ "#00E00", "#00E00" },
{ "#,##0", "#,##0" },
{ "#;#", "0;0" },
{ "#;-#", "0" }, // ignore a negative prefix pattern of '-' since that is the default
{ "pp#,000;(#)", "pp#,000;(#,000)" },
{ "**##0", "**##0" },
{ "*'x'##0", "*x##0" },
{ "a''b0", "a''b0" },