ICU-9889 Implement scaling for decimalFormat

X-SVN-Rev: 33138
This commit is contained in:
John Emmons 2013-02-07 19:48:29 +00:00
parent feddf0fa6b
commit 96f4a704b2
5 changed files with 130 additions and 12 deletions

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2012, International Business Machines Corporation and *
* Copyright (C) 1997-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@ -341,6 +341,7 @@ DecimalFormat::init(UErrorCode &status) {
fNegSuffixPattern = 0;
fCurrencyChoice = 0;
fMultiplier = NULL;
fScale = 0;
fGroupingSize = 0;
fGroupingSize2 = 0;
fDecimalSeparatorAlwaysShown = FALSE;
@ -1057,6 +1058,8 @@ void DecimalFormat::handleChanged() {
debug("No format fastpath: fMinSignificantDigits!=1");
} else if(fMultiplier!=NULL) {
debug("No format fastpath: fMultiplier!=NULL");
} else if(fScale!=0) {
debug("No format fastpath: fScale!=0");
} else if(0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)) {
debug("No format fastpath: 0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)");
} else if(fDecimalSeparatorAlwaysShown) {
@ -1368,6 +1371,26 @@ DecimalFormat::_round(const DigitList &number, DigitList &adjustedNum, UBool& is
}
}
if (fScale != 0) {
DigitList ten;
ten.set(10);
if (fScale > 0) {
for (int32_t i = fScale ; i > 0 ; i--) {
adjustedNum.mult(ten, status);
if (U_FAILURE(status)) {
return adjustedNum;
}
}
} else {
for (int32_t i = fScale ; i < 0 ; i++) {
adjustedNum.div(ten, status);
if (U_FAILURE(status)) {
return adjustedNum;
}
}
}
}
/*
* Note: sign is important for zero as well as non-zero numbers.
* Proper detection of -0.0 is needed to deal with the
@ -1997,6 +2020,22 @@ void DecimalFormat::parse(const UnicodeString& text,
digits->div(*fMultiplier, ec);
}
if (fScale != 0) {
DigitList ten;
ten.set(10);
if (fScale > 0) {
for (int32_t i = fScale; i > 0; i--) {
UErrorCode ec = U_ZERO_ERROR;
digits->div(ten,ec);
}
} else {
for (int32_t i = fScale; i < 0; i++) {
UErrorCode ec = U_ZERO_ERROR;
digits->mult(ten,ec);
}
}
}
// Negative zero special case:
// if parsing integerOnly, change to +0, which goes into an int32 in a Formattable.
// if not parsing integerOnly, leave as -0, which a double can represent.
@ -5505,6 +5544,10 @@ DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr,
}
break;
case UNUM_SCALE:
fScale = newValue;
break;
default:
status = U_UNSUPPORTED_ERROR;
break;
@ -5580,6 +5623,9 @@ int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr,
case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
return fBoolFlags.get(attr);
case UNUM_SCALE:
return fScale;
default:
status = U_UNSUPPORTED_ERROR;
break;

View File

@ -1,6 +1,6 @@
/*
********************************************************************************
* Copyright (C) 1997-2012, International Business Machines
* Copyright (C) 1997-2013, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************************
*
@ -17,7 +17,8 @@
* 07/10/97 helena Made ParsePosition a class and get rid of the function
* hiding problems.
* 09/09/97 aliu Ported over support for exponential formats.
* 07/20/98 stephen Changed documentation
* 07/20/98 stephen Changed documentation
* 01/30/13 emmons Added Scaling methods
********************************************************************************
*/
@ -2234,6 +2235,7 @@ private:
ChoiceFormat* fCurrencyChoice;
DigitList * fMultiplier; // NULL for multiplier of one
int32_t fScale;
int32_t fGroupingSize;
int32_t fGroupingSize2;
UBool fDecimalSeparatorAlwaysShown;

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2012, International Business Machines Corporation and others.
* Copyright (C) 1997-2013, International Business Machines Corporation and others.
* All Rights Reserved.
* Modification History:
*
@ -795,7 +795,16 @@ typedef enum UNumberFormatAttribute {
*/
UNUM_PARSE_ALL_INPUT,
#endif
/**
* Scale, which adjusts the position of the
* decimal point when formatting. Amounts will be multiplied by 10 ^ (scale)
* before they are formatted. The default value for the scale is 0 ( no adjustment ).
*
* <p>Example: setting the scale to 3, 123 formats as "123,000"
* <p>Example: setting the scale to -4, 123 formats as "0.0123"
*
* @draft ICU 51 */
UNUM_SCALE,
/** Count of "regular" numeric attributes.
* @internal */
UNUM_NUMERIC_ATTRIBUTE_COUNT,
@ -831,7 +840,8 @@ typedef enum UNumberFormatAttribute {
* @param attr The attribute to query; one of UNUM_PARSE_INT_ONLY, UNUM_GROUPING_USED,
* UNUM_DECIMAL_ALWAYS_SHOWN, UNUM_MAX_INTEGER_DIGITS, UNUM_MIN_INTEGER_DIGITS, UNUM_INTEGER_DIGITS,
* UNUM_MAX_FRACTION_DIGITS, UNUM_MIN_FRACTION_DIGITS, UNUM_FRACTION_DIGITS, UNUM_MULTIPLIER,
* UNUM_GROUPING_SIZE, UNUM_ROUNDING_MODE, UNUM_FORMAT_WIDTH, UNUM_PADDING_POSITION, UNUM_SECONDARY_GROUPING_SIZE.
* UNUM_GROUPING_SIZE, UNUM_ROUNDING_MODE, UNUM_FORMAT_WIDTH, UNUM_PADDING_POSITION, UNUM_SECONDARY_GROUPING_SIZE,
* UNUM_SCALE.
* @return The value of attr.
* @see unum_setAttribute
* @see unum_getDoubleAttribute
@ -854,7 +864,7 @@ unum_getAttribute(const UNumberFormat* fmt,
* UNUM_DECIMAL_ALWAYS_SHOWN, UNUM_MAX_INTEGER_DIGITS, UNUM_MIN_INTEGER_DIGITS, UNUM_INTEGER_DIGITS,
* UNUM_MAX_FRACTION_DIGITS, UNUM_MIN_FRACTION_DIGITS, UNUM_FRACTION_DIGITS, UNUM_MULTIPLIER,
* UNUM_GROUPING_SIZE, UNUM_ROUNDING_MODE, UNUM_FORMAT_WIDTH, UNUM_PADDING_POSITION, UNUM_SECONDARY_GROUPING_SIZE,
* or UNUM_LENIENT_PARSE.
* UNUM_LENIENT_PARSE, or UNUM_SCALE.
* @param newValue The new value of attr.
* @see unum_getAttribute
* @see unum_getDoubleAttribute

View File

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2010, International Business Machines Corporation and
* Copyright (c) 1997-2013, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@ -54,6 +54,12 @@ void IntlTestDecimalFormatAPI::runIndexedTest( int32_t index, UBool exec, const
TestCurrencyPluralInfo();
}
break;
case 4: name = "TestScale";
if(exec) {
logln((UnicodeString)"Scale test---");
TestScale();
}
break;
default: name = ""; break;
}
}
@ -448,14 +454,14 @@ void IntlTestDecimalFormatAPI::testRounding(/*char *par*/)
//for +2.55 with RoundingIncrement=1.0
pat.setRoundingIncrement(1.0);
pat.format(Roundingnumber, resultStr);
message= (UnicodeString)"round(" + (double)Roundingnumber + UnicodeString(",") + mode + UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
message= (UnicodeString)"Round() failed: round(" + (double)Roundingnumber + UnicodeString(",") + mode + UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
verify(message, resultStr, result[i++]);
message.remove();
resultStr.remove();
//for -2.55 with RoundingIncrement=1.0
pat.format(Roundingnumber1, resultStr);
message= (UnicodeString)"round(" + (double)Roundingnumber1 + UnicodeString(",") + mode + UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
message= (UnicodeString)"Round() failed: round(" + (double)Roundingnumber1 + UnicodeString(",") + mode + UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
verify(message, resultStr, result[i++]);
message.remove();
resultStr.remove();
@ -467,7 +473,14 @@ void IntlTestDecimalFormatAPI::verify(const UnicodeString& message, const Unicod
UnicodeString expectedStr("");
expectedStr=expectedStr + expected;
if(got != expectedStr ) {
errln((UnicodeString)"ERROR: Round() failed: " + message + got + (UnicodeString)" Expected : " + expectedStr);
errln((UnicodeString)"ERROR: " + message + got + (UnicodeString)" Expected : " + expectedStr);
}
}
void IntlTestDecimalFormatAPI::verifyString(const UnicodeString& message, const UnicodeString& got, UnicodeString& expected){
logln((UnicodeString)message + got + (UnicodeString)" Expected : " + expected);
if(got != expected ) {
errln((UnicodeString)"ERROR: " + message + got + (UnicodeString)" Expected : " + expected);
}
}
@ -501,4 +514,49 @@ void IntlTestDecimalFormatAPI::testRoundingInc(/*char *par*/)
}
}
void IntlTestDecimalFormatAPI::TestScale()
{
typedef struct TestData {
double inputValue;
int inputScale;
char *expectedOutput;
} TestData;
static TestData testData[] = {
{ 100.0, 3, "100,000" },
{ 10034.0, -2, "100.34" },
{ 0.86, -3, "0.0009" },
{ -0.000455, 1, "-0%" },
{ -0.000555, 1, "-1%" },
{ 0.000455, 1, "0%" },
{ 0.000555, 1, "1%" },
};
UErrorCode status = U_ZERO_ERROR;
DecimalFormat pat(status);
if(U_FAILURE(status)) {
errcheckln(status, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status));
return;
}
UnicodeString message;
UnicodeString resultStr;
UnicodeString exp;
UnicodeString percentPattern("#,##0%");
pat.setMaximumFractionDigits(4);
for(int32_t i=0;i < sizeof(testData)/sizeof(testData[0]);i++) {
if ( i > 2 ) {
pat.applyPattern(percentPattern,status);
}
pat.setAttribute(UNUM_SCALE,testData[i].inputScale,status);
pat.format(testData[i].inputValue, resultStr);
message = UnicodeString("Unexpected output for ") + testData[i].inputValue + UnicodeString(" and scale ") + testData[i].inputScale + UnicodeString(". Got: ");
exp = testData[i].expectedOutput;
verifyString(message, resultStr, exp);
message.remove();
resultStr.remove();
exp.remove();
}
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View File

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2009, International Business Machines Corporation and
* Copyright (c) 1997-2013, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@ -27,9 +27,11 @@ public:
void testRounding(/*char *par*/);
void testRoundingInc(/*char *par*/);
void TestCurrencyPluralInfo();
void TestScale();
private:
/*Helper functions */
void verify(const UnicodeString& message, const UnicodeString& got, double expected);
void verifyString(const UnicodeString& message, const UnicodeString& got, UnicodeString& expected);
};
#endif /* #if !UCONFIG_NO_FORMATTING */