mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-08 15:05:53 +00:00
ICU-5350 Fix decimal rounding
X-SVN-Rev: 21647
This commit is contained in:
parent
44e1e346ca
commit
5369d809be
5 changed files with 114 additions and 14 deletions
|
@ -416,6 +416,7 @@ DecimalFormat::operator=(const DecimalFormat& rhs)
|
|||
*fRoundingIncrement = *rhs.fRoundingIncrement;
|
||||
}
|
||||
fRoundingDouble = rhs.fRoundingDouble;
|
||||
fRoundingMode = rhs.fRoundingMode;
|
||||
fMultiplier = rhs.fMultiplier;
|
||||
fGroupingSize = rhs.fGroupingSize;
|
||||
fGroupingSize2 = rhs.fGroupingSize2;
|
||||
|
@ -732,6 +733,10 @@ DecimalFormat::format( double number,
|
|||
DigitList digits;
|
||||
|
||||
// This detects negativity too.
|
||||
if (fRoundingIncrement == NULL) {
|
||||
// If we did not round in binary space, round in decimal space
|
||||
digits.fRoundingMode = fRoundingMode;
|
||||
}
|
||||
digits.set(number, precision(FALSE),
|
||||
!fUseExponentialNotation && !areSignificantDigitsUsed());
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) 1997-2005, International Business Machines
|
||||
* Copyright (C) 1997-2007, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
*
|
||||
|
@ -94,6 +94,7 @@ DigitList::operator=(const DigitList& other)
|
|||
fDecimalAt = other.fDecimalAt;
|
||||
fCount = other.fCount;
|
||||
fIsPositive = other.fIsPositive;
|
||||
fRoundingMode = other.fRoundingMode;
|
||||
uprv_strncpy(fDigits, other.fDigits, fCount);
|
||||
}
|
||||
return *this;
|
||||
|
@ -108,6 +109,7 @@ DigitList::operator==(const DigitList& that) const
|
|||
(fDecimalAt == that.fDecimalAt &&
|
||||
fCount == that.fCount &&
|
||||
fIsPositive == that.fIsPositive &&
|
||||
fRoundingMode == that.fRoundingMode &&
|
||||
uprv_strncmp(fDigits, that.fDigits, fCount) == 0));
|
||||
}
|
||||
|
||||
|
@ -120,6 +122,7 @@ DigitList::clear()
|
|||
fDecimalAt = 0;
|
||||
fCount = 0;
|
||||
fIsPositive = TRUE;
|
||||
fRoundingMode = DecimalFormat::kRoundHalfEven;
|
||||
|
||||
// Don't bother initializing fDigits because fCount is 0.
|
||||
}
|
||||
|
@ -548,7 +551,7 @@ DigitList::round(int32_t maximumDigits)
|
|||
/**
|
||||
* Return true if truncating the representation to the given number
|
||||
* of digits will result in an increment to the last digit. This
|
||||
* method implements half-even rounding, the default rounding mode.
|
||||
* method implements the requested rounding mode.
|
||||
* [bnf]
|
||||
* @param maximumDigits the number of digits to keep, from 0 to
|
||||
* <code>count-1</code>. If 0, then all digits are rounded away, and
|
||||
|
@ -558,16 +561,38 @@ DigitList::round(int32_t maximumDigits)
|
|||
* incremented
|
||||
*/
|
||||
UBool DigitList::shouldRoundUp(int32_t maximumDigits) const {
|
||||
// Implement IEEE half-even rounding
|
||||
if (fDigits[maximumDigits] == '5' ) {
|
||||
for (int i=maximumDigits+1; i<fCount; ++i) {
|
||||
if (fDigits[i] != kZero) {
|
||||
switch (fRoundingMode) {
|
||||
case DecimalFormat::kRoundCeiling:
|
||||
return fIsPositive;
|
||||
case DecimalFormat::kRoundFloor:
|
||||
return !fIsPositive;
|
||||
case DecimalFormat::kRoundDown:
|
||||
return FALSE;
|
||||
case DecimalFormat::kRoundUp:
|
||||
return TRUE;
|
||||
case DecimalFormat::kRoundHalfEven:
|
||||
case DecimalFormat::kRoundHalfDown:
|
||||
case DecimalFormat::kRoundHalfUp:
|
||||
default:
|
||||
if (fDigits[maximumDigits] == '5' ) {
|
||||
for (int i=maximumDigits+1; i<fCount; ++i) {
|
||||
if (fDigits[i] != kZero) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
switch (fRoundingMode) {
|
||||
case DecimalFormat::kRoundHalfEven:
|
||||
default:
|
||||
// Implement IEEE half-even rounding
|
||||
return maximumDigits > 0 && (fDigits[maximumDigits-1] % 2 != 0);
|
||||
case DecimalFormat::kRoundHalfDown:
|
||||
return FALSE;
|
||||
case DecimalFormat::kRoundHalfUp:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return maximumDigits > 0 && (fDigits[maximumDigits-1] % 2 != 0);
|
||||
return (fDigits[maximumDigits] > '5');
|
||||
}
|
||||
return (fDigits[maximumDigits] > '5');
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1997-2004, International Business Machines
|
||||
* Copyright (C) 1997-2007, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
*
|
||||
******************************************************************************
|
||||
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "unicode/utypes.h"
|
||||
#include "unicode/uobject.h"
|
||||
#include "unicode/decimfmt.h"
|
||||
#include <float.h>
|
||||
|
||||
// Decimal digits in a 64-bit int
|
||||
|
@ -218,10 +219,11 @@ public:
|
|||
* Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
|
||||
* for all i <= fCount == '0'.
|
||||
*/
|
||||
int32_t fDecimalAt;
|
||||
int32_t fCount;
|
||||
UBool fIsPositive;
|
||||
char *fDigits;
|
||||
int32_t fDecimalAt;
|
||||
int32_t fCount;
|
||||
UBool fIsPositive;
|
||||
char *fDigits;
|
||||
DecimalFormat::ERoundingMode fRoundingMode;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ void addNumFrDepTest(TestNode** root)
|
|||
addTest(root, &TestDoubleAttribute, "tsformat/cnmdptst/TestDoubleAttribute");
|
||||
addTest(root, &TestSecondaryGrouping, "tsformat/cnmdptst/TestSecondaryGrouping");
|
||||
addTest(root, &TestCurrencyKeywords, "tsformat/cnmdptst/TestCurrencyKeywords");
|
||||
addTest(root, &TestRounding5350, "tsformat/cnmdptst/TestRounding5350");
|
||||
}
|
||||
|
||||
/*Test Various format patterns*/
|
||||
|
@ -861,4 +862,67 @@ static void TestCurrencyKeywords(void)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test proper handling of rounding modes.
|
||||
*/
|
||||
static void TestRounding5350(void)
|
||||
{
|
||||
UNumberFormat *nnf;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
/* this is supposed to open default date format, but later on it treats it like it is "en_US"
|
||||
- very bad if you try to run the tests on machine where default locale is NOT "en_US" */
|
||||
/* nnf = unum_open(UNUM_DEFAULT, NULL, &status); */
|
||||
nnf = unum_open(UNUM_DEFAULT, NULL,0,"en_US",NULL, &status);
|
||||
|
||||
if(U_FAILURE(status)){
|
||||
log_err("FAIL: failure in the construction of number format: %s\n", myErrorName(status));
|
||||
} else {
|
||||
unum_setAttribute(nnf, UNUM_MAX_FRACTION_DIGITS, 2);
|
||||
roundingTest2(nnf, -0.125, UNUM_ROUND_CEILING, "-0.12");
|
||||
roundingTest2(nnf, -0.125, UNUM_ROUND_FLOOR, "-0.13");
|
||||
roundingTest2(nnf, -0.125, UNUM_ROUND_DOWN, "-0.12");
|
||||
roundingTest2(nnf, -0.125, UNUM_ROUND_UP, "-0.13");
|
||||
roundingTest2(nnf, 0.125, UNUM_FOUND_HALFEVEN, "0.12");
|
||||
roundingTest2(nnf, 0.135, UNUM_ROUND_HALFDOWN, "0.13");
|
||||
roundingTest2(nnf, 0.125, UNUM_ROUND_HALFUP, "0.13");
|
||||
roundingTest2(nnf, 0.135, UNUM_FOUND_HALFEVEN, "0.14");
|
||||
}
|
||||
|
||||
unum_close(nnf);
|
||||
}
|
||||
|
||||
/*-------------------------------------*/
|
||||
|
||||
static void roundingTest2(UNumberFormat* nf, double x, int32_t roundingMode, const char* expected)
|
||||
{
|
||||
UChar *out = NULL;
|
||||
UChar *res;
|
||||
UFieldPosition pos;
|
||||
UErrorCode status;
|
||||
int32_t lneed;
|
||||
status=U_ZERO_ERROR;
|
||||
unum_setAttribute(nf, UNUM_ROUNDING_MODE, roundingMode);
|
||||
lneed=0;
|
||||
lneed=unum_formatDouble(nf, x, NULL, lneed, NULL, &status);
|
||||
if(status==U_BUFFER_OVERFLOW_ERROR){
|
||||
status=U_ZERO_ERROR;
|
||||
out=(UChar*)malloc(sizeof(UChar) * (lneed+1) );
|
||||
pos.field=0;
|
||||
unum_formatDouble(nf, x, out, lneed+1, &pos, &status);
|
||||
}
|
||||
if(U_FAILURE(status)) {
|
||||
log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status) );
|
||||
}
|
||||
/*Need to use log_verbose here. Problem with the float*/
|
||||
/*printf("%f format with %d fraction digits to %s\n", x, maxFractionDigits, austrdup(out) );*/
|
||||
res=(UChar*)malloc(sizeof(UChar) * (strlen(expected)+1) );
|
||||
u_uastrcpy(res, expected);
|
||||
if (u_strcmp(out, res) != 0)
|
||||
log_err("FAIL: Expected: %s or %s\n", expected, austrdup(res) );
|
||||
free(res);
|
||||
if(out != NULL) {
|
||||
free(out);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/********************************************************************
|
||||
* COPYRIGHT:
|
||||
* Copyright (c) 1997-2003, International Business Machines Corporation and
|
||||
* Copyright (c) 1997-2003, 2007 International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
********************************************************************/
|
||||
/********************************************************************************
|
||||
|
@ -38,6 +38,9 @@ static void TestCurrencySign(void);
|
|||
/* Test proper rounding by the format method.*/
|
||||
static void TestRounding487(void);
|
||||
|
||||
/* Test proper handling of rounding modes. */
|
||||
static void TestRounding5350(void);
|
||||
|
||||
/* Test localized currency patterns. */
|
||||
static void TestCurrency(void);
|
||||
|
||||
|
@ -48,6 +51,7 @@ static void TestSecondaryGrouping(void);
|
|||
|
||||
/*Internal functions used*/
|
||||
static void roundingTest(UNumberFormat*, double, int32_t, const char*);
|
||||
static void roundingTest2(UNumberFormat*, double, int32_t, const char*);
|
||||
|
||||
static void TestCurrencyKeywords(void);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue