mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-08 06:53:45 +00:00
ICU-13634 Formatting section of data-driven test file is passing.
X-SVN-Rev: 41120
This commit is contained in:
parent
4fad01c342
commit
2edb4ec82a
14 changed files with 101 additions and 55 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" },
|
||||
|
|
Loading…
Add table
Reference in a new issue