ICU-9449 Merge in decimal format performance improvements from branch.

Improvements to 'howExpensiveIs' benchmark test.
Use internal digitlist in Formattable (save mallocs).
Enable fastpath by default.
Enable internal API "parse all input", returning an error if all input was not consumed.

X-SVN-Rev: 32397
This commit is contained in:
Steven R. Loomis 2012-09-17 19:03:01 +00:00
parent f985dceb39
commit 9077d5dc25
12 changed files with 280 additions and 96 deletions

View File

@ -385,19 +385,6 @@
# define UCONFIG_NO_SERVICE 0
#endif
/**
* \def UCONFIG_INTERNAL_DIGITLIST
* This switch turns on the fast but binary-incompatible Formattable class with an internal DigitList
*
* @internal
*/
#ifndef UCONFIG_INTERNAL_DIGITLIST
# define UCONFIG_INTERNAL_DIGITLIST 0
#endif
/**
* \def UCONFIG_HAVE_PARSEALLINPUT
* This switch turns on the "parse all input" attribute. Binary incompatible.
@ -405,7 +392,7 @@
* @internal
*/
#ifndef UCONFIG_HAVE_PARSEALLINPUT
# define UCONFIG_HAVE_PARSEALLINPUT 0
# define UCONFIG_HAVE_PARSEALLINPUT 1
#endif
@ -416,7 +403,7 @@
* @internal
*/
#ifndef UCONFIG_FORMAT_FASTPATHS_49
# define UCONFIG_FORMAT_FASTPATHS_49 0
# define UCONFIG_FORMAT_FASTPATHS_49 1
#endif
#endif

View File

@ -187,9 +187,6 @@ U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2) {
U_CDECL_END
//#define FMT_DEBUG
#ifdef FMT_DEBUG
#include <stdio.h>
static void _debugout(const char *f, int l, const UnicodeString& s) {
@ -1011,9 +1008,12 @@ void DecimalFormat::handleChanged() {
data.fFastpathStatus = kFastpathNO;
if (fGroupingSize!=0) {
debug("No fastpath: fGroupingSize!=0"); // TODO: revisit, should handle ex. up to 999 if groupingsize is 3.
} else if(fGroupingSize2!=0) {
if (fGroupingSize!=0 && isGroupingUsed()) {
debug("No fastpath: fGroupingSize!=0 and grouping is used");
#ifdef FMT_DEBUG
printf("groupingsize=%d\n", fGroupingSize);
#endif
} else if(fGroupingSize2!=0 && isGroupingUsed()) {
debug("No fastpath: fGroupingSize2!=0");
} else if(fUseExponentialNotation) {
debug("No fastpath: fUseExponentialNotation");
@ -1109,7 +1109,7 @@ DecimalFormat::_format(int64_t number,
// Slide the number to the start of the output str
U_ASSERT(destIdx >= 0);
int32_t length = MAX_IDX - destIdx -1;
int32_t prefixLen = appendAffix(appendTo, number, handler, number<0, TRUE);
/*int32_t prefixLen = */ appendAffix(appendTo, number, handler, number<0, TRUE);
int32_t maxIntDig = getMaximumIntegerDigits();
int32_t destlength = length<=maxIntDig?length:maxIntDig; // dest length pinned to max int digits
@ -1129,7 +1129,7 @@ DecimalFormat::_format(int64_t number,
destlength);
handler.addAttribute(kIntegerField, intBegin, appendTo.length());
int32_t suffixLen = appendAffix(appendTo, number, handler, number<0, FALSE);
/*int32_t suffixLen =*/ appendAffix(appendTo, number, handler, number<0, FALSE);
//outputStr[length]=0;
@ -1869,11 +1869,7 @@ void DecimalFormat::parse(const UnicodeString& text,
// status is used to record whether a number is infinite.
UBool status[fgStatusLength];
#if UCONFIG_INTERNAL_DIGITLIST
DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer
#else
DigitList *digits = new DigitList;
#endif
if (digits == NULL) {
return; // no way to report error from here.
}
@ -1881,9 +1877,6 @@ void DecimalFormat::parse(const UnicodeString& text,
if (fCurrencySignCount > fgCurrencySignCountZero) {
if (!parseForCurrency(text, parsePosition, *digits,
status, currency)) {
#if !UCONFIG_INTERNAL_DIGITLIST
delete digits;
#endif
return;
}
} else {
@ -1894,9 +1887,6 @@ void DecimalFormat::parse(const UnicodeString& text,
parsePosition, *digits, status, currency)) {
debug("!subparse(...) - rewind");
parsePosition.setIndex(startIdx);
#if !UCONFIG_INTERNAL_DIGITLIST
delete digits;
#endif
return;
}
}
@ -1905,9 +1895,6 @@ void DecimalFormat::parse(const UnicodeString& text,
if (status[fgStatusInfinite]) {
double inf = uprv_getInfinity();
result.setDouble(digits->isPositive() ? inf : -inf);
#if !UCONFIG_INTERNAL_DIGITLIST
delete digits;
#endif
// TODO: set the dl to infinity, and let it fall into the code below.
}
@ -2100,7 +2087,7 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
DBGAPPD(posPrefix);
DBGAPPD(posSuffix);
debugout(s);
printf("currencyParsing=%d, fFormatWidth=%d, text.length=%d negPrefLen=%d\n", currencyParsing, fFormatWidth, text.length(), negPrefix!=NULL?negPrefix->length():-1);
printf("currencyParsing=%d, fFormatWidth=%d, isParseIntegerOnly=%c text.length=%d negPrefLen=%d\n", currencyParsing, fFormatWidth, (isParseIntegerOnly())?'Y':'N', text.length(), negPrefix!=NULL?negPrefix->length():-1);
#endif
UBool fastParseOk = false; /* TRUE iff fast parse is OK */
@ -2117,7 +2104,7 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
fFormatWidth==0 &&
// (negPrefix!=NULL&&negPrefix->isEmpty()) ||
text.length()>0 &&
text.length()<20 &&
text.length()<32 &&
(posPrefix==NULL||posPrefix->isEmpty()) &&
(posSuffix==NULL||posSuffix->isEmpty()) &&
// (negPrefix==NULL||negPrefix->isEmpty()) &&
@ -2131,9 +2118,11 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
UChar32 ch = text.char32At(j);
const UnicodeString *decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
UChar32 decimalChar = 0;
UBool intOnly = FALSE;
int32_t decimalCount = decimalString->countChar32(0,3);
if(isParseIntegerOnly()) {
decimalChar = 0; // not allowed
intOnly = TRUE;
} else if(decimalCount==1) {
decimalChar = decimalString->char32At(0);
} else if(decimalCount==0) {
@ -2165,6 +2154,8 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
parsedNum.append((char)('.'), err);
decimalChar=0; // no more decimals.
fastParseHadDecimal=TRUE;
} else if(intOnly && !u_isdigit(ch)) {
break; // hit a non-integer. (fall through if integer, to slow parse)
} else {
digitCount=-1; // fail
break;
@ -2172,7 +2163,9 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
j+=U16_LENGTH(ch);
ch = text.char32At(j); // for next
}
if(j==l && (digitCount>0)) {
if(
((j==l)||intOnly)
&& (digitCount>0)) {
#ifdef FMT_DEBUG
printf("PP -> %d, good = [%s] digitcount=%d, fGroupingSize=%d fGroupingSize2=%d!\n", j, parsedNum.data(), digitCount, fGroupingSize, fGroupingSize2);
#endif
@ -2194,6 +2187,15 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
#endif
parsedNum.clear();
}
} else {
#ifdef FMT_DEBUG
printf("Could not fastpath parse. ");
printf("fFormatWidth=%d ", fFormatWidth);
printf("text.length()=%d ", text.length());
printf("posPrefix=%p posSuffix=%p ", posPrefix, posSuffix);
printf("\n");
#endif
}
if(!fastParseOk
@ -2587,7 +2589,13 @@ printf("PP -> %d, SLOW = [%s]! pp=%d, os=%d, err=%s\n", position, parsedNum.d
return FALSE;
}
#endif
digits.set(parsedNum.toStringPiece(), err);
// uint32_t bits = (fastParseOk?kFastpathOk:0) |
// (fastParseHadDecimal?0:kNoDecimal);
//printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits);
digits.set(parsedNum.toStringPiece(),
err,
0//bits
);
if (U_FAILURE(err)) {
#ifdef FMT_DEBUG

View File

@ -732,29 +732,56 @@ DigitList::setInteger(int64_t source)
* be acceptable for a public API.
*/
void
DigitList::set(const StringPiece &source, UErrorCode &status) {
DigitList::set(const StringPiece &source, UErrorCode &status, uint32_t /*fastpathBits*/) {
if (U_FAILURE(status)) {
return;
}
// Figure out a max number of digits to use during the conversion, and
// resize the number up if necessary.
int32_t numDigits = source.length();
if (numDigits > fContext.digits) {
#if 0
if(fastpathBits==(kFastpathOk|kNoDecimal)) {
int32_t size = source.size();
const char *data = source.data();
int64_t r = 0;
int64_t m = 1;
// fast parse
while(size>0) {
char ch = data[--size];
if(ch=='+') {
break;
} else if(ch=='-') {
r = -r;
break;
} else {
int64_t d = ch-'0';
//printf("CH[%d]=%c, %d, *=%d\n", size,ch, (int)d, (int)m);
r+=(d)*m;
m *= 10;
}
}
//printf("R=%d\n", r);
set(r);
} else
#endif
{
// Figure out a max number of digits to use during the conversion, and
// resize the number up if necessary.
int32_t numDigits = source.length();
if (numDigits > fContext.digits) {
// fContext.digits == fStorage.getCapacity()
decNumber *t = fStorage.resize(numDigits, fStorage.getCapacity());
if (t == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
fDecNumber = t;
fContext.digits = numDigits;
}
}
fContext.status = 0;
uprv_decNumberFromString(fDecNumber, source.data(), &fContext);
if ((fContext.status & DEC_Conversion_syntax) != 0) {
fContext.status = 0;
uprv_decNumberFromString(fDecNumber, source.data(), &fContext);
if ((fContext.status & DEC_Conversion_syntax) != 0) {
status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
}
}
internalClear();
}

View File

@ -68,6 +68,8 @@ template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGI
enum EStackMode { kOnStack };
enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 };
/**
* Digit List is actually a Decimal Floating Point number.
* The original implementation has been replaced by a thin wrapper onto a
@ -262,8 +264,9 @@ public:
* 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.
* @param fastpathBits special flags for fast parsing
*/
void set(const StringPiece &source, UErrorCode &status);
void set(const StringPiece &source, UErrorCode &status, uint32_t fastpathBits = 0);
/**
* Multiply this = this * arg

View File

@ -360,16 +360,12 @@ void Formattable::dispose()
delete fDecimalStr;
fDecimalStr = NULL;
#if UCONFIG_INTERNAL_DIGITLIST
FmtStackData *stackData = (FmtStackData*)fStackData;
if(fDecimalNum != &(stackData->stackDecimalNum)) {
delete fDecimalNum;
} else {
fDecimalNum->~DigitList(); // destruct, don't deallocate
}
#else
delete fDecimalNum;
#endif
fDecimalNum = NULL;
}
@ -748,7 +744,6 @@ StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
}
#if UCONFIG_INTERNAL_DIGITLIST
DigitList *
Formattable::getInternalDigitList() {
FmtStackData *stackData = (FmtStackData*)fStackData;
@ -760,7 +755,6 @@ Formattable::getInternalDigitList() {
}
return fDecimalNum;
}
#endif
// ---------------------------------------
void

View File

@ -605,13 +605,10 @@ public:
*/
DigitList *getDigitList() const { return fDecimalNum;}
#if UCONFIG_INTERNAL_DIGITLIST
/**
* @internal
*/
DigitList *getInternalDigitList();
#endif
/**
* Adopt, and set value from, a DigitList
@ -652,9 +649,7 @@ private:
DigitList *fDecimalNum;
#if UCONFIG_INTERNAL_DIGITLIST
char fStackData[128]; // must be big enough for DigitList
#endif
Type fType;
UnicodeString fBogus; // Bogus string when it's needed.

View File

@ -1,5 +1,5 @@
## Makefile.in for ICU - samples/date
## Copyright (c) 1999-2011, International Business Machines Corporation and
## Copyright (c) 1999-2012, International Business Machines Corporation and
## others. All Rights Reserved.
## Source directory information
@ -56,7 +56,7 @@ distclean-local: clean-local
$(RMV) Makefile
check-local:
-$(INVOKE) ./$(TARGET)
-$(INVOKE) ./$(TARGET) $(ICUDATE_OPTS)
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \

View File

@ -1,5 +1,5 @@
## Makefile.in for ICU - test/perf/howExpensiveIs
## Copyright (c) 2001-2011, International Business Machines Corporation and
## Copyright (c) 2001-2012, International Business Machines Corporation and
## others. All Rights Reserved.
## Source directory information

View File

@ -5,11 +5,23 @@
**********************************************************************
*/
#include <stdio.h>
#include <string.h>
#include "sieve.h"
#include "unicode/utimer.h"
#include "udbgutil.h"
#include "unicode/ustring.h"
#include "unicode/decimfmt.h"
#include "unicode/udat.h"
#if U_PLATFORM_IMPLEMENTS_POSIX
#include <unistd.h>
static void usage(const char *prog) {
fprintf(stderr, "Usage: %s [ -f outfile.xml ] [ -t 'TestName' ]\n", prog);
}
#endif
void runTests(void);
#ifndef ITERATIONS
@ -19,8 +31,24 @@ void runTests(void);
FILE *out = NULL;
UErrorCode setupStatus = U_ZERO_ERROR;
const char *outName = NULL;
int listmode = 0;
const char *testName = NULL;
const char *progname = NULL;
int errflg = 0;
int testhit = 0;
int main(int argc, const char* argv[]){
int testMatch(const char *aName) {
if(testName==NULL) return 1;
int len = strlen(testName);
if(testName[len-1]=='*') {
return strncmp(testName,aName,len-1);
} else {
return strcmp(testName,aName);
}
}
int main(int argc, char * const * argv){
#if U_DEBUG
fprintf(stderr,"%s: warning: U_DEBUG is on.\n", argv[0]);
#endif
@ -32,20 +60,67 @@ int main(int argc, const char* argv[]){
}
#endif
#if U_PLATFORM_IMPLEMENTS_POSIX
int c;
extern int optind;
extern char *optarg;
while((c=getopt(argc,argv,"lf:t:")) != EOF) {
switch(c) {
case 'f':
outName = optarg;
break;
case 'l':
listmode++;
break;
case 't':
testName = optarg;
break;
case '?':
errflg++;
}
if(errflg) {
usage(progname);
return 0;
}
}
/* for ( ; optind < argc; optind++) { ... argv[optind] } */
#else
if(argc==2) {
out=fopen(argv[1],"w");
outName = argv[1];
} else if(argc>2) {
fprintf(stderr, "Err: usage: %s [ output-file.xml ]\n", argv[0]);
}
#endif
if(listmode && outName != NULL ) {
fprintf(stderr, "Warning: no output when list mode\n");
outName=NULL;
}
if(outName != NULL) {
out=fopen(outName,"w");
if(out==NULL) {
fprintf(stderr,"Err: can't open %s for writing.\n", argv[1]);
fprintf(stderr,"Err: can't open %s for writing.\n", outName);
return 1;
} else {
fprintf(stderr, "# writing results to %s\n", outName);
}
fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
fprintf(out, "<tests icu=\"%s\">\n", U_ICU_VERSION);
fprintf(out, "<!-- %s -->\n", U_COPYRIGHT_STRING);
} else if(argc>2) {
fprintf(stderr, "Err: usage: %s [ output-file.xml ]\n", argv[0]);
} else {
fprintf(stderr, "# (no output)\n");
}
if(listmode && testName!=NULL) {
fprintf(stderr, "ERR: no -l mode when specific test with -t\n");
usage(progname);
return 1;
}
runTests();
@ -99,7 +174,8 @@ public:
fflush(stderr);
#endif
}
*subTime = uprv_getMeanTime(times,ITERATIONS,marginOfError);
uint32_t iterations = ITERATIONS;
*subTime = uprv_getMeanTime(times,&iterations,marginOfError);
return subIterations;
}
public:
@ -111,7 +187,16 @@ public:
void runTestOn(HowExpensiveTest &t) {
if(U_FAILURE(setupStatus)) return; // silently
fprintf(stderr, "%s:%d: Running: %s\n", t.fFile, t.fLine, t.getName());
const char *tn = t.getName();
if(testName!=NULL && testMatch(tn)) return; // skipped.
if(listmode) {
fprintf(stderr, "%s:%d:\t%s\n", t.fFile, t.fLine, t.getName());
testhit++;
return;
} else {
fprintf(stderr, "%s:%d: Running: %s\n", t.fFile, t.fLine, t.getName());
testhit++;
}
double sieveTime = uprv_getSieveTime(NULL);
double st;
double me;
@ -132,7 +217,7 @@ void runTestOn(HowExpensiveTest &t) {
if(out!=NULL) {
fprintf(out, " <test name=\"%s\" standardizedTime=\"%f\" realDuration=\"%f\" marginOfError=\"%f\" iterations=\"%d\" />\n",
t.getName(),stn,st,me,iter);
tn,stn,st,me,iter);
fflush(out);
}
}
@ -260,6 +345,34 @@ public:
#define DO_AttrNumTest(p,n,x,a,v) { AttrNumTest t(p,n,x,__FILE__,__LINE__,a,v); runTestOn(t); }
class NOXNumTest : public NumTest
{
private:
UNumberFormatAttribute fAttr;
int32_t fAttrValue;
char name2[100];
protected:
virtual const char *getClassName() {
sprintf(name2,"NOXNumTest:%d=%d", fAttr,fAttrValue);
return name2;
}
public:
NOXNumTest(const char *pat, const char *num, double expect, const char *FILE, int LINE /*, UNumberFormatAttribute attr, int32_t newValue */)
: NumTest(pat,num,expect,FILE,LINE) /* ,
fAttr(attr),
fAttrValue(newValue) */
{
}
virtual UNumberFormat* initFmt() {
UNumberFormat *fmt = NumTest::initFmt();
//unum_setAttribute(fmt, fAttr,fAttrValue);
return fmt;
}
};
#define DO_NOXNumTest(p,n,x) { NOXNumTest t(p,n,x,__FILE__,__LINE__); runTestOn(t); }
#define DO_TripleNumTest(p,n,x) DO_AttrNumTest(p,n,x,UNUM_PARSE_ALL_INPUT,UNUM_YES) \
DO_AttrNumTest(p,n,x,UNUM_PARSE_ALL_INPUT,UNUM_NO) \
DO_AttrNumTest(p,n,x,UNUM_PARSE_ALL_INPUT,UNUM_MAYBE)
@ -485,7 +598,7 @@ public:
int32_t run() {
int32_t trial;
int i;
int i=0;
UnicodeString buf;
if(U_SUCCESS(setupStatus)) {
for(i=0;i<U_LOTS_OF_TIMES;i++){
@ -515,10 +628,41 @@ QuickTest(NumParseTest,{ static UChar pattern[] = { 0x23 }; NumParseTest_f
QuickTest(NumParseTestdot,{ static UChar pattern[] = { 0x23 }; NumParseTest_fmt = unum_open(UNUM_PATTERN_DECIMAL, pattern, 1, "en_US", 0, &setupStatus); },{ int32_t i; double val; for(i=0;i<U_LOTS_OF_TIMES;i++) { val=unum_parse(NumParseTest_fmt,strdot,1,NULL,&setupStatus); } return i; },{unum_close(NumParseTest_fmt);})
QuickTest(NumParseTestspc,{ static UChar pattern[] = { 0x23 }; NumParseTest_fmt = unum_open(UNUM_PATTERN_DECIMAL, pattern, 1, "en_US", 0, &setupStatus); },{ int32_t i; double val; for(i=0;i<U_LOTS_OF_TIMES;i++) { val=unum_parse(NumParseTest_fmt,strspc,1,NULL,&setupStatus); } return i; },{unum_close(NumParseTest_fmt);})
QuickTest(NumParseTestgrp,{ static UChar pattern[] = { 0x23 }; NumParseTest_fmt = unum_open(UNUM_PATTERN_DECIMAL, pattern, 1, "en_US", 0, &setupStatus); },{ int32_t i; double val; for(i=0;i<U_LOTS_OF_TIMES;i++) { val=unum_parse(NumParseTest_fmt,strgrp,-1,NULL,&setupStatus); } return i; },{unum_close(NumParseTest_fmt);})
QuickTest(NumParseTestbeng,{ static UChar pattern[] = { 0x23 }; NumParseTest_fmt = unum_open(UNUM_PATTERN_DECIMAL, pattern, 1, "en_US", 0, &setupStatus); },{ int32_t i; double val; for(i=0;i<U_LOTS_OF_TIMES;i++) { val=unum_parse(NumParseTest_fmt,strbeng,-1,NULL,&setupStatus); } return i; },{unum_close(NumParseTest_fmt);})
UDateFormat *DateFormatTest_fmt = NULL;
UDate sometime = 100000000.0;
UChar onekbuf[1024];
const int32_t onekbuf_len = sizeof(onekbuf)/sizeof(onekbuf[0]);
QuickTest(DateFormatTestBasic, \
{ \
DateFormatTest_fmt = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, NULL, NULL, -1, NULL, -1, &setupStatus); \
}, \
{ \
int i; \
for(i=0;i<U_LOTS_OF_TIMES;i++) \
{ \
udat_format(DateFormatTest_fmt, sometime, onekbuf, onekbuf_len, NULL, &setupStatus); \
} \
return i; \
}, \
{ \
udat_close(DateFormatTest_fmt); \
} \
)
QuickTest(NullTest,{},{int j=U_LOTS_OF_TIMES;while(--j);return U_LOTS_OF_TIMES;},{})
#if 0
#include <time.h>
QuickTest(RandomTest,{},{timespec ts; ts.tv_sec=rand()%4; int j=U_LOTS_OF_TIMES;while(--j) { ts.tv_nsec=100000+(rand()%10000)*1000000; nanosleep(&ts,NULL); return j;} return U_LOTS_OF_TIMES;},{})
#endif
OpenCloseTest(pattern,unum,open,{},(UNUM_PATTERN_DECIMAL,pattern,1,"en_US",0,&setupStatus),{})
OpenCloseTest(default,unum,open,{},(UNUM_DEFAULT,NULL,-1,"en_US",0,&setupStatus),{})
#if !UCONFIG_NO_CONVERSION
@ -533,11 +677,24 @@ void runTests() {
SieveTest t;
runTestOn(t);
}
#if 0
{
RandomTest t;
runTestOn(t);
}
#endif
{
NullTest t;
runTestOn(t);
}
#ifndef SKIP_DATEFMT_TESTS
{
DateFormatTestBasic t;
runTestOn(t);
}
#endif
#ifndef SKIP_NUMPARSE_TESTS
{
// parse tests
@ -548,8 +705,8 @@ void runTests() {
DO_NumTest("#","-2 ",-2);
DO_NumTest("+#","+2",2);
DO_NumTest("#,###.0","2222.0",2222.0);
DO_NumTest("#.0","1.000000000000000000000000000000000000000000000000000000000000000000000000000000",1.0);
DO_NumTest("#","123456",123456);
// attr
#ifdef HAVE_UNUM_MAYBE
@ -567,7 +724,6 @@ void runTests() {
}
#endif
#ifndef SKIP_NUMFORMAT_TESTS
// format tests
{
@ -587,7 +743,6 @@ void runTests() {
DO_NumFmtStringPieceTest("#.0000","123.4560",spPI);
DO_NumFmtStringPieceTest("#.00","123.46",spPI);
#if 1
DO_NumFmtTest("#","0",0.0);
DO_NumFmtTest("#","12345",12345);
DO_NumFmtTest("#","-2",-2);
@ -600,24 +755,31 @@ void runTests() {
DO_NumFmtInt64Test("#","-2",-2);
DO_NumFmtInt64Test("+#","+2",2);
}
#endif
#ifndef SKIP_NUM_OPEN_TEST
{
Test_unum_opendefault t;
runTestOn(t);
}
{
Test_unum_openpattern t;
runTestOn(t);
}
#endif
#endif /* skip numformat tests */
#if !UCONFIG_NO_CONVERSION
{
Test_ucnv_opengb18030 t;
runTestOn(t);
}
#endif
{
Test_unum_openpattern t;
runTestOn(t);
}
{
Test_ures_openroot t;
runTestOn(t);
}
if(testhit==0) {
fprintf(stderr, "ERROR: no tests matched.\n");
}
}

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2011,International Business Machines
* Copyright (c) 2011-2012,International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
*/
@ -108,9 +108,9 @@ double qs(double *times, int n, double *q1, double *q2, double *q3) {
return *q3-*q1;
}
U_CAPI double uprv_getMeanTime(double *times, uint32_t timeCount, double *marginOfError) {
U_CAPI double uprv_getMeanTime(double *times, uint32_t *timeCount, double *marginOfError) {
double q1,q2,q3;
int n = timeCount;
int n = *timeCount;
/* calculate medians */
qsort(times,n,sizeof(times[0]),comdoub);
@ -126,18 +126,23 @@ U_CAPI double uprv_getMeanTime(double *times, uint32_t timeCount, double *margin
for(int i=0;i<newN;i++) {
if(times[i]<rangeMin || times[i]>rangeMax) {
#if U_DEBUG
printf("Knocking out: %.9f from [%.9f:%.9f]\n", times[i], rangeMin, rangeMax);
printf("Removing outlier: %.9f outside [%.9f:%.9f]\n", times[i], rangeMin, rangeMax);
#endif
times[i--] = times[--newN]; // bring down a new value
}
}
#if U_DEBUG
UBool didRemove = false;
#endif
/* if we removed any outliers, recalculate iqr */
if(newN<n) {
#if U_DEBUG
printf("Kicked out %d, retrying..\n", n-newN);
didRemove = true;
printf("removed %d outlier(s), recalculating IQR..\n", n-newN);
#endif
n = newN;
*timeCount = n;
qsort(times,n,sizeof(times[0]),comdoub);
double iqr = qs(times,n,&q1,&q2,&q3);
@ -160,11 +165,13 @@ U_CAPI double uprv_getMeanTime(double *times, uint32_t timeCount, double *margin
double sd = 0;
for(int i=0;i<n;i++) {
#if U_DEBUG
printf(" %d: %.9f\n", i, times[i]);
if(didRemove) {
printf("recalc %d/%d: %.9f\n", i, n, times[i]);
}
#endif
sd += (times[i]-meanTime)*(times[i]-meanTime);
}
sd = sqrt(sd/(n-1));
sd = sqrt(sd/((double)n-1.0));
#if U_DEBUG
printf("sd: %.9f, mean: %.9f\n", sd, meanTime);
@ -173,7 +180,7 @@ U_CAPI double uprv_getMeanTime(double *times, uint32_t timeCount, double *margin
#endif
/* 1.960 = z sub 0.025 */
*marginOfError = 1.960 * (sd/sqrt(n));
*marginOfError = 1.960 * (sd/sqrt((double)n));
/*printf("Margin of Error = %.4f (95%% confidence)\n", me);*/
return meanTime;
@ -186,16 +193,17 @@ double meanSieveME = 0.0;
U_CAPI double uprv_getSieveTime(double *marginOfError) {
if(calcSieveTime==FALSE) {
#define SAMPLES 50
uint32_t samples = SAMPLES;
double times[SAMPLES];
for(int i=0;i<SAMPLES;i++) {
times[i] = uprv_calcSieveTime();
#if U_DEBUG
printf("#%d/%d: %.9f\n", i,SAMPLES, times[i]);
printf("sieve: %d/%d: %.9f\n", i,SAMPLES, times[i]);
#endif
}
meanSieveTime = uprv_getMeanTime(times, SAMPLES,&meanSieveME);
meanSieveTime = uprv_getMeanTime(times, &samples,&meanSieveME);
calcSieveTime=TRUE;
}
if(marginOfError!=NULL) {

View File

@ -21,11 +21,11 @@ U_INTERNAL double uprv_calcSieveTime(void);
/**
* Calculate the mean time, with margin of error
* @param times array of times (modified/sorted)
* @param timeCount length of array
* @param timeCount length of array - on return, how many remain after throwing out outliers
* @param marginOfError out parameter: gives +/- margin of err at 95% confidence
* @return the mean time, or negative if error/imprecision.
*/
U_INTERNAL double uprv_getMeanTime(double *times, uint32_t timeCount, double *marginOfError);
U_INTERNAL double uprv_getMeanTime(double *times, uint32_t *timeCount, double *marginOfError);
/**
* Get the standardized sieve time. (Doesn't recalculate if already computed.

View File

@ -524,7 +524,7 @@ static const USystemParams systemParams[] = {
#if defined (CYGWINMSVC)
{ "build.cygwinmsvc", paramInteger, "b", 1},
#endif
{ "uconfig.internal_digitlist", paramInteger, "b", UCONFIG_INTERNAL_DIGITLIST},
{ "uconfig.internal_digitlist", paramInteger, "b", 1}, /* always 1 */
{ "uconfig.have_parseallinput", paramInteger, "b", UCONFIG_HAVE_PARSEALLINPUT},
{ "uconfig.format_fastpaths_49",paramInteger, "b", UCONFIG_FORMAT_FASTPATHS_49},