ICU-5193 Big decimal number formatting.

X-SVN-Rev: 27696
This commit is contained in:
Andy Heninger 2010-02-26 02:29:00 +00:00
parent cae10acab5
commit 4e56218eb1
33 changed files with 2717 additions and 1212 deletions

View file

@ -1,7 +1,7 @@
/*
******************************************************************************
*
* Copyright (C) 1997-2009, International Business Machines
* Copyright (C) 1997-2010, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
@ -250,16 +250,24 @@ private:
}
}
/* No comparison operators with other MaybeStackArray's. */
bool operator==(const MaybeStackArray &other);
bool operator!=(const MaybeStackArray &other);
bool operator==(const MaybeStackArray & /*other*/) {return FALSE;};
bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;};
/* No ownership transfer: No copy constructor, no assignment operator. */
MaybeStackArray(const MaybeStackArray &other);
void operator=(const MaybeStackArray &other);
/* No heap allocation. Use only on the stack. */
static void * U_EXPORT2 operator new(size_t size);
static void * U_EXPORT2 operator new[](size_t size);
MaybeStackArray(const MaybeStackArray & /*other*/) {};
void operator=(const MaybeStackArray & /*other*/) {};
// No heap allocation. Use only on the stack.
// (Declaring these functions private triggers a cascade of problems:
// MSVC insists on exporting an instantiation of MaybeStackArray, which
// requires that all functions be defined.
// An empty implementation of new() is rejected, it must return a value.
// Returning NULL is rejected by gcc for operator new.
// The expedient thing is just not to override operator new.
// While relatively pointless, heap allocated instances will function.
// static void * U_EXPORT2 operator new(size_t size);
// static void * U_EXPORT2 operator new[](size_t size);
#if U_HAVE_PLACEMENT_NEW
static void * U_EXPORT2 operator new(size_t, void *ptr);
// static void * U_EXPORT2 operator new(size_t, void *ptr);
#endif
};

View file

@ -742,6 +742,7 @@ typedef enum UErrorCode {
U_DUPLICATE_KEYWORD, /**< Duplicate keyword in PluralFormat */
U_UNDEFINED_KEYWORD, /**< Undefined Plural keyword */
U_DEFAULT_KEYWORD_MISSING, /**< Missing DEFAULT rule in plural rules */
U_DECIMAL_NUMBER_SYNTAX_ERROR, /**< Decimal number syntax error */
U_FMT_PARSE_ERROR_LIMIT, /**< The limit for format library errors */
/*

View file

@ -121,7 +121,8 @@ _uFmtErrorName[U_FMT_PARSE_ERROR_LIMIT - U_FMT_PARSE_ERROR_START] = {
"U_ARGUMENT_TYPE_MISMATCH",
"U_DUPLICATE_KEYWORD",
"U_UNDEFINED_KEYWORD",
"U_DEFAULT_KEYWORD_MISSING"
"U_DEFAULT_KEYWORD_MISSING",
"U_DECIMAL_NUMBER_SYNTAX_ERROR"
};
static const char * const

View file

@ -84,7 +84,7 @@ zonemeta.o zstrfmt.o plurrule.o plurfmt.o selfmt.o dtitvfmt.o dtitvinf.o \
tmunit.o tmutamt.o tmutfmt.o colldata.o bmsearch.o bms.o currpinf.o \
uspoof.o uspoof_impl.o uspoof_build.o uspoof_conf.o uspoof_wsconf.o \
ztrans.o zrule.o vzone.o fphdlimp.o fpositer.o locdspnm.o \
decNumber.o decContext.o
decNumber.o decContext.o decnumstr.o
## Header files to install
HEADERS = $(srcdir)/unicode/*.h

View file

@ -51,7 +51,7 @@ const uInt DECPOWERS[10]={1, 10, 100, 1000, 10000, 100000, 1000000,
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
decContext *uprv_decContextClearStatus(decContext *context, uInt mask) {
U_CAPI decContext * U_EXPORT2 uprv_decContextClearStatus(decContext *context, uInt mask) {
context->status&=~mask;
return context;
} /* decContextClearStatus */
@ -69,7 +69,7 @@ decContext *uprv_decContextClearStatus(decContext *context, uInt mask) {
/* Invalid_operation set in the status field. */
/* returns a context structure with the appropriate initial values. */
/* ------------------------------------------------------------------ */
decContext * uprv_decContextDefault(decContext *context, Int kind) {
U_CAPI decContext * U_EXPORT2 uprv_decContextDefault(decContext *context, Int kind) {
/* set defaults... */
context->digits=9; /* 9 digits */
context->emax=DEC_MAX_EMAX; /* 9-digit exponents */
@ -134,7 +134,7 @@ decContext * uprv_decContextDefault(decContext *context, Int kind) {
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
enum rounding uprv_decContextGetRounding(decContext *context) {
U_CAPI enum rounding U_EXPORT2 uprv_decContextGetRounding(decContext *context) {
return context->round;
} /* decContextGetRounding */
@ -146,7 +146,7 @@ enum rounding uprv_decContextGetRounding(decContext *context) {
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
uInt uprv_decContextGetStatus(decContext *context) {
U_CAPI uInt U_EXPORT2 uprv_decContextGetStatus(decContext *context) {
return context->status;
} /* decContextGetStatus */
@ -162,7 +162,7 @@ uInt uprv_decContextGetStatus(decContext *context) {
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
decContext *uprv_decContextRestoreStatus(decContext *context,
U_CAPI decContext * U_EXPORT2 uprv_decContextRestoreStatus(decContext *context,
uInt newstatus, uInt mask) {
context->status&=~mask; /* clear the selected bits */
context->status|=(mask&newstatus); /* or in the new bits */
@ -179,7 +179,7 @@ decContext *uprv_decContextRestoreStatus(decContext *context,
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
uInt uprv_decContextSaveStatus(decContext *context, uInt mask) {
U_CAPI uInt U_EXPORT2 uprv_decContextSaveStatus(decContext *context, uInt mask) {
return context->status&mask;
} /* decContextSaveStatus */
@ -192,7 +192,7 @@ uInt uprv_decContextSaveStatus(decContext *context, uInt mask) {
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
decContext *uprv_decContextSetRounding(decContext *context,
U_CAPI decContext * U_EXPORT2 uprv_decContextSetRounding(decContext *context,
enum rounding newround) {
context->round=newround;
return context;
@ -208,7 +208,7 @@ decContext *uprv_decContextSetRounding(decContext *context,
/* Control may never return from this routine, if there is a signal */
/* handler and it takes a long jump. */
/* ------------------------------------------------------------------ */
decContext * uprv_decContextSetStatus(decContext *context, uInt status) {
U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatus(decContext *context, uInt status) {
context->status|=status;
if (status & context->traps) raise(SIGFPE);
return context;} /* decContextSetStatus */
@ -227,7 +227,7 @@ decContext * uprv_decContextSetStatus(decContext *context, uInt status) {
/* DEC_Condition_MU or is not recognized. In these cases NULL is */
/* returned. */
/* ------------------------------------------------------------------ */
decContext * uprv_decContextSetStatusFromString(decContext *context,
U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusFromString(decContext *context,
const char *string) {
if (strcmp(string, DEC_Condition_CS)==0)
return uprv_decContextSetStatus(context, DEC_Conversion_syntax);
@ -278,7 +278,7 @@ decContext * uprv_decContextSetStatusFromString(decContext *context,
/* DEC_Condition_MU or is not recognized. In these cases NULL is */
/* returned. */
/* ------------------------------------------------------------------ */
decContext * uprv_decContextSetStatusFromStringQuiet(decContext *context,
U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusFromStringQuiet(decContext *context,
const char *string) {
if (strcmp(string, DEC_Condition_CS)==0)
return uprv_decContextSetStatusQuiet(context, DEC_Conversion_syntax);
@ -324,7 +324,7 @@ decContext * uprv_decContextSetStatusFromStringQuiet(decContext *context,
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
decContext * uprv_decContextSetStatusQuiet(decContext *context, uInt status) {
U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusQuiet(decContext *context, uInt status) {
context->status|=status;
return context;} /* decContextSetStatusQuiet */
@ -336,7 +336,7 @@ decContext * uprv_decContextSetStatusQuiet(decContext *context, uInt status) {
/* returns a constant string describing the condition. If multiple */
/* (or no) flags are set, a generic constant message is returned. */
/* ------------------------------------------------------------------ */
const char *uprv_decContextStatusToString(const decContext *context) {
U_CAPI const char * U_EXPORT2 uprv_decContextStatusToString(const decContext *context) {
Int status=context->status;
/* test the five IEEE first, as some of the others are ambiguous when */
@ -374,7 +374,7 @@ const char *uprv_decContextStatusToString(const decContext *context) {
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
Int uprv_decContextTestEndian(Flag quiet) {
U_CAPI Int U_EXPORT2 uprv_decContextTestEndian(Flag quiet) {
Int res=0; /* optimist */
uInt dle=(uInt)DECLITEND; /* unsign */
if (dle>1) dle=1; /* ensure 0 or 1 */
@ -402,7 +402,7 @@ Int uprv_decContextTestEndian(Flag quiet) {
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
uInt uprv_decContextTestSavedStatus(uInt oldstatus, uInt mask) {
U_CAPI uInt U_EXPORT2 uprv_decContextTestSavedStatus(uInt oldstatus, uInt mask) {
return (oldstatus&mask)!=0;
} /* decContextTestSavedStatus */
@ -416,7 +416,7 @@ uInt uprv_decContextTestSavedStatus(uInt oldstatus, uInt mask) {
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
uInt uprv_decContextTestStatus(decContext *context, uInt mask) {
U_CAPI uInt U_EXPORT2 uprv_decContextTestStatus(decContext *context, uInt mask) {
return (context->status&mask)!=0;
} /* decContextTestStatus */
@ -428,7 +428,7 @@ uInt uprv_decContextTestStatus(decContext *context, uInt mask) {
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
decContext *uprv_decContextZeroStatus(decContext *context) {
U_CAPI decContext * U_EXPORT2 uprv_decContextZeroStatus(decContext *context) {
context->status=0;
return context;
} /* decContextZeroStatus */

View file

@ -247,21 +247,21 @@
#define DEC_INIT_DECQUAD DEC_INIT_DECIMAL128
/* decContext routines */
extern decContext * uprv_decContextClearStatus(decContext *, uint32_t);
extern decContext * uprv_decContextDefault(decContext *, int32_t);
extern enum rounding uprv_decContextGetRounding(decContext *);
extern uint32_t uprv_decContextGetStatus(decContext *);
extern decContext * uprv_decContextRestoreStatus(decContext *, uint32_t, uint32_t);
extern uint32_t uprv_decContextSaveStatus(decContext *, uint32_t);
extern decContext * uprv_decContextSetRounding(decContext *, enum rounding);
extern decContext * uprv_decContextSetStatus(decContext *, uint32_t);
extern decContext * uprv_decContextSetStatusFromString(decContext *, const char *);
extern decContext * uprv_decContextSetStatusFromStringQuiet(decContext *, const char *);
extern decContext * uprv_decContextSetStatusQuiet(decContext *, uint32_t);
extern const char * uprv_decContextStatusToString(const decContext *);
extern int32_t uprv_decContextTestEndian(uint8_t);
extern uint32_t uprv_decContextTestSavedStatus(uint32_t, uint32_t);
extern uint32_t uprv_decContextTestStatus(decContext *, uint32_t);
extern decContext * uprv_decContextZeroStatus(decContext *);
U_INTERNAL decContext * U_EXPORT2 uprv_decContextClearStatus(decContext *, uint32_t);
U_INTERNAL decContext * U_EXPORT2 uprv_decContextDefault(decContext *, int32_t);
U_INTERNAL enum rounding U_EXPORT2 uprv_decContextGetRounding(decContext *);
U_INTERNAL uint32_t U_EXPORT2 uprv_decContextGetStatus(decContext *);
U_INTERNAL decContext * U_EXPORT2 uprv_decContextRestoreStatus(decContext *, uint32_t, uint32_t);
U_INTERNAL uint32_t U_EXPORT2 uprv_decContextSaveStatus(decContext *, uint32_t);
U_INTERNAL decContext * U_EXPORT2 uprv_decContextSetRounding(decContext *, enum rounding);
U_INTERNAL decContext * U_EXPORT2 uprv_decContextSetStatus(decContext *, uint32_t);
U_INTERNAL decContext * U_EXPORT2 uprv_decContextSetStatusFromString(decContext *, const char *);
U_INTERNAL decContext * U_EXPORT2 uprv_decContextSetStatusFromStringQuiet(decContext *, const char *);
U_INTERNAL decContext * U_EXPORT2 uprv_decContextSetStatusQuiet(decContext *, uint32_t);
U_INTERNAL const char * U_EXPORT2 uprv_decContextStatusToString(const decContext *);
U_INTERNAL int32_t U_EXPORT2 uprv_decContextTestEndian(uint8_t);
U_INTERNAL uint32_t U_EXPORT2 uprv_decContextTestSavedStatus(uint32_t, uint32_t);
U_INTERNAL uint32_t U_EXPORT2 uprv_decContextTestStatus(decContext *, uint32_t);
U_INTERNAL decContext * U_EXPORT2 uprv_decContextZeroStatus(decContext *);
#endif

View file

@ -348,7 +348,7 @@ static void decDumpAr(char, const Unit *, Int);
/* */
/* No error is possible. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberFromInt32(decNumber *dn, Int in) {
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromInt32(decNumber *dn, Int in) {
uInt unsig;
if (in>=0) unsig=in;
else { /* negative (possibly BADINT) */
@ -361,7 +361,7 @@ decNumber * uprv_decNumberFromInt32(decNumber *dn, Int in) {
return dn;
} /* decNumberFromInt32 */
decNumber * uprv_decNumberFromUInt32(decNumber *dn, uInt uin) {
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromUInt32(decNumber *dn, uInt uin) {
Unit *up; /* work pointer */
uprv_decNumberZero(dn); /* clean */
if (uin==0) return dn; /* [or decGetDigits bad call] */
@ -383,7 +383,7 @@ decNumber * uprv_decNumberFromUInt32(decNumber *dn, uInt uin) {
/* Invalid is set if the decNumber does not have exponent==0 or if */
/* it is a NaN, Infinite, or out-of-range. */
/* ------------------------------------------------------------------ */
Int uprv_decNumberToInt32(const decNumber *dn, decContext *set) {
U_CAPI Int U_EXPORT2 uprv_decNumberToInt32(const decNumber *dn, decContext *set) {
#if DECCHECK
if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
#endif
@ -419,7 +419,7 @@ Int uprv_decNumberToInt32(const decNumber *dn, decContext *set) {
return 0;
} /* decNumberToInt32 */
uInt uprv_decNumberToUInt32(const decNumber *dn, decContext *set) {
U_CAPI uInt U_EXPORT2 uprv_decNumberToUInt32(const decNumber *dn, decContext *set) {
#if DECCHECK
if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
#endif
@ -462,12 +462,12 @@ uInt uprv_decNumberToUInt32(const decNumber *dn, decContext *set) {
/* */
/* No error is possible, and no status can be set. */
/* ------------------------------------------------------------------ */
char * uprv_decNumberToString(const decNumber *dn, char *string){
U_CAPI char * U_EXPORT2 uprv_decNumberToString(const decNumber *dn, char *string){
decToString(dn, string, 0);
return string;
} /* DecNumberToString */
char * uprv_decNumberToEngString(const decNumber *dn, char *string){
U_CAPI char * U_EXPORT2 uprv_decNumberToEngString(const decNumber *dn, char *string){
decToString(dn, string, 1);
return string;
} /* DecNumberToEngString */
@ -492,7 +492,7 @@ char * uprv_decNumberToEngString(const decNumber *dn, char *string){
/* */
/* If bad syntax is detected, the result will be a quiet NaN. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberFromString(decNumber *dn, const char chars[],
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromString(decNumber *dn, const char chars[],
decContext *set) {
Int exponent=0; /* working exponent [assume 0] */
uByte bits=0; /* working flags [assume +ve] */
@ -741,7 +741,7 @@ decNumber * uprv_decNumberFromString(decNumber *dn, const char chars[],
/* This has the same effect as decNumberPlus unless A is negative, */
/* in which case it has the same effect as decNumberMinus. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberAbs(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberAbs(decNumber *res, const decNumber *rhs,
decContext *set) {
decNumber dzero; /* for 0 */
uInt status=0; /* accumulator */
@ -773,7 +773,7 @@ decNumber * uprv_decNumberAbs(decNumber *res, const decNumber *rhs,
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
/* This just calls the routine shared with Subtract */
decNumber * uprv_decNumberAdd(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberAdd(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decAddOp(res, lhs, rhs, set, 0, &status);
@ -799,7 +799,7 @@ decNumber * uprv_decNumberAdd(decNumber *res, const decNumber *lhs,
/* Logical function restrictions apply (see above); a NaN is */
/* returned with Invalid_operation if a restriction is violated. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberAnd(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberAnd(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
const Unit *ua, *ub; /* -> operands */
const Unit *msua, *msub; /* -> operand msus */
@ -867,7 +867,7 @@ decNumber * uprv_decNumberAnd(decNumber *res, const decNumber *lhs,
/* */
/* C must have space for one digit (or NaN). */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberCompare(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompare(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decCompareOp(res, lhs, rhs, set, COMPARE, &status);
@ -887,7 +887,7 @@ decNumber * uprv_decNumberCompare(decNumber *res, const decNumber *lhs,
/* */
/* C must have space for one digit (or NaN). */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberCompareSignal(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareSignal(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decCompareOp(res, lhs, rhs, set, COMPSIG, &status);
@ -908,7 +908,7 @@ decNumber * uprv_decNumberCompareSignal(decNumber *res, const decNumber *lhs,
/* C must have space for one digit; the result will always be one of */
/* -1, 0, or 1. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberCompareTotal(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotal(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
@ -929,7 +929,7 @@ decNumber * uprv_decNumberCompareTotal(decNumber *res, const decNumber *lhs,
/* C must have space for one digit; the result will always be one of */
/* -1, 0, or 1. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberCompareTotalMag(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotalMag(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
uInt needbytes; /* for space calculations */
@ -994,7 +994,7 @@ decNumber * uprv_decNumberCompareTotalMag(decNumber *res, const decNumber *lhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberDivide(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivide(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decDivideOp(res, lhs, rhs, set, DIVIDE, &status);
@ -1017,7 +1017,7 @@ decNumber * uprv_decNumberDivide(decNumber *res, const decNumber *lhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberDivideInteger(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivideInteger(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decDivideOp(res, lhs, rhs, set, DIVIDEINT, &status);
@ -1050,7 +1050,7 @@ decNumber * uprv_decNumberDivideInteger(decNumber *res, const decNumber *lhs,
/* (double) range needed by Ln (which has to be able to calculate */
/* exp(-a) where a can be the tiniest number (Ntiny). */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberExp(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberExp(decNumber *res, const decNumber *rhs,
decContext *set) {
uInt status=0; /* accumulator */
#if DECSUBSET
@ -1106,7 +1106,7 @@ decNumber * uprv_decNumberExp(decNumber *res, const decNumber *rhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberFMA(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFMA(decNumber *res, const decNumber *lhs,
const decNumber *rhs, const decNumber *fhs,
decContext *set) {
uInt status=0; /* accumulator */
@ -1197,7 +1197,7 @@ decNumber * uprv_decNumberFMA(decNumber *res, const decNumber *lhs,
/* Logical function restrictions apply (see above); a NaN is */
/* returned with Invalid_operation if a restriction is violated. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberInvert(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberInvert(decNumber *res, const decNumber *rhs,
decContext *set) {
const Unit *ua, *msua; /* -> operand and its msu */
Unit *uc, *msuc; /* -> result and its msu */
@ -1270,7 +1270,7 @@ decNumber * uprv_decNumberInvert(decNumber *res, const decNumber *rhs,
/* (+11) range needed by Ln, Log10, etc. (which may have to be able */
/* to calculate at p+e+2). */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberLn(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberLn(decNumber *res, const decNumber *rhs,
decContext *set) {
uInt status=0; /* accumulator */
#if DECSUBSET
@ -1336,7 +1336,7 @@ decNumber * uprv_decNumberLn(decNumber *res, const decNumber *rhs,
/* A=1 exactly -> 0 (Exact) */
/* NaNs are propagated as usual */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberLogB(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberLogB(decNumber *res, const decNumber *rhs,
decContext *set) {
uInt status=0; /* accumulator */
@ -1392,7 +1392,7 @@ decNumber * uprv_decNumberLogB(decNumber *res, const decNumber *rhs,
/* fastpath in decLnOp. The final division is done to the requested */
/* precision. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberLog10(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberLog10(decNumber *res, const decNumber *rhs,
decContext *set) {
uInt status=0, ignore=0; /* status accumulators */
uInt needbytes; /* for space calculations */
@ -1540,7 +1540,7 @@ decNumber * uprv_decNumberLog10(decNumber *res, const decNumber *rhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberMax(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberMax(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decCompareOp(res, lhs, rhs, set, COMPMAX, &status);
@ -1563,7 +1563,7 @@ decNumber * uprv_decNumberMax(decNumber *res, const decNumber *lhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberMaxMag(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberMaxMag(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decCompareOp(res, lhs, rhs, set, COMPMAXMAG, &status);
@ -1586,7 +1586,7 @@ decNumber * uprv_decNumberMaxMag(decNumber *res, const decNumber *lhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberMin(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberMin(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decCompareOp(res, lhs, rhs, set, COMPMIN, &status);
@ -1609,7 +1609,7 @@ decNumber * uprv_decNumberMin(decNumber *res, const decNumber *lhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberMinMag(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberMinMag(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decCompareOp(res, lhs, rhs, set, COMPMINMAG, &status);
@ -1634,7 +1634,7 @@ decNumber * uprv_decNumberMinMag(decNumber *res, const decNumber *lhs,
/* ------------------------------------------------------------------ */
/* Simply use AddOp for the subtract, which will do the necessary. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberMinus(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberMinus(decNumber *res, const decNumber *rhs,
decContext *set) {
decNumber dzero;
uInt status=0; /* accumulator */
@ -1664,7 +1664,7 @@ decNumber * uprv_decNumberMinus(decNumber *res, const decNumber *rhs,
/* */
/* This is a generalization of 754 NextDown. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberNextMinus(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextMinus(decNumber *res, const decNumber *rhs,
decContext *set) {
decNumber dtiny; /* constant */
decContext workset=*set; /* work */
@ -1700,7 +1700,7 @@ decNumber * uprv_decNumberNextMinus(decNumber *res, const decNumber *rhs,
/* */
/* This is a generalization of 754 NextUp. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberNextPlus(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextPlus(decNumber *res, const decNumber *rhs,
decContext *set) {
decNumber dtiny; /* constant */
decContext workset=*set; /* work */
@ -1740,7 +1740,7 @@ decNumber * uprv_decNumberNextPlus(decNumber *res, const decNumber *rhs,
/* */
/* This is a generalization of 754-1985 NextAfter. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberNextToward(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextToward(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
decNumber dtiny; /* constant */
decContext workset=*set; /* work */
@ -1808,7 +1808,7 @@ decNumber * uprv_decNumberNextToward(decNumber *res, const decNumber *lhs,
/* Logical function restrictions apply (see above); a NaN is */
/* returned with Invalid_operation if a restriction is violated. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberOr(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberOr(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
const Unit *ua, *ub; /* -> operands */
const Unit *msua, *msub; /* -> operand msus */
@ -1878,7 +1878,7 @@ decNumber * uprv_decNumberOr(decNumber *res, const decNumber *lhs,
/* Performance is a concern here, as this routine is often used to */
/* check operands and apply rounding and overflow/underflow testing. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberPlus(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberPlus(decNumber *res, const decNumber *rhs,
decContext *set) {
decNumber dzero;
uInt status=0; /* accumulator */
@ -1908,7 +1908,7 @@ decNumber * uprv_decNumberPlus(decNumber *res, const decNumber *rhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberMultiply(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberMultiply(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decMultiplyOp(res, lhs, rhs, set, &status);
@ -1945,7 +1945,7 @@ decNumber * uprv_decNumberMultiply(decNumber *res, const decNumber *lhs,
/* almost always be correctly rounded, but may be up to 1 ulp in */
/* error in rare cases. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberPower(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberPower(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
#if DECSUBSET
decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
@ -2290,7 +2290,7 @@ decNumber * uprv_decNumberPower(decNumber *res, const decNumber *lhs,
/* Unless there is an error or the result is infinite, the exponent */
/* after the operation is guaranteed to be equal to that of B. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberQuantize(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberQuantize(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decQuantizeOp(res, lhs, rhs, set, 1, &status);
@ -2310,12 +2310,12 @@ decNumber * uprv_decNumberQuantize(decNumber *res, const decNumber *lhs,
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
/* Previously known as Normalize */
decNumber * uprv_decNumberNormalize(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberNormalize(decNumber *res, const decNumber *rhs,
decContext *set) {
return uprv_decNumberReduce(res, rhs, set);
} /* decNumberNormalize */
decNumber * uprv_decNumberReduce(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberReduce(decNumber *res, const decNumber *rhs,
decContext *set) {
#if DECSUBSET
decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
@ -2379,7 +2379,7 @@ decNumber * uprv_decNumberReduce(decNumber *res, const decNumber *rhs,
/* Unless there is an error or the result is infinite, the exponent */
/* after the operation is guaranteed to be equal to B. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberRescale(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberRescale(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decQuantizeOp(res, lhs, rhs, set, 0, &status);
@ -2399,7 +2399,7 @@ decNumber * uprv_decNumberRescale(decNumber *res, const decNumber *lhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberRemainder(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberRemainder(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decDivideOp(res, lhs, rhs, set, REMAINDER, &status);
@ -2422,7 +2422,7 @@ decNumber * uprv_decNumberRemainder(decNumber *res, const decNumber *lhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberRemainderNear(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberRemainderNear(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decDivideOp(res, lhs, rhs, set, REMNEAR, &status);
@ -2458,7 +2458,7 @@ decNumber * uprv_decNumberRemainderNear(decNumber *res, const decNumber *lhs,
/* B must be valid). No status is set unless B is invalid or an */
/* operand is an sNaN. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberRotate(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberRotate(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
Int rotate; /* rhs as an Int */
@ -2579,7 +2579,7 @@ decNumber * uprv_decNumberRotate(decNumber *res, const decNumber *lhs,
/* */
/* No errors are possible and no context is needed. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberSameQuantum(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberSameQuantum(decNumber *res, const decNumber *lhs,
const decNumber *rhs) {
Unit ret=0; /* return value */
@ -2614,7 +2614,7 @@ decNumber * uprv_decNumberSameQuantum(decNumber *res, const decNumber *lhs,
/* */
/* The result may underflow or overflow. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberScaleB(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberScaleB(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
Int reqexp; /* requested exponent change [B] */
uInt status=0; /* accumulator */
@ -2671,7 +2671,7 @@ decNumber * uprv_decNumberScaleB(decNumber *res, const decNumber *lhs,
/* B must be valid). No status is set unless B is invalid or an */
/* operand is an sNaN. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberShift(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberShift(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
Int shift; /* rhs as an Int */
@ -2800,7 +2800,7 @@ decNumber * uprv_decNumberShift(decNumber *res, const decNumber *lhs,
/* result setexp(approx, e div 2) % fix exponent */
/* end sqrt */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberSquareRoot(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberSquareRoot(decNumber *res, const decNumber *rhs,
decContext *set) {
decContext workset, approxset; /* work contexts */
decNumber dzero; /* used for constant zero */
@ -3142,7 +3142,7 @@ decNumber * uprv_decNumberSquareRoot(decNumber *res, const decNumber *rhs,
/* */
/* C must have space for set->digits digits. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberSubtract(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberSubtract(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
@ -3175,7 +3175,7 @@ decNumber * uprv_decNumberSubtract(decNumber *res, const decNumber *lhs,
/* Inexact if the result differs numerically from rhs; the other */
/* never signals Inexact. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberToIntegralExact(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberToIntegralExact(decNumber *res, const decNumber *rhs,
decContext *set) {
decNumber dn;
decContext workset; /* working context */
@ -3205,7 +3205,7 @@ decNumber * uprv_decNumberToIntegralExact(decNumber *res, const decNumber *rhs,
return res;
} /* decNumberToIntegralExact */
decNumber * uprv_decNumberToIntegralValue(decNumber *res, const decNumber *rhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberToIntegralValue(decNumber *res, const decNumber *rhs,
decContext *set) {
decContext workset=*set; /* working context */
workset.traps=0; /* no traps */
@ -3231,7 +3231,7 @@ decNumber * uprv_decNumberToIntegralValue(decNumber *res, const decNumber *rhs,
/* Logical function restrictions apply (see above); a NaN is */
/* returned with Invalid_operation if a restriction is violated. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberXor(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberXor(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set) {
const Unit *ua, *ub; /* -> operands */
const Unit *msua, *msub; /* -> operand msus */
@ -3349,7 +3349,7 @@ const char *uprv_decNumberClassToString(enum decClass eclass) {
/* All fields are updated as required. This is a utility operation, */
/* so special values are unchanged and no error is possible. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberCopy(decNumber *dest, const decNumber *src) {
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopy(decNumber *dest, const decNumber *src) {
#if DECCHECK
if (src==NULL) return uprv_decNumberZero(dest);
@ -3389,7 +3389,7 @@ decNumber * uprv_decNumberCopy(decNumber *dest, const decNumber *src) {
/* No exception or error can occur; this is a quiet bitwise operation.*/
/* See also decNumberAbs for a checking version of this. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberCopyAbs(decNumber *res, const decNumber *rhs) {
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopyAbs(decNumber *res, const decNumber *rhs) {
#if DECCHECK
if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
#endif
@ -3410,7 +3410,7 @@ decNumber * uprv_decNumberCopyAbs(decNumber *res, const decNumber *rhs) {
/* No exception or error can occur; this is a quiet bitwise operation.*/
/* See also decNumberMinus for a checking version of this. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberCopyNegate(decNumber *res, const decNumber *rhs) {
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopyNegate(decNumber *res, const decNumber *rhs) {
#if DECCHECK
if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
#endif
@ -3431,7 +3431,7 @@ decNumber * uprv_decNumberCopyNegate(decNumber *res, const decNumber *rhs) {
/* C must have space for set->digits digits. */
/* No exception or error can occur; this is a quiet bitwise operation.*/
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberCopySign(decNumber *res, const decNumber *lhs,
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopySign(decNumber *res, const decNumber *lhs,
const decNumber *rhs) {
uByte sign; /* rhs sign */
#if DECCHECK
@ -3454,7 +3454,7 @@ decNumber * uprv_decNumberCopySign(decNumber *res, const decNumber *lhs,
/* bcd must have at least dn->digits bytes. No error is possible; if */
/* dn is a NaN or Infinite, digits must be 1 and the coefficient 0. */
/* ------------------------------------------------------------------ */
uByte * uprv_decNumberGetBCD(const decNumber *dn, uByte *bcd) {
U_CAPI uByte * U_EXPORT2 uprv_decNumberGetBCD(const decNumber *dn, uByte *bcd) {
uByte *ub=bcd+dn->digits-1; /* -> lsd */
const Unit *up=dn->lsu; /* Unit pointer, -> lsu */
@ -3488,7 +3488,7 @@ uByte * uprv_decNumberGetBCD(const decNumber *dn, uByte *bcd) {
/* if dn is a NaN, or Infinite, or is to become a zero, n must be 1 */
/* and bcd[0] zero. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberSetBCD(decNumber *dn, const uByte *bcd, uInt n) {
U_CAPI decNumber * U_EXPORT2 uprv_decNumberSetBCD(decNumber *dn, const uByte *bcd, uInt n) {
Unit *up=dn->lsu+D2U(dn->digits)-1; /* -> msu [target pointer] */
const uByte *ub=bcd; /* -> source msd */
@ -3557,7 +3557,7 @@ Int uprv_decNumberIsSubnormal(const decNumber *dn, decContext *set) {
/* so special values are unchanged and no error is possible. The */
/* zeros are removed unconditionally. */
/* ------------------------------------------------------------------ */
decNumber * uprv_decNumberTrim(decNumber *dn) {
U_CAPI decNumber * U_EXPORT2 uprv_decNumberTrim(decNumber *dn) {
Int dropped; /* work */
decContext set; /* .. */
#if DECCHECK
@ -3585,7 +3585,7 @@ const char * uprv_decNumberVersion(void) {
/* No error is possible. */
/* ------------------------------------------------------------------ */
/* Memset is not used as it is much slower in some environments. */
decNumber * uprv_decNumberZero(decNumber *dn) {
U_CAPI decNumber * U_EXPORT2 uprv_decNumberZero(decNumber *dn) {
#if DECCHECK
if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn;
@ -6001,7 +6001,7 @@ static decNumber * decQuantizeOp(decNumber *res, const decNumber *lhs,
/* The emphasis here is on speed for common cases, and avoiding */
/* coefficient comparison if possible. */
/* ------------------------------------------------------------------ */
decNumber * decCompareOp(decNumber *res, const decNumber *lhs,
static decNumber * decCompareOp(decNumber *res, const decNumber *lhs,
const decNumber *rhs, decContext *set,
Flag op, uInt *status) {
#if DECSUBSET

View file

@ -51,7 +51,10 @@
/* constant. This must not be changed without recompiling the */
/* decNumber library modules. */
#define DECDPUN 3 /* DECimal Digits Per UNit [must be >0 */
/* For ICU, use one digit per byte, to make it easier to emulate the
* old DigitList interface on top of a decNumber
*/
#define DECDPUN 1 /* DECimal Digits Per UNit [must be >0 */
/* and <10; 3 or powers of 2 are best]. */
/* DECNUMDIGITS is the default number of digits that can be held in */
@ -107,74 +110,74 @@
/* decNumber public functions and macros */
/* ---------------------------------------------------------------- */
/* Conversions */
decNumber * uprv_decNumberFromInt32(decNumber *, int32_t);
decNumber * uprv_decNumberFromUInt32(decNumber *, uint32_t);
decNumber * uprv_decNumberFromString(decNumber *, const char *, decContext *);
char * uprv_decNumberToString(const decNumber *, char *);
char * uprv_decNumberToEngString(const decNumber *, char *);
uint32_t uprv_decNumberToUInt32(const decNumber *, decContext *);
int32_t uprv_decNumberToInt32(const decNumber *, decContext *);
uint8_t * uprv_decNumberGetBCD(const decNumber *, uint8_t *);
decNumber * uprv_decNumberSetBCD(decNumber *, const uint8_t *, uint32_t);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberFromInt32(decNumber *, int32_t);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberFromUInt32(decNumber *, uint32_t);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberFromString(decNumber *, const char *, decContext *);
U_INTERNAL char * U_EXPORT2 uprv_decNumberToString(const decNumber *, char *);
U_INTERNAL char * U_EXPORT2 uprv_decNumberToEngString(const decNumber *, char *);
U_INTERNAL uint32_t U_EXPORT2 uprv_decNumberToUInt32(const decNumber *, decContext *);
U_INTERNAL int32_t U_EXPORT2 uprv_decNumberToInt32(const decNumber *, decContext *);
U_INTERNAL uint8_t * U_EXPORT2 uprv_decNumberGetBCD(const decNumber *, uint8_t *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberSetBCD(decNumber *, const uint8_t *, uint32_t);
/* Operators and elementary functions */
decNumber * uprv_decNumberAbs(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberAdd(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberAnd(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberCompare(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberCompareSignal(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberCompareTotal(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberCompareTotalMag(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberDivide(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberDivideInteger(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberExp(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberFMA(decNumber *, const decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberInvert(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberLn(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberLogB(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberLog10(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberMax(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberMaxMag(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberMin(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberMinMag(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberMinus(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberMultiply(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberNormalize(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberOr(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberPlus(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberPower(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberQuantize(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberReduce(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberRemainder(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberRemainderNear(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberRescale(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberRotate(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberSameQuantum(decNumber *, const decNumber *, const decNumber *);
decNumber * uprv_decNumberScaleB(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberShift(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberSquareRoot(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberSubtract(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberToIntegralExact(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberToIntegralValue(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberXor(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberAbs(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberAdd(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberAnd(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCompare(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCompareSignal(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCompareTotal(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCompareTotalMag(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberDivide(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberDivideInteger(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberExp(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberFMA(decNumber *, const decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberInvert(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberLn(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberLogB(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberLog10(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMax(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMaxMag(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMin(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMinMag(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMinus(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberMultiply(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberNormalize(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberOr(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberPlus(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberPower(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberQuantize(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberReduce(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberRemainder(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberRemainderNear(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberRescale(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberRotate(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberSameQuantum(decNumber *, const decNumber *, const decNumber *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberScaleB(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberShift(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberSquareRoot(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberSubtract(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberToIntegralExact(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberToIntegralValue(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberXor(decNumber *, const decNumber *, const decNumber *, decContext *);
/* Utilities */
enum decClass uprv_decNumberClass(const decNumber *, decContext *);
const char * uprv_decNumberClassToString(enum decClass);
decNumber * uprv_decNumberCopy(decNumber *, const decNumber *);
decNumber * uprv_decNumberCopyAbs(decNumber *, const decNumber *);
decNumber * uprv_decNumberCopyNegate(decNumber *, const decNumber *);
decNumber * uprv_decNumberCopySign(decNumber *, const decNumber *, const decNumber *);
decNumber * uprv_decNumberNextMinus(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberNextPlus(decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberNextToward(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * uprv_decNumberTrim(decNumber *);
const char * uprv_decNumberVersion(void);
decNumber * uprv_decNumberZero(decNumber *);
U_INTERNAL const char * U_EXPORT2 uprv_decNumberClassToString(enum decClass);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCopy(decNumber *, const decNumber *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCopyAbs(decNumber *, const decNumber *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCopyNegate(decNumber *, const decNumber *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberCopySign(decNumber *, const decNumber *, const decNumber *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberNextMinus(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberNextPlus(decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberNextToward(decNumber *, const decNumber *, const decNumber *, decContext *);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberTrim(decNumber *);
U_INTERNAL const char * U_EXPORT2 uprv_decNumberVersion(void);
U_INTERNAL decNumber * U_EXPORT2 uprv_decNumberZero(decNumber *);
/* Functions for testing decNumbers (normality depends on context) */
int32_t uprv_decNumberIsNormal(const decNumber *, decContext *);
int32_t uprv_decNumberIsSubnormal(const decNumber *, decContext *);
U_INTERNAL int32_t U_EXPORT2 uprv_decNumberIsNormal(const decNumber *, decContext *);
U_INTERNAL int32_t U_EXPORT2 uprv_decNumberIsSubnormal(const decNumber *, decContext *);
/* Macros for testing decNumber *dn */
#define decNumberIsCanonical(dn) (1) /* All decNumbers are saintly */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,100 @@
/*
******************************************************************************
*
* Copyright (C) 2010, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
*
* File decnumstr.cpp
*
*/
#include "unicode/utypes.h"
#include "decnumstr.h"
#include "cmemory.h"
#include "uassert.h"
U_NAMESPACE_BEGIN
DecimalNumberString::DecimalNumberString() {
fLength = 0;
fText[0] = 0;
}
DecimalNumberString::~DecimalNumberString() {
}
DecimalNumberString::DecimalNumberString(const StringPiece &source, UErrorCode &status) {
fLength = 0;
fText[0] = 0;
append(source, status);
}
DecimalNumberString & DecimalNumberString::append(char c, UErrorCode &status) {
if (ensureCapacity(fLength + 2, status) == FALSE) {
return *this;
}
fText[fLength++] = c;
fText[fLength] = 0;
return *this;
}
DecimalNumberString &DecimalNumberString::append(const StringPiece &str, UErrorCode &status) {
int32_t sLength = str.length();
if (ensureCapacity(fLength + sLength + 1, status) == FALSE) {
return *this;
}
uprv_memcpy(&fText[fLength], str.data(), sLength);
fLength += sLength;
fText[fLength] = 0;
return *this;
}
char & DecimalNumberString::operator [] (int32_t index) {
U_ASSERT(index>=0 && index<fLength);
return fText[index];
}
const char & DecimalNumberString::operator [] (int32_t index) const {
U_ASSERT(index>=0 && index<fLength);
return fText[index];
}
int32_t DecimalNumberString::length() const {
return fLength;
}
void DecimalNumberString::setLength(int32_t length, UErrorCode &status) {
if (ensureCapacity(length+1, status) == FALSE) {
return;
}
if (length > fLength) {
uprv_memset(&fText[fLength], length - fLength, 0);
}
fLength = length;
fText[fLength] = 0;
}
DecimalNumberString::operator StringPiece() const {
return StringPiece(fText, fLength);
}
UBool DecimalNumberString::ensureCapacity(int32_t neededSize, UErrorCode &status) {
if (U_FAILURE(status)) {
return FALSE;
}
if (fText.getCapacity() < neededSize) {
char *newBuf = fText.resize(neededSize, fText.getCapacity());
if (newBuf == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return FALSE;
}
U_ASSERT(fText.getCapacity() >= neededSize);
U_ASSERT(fText.getAlias() == newBuf);
}
return TRUE;
}
U_NAMESPACE_END

View file

@ -0,0 +1,54 @@
/*
******************************************************************************
*
* Copyright (C) 2010, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
*
* File decnumstr.h
*
* A simple eight bit char string class.
* Used by decimal number formatting to hold the string form of numbers.
*
* For internal ICU use only. Not public API.
*
* TODO: ICU should have a light-weight general purpose (char *) string class
* available for internal use; this would eliminate the
* need for this class.
*/
#ifndef DECNUMSTR_H
#define DECNUMSTR_H
#include "unicode/utypes.h"
#include "unicode/stringpiece.h"
#include "cmemory.h"
U_NAMESPACE_BEGIN
class DecimalNumberString: public UMemory {
public:
DecimalNumberString();
~DecimalNumberString();
DecimalNumberString(const StringPiece &, UErrorCode &status);
DecimalNumberString &append(char, UErrorCode &status);
DecimalNumberString &append(const StringPiece &s, UErrorCode &status);
char &operator[] (int32_t index);
const char &operator[] (int32_t index) const;
int32_t length() const;
void setLength(int32_t length, UErrorCode &status);
operator StringPiece() const;
private:
int32_t fLength;
MaybeStackArray<char, 40> fText;
UBool ensureCapacity(int32_t neededSize, UErrorCode &status);
};
U_NAMESPACE_END
#endif // DECNUMSTR_H

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/*
******************************************************************************
*
* Copyright (C) 1997-2007, International Business Machines
* Copyright (C) 1997-2010, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
@ -29,9 +29,12 @@
#if !UCONFIG_NO_FORMATTING
#include "unicode/decimfmt.h"
#include <float.h>
#include "decContext.h"
#include "decNumber.h"
#include "cmemory.h"
#include "decnumstr.h"
// Decimal digits in a 64-bit int
//#define LONG_DIGITS 19
#define INT64_DIGITS 19
typedef enum EDigitListValues {
@ -40,6 +43,7 @@ typedef enum EDigitListValues {
MAX_DIGITS = MAX_I64_DIGITS,
MAX_EXPONENT = DBL_DIG,
DIGIT_PADDING = 3,
DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed.
// "+." + fDigits + "e" + fDecimalAt
MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
@ -47,7 +51,34 @@ typedef enum EDigitListValues {
U_NAMESPACE_BEGIN
// Export an explicit template instantiation of the MaybeStackArray that
// is used as a data member of DigitList.
//
// MSVC requires this, even though it should not be necessary.
// No direct access to the MaybeStackArray leaks out of the i18n library.
//
// Macintosh produces duplicate definition linker errors with the explicit template
// instantiation.
//
#if !defined(U_DARWIN)
template class U_I18N_API MaybeStackArray<char, sizeof(decNumber) + DEFAULT_DIGITS>;
#endif
/**
* Digit List is actually a Decimal Floating Point number.
* The original implementation has been replaced by a thin wrapper onto a
* decimal number from the decNumber library.
*
* The original DigitList API has been retained, to minimize the impact of
* the change on the rest of the ICU formatting code.
*
* The change to decNumber enables support for big decimal numbers, and
* allows rounding computations to be done directly in decimal, avoiding
* extra, and inaccurate, conversions to and from doubles.
*
* Original DigitList comments:
*
* Digit List utility class. Private to DecimalFormat. Handles the transcoding
* between numeric values and strings of characters. Only handles
* non-negative numbers. The division of labor between DigitList and
@ -65,9 +96,31 @@ U_NAMESPACE_BEGIN
* object can be computed by mulitplying the fraction f, where 0 <= f < 1,
* derived by placing all the digits of the list to the right of the
* decimal point, by 10^exponent.
*
* --------
*
* DigitList vs. decimalNumber:
*
* DigitList stores digits with the most significant first.
* decNumber stores digits with the least significant first.
*
* DigitList, decimal point is before the most significant.
* decNumber, decimal point is after the least signficant digit.
*
* digitList: 0.ddddd * 10 ^ exp
* decNumber: ddddd. * 10 ^ exp
*
* digitList exponent = decNumber exponent + digit count
*
* digitList, digits are chars, '0' - '9'
* decNumber, digits are binary, one per byte, 0 - 9.
*
* (decNumber library is configurable in how digits are stored, ICU has configured
* it this way for convenience in replacing the old DigitList implementation.)
*/
class DigitList : public UMemory { // Declare external to make compiler happy
class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
public:
DigitList();
~DigitList();
@ -91,12 +144,10 @@ public:
*/
UBool operator==(const DigitList& other) const;
private:
/**
* Commented out due to lack of usage and low code coverage.
*/
inline UBool operator!=(const DigitList& other) const;
public:
int32_t compare(const DigitList& other);
inline UBool operator!=(const DigitList& other) const { return !operator==(other); };
/**
* Clears out the digits.
@ -108,18 +159,30 @@ public:
void clear(void);
/**
* Appends digits to the list. Ignores all digits beyond the first DBL_DIG,
* since they are not significant for either longs or doubles.
* Remove, by rounding, any fractional part of the decimal number,
* leaving an integer value.
*/
void toIntegralValue();
/**
* Appends digits to the list.
* CAUTION: this function is not recommended for new code.
* In the original DigitList implementation, decimal numbers were
* parsed by appending them to a digit list as they were encountered.
* With the revamped DigitList based on decNumber, append is very
* inefficient, and the interaction with the exponent value is confusing.
* Best avoided.
* TODO: remove this function once all use has been replaced.
* @param digit The digit to be appended.
*/
inline void append(char digit);
void append(char digit);
/**
* Utility routine to get the value of the digit list
* Returns 0.0 if zero length.
* @return the value of the digit list.
*/
double getDouble(void) /*const*/;
double getDouble(void) const;
/**
* Utility routine to get the value of the digit list
@ -137,6 +200,11 @@ public:
*/
int64_t getInt64(void) /*const*/;
/**
* Utility routine to get the value of the digit list as a decimal string.
*/
void getDecimal(DecimalNumberString &str, UErrorCode &status);
/**
* Return true if the number represented by this object can fit into
* a long.
@ -156,49 +224,105 @@ public:
UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/;
/**
* Utility routine to set the value of the digit list from a double
* Input must be non-negative, and must not be Inf, -Inf, or NaN.
* The maximum fraction digits helps us round properly.
* Utility routine to set the value of the digit list from a double.
* @param source The value to be set
* @param maximunDigits The maximum number of digits to be shown
* @param fixedPoint True if the point is fixed
*/
void set(double source, int32_t maximumDigits, UBool fixedPoint = TRUE);
void set(double source);
/**
* Utility routine to set the value of the digit list from a long.
* If a non-zero maximumDigits is specified, no more than that number of
* significant digits will be produced.
* @param source The value to be set
* @param maximunDigits The maximum number of digits to be shown
*/
void set(int32_t source, int32_t maximumDigits = 0);
void set(int32_t source);
/**
* Utility routine to set the value of the digit list from an int64.
* If a non-zero maximumDigits is specified, no more than that number of
* significant digits will be produced.
* @param source The value to be set
* @param maximunDigits The maximum number of digits to be shown
*/
void set(int64_t source, int32_t maximumDigits = 0);
void set(int64_t source);
/**
* Utility routine to set the value of the digit list from a decimal number
* string.
* @param source The value to be set. The string must be nul-terminated.
*/
void set(const StringPiece &source, UErrorCode &status);
/**
* Return true if this is a representation of zero.
* @return true if this is a representation of zero.
* Multiply this = this * arg
* This digitlist will be expanded if necessary to accomodate the result.
* @param arg the number to multiply by.
*/
void mult(const DigitList &arg, UErrorCode &status);
/**
* Divide this = this / arg
*/
void div(const DigitList &arg, UErrorCode &status);
// The following functions replace direct access to the original DigitList implmentation
// data structures.
void setRoundingMode(DecimalFormat::ERoundingMode m);
/** Test a number for zero.
* @return TRUE if the number is zero
*/
UBool isZero(void) const;
/**
* Return true if this is a representation of LONG_MIN. You must use
* this method to determine if this is so; you cannot check directly,
* because a special format is used to handle this.
/** Test for a Nan
* @return TRUE if the number is a NaN
*/
// This code is unused.
//UBool isLONG_MIN(void) const;
UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);};
UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);};
/** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */
void reduce();
/** Remove trailing fraction zeros, adjust exponent accordingly. */
void trim();
/** Set to zero */
void setToZero() {uprv_decNumberZero(fDecNumber);};
/** get the number of digits in the decimal number */
int32_t digits() const {return fDecNumber->digits;};
public:
/**
* Round the number to the given number of digits.
* @param maximumDigits The maximum number of digits to be shown.
* Upon return, count will be less than or equal to maximumDigits.
*/
void round(int32_t maximumDigits);
void roundFixedPoint(int32_t maximumFractionDigits);
/** Ensure capacity for digits. Grow the storage if it is currently less than
* the requested size. Capacity is not reduced if it is already greater
* than requested.
*/
void ensureCapacity(int32_t requestedSize, UErrorCode &status);
UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;};
void setPositive(UBool s);
void setDecimalAt(int32_t d);
int32_t getDecimalAt();
void setCount(int32_t c);
int32_t getCount() const;
void setDigit(int32_t i, char v);
char getDigit(int32_t i);
private:
/*
* These data members are intentionally public and can be set directly.
*<P>
* The value represented is given by placing the decimal point before
@ -218,46 +342,32 @@ public:
* <P>
* 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;
* DecimalFormat::ERoundingMode fRoundingMode;
*/
int32_t fDecimalAt;
int32_t fCount;
UBool fIsPositive;
char *fDigits;
DecimalFormat::ERoundingMode fRoundingMode;
private:
/* One character before fDigits for the decimal*/
char fDecimalDigits[MAX_DEC_DIGITS + 1];
/**
* Round the representation to the given number of digits.
* @param maximumDigits The maximum number of digits to be shown.
* Upon return, count will be less than or equal to maximumDigits.
decContext fContext;
decNumber *fDecNumber;
MaybeStackArray<char, sizeof(decNumber) + DEFAULT_DIGITS> fStorage;
/* Cached double value corresponding to this decimal number.
* This is an optimization for the formatting implementation, which may
* ask for the double value multiple times.
*/
void round(int32_t maximumDigits);
double fDouble;
UBool fHaveDouble;
UBool shouldRoundUp(int32_t maximumDigits) const;
};
// -------------------------------------
// Appends the digit to the digit list if it's not out of scope.
// Ignores the digit, otherwise.
inline void
DigitList::append(char digit)
{
// Ignore digits which exceed the precision we can represent
if (fCount < MAX_DIGITS)
fDigits[fCount++] = digit;
}
#if 0
inline UBool
DigitList::operator!=(const DigitList& other) const {
return !operator==(other);
}
#endif
U_NAMESPACE_END

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2008, International Business Machines Corporation and *
* Copyright (C) 1997-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@ -22,6 +22,10 @@
#include "unicode/measure.h"
#include "unicode/curramt.h"
#include "cmemory.h"
#include "cstring.h"
#include "decNumber.h"
#include "decnumstr.h"
#include "digitlst.h"
// *****************************************************************************
// class Formattable
@ -68,7 +72,7 @@ static inline UBool instanceOfMeasure(const UObject* a) {
* @param count the original array count
* @return the new Formattable array.
*/
static inline Formattable* createArrayCopy(const Formattable* array, int32_t count) {
static Formattable* createArrayCopy(const Formattable* array, int32_t count) {
Formattable *result = new Formattable[count];
if (result != NULL) {
for (int32_t i=0; i<count; ++i)
@ -82,30 +86,39 @@ static inline Formattable* createArrayCopy(const Formattable* array, int32_t cou
/**
* Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode.
*/
static inline void setError(UErrorCode& ec, UErrorCode err) {
static void setError(UErrorCode& ec, UErrorCode err) {
if (U_SUCCESS(ec)) {
ec = err;
}
}
//
// Common initialization code, shared by constructors.
// Put everything into a known state.
//
void Formattable::init() {
fValue.fInt64 = 0;
fType = kLong;
fDecimalStr = NULL;
fDecimalNum = NULL;
fBogus.setToBogus();
}
// -------------------------------------
// default constructor.
// Creates a formattable object with a long value 0.
Formattable::Formattable()
: UObject(), fType(kLong)
{
fBogus.setToBogus();
fValue.fInt64 = 0;
Formattable::Formattable() {
init();
}
// -------------------------------------
// Creates a formattable object with a Date instance.
Formattable::Formattable(UDate date, ISDATE /*isDate*/)
: UObject(), fType(kDate)
{
fBogus.setToBogus();
init();
fType = kDate;
fValue.fDate = date;
}
@ -113,39 +126,47 @@ Formattable::Formattable(UDate date, ISDATE /*isDate*/)
// Creates a formattable object with a double value.
Formattable::Formattable(double value)
: UObject(), fType(kDouble)
{
fBogus.setToBogus();
init();
fType = kDouble;
fValue.fDouble = value;
}
// -------------------------------------
// Creates a formattable object with a long value.
// Creates a formattable object with an int32_t value.
Formattable::Formattable(int32_t value)
: UObject(), fType(kLong)
{
fBogus.setToBogus();
init();
fValue.fInt64 = value;
}
// -------------------------------------
// Creates a formattable object with a long value.
// Creates a formattable object with an int64_t value.
Formattable::Formattable(int64_t value)
: UObject(), fType(kInt64)
{
fBogus.setToBogus();
init();
fType = kInt64;
fValue.fInt64 = value;
}
// -------------------------------------
// Creates a formattable object with a decimal number value from a string.
Formattable::Formattable(const StringPiece &number, UErrorCode &status) {
init();
setDecimalNumber(number, status);
}
// -------------------------------------
// Creates a formattable object with a UnicodeString instance.
Formattable::Formattable(const UnicodeString& stringToCopy)
: UObject(), fType(kString)
{
fBogus.setToBogus();
init();
fType = kString;
fValue.fString = new UnicodeString(stringToCopy);
}
@ -154,16 +175,16 @@ Formattable::Formattable(const UnicodeString& stringToCopy)
// (adopting symantics)
Formattable::Formattable(UnicodeString* stringToAdopt)
: UObject(), fType(kString)
{
fBogus.setToBogus();
init();
fType = kString;
fValue.fString = stringToAdopt;
}
Formattable::Formattable(UObject* objectToAdopt)
: UObject(), fType(kObject)
{
fBogus.setToBogus();
init();
fType = kObject;
fValue.fObject = objectToAdopt;
}
@ -172,7 +193,8 @@ Formattable::Formattable(UObject* objectToAdopt)
Formattable::Formattable(const Formattable* arrayToCopy, int32_t count)
: UObject(), fType(kArray)
{
fBogus.setToBogus();
init();
fType = kArray;
fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count);
fValue.fArrayAndCount.fCount = count;
}
@ -180,10 +202,11 @@ Formattable::Formattable(const Formattable* arrayToCopy, int32_t count)
// -------------------------------------
// copy constructor
Formattable::Formattable(const Formattable &source)
: UObject(source), fType(kLong)
: UObject(*this)
{
fBogus.setToBogus();
init();
*this = source;
}
@ -229,6 +252,18 @@ Formattable::operator=(const Formattable& source)
fValue.fObject = objectClone(source.fValue.fObject);
break;
}
UErrorCode status = U_ZERO_ERROR;
if (source.fDecimalNum != NULL) {
fDecimalNum = new DigitList(*source.fDecimalNum);
}
if (source.fDecimalStr != NULL) {
fDecimalStr = new DecimalNumberString(*source.fDecimalStr, status);
if (U_FAILURE(status)) {
delete fDecimalStr;
fDecimalStr = NULL;
}
}
}
return *this;
}
@ -283,6 +318,7 @@ Formattable::operator==(const Formattable& that) const
break;
}
// TODO: compare digit lists if numeric.
return equal;
}
@ -311,6 +347,13 @@ void Formattable::dispose()
default:
break;
}
fType = kLong;
fValue.fInt64 = 0;
delete fDecimalStr;
fDecimalStr = NULL;
delete fDecimalNum;
fDecimalNum = NULL;
}
Formattable *
@ -625,6 +668,113 @@ Formattable::getBogus() const
return (UnicodeString*)&fBogus; /* cast away const :-( */
}
// --------------------------------------
StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
if (U_FAILURE(status)) {
return "";
}
if (fDecimalStr != NULL) {
return *fDecimalStr;
}
if (fDecimalNum == NULL) {
// No decimal number for the formattable yet. Which means the value was
// set directly by the user as an int, int64 or double. If the value came
// from parsing, or from the user setting a decimal number, fDecimalNum
// would already be set.
//
fDecimalNum = new DigitList;
if (fDecimalNum == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return "";
}
switch (fType) {
case kDouble:
fDecimalNum->set(this->getDouble());
break;
case kLong:
fDecimalNum->set(this->getLong());
break;
case kInt64:
fDecimalNum->set(this->getInt64());
break;
default:
// The formattable's value is not a numeric type.
status = U_INVALID_STATE_ERROR;
return "";
}
}
fDecimalStr = new DecimalNumberString;
if (fDecimalStr == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return "";
}
fDecimalNum->getDecimal(*fDecimalStr, status);
return *fDecimalStr;
}
// ---------------------------------------
void
Formattable::adoptDigitList(DigitList *dl) {
dispose();
fDecimalNum = dl;
// Set the value into the Union of simple type values.
// Cannot use the set() functions because they would delete the fDecimalNum value,
if (fDecimalNum->fitsIntoLong(FALSE)) {
fType = kLong;
fValue.fInt64 = fDecimalNum->getLong();
} else if (fDecimalNum->fitsIntoInt64(FALSE)) {
fType = kInt64;
fValue.fInt64 = fDecimalNum->getInt64();
} else {
fType = kDouble;
fValue.fDouble = fDecimalNum->getDouble();
}
}
// ---------------------------------------
void
Formattable::setDecimalNumber(const StringPiece &numberString, UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
dispose();
// Copy the input string and nul-terminate it.
// The decNumber library requires nul-terminated input. StringPiece input
// is not guaranteed nul-terminated. Too bad.
// DecimalNumberStrings automatically adds the nul.
DecimalNumberString s(numberString, status);
if (U_FAILURE(status)) {
return;
}
DigitList *dnum = new DigitList();
if (dnum == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
dnum->set(s, status);
if (U_FAILURE(status)) {
delete dnum;
return; // String didn't contain a decimal number.
}
adoptDigitList(dnum);
// Note that we do not hang on to the caller's input string.
// If we are asked for the string, we will regenerate one from fDecimalNum.
}
#if 0
//----------------------------------------------------
// console I/O

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2005, International Business Machines Corporation and *
* Copyright (C) 1997-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@ -31,9 +31,9 @@ U_NAMESPACE_BEGIN
// This is just a grandfathered API.
Formattable::Formattable(const char* stringToCopy)
: UObject(), fType(kString)
{
fBogus.setToBogus();
init();
fType = kString;
fValue.fString = new UnicodeString(stringToCopy);
}

View file

@ -88,8 +88,10 @@ Format::Format(const Format &that)
Format&
Format::operator=(const Format& that)
{
uprv_strcpy(validLocale, that.validLocale);
uprv_strcpy(actualLocale, that.actualLocale);
if (this != &that) {
uprv_strcpy(validLocale, that.validLocale);
uprv_strcpy(actualLocale, that.actualLocale);
}
return *this;
}

View file

@ -1426,6 +1426,14 @@
RelativePath=".\decNumberLocal.h"
>
</File>
<File
RelativePath=".\decnumstr.cpp"
>
</File>
<File
RelativePath=".\decnumstr.h"
>
</File>
<File
RelativePath=".\digitlst.cpp"
>

View file

@ -1,6 +1,6 @@
/*
******************************************************************************
* Copyright (C) 1997-2007, International Business Machines
* Copyright (C) 1997-2010, International Business Machines
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: nfsubs.cpp
@ -1041,25 +1041,22 @@ FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser
// }
DigitList dl;
dl.set(number, 20, TRUE);
dl.set(number);
dl.roundFixedPoint(20); // round to 20 fraction digits.
dl.reduce(); // Removes any trailing zeros.
UBool pad = FALSE;
while (dl.fCount > (dl.fDecimalAt <= 0 ? 0 : dl.fDecimalAt)) {
for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) {
// Loop iterates over fraction digits, starting with the LSD.
// include both real digits from the number, and zeros
// to the left of the MSD but to the right of the decimal point.
if (pad && useSpaces) {
toInsertInto.insert(_pos + getPos(), gSpace);
} else {
pad = TRUE;
}
getRuleSet()->format((int64_t)(dl.fDigits[--dl.fCount] - '0'), toInsertInto, _pos + getPos());
}
while (dl.fDecimalAt < 0) {
if (pad && useSpaces) {
toInsertInto.insert(_pos + getPos(), gSpace);
} else {
pad = TRUE;
}
getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos());
++dl.fDecimalAt;
int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0;
getRuleSet()->format(digit, toInsertInto, _pos + getPos());
}
if (!pad) {
@ -1156,7 +1153,7 @@ FractionalPartSubstitution::doParse(const UnicodeString& text,
}
delete fmt;
result = dl.fCount == 0 ? 0 : dl.getDouble();
result = dl.getCount() == 0 ? 0 : dl.getDouble();
result = composeRuleValue(result, baseValue);
resVal.setDouble(result);
return TRUE;

View file

@ -44,6 +44,7 @@
#include "cstring.h"
#include "putilimp.h"
#include "umutex.h"
#include "digitlst.h"
#include <float.h>
//#define FMT_DEBUG
@ -210,6 +211,7 @@ NumberFormat::operator=(const NumberFormat& rhs)
{
if (this != &rhs)
{
Format::operator=(rhs);
fGroupingUsed = rhs.fGroupingUsed;
fMaxIntegerDigits = rhs.fMaxIntegerDigits;
fMinIntegerDigits = rhs.fMinIntegerDigits;
@ -322,18 +324,29 @@ NumberFormat::format(int64_t /* unused number */,
}
// -------------------------------------
// Default implementation sets unsupported error; subclasses should
// override.
// Decimal Number format() default implementation
// Subclasses do not normally override this function, but rather the DigitList
// formatting functions..
// The expected call chain from here is
// this function ->
// NumberFormat::format(Formattable ->
// DecimalFormat::format(DigitList
//
// Or, for subclasses of Formattable that do not know about DigitList,
// this Function ->
// NumberFormat::format(Formattable ->
// NumberFormat::format(DigitList ->
// XXXFormat::format(double
UnicodeString&
NumberFormat::format(const StringPiece & /* unused decimal number */,
NumberFormat::format(const StringPiece &decimalNum,
UnicodeString& toAppendTo,
FieldPositionIterator* /* unused posIter */,
FieldPositionIterator* fpi,
UErrorCode& status) const
{
if (!U_FAILURE(status)) {
status = U_UNSUPPORTED_ERROR;
}
Formattable f;
f.setDecimalNumber(decimalNum, status);
format(f, toAppendTo, fpi, status);
return toAppendTo;
}
@ -388,6 +401,39 @@ ArgExtractor::~ArgExtractor() {
}
}
UnicodeString& NumberFormat::format(const DigitList &number,
UnicodeString& appendTo,
FieldPositionIterator* posIter,
UErrorCode& status) const {
// DecimalFormat overrides this function, and handles DigitList based big decimals.
// Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists,
// so this default implementation falls back to formatting decimal numbers as doubles.
if (U_FAILURE(status)) {
return appendTo;
}
double dnum = number.getDouble();
format(dnum, appendTo, posIter, status);
return appendTo;
}
UnicodeString&
NumberFormat::format(const DigitList &number,
UnicodeString& appendTo,
FieldPosition& pos,
UErrorCode &status) const {
// DecimalFormat overrides this function, and handles DigitList based big decimals.
// Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists,
// so this default implementation falls back to formatting decimal numbers as doubles.
if (U_FAILURE(status)) {
return appendTo;
}
double dnum = number.getDouble();
format(dnum, appendTo, pos, status);
return appendTo;
}
UnicodeString&
NumberFormat::format(const Formattable& obj,
UnicodeString& appendTo,
@ -399,19 +445,31 @@ NumberFormat::format(const Formattable& obj,
ArgExtractor arg(*this, obj, status);
const Formattable *n = arg.number();
switch (n->getType()) {
case Formattable::kDouble:
format(n->getDouble(), appendTo, pos);
break;
case Formattable::kLong:
format(n->getLong(), appendTo, pos);
break;
case Formattable::kInt64:
format(n->getInt64(), appendTo, pos);
break;
default:
status = U_INVALID_FORMAT_ERROR;
break;
if (n->isNumeric() && n->getDigitList() != NULL) {
// Decimal Number. We will have a DigitList available if the value was
// set to a decimal number, or if the value originated with a parse.
//
// The default implementation for formatting a DigitList converts it
// to a double, and formats that, allowing formatting classes that don't
// know about DigitList to continue to operate as they had.
//
// DecimalFormat overrides the DigitList formatting functions.
format(*n->getDigitList(), appendTo, pos, status);
} else {
switch (n->getType()) {
case Formattable::kDouble:
format(n->getDouble(), appendTo, pos);
break;
case Formattable::kLong:
format(n->getLong(), appendTo, pos);
break;
case Formattable::kInt64:
format(n->getInt64(), appendTo, pos);
break;
default:
status = U_INVALID_FORMAT_ERROR;
break;
}
}
return appendTo;
@ -432,19 +490,24 @@ NumberFormat::format(const Formattable& obj,
ArgExtractor arg(*this, obj, status);
const Formattable *n = arg.number();
switch (n->getType()) {
case Formattable::kDouble:
format(n->getDouble(), appendTo, posIter, status);
break;
case Formattable::kLong:
format(n->getLong(), appendTo, posIter, status);
break;
case Formattable::kInt64:
format(n->getInt64(), appendTo, posIter, status);
break;
default:
status = U_INVALID_FORMAT_ERROR;
break;
if (n->isNumeric() && n->getDigitList() != NULL) {
// Decimal Number
format(*n->getDigitList(), appendTo, posIter, status);
} else {
switch (n->getType()) {
case Formattable::kDouble:
format(n->getDouble(), appendTo, posIter, status);
break;
case Formattable::kLong:
format(n->getLong(), appendTo, posIter, status);
break;
case Formattable::kInt64:
format(n->getInt64(), appendTo, posIter, status);
break;
default:
status = U_INVALID_FORMAT_ERROR;
break;
}
}
return appendTo;

View file

@ -201,7 +201,7 @@ public:
/**
* Get one of the format symbols by its enum constant.
* Each symbol is stored as a string so that graphemes
* (characters with modifyer letters) can be used.
* (characters with modifier letters) can be used.
*
* @param symbol Constant to indicate a number format symbol.
* @return the format symbols by the param 'symbol'
@ -212,10 +212,10 @@ public:
/**
* Set one of the format symbols by its enum constant.
* Each symbol is stored as a string so that graphemes
* (characters with modifyer letters) can be used.
* (characters with modifier letters) can be used.
*
* @param symbol Constant to indicate a number format symbol.
* @param value value of the format sybmol
* @param value value of the format symbol
* @stable ICU 2.0
*/
void setSymbol(ENumberFormatSymbol symbol, const UnicodeString &value);

View file

@ -946,6 +946,48 @@ public:
FieldPositionIterator* posIter,
UErrorCode& status) const;
/**
* Format a decimal number.
* The number is a DigitList wrapper onto a floating point decimal number.
* The default implementation in NumberFormat converts the decimal number
* to a double and formats that.
*
* @param number The number, a DigitList format Decimal Floating Point.
* @param appendTo Output parameter to receive result.
* Result is appended to existing contents.
* @param posIter On return, can be used to iterate over positions
* of fields generated by this format call.
* @param status Output param filled with success/failure status.
* @return Reference to 'appendTo' parameter.
* @internal
*/
virtual UnicodeString& format(const DigitList &number,
UnicodeString& appendTo,
FieldPositionIterator* posIter,
UErrorCode& status) const;
/**
* Format a decimal number.
* The number is a DigitList wrapper onto a floating point decimal number.
* The default implementation in NumberFormat converts the decimal number
* to a double and formats that.
*
* @param number The number, a DigitList format Decimal Floating Point.
* @param appendTo Output parameter to receive result.
* Result is appended to existing contents.
* @param pos On input: an alignment field, if desired.
* On output: the offsets of the alignment field.
* @param status Output param filled with success/failure status.
* @return Reference to 'appendTo' parameter.
* @internal
*/
virtual UnicodeString& format(const DigitList &number,
UnicodeString& appendTo,
FieldPosition& pos,
UErrorCode& status) const;
/**
* Format a Formattable using base-10 representation.
*
@ -1806,7 +1848,13 @@ private:
DecimalFormat(); // default constructor not implemented
int32_t precision(UBool isIntegral) const;
int32_t precision() const;
/**
* Initialize all fields of a new DecimalFormatter.
* Common code for use by constructors.
*/
void init();
/**
* Do real work of constructing a new DecimalFormat.
@ -1977,8 +2025,6 @@ private:
void expandAffixes(const UnicodeString* pluralCount);
static double round(double a, ERoundingMode mode, UBool isNegative);
void addPadding(UnicodeString& appendTo,
FieldPositionHandler& handler,
int32_t prefixLen, int32_t suffixLen) const;
@ -2026,6 +2072,10 @@ private:
UnicodeString& _format(double number,
UnicodeString& appendTo,
FieldPositionHandler& handler) const;
UnicodeString& _format(const DigitList &number,
UnicodeString& appendTo,
FieldPositionHandler& handler,
UErrorCode &status) const;
// currency sign count
enum {
@ -2038,9 +2088,6 @@ private:
/**
* Constants.
*/
//static const int8_t fgMaxDigit; // The largest digit, in this case 9
/*transient*/ //DigitList* fDigitList;
UnicodeString fPositivePrefix;
UnicodeString fPositiveSuffix;
@ -2058,7 +2105,7 @@ private:
*/
ChoiceFormat* fCurrencyChoice;
int32_t fMultiplier;
DigitList * fMultiplier; // NULL for multiplier of one
int32_t fGroupingSize;
int32_t fGroupingSize2;
UBool fDecimalSeparatorAlwaysShown;
@ -2072,12 +2119,7 @@ private:
int8_t fMinExponentDigits;
UBool fExponentSignAlwaysShown;
/* If fRoundingIncrement is NULL, there is no rounding. Otherwise, round to
* fRoundingIncrement.getDouble(). Since this operation may be expensive,
* we cache the result in fRoundingDouble. All methods that update
* fRoundingIncrement also update fRoundingDouble. */
DigitList* fRoundingIncrement;
/*transient*/ double fRoundingDouble;
DigitList* fRoundingIncrement; // NULL if no rounding increment specified.
ERoundingMode fRoundingMode;
UChar32 fPad;

View file

@ -28,6 +28,9 @@
U_NAMESPACE_BEGIN
class DecimalNumberString;
class DigitList;
/**
* Formattable objects can be passed to the Format class or
* its subclasses for formatting. Formattable is a thin wrapper
@ -464,10 +467,18 @@ public:
* the full precision and range of the original input, unconstrained by
* the limits of a double floating point or a 64 bit int.
*
* This function is not thread safe, and therfore is not declared const,
* even though it is logically const.
*
* Possible errors include U_MEMORY_ALLOCATION_ERROR, and
* U_INVALID_STATE if the formattable object has not been set to
* a numeric type.
*
* @param status the error code.
* @return the unformatted string representation of a number.
* @draft ICU 4.4
*/
const StringPiece &getDecimalNumber() const;
StringPiece getDecimalNumber(UErrorCode &status);
/**
* Sets the double value of this object and changes the type to
@ -581,12 +592,36 @@ public:
*/
inline int32_t getLong(UErrorCode* status) const;
/**
* Internal function, do not use.
* TODO: figure out how to make this be non-public.
* NumberFormat::format(Formattable, ...
* needs to get at the DigitList, if it exists, for
* big decimal formatting.
* @internal
*/
DigitList *getDigitList() const { return fDecimalNum;};
/**
* Adopt, and set value from, a DigitList
* Internal Function, do not use.
* @param dl the Digit List to be adopted
* @param status reports errors
* @internal
*/
void adoptDigitList(DigitList *dl);
private:
/**
* Cleans up the memory for unwanted values. For example, the adopted
* string or array objects.
*/
void dispose(void);
/**
* Common initialization, for use by constructors.
*/
void init();
UnicodeString* getBogus() const;
@ -602,6 +637,9 @@ private:
} fArrayAndCount;
} fValue;
DecimalNumberString *fDecimalStr;
DigitList *fDecimalNum;
Type fType;
UnicodeString fBogus; // Bogus string when it's needed.
};

View file

@ -471,9 +471,52 @@ public:
UnicodeString& appendTo,
FieldPositionIterator* posIter,
UErrorCode& status) const;
public:
/**
* Format a decimal number.
* The number is a DigitList wrapper onto a floating point decimal number.
* The default implementation in NumberFormat converts the decimal number
* to a double and formats that. Subclasses of NumberFormat that want
* to specifically handle big decimal numbers must override this method.
* class DecimalFormat does so.
*
* @param number The number, a DigitList format Decimal Floating Point.
* @param appendTo Output parameter to receive result.
* Result is appended to existing contents.
* @param posIter On return, can be used to iterate over positions
* of fields generated by this format call.
* @param status Output param filled with success/failure status.
* @return Reference to 'appendTo' parameter.
* @internal
*/
virtual UnicodeString& format(const DigitList &number,
UnicodeString& appendTo,
FieldPositionIterator* posIter,
UErrorCode& status) const;
// TODO: do we also want a format of a decimal number that takes a
// FieldPosition parameter?
/**
* Format a decimal number.
* The number is a DigitList wrapper onto a floating point decimal number.
* The default implementation in NumberFormat converts the decimal number
* to a double and formats that. Subclasses of NumberFormat that want
* to specifically handle big decimal numbers must override this method.
* class DecimalFormat does so.
*
* @param number The number, a DigitList format Decimal Floating Point.
* @param appendTo Output parameter to receive result.
* Result is appended to existing contents.
* @param pos On input: an alignment field, if desired.
* On output: the offsets of the alignment field.
* @param status Output param filled with success/failure status.
* @return Reference to 'appendTo' parameter.
* @internal
*/
virtual UnicodeString& format(const DigitList &number,
UnicodeString& appendTo,
FieldPosition& pos,
UErrorCode& status) const;
public:
/**
* Redeclared Format method.

View file

@ -57,7 +57,7 @@ itrbnf.o itrbnfrt.o itrbnfp.o ucaconf.o icusvtst.o \
uobjtest.o idnaref.o idnaconf.o nptrans.o punyref.o testidn.o testidna.o incaltst.o \
calcasts.o v32test.o uvectest.o textfile.o tokiter.o utxttest.o \
windttst.o winnmtst.o winutil.o csdetest.o tzrulets.o tzoffloc.o tzfmttst.o ssearch.o dtifmtts.o \
tufmtts.o itspoof.o simplethread.o bidiconf.o locnmtst.o
tufmtts.o itspoof.o simplethread.o bidiconf.o locnmtst.o dcfmtest.o
DEPS = $(OBJECTS:.o=.d)

View file

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2009, International Business Machines Corporation and
* Copyright (c) 1997-2010, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@ -487,11 +487,15 @@ void IntlTestDecimalFormatAPI::testRoundingInc(/*char *par*/)
return;
}
// With rounding now being handled by decNumber, we no longer
// set a rounding increment to enable non-default mode rounding,
// checking of which was the original point of this test.
// set rounding mode with zero increment. Rounding
// increment should be set by this operation
// increment should not be set by this operation
pat.setRoundingMode((DecimalFormat::ERoundingMode)0);
roundingInc = pat.getRoundingIncrement();
if (roundingInc == 0.0) {
if (roundingInc != 0.0) {
errln((UnicodeString)"ERROR: Rounding increment zero");
return;
}

View file

@ -0,0 +1,517 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 2002-2010, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
//
// dcfmtest.cpp
//
// Decimal Formatter tests, data driven.
//
#include "intltest.h"
#if !UCONFIG_NO_REGULAR_EXPRESSIONS
#include "unicode/regex.h"
#include "unicode/uchar.h"
#include "unicode/ustring.h"
#include "unicode/unistr.h"
#include "unicode/dcfmtsym.h"
#include "unicode/decimfmt.h"
#include "unicode/locid.h"
#include "cmemory.h"
#include "dcfmtest.h"
#include "util.h"
#include "cstring.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <string>
#include <iostream>
//---------------------------------------------------------------------------
//
// Test class boilerplate
//
//---------------------------------------------------------------------------
DecimalFormatTest::DecimalFormatTest()
{
}
DecimalFormatTest::~DecimalFormatTest()
{
}
void DecimalFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
{
if (exec) logln("TestSuite DecimalFormatTest: ");
switch (index) {
#if !UCONFIG_NO_FILE_IO
case 0: name = "DataDrivenTests";
if (exec) DataDrivenTests();
break;
#else
case 0: name = "skip";
break;
#endif
default: name = "";
break; //needed to end loop
}
}
//---------------------------------------------------------------------------
//
// Error Checking / Reporting macros used in all of the tests.
//
//---------------------------------------------------------------------------
#define DF_CHECK_STATUS {if (U_FAILURE(status)) \
{dataerrln("DecimalFormatTest failure at line %d. status=%s", \
__LINE__, u_errorName(status)); return 0;}}
#define DF_ASSERT(expr) {if ((expr)==FALSE) {errln("DecimalFormatTest failure at line %d.\n", __LINE__);};}
#define DF_ASSERT_FAIL(expr, errcode) {UErrorCode status=U_ZERO_ERROR; (expr);\
if (status!=errcode) {dataerrln("DecimalFormatTest failure at line %d. Expected status=%s, got %s", \
__LINE__, u_errorName(errcode), u_errorName(status));};}
#define DF_CHECK_STATUS_L(line) {if (U_FAILURE(status)) {errln( \
"DecimalFormatTest failure at line %d, from %d. status=%d\n",__LINE__, (line), status); }}
#define DF_ASSERT_L(expr, line) {if ((expr)==FALSE) { \
errln("DecimalFormatTest failure at line %d, from %d.", __LINE__, (line)); return;}}
//
// InvariantStringPiece
// Wrap a StringPiece around the extracted invariant data of a UnicodeString.
// The data is guaranteed to be nul terminated. (This is not true of StringPiece
// in general, but is true of InvariantStringPiece)
//
class InvariantStringPiece: public StringPiece {
public:
InvariantStringPiece(const UnicodeString &s);
~InvariantStringPiece() {};
private:
MaybeStackArray<char, 20> buf;
};
InvariantStringPiece::InvariantStringPiece(const UnicodeString &s) {
int32_t len = s.length();
if (len+1 > buf.getCapacity()) {
buf.resize(len+1);
}
// Buffer size is len+1 so that s.extract() will nul-terminate the string.
s.extract(0, len, buf.getAlias(), len+1, US_INV);
this->set(buf, len);
}
// UnicodeStringPiece
// Wrap a StringPiece around the extracted (to the default charset) data of
// a UnicodeString. The extracted data is guaranteed to be nul terminated.
// (This is not true of StringPiece in general, but is true of UnicodeStringPiece)
//
class UnicodeStringPiece: public StringPiece {
public:
UnicodeStringPiece(const UnicodeString &s);
~UnicodeStringPiece() {};
private:
MaybeStackArray<char, 20> buf;
};
UnicodeStringPiece::UnicodeStringPiece(const UnicodeString &s) {
int32_t len = s.length();
int32_t capacity = buf.getCapacity();
int32_t requiredCapacity = s.extract(0, len, buf.getAlias(), capacity) + 1;
if (capacity < requiredCapacity) {
buf.resize(requiredCapacity);
capacity = requiredCapacity;
s.extract(0, len, buf.getAlias(), capacity);
}
this->set(buf, requiredCapacity - 1);
}
//---------------------------------------------------------------------------
//
// DataDrivenTests
// The test cases are in a separate data file,
//
//---------------------------------------------------------------------------
// Translate a Formattable::type enum value to a string, for error message formatting.
static const char *formattableType(Formattable::Type typ) {
static const char *types[] = {"kDate",
"kDouble",
"kLong",
"kString",
"kArray",
"kInt64",
"kObject"
};
if (typ<0 || typ>Formattable::kObject) {
return "Unknown";
}
return types[typ];
}
const char *
DecimalFormatTest::getPath(char *buffer, const char *filename) {
UErrorCode status=U_ZERO_ERROR;
const char *testDataDirectory = IntlTest::getSourceTestData(status);
DF_CHECK_STATUS;
strcpy(buffer, testDataDirectory);
strcat(buffer, filename);
return buffer;
}
void DecimalFormatTest::DataDrivenTests() {
char tdd[2048];
const char *srcPath;
UErrorCode status = U_ZERO_ERROR;
int32_t lineNum = 0;
//
// Open and read the test data file.
//
srcPath=getPath(tdd, "dcfmtest.txt");
if(srcPath==NULL) {
return; /* something went wrong, error already output */
}
int32_t len;
UChar *testData = ReadAndConvertFile(srcPath, len, status);
if (U_FAILURE(status)) {
return; /* something went wrong, error already output */
}
//
// Put the test data into a UnicodeString
//
UnicodeString testString(FALSE, testData, len);
RegexMatcher parseLineMat(UnicodeString(
"(?i)\\s*parse\\s+"
"\"([^\"]*)\"\\s+" // Capture group 1: input text
"([ild])\\s+" // Capture group 2: expected parsed type
"\"([^\"]*)\"\\s+" // Capture group 3: expected parsed decimal
"\\s*(?:#.*)?"), // Trailing comment
0, status);
RegexMatcher formatLineMat(UnicodeString(
"(?i)\\s*format\\s+"
"(\\S+)\\s+" // Capture group 1: pattern
"(ceiling|floor|down|up|halfeven|halfdown|halfup|default)\\s+" // Capture group 2: Rounding Mode
"\"([^\"]*)\"\\s+" // Capture group 3: input
"\"([^\"]*)\"" // Capture group 4: expected output
"\\s*(?:#.*)?"), // Trailing comment
0, status);
RegexMatcher commentMat (UNICODE_STRING_SIMPLE("\\s*(#.*)?$"), 0, status);
RegexMatcher lineMat(UNICODE_STRING_SIMPLE("(?m)^(.*?)$"), testString, 0, status);
if (U_FAILURE(status)){
dataerrln("Construct RegexMatcher() error.");
delete [] testData;
return;
}
//
// Loop over the test data file, once per line.
//
while (lineMat.find()) {
lineNum++;
if (U_FAILURE(status)) {
errln("File dcfmtest.txt, line %d: ICU Error \"%s\"", lineNum, u_errorName(status));
}
status = U_ZERO_ERROR;
UnicodeString testLine = lineMat.group(1, status);
// printf("%s\n", UnicodeStringPiece(testLine).data());
if (testLine.length() == 0) {
continue;
}
//
// Parse the test line. Skip blank and comment only lines.
// Separate out the three main fields - pattern, flags, target.
//
commentMat.reset(testLine);
if (commentMat.lookingAt(status)) {
// This line is a comment, or blank.
continue;
}
//
// Handle "parse" test case line from file
//
parseLineMat.reset(testLine);
if (parseLineMat.lookingAt(status)) {
execParseTest(lineNum,
parseLineMat.group(1, status), // input
parseLineMat.group(2, status), // Expected Type
parseLineMat.group(3, status), // Expected Decimal String
status
);
continue;
}
//
// Handle "format" test case line
//
formatLineMat.reset(testLine);
if (formatLineMat.lookingAt(status)) {
execFormatTest(lineNum,
formatLineMat.group(1, status), // Pattern
formatLineMat.group(2, status), // rounding mode
formatLineMat.group(3, status), // input decimal number
formatLineMat.group(4, status), // expected formatted result
status);
continue;
}
//
// Line is not a recognizable test case.
//
errln("Badly formed test case at line %d.\n%s\n",
lineNum, UnicodeStringPiece(testLine).data());
}
delete [] testData;
}
void DecimalFormatTest::execParseTest(int32_t lineNum,
const UnicodeString &inputText,
const UnicodeString &expectedType,
const UnicodeString &expectedDecimal,
UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
DecimalFormatSymbols symbols(Locale::getUS(), status);
UnicodeString pattern = UNICODE_STRING_SIMPLE("####");
DecimalFormat format(pattern, symbols, status);
Formattable result;
if (U_FAILURE(status)) {
errln("file dcfmtest.txt, line %d: %s error creating the formatter.",
lineNum, u_errorName(status));
return;
}
ParsePosition pos;
int32_t expectedParseEndPosition = inputText.length();
format.parse(inputText, result, pos);
if (expectedParseEndPosition != pos.getIndex()) {
errln("file dcfmtest.txt, line %d: Expected parse position afeter parsing: %d. "
"Actual parse position: %d", expectedParseEndPosition, pos.getIndex());
return;
}
char expectedTypeC[2];
expectedType.extract(0, 1, expectedTypeC, 2, US_INV);
Formattable::Type expectType = Formattable::kDate;
switch (expectedTypeC[0]) {
case 'd': expectType = Formattable::kDouble; break;
case 'i': expectType = Formattable::kLong; break;
case 'l': expectType = Formattable::kInt64; break;
default:
errln("file dcfmtest.tx, line %d: unrecongized expected type \"%s\"",
lineNum, InvariantStringPiece(expectedType).data());
return;
}
if (result.getType() != expectType) {
errln("file dcfmtest.txt, line %d: expectedParseType(%s) != actual parseType(%s)",
lineNum, formattableType(expectType), formattableType(result.getType()));
return;
}
StringPiece decimalResult = result.getDecimalNumber(status);
if (U_FAILURE(status)) {
errln("File %s, line %d: error %s. Line in file dcfmtest.txt: %d:",
__FILE__, __LINE__, u_errorName(status), lineNum);
return;
}
InvariantStringPiece expectedResults(expectedDecimal);
if (decimalResult != expectedResults) {
errln("file dcfmtest.txt, line %d: expected \"%s\", got \"%s\"",
lineNum, expectedResults.data(), decimalResult.data());
}
return;
}
void DecimalFormatTest::execFormatTest(int32_t lineNum,
const UnicodeString &pattern, // Pattern
const UnicodeString &round, // rounding mode
const UnicodeString &input, // input decimal number
const UnicodeString &expected, // expected formatted result
UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
DecimalFormatSymbols symbols(Locale::getUS(), status);
// printf("Pattern = %s\n", UnicodeStringPiece(pattern).data());
DecimalFormat fmtr(pattern, symbols, status);
if (U_FAILURE(status)) {
errln("file dcfmtest.txt, line %d: %s error creating the formatter.",
lineNum, u_errorName(status));
return;
}
if (round=="ceiling") {
fmtr.setRoundingMode(DecimalFormat::kRoundCeiling);
} else if (round=="floor") {
fmtr.setRoundingMode(DecimalFormat::kRoundFloor);
} else if (round=="down") {
fmtr.setRoundingMode(DecimalFormat::kRoundDown);
} else if (round=="up") {
fmtr.setRoundingMode(DecimalFormat::kRoundUp);
} else if (round=="halfeven") {
fmtr.setRoundingMode(DecimalFormat::kRoundHalfEven);
} else if (round=="halfdown") {
fmtr.setRoundingMode(DecimalFormat::kRoundHalfDown);
} else if (round=="halfup") {
fmtr.setRoundingMode(DecimalFormat::kRoundHalfUp);
} else if (round=="default") {
// don't set any value.
} else {
fmtr.setRoundingMode(DecimalFormat::kRoundFloor);
errln("file dcfmtest.txt, line %d: Bad rounding mode \"%s\"",
lineNum, UnicodeStringPiece(round).data());
}
UnicodeString result;
UnicodeStringPiece spInput(input);
//fmtr.format(spInput, result, NULL, status);
Formattable fmtbl;
fmtbl.setDecimalNumber(spInput, status);
NumberFormat &nfmtr = fmtr;
fmtr.format(fmtbl, result, NULL, status);
if (U_FAILURE(status)) {
errln("file dcfmtest.txt, line %d: format() returned %s.",
lineNum, u_errorName(status));
return;
}
if (result != expected) {
errln("file dcfmtest.txt, line %d: expected \"%s\", got \"%s\"",
lineNum, UnicodeStringPiece(expected).data(), UnicodeStringPiece(result).data());
}
}
//-------------------------------------------------------------------------------
//
// Read a text data file, convert it from UTF-8 to UChars, and return the data
// in one big UChar * buffer, which the caller must delete.
//
// (Lightly modified version of a similar function in regextst.cpp)
//
//--------------------------------------------------------------------------------
UChar *DecimalFormatTest::ReadAndConvertFile(const char *fileName, int32_t &ulen,
UErrorCode &status) {
UChar *retPtr = NULL;
char *fileBuf = NULL;
const char *fileBufNoBOM = NULL;
FILE *f = NULL;
ulen = 0;
if (U_FAILURE(status)) {
return retPtr;
}
//
// Open the file.
//
f = fopen(fileName, "rb");
if (f == 0) {
dataerrln("Error opening test data file %s\n", fileName);
status = U_FILE_ACCESS_ERROR;
return NULL;
}
//
// Read it in
//
int32_t fileSize;
int32_t amtRead;
int32_t amtReadNoBOM;
fseek( f, 0, SEEK_END);
fileSize = ftell(f);
fileBuf = new char[fileSize];
fseek(f, 0, SEEK_SET);
amtRead = fread(fileBuf, 1, fileSize, f);
if (amtRead != fileSize || fileSize <= 0) {
errln("Error reading test data file.");
goto cleanUpAndReturn;
}
//
// Look for a UTF-8 BOM on the data just read.
// The test data file is UTF-8.
// The BOM needs to be there in the source file to keep the Windows &
// EBCDIC machines happy, so force an error if it goes missing.
// Many Linux editors will silently strip it.
//
fileBufNoBOM = fileBuf + 3;
amtReadNoBOM = amtRead - 3;
if (fileSize<3 || uprv_strncmp(fileBuf, "\xEF\xBB\xBF", 3) != 0) {
// TODO: restore this check.
// errln("Test data file %s is missing its BOM", fileName);
fileBufNoBOM = fileBuf;
amtReadNoBOM = amtRead;
}
//
// Find the length of the input in UTF-16 UChars
// (by preflighting the conversion)
//
u_strFromUTF8(NULL, 0, &ulen, fileBufNoBOM, amtReadNoBOM, &status);
//
// Convert file contents from UTF-8 to UTF-16
//
if (status == U_BUFFER_OVERFLOW_ERROR) {
// Buffer Overflow is expected from the preflight operation.
status = U_ZERO_ERROR;
retPtr = new UChar[ulen+1];
u_strFromUTF8(retPtr, ulen+1, NULL, fileBufNoBOM, amtReadNoBOM, &status);
}
cleanUpAndReturn:
fclose(f);
delete[] fileBuf;
if (U_FAILURE(status)) {
errln("ICU Error \"%s\"\n", u_errorName(status));
delete retPtr;
retPtr = NULL;
};
return retPtr;
}
#endif /* !UCONFIG_NO_REGULAR_EXPRESSIONS */

View file

@ -0,0 +1,53 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 2010, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
//
// file: dcfmtest.h
//
// Data driven decimal formatter test.
// Includes testing of both parsing and formatting.
// Tests are in the text file dcfmtest.txt, in the source/test/testdata/ directory.
//
#ifndef DCFMTEST_H
#define DCFMTEST_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_REGULAR_EXPRESSIONS
#include "intltest.h"
class DecimalFormatTest: public IntlTest {
public:
DecimalFormatTest();
virtual ~DecimalFormatTest();
virtual void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL );
// The following are test functions that are visible from the intltest test framework.
virtual void DataDrivenTests();
// The following functions are internal to the decimal format tests.
virtual UChar *ReadAndConvertFile(const char *fileName, int32_t &len, UErrorCode &status);
virtual const char *getPath(char buffer[2048], const char *filename);
virtual void execParseTest(int32_t lineNum,
const UnicodeString &inputText,
const UnicodeString &expectedType,
const UnicodeString &expectedDecimal,
UErrorCode &status);
virtual void execFormatTest(int32_t lineNum,
const UnicodeString &pattern,
const UnicodeString &round,
const UnicodeString &input,
const UnicodeString &expected,
UErrorCode &status);
};
#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
#endif

View file

@ -845,6 +845,14 @@
RelativePath=".\dcfmapts.h"
>
</File>
<File
RelativePath=".\dcfmtest.cpp"
>
</File>
<File
RelativePath=".\dcfmtest.h"
>
</File>
<File
RelativePath=".\dtfmapts.cpp"
>

View file

@ -54,6 +54,7 @@
#include "dtifmtts.h" // DateIntervalFormatTest
#include "tufmtts.h" // TimeUnitTest
#include "locnmtst.h" // LocaleDisplayNamesTest
#include "dcfmtest.h" // DecimalFormatTest
#define TESTCLASS(id, TestClass) \
case id: \
@ -127,6 +128,7 @@ void IntlTestFormat::runIndexedTest( int32_t index, UBool exec, const char* &nam
TESTCLASS(38,TimeUnitTest);
TESTCLASS(39,SelectFormatTest);
TESTCLASS(40,LocaleDisplayNamesTest);
TESTCLASS(41,DecimalFormatTest);
default: name = ""; break; //needed to end loop
}

View file

@ -33,6 +33,7 @@
//#define NUMFMTST_CACHE_DEBUG 1
#include "stdio.h" /* for sprintf */
// #include "iostream" // for cout
//#define NUMFMTST_DEBUG 1
@ -106,6 +107,7 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
CASE(44,TestParseCurrencyInUCurr);
CASE(45,TestFormatAttributes);
CASE(46,TestFieldPositionIterator);
CASE(47,TestDecimal);
default: name = ""; break;
}
}
@ -2570,26 +2572,26 @@ void NumberFormatTest::TestNonpositiveMultiplier() {
expect(df, "1.2", -1.2);
expect(df, "-1.2", 1.2);
// TODO: change all the following int64_t tests once BigInteger is ported
// (right now the big numbers get turned into doubles and lose tons of accuracy)
static const char* posOutOfRange = "9223372036854780000";
static const char* negOutOfRange = "-9223372036854780000";
expect(df, U_INT64_MIN, posOutOfRange);
expect(df, U_INT64_MIN+1, "9223372036854775807");
expect(df, (int64_t)-123, "123");
expect(df, (int64_t)123, "-123");
// Note: the tests with the final parameter of FALSE will not round trip.
// The initial numeric value will format correctly, after the multiplier.
// Parsing the formatted text will be out-of-range for an int64, however.
// The expect() function could be modified to detect this and fall back
// to looking at the decimal parsed value, but it doesn't.
expect(df, U_INT64_MIN, "9223372036854775808", FALSE);
expect(df, U_INT64_MIN+1, "9223372036854775807");
expect(df, (int64_t)-123, "123");
expect(df, (int64_t)123, "-123");
expect(df, U_INT64_MAX-1, "-9223372036854775806");
expect(df, U_INT64_MAX, "-9223372036854775807");
expect(df, U_INT64_MAX, "-9223372036854775807");
df.setMultiplier(-2);
expect(df, -(U_INT64_MIN/2)-1, "-9223372036854775806");
expect(df, -(U_INT64_MIN/2), "-9223372036854775808");
expect(df, -(U_INT64_MIN/2)+1, negOutOfRange);
expect(df, -(U_INT64_MIN/2), "-9223372036854775808");
expect(df, -(U_INT64_MIN/2)+1, "-9223372036854775810", FALSE);
df.setMultiplier(-7);
expect(df, -(U_INT64_MAX/7)-1, posOutOfRange);
expect(df, -(U_INT64_MAX/7), "9223372036854775807");
expect(df, -(U_INT64_MAX/7)-1, "9223372036854775814", FALSE);
expect(df, -(U_INT64_MAX/7), "9223372036854775807");
expect(df, -(U_INT64_MAX/7)+1, "9223372036854775800");
// TODO: uncomment (and fix up) all the following int64_t tests once BigInteger is ported
@ -5964,4 +5966,151 @@ const char* attrString(int32_t attrId) {
}
}
//
// Test formatting & parsing of big decimals.
// API test, not a comprehensive test.
// See DecimalFormatTest/DataDrivenTests
//
#define ASSERT_SUCCESS(status) {if (U_FAILURE(status)) errln("file %s, line %d: status: %s", \
__FILE__, __LINE__, u_errorName(status));}
#define ASSERT_EQUALS(expected, actual) {if ((expected) != (actual)) \
errln("file %s, line %d: %s != %s", __FILE__, __LINE__, #expected, #actual);}
static UBool operator != (const char *s1, UnicodeString &s2) {
// This function lets ASSERT_EQUALS("literal", UnicodeString) work.
UnicodeString us1(s1);
return us1 != s2;
}
void NumberFormatTest::TestDecimal() {
{
UErrorCode status = U_ZERO_ERROR;
Formattable f("12.345678999987654321E666", status);
ASSERT_SUCCESS(status);
StringPiece s = f.getDecimalNumber(status);
ASSERT_SUCCESS(status);
ASSERT_EQUALS("1.2345678999987654321E+667", s);
//printf("%s\n", s.data());
}
{
UErrorCode status = U_ZERO_ERROR;
Formattable f1("this is not a number", status);
ASSERT_EQUALS(U_DECIMAL_NUMBER_SYNTAX_ERROR, status);
}
{
UErrorCode status = U_ZERO_ERROR;
Formattable f;
f.setDecimalNumber("123.45", status);
ASSERT_SUCCESS(status);
ASSERT_EQUALS( Formattable::kDouble, f.getType());
ASSERT_EQUALS(123.45, f.getDouble());
ASSERT_EQUALS(123.45, f.getDouble(status));
ASSERT_SUCCESS(status);
ASSERT_EQUALS("123.45", f.getDecimalNumber(status));
ASSERT_SUCCESS(status);
f.setDecimalNumber("4.5678E7", status);
int32_t n;
n = f.getLong();
ASSERT_EQUALS(45678000, n);
status = U_ZERO_ERROR;
f.setDecimalNumber("-123", status);
ASSERT_SUCCESS(status);
ASSERT_EQUALS( Formattable::kLong, f.getType());
ASSERT_EQUALS(-123, f.getLong());
ASSERT_EQUALS(-123, f.getLong(status));
ASSERT_SUCCESS(status);
ASSERT_EQUALS("-123", f.getDecimalNumber(status));
ASSERT_SUCCESS(status);
status = U_ZERO_ERROR;
f.setDecimalNumber("1234567890123", status); // Number too big for 32 bits
ASSERT_SUCCESS(status);
ASSERT_EQUALS( Formattable::kInt64, f.getType());
ASSERT_EQUALS(1234567890123LL, f.getInt64());
ASSERT_EQUALS(1234567890123LL, f.getInt64(status));
ASSERT_SUCCESS(status);
ASSERT_EQUALS("1234567890123", f.getDecimalNumber(status));
ASSERT_SUCCESS(status);
}
{
UErrorCode status = U_ZERO_ERROR;
NumberFormat *fmtr = NumberFormat::createInstance(
Locale::getUS(), NumberFormat::kNumberStyle, status);
UnicodeString formattedResult;
StringPiece num("244444444444444444444444444444444444446.4");
fmtr->format(num, formattedResult, NULL, status);
ASSERT_SUCCESS(status);
ASSERT_EQUALS("244,444,444,444,444,444,444,444,444,444,444,444,446.4", formattedResult);
//std::string ss; std::cout << formattedResult.toUTF8String(ss);
delete fmtr;
}
{
// Check formatting a DigitList. DigitList is internal, but this is
// a critical interface that must work.
UErrorCode status = U_ZERO_ERROR;
NumberFormat *fmtr = NumberFormat::createInstance(
Locale::getUS(), NumberFormat::kNumberStyle, status);
ASSERT_SUCCESS(status);
UnicodeString formattedResult;
DigitList dl;
StringPiece num("123.4566666666666666666666666666666666621E+40");
dl.set(num, status);
ASSERT_SUCCESS(status);
fmtr->format(dl, formattedResult, NULL, status);
ASSERT_SUCCESS(status);
ASSERT_EQUALS("1,234,566,666,666,666,666,666,666,666,666,666,666,621,000", formattedResult);
status = U_ZERO_ERROR;
num.set("666.666");
dl.set(num, status);
FieldPosition pos(NumberFormat::FRACTION_FIELD);
ASSERT_SUCCESS(status);
formattedResult.remove();
fmtr->format(dl, formattedResult, pos, status);
ASSERT_SUCCESS(status);
ASSERT_EQUALS("666.666", formattedResult);
ASSERT_EQUALS(4, pos.getBeginIndex());
ASSERT_EQUALS(7, pos.getEndIndex());
delete fmtr;
}
{
// Check a parse with a formatter with a multiplier.
UErrorCode status = U_ZERO_ERROR;
NumberFormat *fmtr = NumberFormat::createInstance(
Locale::getUS(), NumberFormat::kPercentStyle, status);
ASSERT_SUCCESS(status);
UnicodeString input = "1.84%";
Formattable result;
fmtr->parse(input, result, status);
ASSERT_SUCCESS(status);
ASSERT_EQUALS(0, strcmp("0.0184", result.getDecimalNumber(status).data()));
//std::cout << result.getDecimalNumber(status).data();
delete fmtr;
}
{
// Check that a parse returns a decimal number with full accuracy
UErrorCode status = U_ZERO_ERROR;
NumberFormat *fmtr = NumberFormat::createInstance(
Locale::getUS(), NumberFormat::kNumberStyle, status);
ASSERT_SUCCESS(status);
UnicodeString input = "1.002200044400088880000070000";
Formattable result;
fmtr->parse(input, result, status);
ASSERT_SUCCESS(status);
ASSERT_EQUALS(0, strcmp("1.00220004440008888000007", result.getDecimalNumber(status).data()));
ASSERT_EQUALS(1.00220004440008888, result.getDouble());
//std::cout << result.getDecimalNumber(status).data();
delete fmtr;
}
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -145,6 +145,8 @@ class NumberFormatTest: public CalendarTimeZoneTest {
void TestFormatAttributes();
void TestFieldPositionIterator();
void TestDecimal();
private:
static UBool equalValue(const Formattable& a, const Formattable& b);

View file

@ -1941,6 +1941,7 @@ void NumberFormatRegressionTest::Test4145457() {
out2 = nf->format(pi, out2, pos);
UnicodeString pat2;
pat2 = nf->toPattern(pat2);
pp.setIndex(0);
nf->parse(out2, num, pp);
double val2 = num.getDouble();

128
icu4c/source/test/testdata/dcfmtest.txt vendored Normal file
View file

@ -0,0 +1,128 @@
# Copyright (c) 2010, International Business Machines Corporation and
# others. All Rights Reserved.
#
# File: dcfmtest.txt
#
# Decimal formatter test cases.
# File Encoding: UTF-8
#
# The syntax for this file is this:
# One test case per line. No continuations. No multiple cases per line.
#
# Parsing Test case line:
# parse "input text" type "expected_decimal_text"
#
# Format Test Case Line:
# format pattern round-mode "decimal number" "expected formatted result"
#
# Fields are separated by spaces or tabs. Input text to be parsed, decimal numbers
# and formatted output are "quoted". Other fields are not.
#
# "type" is a single letter, representing the type that the ICU formattable produces
# for the input.
# d double
# i int32
# l int64
#
# RoundingMode is one of
# default
# ceiling
# floor
# down
# up
# halfeven
# halfdown
# halfup
#
parse "123.45" d "123.45"
format 0.0000E0 default "1234.01" "1.2340E3"
format 00 default "1234" "1234"
format 00 default ".01" "00"
format 00 default "1" "01"
format 00 default "1.9" "02"
format #.# default "12.34" "12.3"
format @@@ default "12.3456" "12.3"
format @@@ default "123456" "123000"
format @@@ default ".00123456" "0.00123"
format @@### default "12345678" "12346000"
format @@### default "12300001" "12300000"
format @@### default ".0012345678" "0.0012346"
format @@### default ".0012300000" "0.00123"
format @@@@E0 default "1234567" "1.235E6"
format 0.0##E0 default "1234567" "1.235E6"
format 00.##E0 default "1234567" "12.35E5"
format 00.##E0 default "1234567E111" "12.35E116"
format 00.##E0 default "-1234567E111" "-12.35E116"
#
# Rounding Modes
#
format 0.00 default "32.045" "32.04"
format 0.00 floor "32.045" "32.04"
format 0.00 ceiling "32.045" "32.05"
format 0.00 down "32.045" "32.04"
format 0.00 up "32.045" "32.05"
format 0.00 halfeven "32.045" "32.04"
format 0.00 halfdown "32.045" "32.04"
format 0.00 halfup "32.045" "32.05"
format 0.00 default "-32.045" "-32.04"
format 0.00 floor "-32.045" "-32.05"
format 0.00 ceiling "-32.045" "-32.04"
format 0.00 down "-32.045" "-32.04"
format 0.00 up "-32.045" "-32.05"
format 0.00 halfeven "-32.045" "-32.04"
format 0.00 halfdown "-32.045" "-32.04"
format 0.00 halfup "-32.045" "-32.05"
format @@@ default "1235.00" "1240"
format @@@ floor "1235.00" "1230"
format @@@ ceiling "1235.00" "1240"
format @@@ down "1235.00" "1230"
format @@@ up "1235.00" "1240"
format @@@ halfeven "1235.00" "1240"
format @@@ halfdown "1235.00" "1230"
format @@@ halfup "1235.00" "1240"
format @@@ default "-1235.00" "-1240"
format @@@ floor "-1235.00" "-1240"
format @@@ ceiling "-1235.00" "-1230"
format @@@ down "-1235.00" "-1230"
format @@@ up "-1235.00" "-1240"
format @@@ halfeven "-1235.00" "-1240"
format @@@ halfdown "-1235.00" "-1230"
format @@@ halfup "-1235.00" "-1240"
format 0.000E0 default "12345" "1.234E4"
format 0.000E0 floor "12345" "1.234E4"
format 0.000E0 ceiling "12345" "1.235E4"
format 0.000E0 down "12345" "1.234E4"
format 0.000E0 up "12345" "1.235E4"
format 0.000E0 halfeven "12345" "1.234E4"
format 0.000E0 halfdown "12345" "1.234E4"
format 0.000E0 halfup "12345" "1.235E4"
format 0.0## default "1.00001" "1.0"
format 0.0## up "1.00001" "1.001"
format 0.0## up "1.0000000000000000000000000000000000000000000000000001" "1.001"
format 0.0## up "1.0000000000000000000000000000000000000000000000000000" "1.0"
format # default "10000000000000000000000000000000000000000000000000001" "10000000000000000000000000000000000000000000000000001"
format 0.#E0 default "1234" "1.2E3"
format 0.##E0 default "1234" "1.23E3"
format .0E0 default "1234" ".1E4"
format .0#E0 default "1234" ".12E4"
format 0.##E0 default "1234" "1.23E3"