1*0e209d39SAndroid Build Coastguard Worker // © 2016 and later: Unicode, Inc. and others.
2*0e209d39SAndroid Build Coastguard Worker // License & terms of use: http://www.unicode.org/copyright.html
3*0e209d39SAndroid Build Coastguard Worker /***********************************************************************
4*0e209d39SAndroid Build Coastguard Worker * COPYRIGHT:
5*0e209d39SAndroid Build Coastguard Worker * Copyright (c) 1997-2015, International Business Machines Corporation
6*0e209d39SAndroid Build Coastguard Worker * and others. All Rights Reserved.
7*0e209d39SAndroid Build Coastguard Worker ***********************************************************************/
8*0e209d39SAndroid Build Coastguard Worker
9*0e209d39SAndroid Build Coastguard Worker #include "unicode/utypes.h"
10*0e209d39SAndroid Build Coastguard Worker
11*0e209d39SAndroid Build Coastguard Worker #if !UCONFIG_NO_FORMATTING
12*0e209d39SAndroid Build Coastguard Worker
13*0e209d39SAndroid Build Coastguard Worker #include "nmfmtrt.h"
14*0e209d39SAndroid Build Coastguard Worker
15*0e209d39SAndroid Build Coastguard Worker #include "unicode/dcfmtsym.h"
16*0e209d39SAndroid Build Coastguard Worker #include "unicode/decimfmt.h"
17*0e209d39SAndroid Build Coastguard Worker #include "unicode/locid.h"
18*0e209d39SAndroid Build Coastguard Worker #include "putilimp.h"
19*0e209d39SAndroid Build Coastguard Worker #include "cstring.h"
20*0e209d39SAndroid Build Coastguard Worker
21*0e209d39SAndroid Build Coastguard Worker #include <float.h>
22*0e209d39SAndroid Build Coastguard Worker #include <stdio.h> // for snprintf
23*0e209d39SAndroid Build Coastguard Worker #include <stdlib.h>
24*0e209d39SAndroid Build Coastguard Worker
25*0e209d39SAndroid Build Coastguard Worker // *****************************************************************************
26*0e209d39SAndroid Build Coastguard Worker // class NumberFormatRoundTripTest
27*0e209d39SAndroid Build Coastguard Worker // *****************************************************************************
28*0e209d39SAndroid Build Coastguard Worker
29*0e209d39SAndroid Build Coastguard Worker UBool NumberFormatRoundTripTest::verbose = false;
30*0e209d39SAndroid Build Coastguard Worker UBool NumberFormatRoundTripTest::STRING_COMPARE = true;
31*0e209d39SAndroid Build Coastguard Worker UBool NumberFormatRoundTripTest::EXACT_NUMERIC_COMPARE = false;
32*0e209d39SAndroid Build Coastguard Worker UBool NumberFormatRoundTripTest::DEBUG_VAR = false;
33*0e209d39SAndroid Build Coastguard Worker double NumberFormatRoundTripTest::MAX_ERROR = 1e-14;
34*0e209d39SAndroid Build Coastguard Worker double NumberFormatRoundTripTest::max_numeric_error = 0.0;
35*0e209d39SAndroid Build Coastguard Worker double NumberFormatRoundTripTest::min_numeric_error = 1.0;
36*0e209d39SAndroid Build Coastguard Worker
37*0e209d39SAndroid Build Coastguard Worker #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
38*0e209d39SAndroid Build Coastguard Worker
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)39*0e209d39SAndroid Build Coastguard Worker void NumberFormatRoundTripTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
40*0e209d39SAndroid Build Coastguard Worker {
41*0e209d39SAndroid Build Coastguard Worker // if (exec) logln((UnicodeString)"TestSuite NumberFormatRoundTripTest");
42*0e209d39SAndroid Build Coastguard Worker switch (index) {
43*0e209d39SAndroid Build Coastguard Worker CASE(0, start)
44*0e209d39SAndroid Build Coastguard Worker default: name = ""; break;
45*0e209d39SAndroid Build Coastguard Worker }
46*0e209d39SAndroid Build Coastguard Worker }
47*0e209d39SAndroid Build Coastguard Worker
48*0e209d39SAndroid Build Coastguard Worker UBool
failure(UErrorCode status,const char * msg,UBool possibleDataError)49*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::failure(UErrorCode status, const char* msg, UBool possibleDataError)
50*0e209d39SAndroid Build Coastguard Worker {
51*0e209d39SAndroid Build Coastguard Worker if(U_FAILURE(status)) {
52*0e209d39SAndroid Build Coastguard Worker if (possibleDataError) {
53*0e209d39SAndroid Build Coastguard Worker dataerrln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
54*0e209d39SAndroid Build Coastguard Worker } else {
55*0e209d39SAndroid Build Coastguard Worker errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
56*0e209d39SAndroid Build Coastguard Worker }
57*0e209d39SAndroid Build Coastguard Worker return true;
58*0e209d39SAndroid Build Coastguard Worker }
59*0e209d39SAndroid Build Coastguard Worker
60*0e209d39SAndroid Build Coastguard Worker return false;
61*0e209d39SAndroid Build Coastguard Worker }
62*0e209d39SAndroid Build Coastguard Worker
63*0e209d39SAndroid Build Coastguard Worker uint32_t
randLong()64*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::randLong()
65*0e209d39SAndroid Build Coastguard Worker {
66*0e209d39SAndroid Build Coastguard Worker // Assume 8-bit (or larger) rand values. Also assume
67*0e209d39SAndroid Build Coastguard Worker // that the system rand() function is very poor, which it always is.
68*0e209d39SAndroid Build Coastguard Worker uint32_t d;
69*0e209d39SAndroid Build Coastguard Worker uint32_t i;
70*0e209d39SAndroid Build Coastguard Worker char* poke = (char*)&d;
71*0e209d39SAndroid Build Coastguard Worker for (i=0; i < sizeof(uint32_t); ++i)
72*0e209d39SAndroid Build Coastguard Worker {
73*0e209d39SAndroid Build Coastguard Worker poke[i] = (char)(rand() & 0xFF);
74*0e209d39SAndroid Build Coastguard Worker }
75*0e209d39SAndroid Build Coastguard Worker return d;
76*0e209d39SAndroid Build Coastguard Worker }
77*0e209d39SAndroid Build Coastguard Worker
78*0e209d39SAndroid Build Coastguard Worker /**
79*0e209d39SAndroid Build Coastguard Worker * Return a random value from -range..+range.
80*0e209d39SAndroid Build Coastguard Worker */
81*0e209d39SAndroid Build Coastguard Worker double
randomDouble(double range)82*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::randomDouble(double range)
83*0e209d39SAndroid Build Coastguard Worker {
84*0e209d39SAndroid Build Coastguard Worker double a = randFraction();
85*0e209d39SAndroid Build Coastguard Worker return (2.0 * range * a) - range;
86*0e209d39SAndroid Build Coastguard Worker }
87*0e209d39SAndroid Build Coastguard Worker
88*0e209d39SAndroid Build Coastguard Worker void
start()89*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::start()
90*0e209d39SAndroid Build Coastguard Worker {
91*0e209d39SAndroid Build Coastguard Worker // test(NumberFormat.getInstance(new Locale("sr", "", "")));
92*0e209d39SAndroid Build Coastguard Worker
93*0e209d39SAndroid Build Coastguard Worker UErrorCode status = U_ZERO_ERROR;
94*0e209d39SAndroid Build Coastguard Worker
95*0e209d39SAndroid Build Coastguard Worker NumberFormat *fmt = nullptr;
96*0e209d39SAndroid Build Coastguard Worker
97*0e209d39SAndroid Build Coastguard Worker logln("Default Locale");
98*0e209d39SAndroid Build Coastguard Worker
99*0e209d39SAndroid Build Coastguard Worker fmt = NumberFormat::createInstance(status);
100*0e209d39SAndroid Build Coastguard Worker if (!failure(status, "NumberFormat::createInstance", true)){
101*0e209d39SAndroid Build Coastguard Worker test(fmt);
102*0e209d39SAndroid Build Coastguard Worker }
103*0e209d39SAndroid Build Coastguard Worker delete fmt;
104*0e209d39SAndroid Build Coastguard Worker
105*0e209d39SAndroid Build Coastguard Worker fmt = NumberFormat::createCurrencyInstance(status);
106*0e209d39SAndroid Build Coastguard Worker if (!failure(status, "NumberFormat::createCurrencyInstance", true)){
107*0e209d39SAndroid Build Coastguard Worker test(fmt);
108*0e209d39SAndroid Build Coastguard Worker }
109*0e209d39SAndroid Build Coastguard Worker delete fmt;
110*0e209d39SAndroid Build Coastguard Worker
111*0e209d39SAndroid Build Coastguard Worker fmt = NumberFormat::createPercentInstance(status);
112*0e209d39SAndroid Build Coastguard Worker if (!failure(status, "NumberFormat::createPercentInstance", true)){
113*0e209d39SAndroid Build Coastguard Worker test(fmt);
114*0e209d39SAndroid Build Coastguard Worker }
115*0e209d39SAndroid Build Coastguard Worker delete fmt;
116*0e209d39SAndroid Build Coastguard Worker
117*0e209d39SAndroid Build Coastguard Worker
118*0e209d39SAndroid Build Coastguard Worker int32_t locCount = 0;
119*0e209d39SAndroid Build Coastguard Worker const Locale *loc = NumberFormat::getAvailableLocales(locCount);
120*0e209d39SAndroid Build Coastguard Worker if(quick) {
121*0e209d39SAndroid Build Coastguard Worker if(locCount > 5)
122*0e209d39SAndroid Build Coastguard Worker locCount = 5;
123*0e209d39SAndroid Build Coastguard Worker logln("Quick mode: only testing first 5 Locales");
124*0e209d39SAndroid Build Coastguard Worker }
125*0e209d39SAndroid Build Coastguard Worker for(int i = 0; i < locCount; ++i) {
126*0e209d39SAndroid Build Coastguard Worker UnicodeString name;
127*0e209d39SAndroid Build Coastguard Worker logln(loc[i].getDisplayName(name));
128*0e209d39SAndroid Build Coastguard Worker
129*0e209d39SAndroid Build Coastguard Worker fmt = NumberFormat::createInstance(loc[i], status);
130*0e209d39SAndroid Build Coastguard Worker failure(status, "NumberFormat::createInstance");
131*0e209d39SAndroid Build Coastguard Worker test(fmt);
132*0e209d39SAndroid Build Coastguard Worker delete fmt;
133*0e209d39SAndroid Build Coastguard Worker
134*0e209d39SAndroid Build Coastguard Worker fmt = NumberFormat::createCurrencyInstance(loc[i], status);
135*0e209d39SAndroid Build Coastguard Worker failure(status, "NumberFormat::createCurrencyInstance");
136*0e209d39SAndroid Build Coastguard Worker test(fmt);
137*0e209d39SAndroid Build Coastguard Worker delete fmt;
138*0e209d39SAndroid Build Coastguard Worker
139*0e209d39SAndroid Build Coastguard Worker fmt = NumberFormat::createPercentInstance(loc[i], status);
140*0e209d39SAndroid Build Coastguard Worker failure(status, "NumberFormat::createPercentInstance");
141*0e209d39SAndroid Build Coastguard Worker test(fmt);
142*0e209d39SAndroid Build Coastguard Worker delete fmt;
143*0e209d39SAndroid Build Coastguard Worker }
144*0e209d39SAndroid Build Coastguard Worker
145*0e209d39SAndroid Build Coastguard Worker logln(UnicodeString("Numeric error ") + min_numeric_error + " to " + max_numeric_error);
146*0e209d39SAndroid Build Coastguard Worker }
147*0e209d39SAndroid Build Coastguard Worker
148*0e209d39SAndroid Build Coastguard Worker
149*0e209d39SAndroid Build Coastguard Worker void
test(NumberFormat * fmt)150*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::test(NumberFormat *fmt)
151*0e209d39SAndroid Build Coastguard Worker {
152*0e209d39SAndroid Build Coastguard Worker #if IEEE_754 && U_PLATFORM != U_PF_OS400
153*0e209d39SAndroid Build Coastguard Worker test(fmt, uprv_getNaN());
154*0e209d39SAndroid Build Coastguard Worker test(fmt, uprv_getInfinity());
155*0e209d39SAndroid Build Coastguard Worker test(fmt, -uprv_getInfinity());
156*0e209d39SAndroid Build Coastguard Worker #endif
157*0e209d39SAndroid Build Coastguard Worker
158*0e209d39SAndroid Build Coastguard Worker test(fmt, (int32_t)500);
159*0e209d39SAndroid Build Coastguard Worker test(fmt, (int32_t)0);
160*0e209d39SAndroid Build Coastguard Worker test(fmt, (int32_t)-0);
161*0e209d39SAndroid Build Coastguard Worker test(fmt, 0.0);
162*0e209d39SAndroid Build Coastguard Worker double negZero = 0.0; negZero /= -1.0;
163*0e209d39SAndroid Build Coastguard Worker test(fmt, negZero);
164*0e209d39SAndroid Build Coastguard Worker test(fmt, 9223372036854775808.0);
165*0e209d39SAndroid Build Coastguard Worker test(fmt, -9223372036854775809.0);
166*0e209d39SAndroid Build Coastguard Worker
167*0e209d39SAndroid Build Coastguard Worker for(int i = 0; i < 10; ++i) {
168*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1));
169*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(10000));
170*0e209d39SAndroid Build Coastguard Worker test(fmt, uprv_floor((randomDouble(10000))));
171*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e50));
172*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e-50));
173*0e209d39SAndroid Build Coastguard Worker #if !(U_PF_OS390 <= U_PLATFORM && U_PLATFORM <= U_PF_OS400)
174*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e100));
175*0e209d39SAndroid Build Coastguard Worker #elif IEEE_754
176*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e75));
177*0e209d39SAndroid Build Coastguard Worker #endif /* OS390 and OS400 */
178*0e209d39SAndroid Build Coastguard Worker // {sfb} When formatting with a percent instance, numbers very close to
179*0e209d39SAndroid Build Coastguard Worker // DBL_MAX will fail the round trip. This is because:
180*0e209d39SAndroid Build Coastguard Worker // 1) Format the double into a string --> INF% (since 100 * double > DBL_MAX)
181*0e209d39SAndroid Build Coastguard Worker // 2) Parse the string into a double --> INF
182*0e209d39SAndroid Build Coastguard Worker // 3) Re-format the double --> INF%
183*0e209d39SAndroid Build Coastguard Worker // 4) The strings are equal, so that works.
184*0e209d39SAndroid Build Coastguard Worker // 5) Calculate the proportional error --> INF, so the test will fail
185*0e209d39SAndroid Build Coastguard Worker // I'll get around this by dividing by the multiplier to make sure
186*0e209d39SAndroid Build Coastguard Worker // the double will stay in range.
187*0e209d39SAndroid Build Coastguard Worker //if(fmt->getMultipler() == 1)
188*0e209d39SAndroid Build Coastguard Worker DecimalFormat *df = dynamic_cast<DecimalFormat *>(fmt);
189*0e209d39SAndroid Build Coastguard Worker if(df != nullptr)
190*0e209d39SAndroid Build Coastguard Worker {
191*0e209d39SAndroid Build Coastguard Worker #if !(U_PF_OS390 <= U_PLATFORM && U_PLATFORM <= U_PF_OS400)
192*0e209d39SAndroid Build Coastguard Worker /* DBL_MAX/2 is here because randomDouble does a *2 in the math */
193*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(DBL_MAX/2.0) / df->getMultiplier());
194*0e209d39SAndroid Build Coastguard Worker #elif IEEE_754
195*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e75) / df->getMultiplier());
196*0e209d39SAndroid Build Coastguard Worker #else
197*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e65) / df->getMultiplier());
198*0e209d39SAndroid Build Coastguard Worker #endif
199*0e209d39SAndroid Build Coastguard Worker }
200*0e209d39SAndroid Build Coastguard Worker
201*0e209d39SAndroid Build Coastguard Worker #if (defined(_MSC_VER) && _MSC_VER < 1400) || defined(__alpha__) || defined(U_OSF)
202*0e209d39SAndroid Build Coastguard Worker // These machines and compilers don't fully support denormalized doubles,
203*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e-292));
204*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e-100));
205*0e209d39SAndroid Build Coastguard Worker #elif U_PF_OS390 <= U_PLATFORM && U_PLATFORM <= U_PF_OS400
206*0e209d39SAndroid Build Coastguard Worker // i5/OS (OS/400) throws exceptions on denormalized numbers
207*0e209d39SAndroid Build Coastguard Worker # if IEEE_754
208*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e-78));
209*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e-78));
210*0e209d39SAndroid Build Coastguard Worker // #else we're using something like the old z/OS floating point.
211*0e209d39SAndroid Build Coastguard Worker # endif
212*0e209d39SAndroid Build Coastguard Worker #else
213*0e209d39SAndroid Build Coastguard Worker // This is a normal machine that can support IEEE754 denormalized doubles without throwing an error.
214*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(DBL_MIN)); /* Usually 2.2250738585072014e-308 */
215*0e209d39SAndroid Build Coastguard Worker test(fmt, randomDouble(1e-100));
216*0e209d39SAndroid Build Coastguard Worker #endif
217*0e209d39SAndroid Build Coastguard Worker }
218*0e209d39SAndroid Build Coastguard Worker }
219*0e209d39SAndroid Build Coastguard Worker
220*0e209d39SAndroid Build Coastguard Worker void
test(NumberFormat * fmt,double value)221*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::test(NumberFormat *fmt, double value)
222*0e209d39SAndroid Build Coastguard Worker {
223*0e209d39SAndroid Build Coastguard Worker test(fmt, Formattable(value));
224*0e209d39SAndroid Build Coastguard Worker }
225*0e209d39SAndroid Build Coastguard Worker
226*0e209d39SAndroid Build Coastguard Worker void
test(NumberFormat * fmt,int32_t value)227*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::test(NumberFormat *fmt, int32_t value)
228*0e209d39SAndroid Build Coastguard Worker {
229*0e209d39SAndroid Build Coastguard Worker test(fmt, Formattable(value));
230*0e209d39SAndroid Build Coastguard Worker }
231*0e209d39SAndroid Build Coastguard Worker
232*0e209d39SAndroid Build Coastguard Worker void
test(NumberFormat * fmt,const Formattable & value)233*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::test(NumberFormat *fmt, const Formattable& value)
234*0e209d39SAndroid Build Coastguard Worker {
235*0e209d39SAndroid Build Coastguard Worker fmt->setMaximumFractionDigits(999);
236*0e209d39SAndroid Build Coastguard Worker DecimalFormat *df = dynamic_cast<DecimalFormat *>(fmt);
237*0e209d39SAndroid Build Coastguard Worker if(df != nullptr) {
238*0e209d39SAndroid Build Coastguard Worker df->setRoundingIncrement(0.0);
239*0e209d39SAndroid Build Coastguard Worker }
240*0e209d39SAndroid Build Coastguard Worker UErrorCode status = U_ZERO_ERROR;
241*0e209d39SAndroid Build Coastguard Worker UnicodeString s, s2, temp;
242*0e209d39SAndroid Build Coastguard Worker if(isDouble(value))
243*0e209d39SAndroid Build Coastguard Worker s = fmt->format(value.getDouble(), s);
244*0e209d39SAndroid Build Coastguard Worker else
245*0e209d39SAndroid Build Coastguard Worker s = fmt->format(value.getLong(), s);
246*0e209d39SAndroid Build Coastguard Worker
247*0e209d39SAndroid Build Coastguard Worker Formattable n;
248*0e209d39SAndroid Build Coastguard Worker UBool show = verbose;
249*0e209d39SAndroid Build Coastguard Worker if(DEBUG_VAR)
250*0e209d39SAndroid Build Coastguard Worker logln(/*value.getString(temp) +*/ " F> " + escape(s));
251*0e209d39SAndroid Build Coastguard Worker
252*0e209d39SAndroid Build Coastguard Worker fmt->parse(s, n, status);
253*0e209d39SAndroid Build Coastguard Worker if(U_FAILURE(status)) {
254*0e209d39SAndroid Build Coastguard Worker UErrorCode infoStatus = U_ZERO_ERROR;
255*0e209d39SAndroid Build Coastguard Worker const char* localeID = fmt->getLocaleID(ULOC_ACTUAL_LOCALE, infoStatus);
256*0e209d39SAndroid Build Coastguard Worker localeID = (U_SUCCESS(infoStatus) && localeID)? localeID: "?";
257*0e209d39SAndroid Build Coastguard Worker errln(UnicodeString("FAIL: fmt->parse failed, locale: ") + localeID + ", error: " + u_errorName(status));
258*0e209d39SAndroid Build Coastguard Worker }
259*0e209d39SAndroid Build Coastguard Worker if(DEBUG_VAR)
260*0e209d39SAndroid Build Coastguard Worker logln(escape(s) + " P> " /*+ n.getString(temp)*/);
261*0e209d39SAndroid Build Coastguard Worker
262*0e209d39SAndroid Build Coastguard Worker if(isDouble(n))
263*0e209d39SAndroid Build Coastguard Worker s2 = fmt->format(n.getDouble(), s2);
264*0e209d39SAndroid Build Coastguard Worker else
265*0e209d39SAndroid Build Coastguard Worker s2 = fmt->format(n.getLong(), s2);
266*0e209d39SAndroid Build Coastguard Worker
267*0e209d39SAndroid Build Coastguard Worker if(DEBUG_VAR)
268*0e209d39SAndroid Build Coastguard Worker logln(/*n.getString(temp) +*/ " F> " + escape(s2));
269*0e209d39SAndroid Build Coastguard Worker
270*0e209d39SAndroid Build Coastguard Worker if(STRING_COMPARE) {
271*0e209d39SAndroid Build Coastguard Worker if (s != s2) {
272*0e209d39SAndroid Build Coastguard Worker errln("*** STRING ERROR \"" + escape(s) + "\" != \"" + escape(s2) + "\"");
273*0e209d39SAndroid Build Coastguard Worker show = true;
274*0e209d39SAndroid Build Coastguard Worker }
275*0e209d39SAndroid Build Coastguard Worker }
276*0e209d39SAndroid Build Coastguard Worker
277*0e209d39SAndroid Build Coastguard Worker if(EXACT_NUMERIC_COMPARE) {
278*0e209d39SAndroid Build Coastguard Worker if(value != n) {
279*0e209d39SAndroid Build Coastguard Worker errln("*** NUMERIC ERROR");
280*0e209d39SAndroid Build Coastguard Worker show = true;
281*0e209d39SAndroid Build Coastguard Worker }
282*0e209d39SAndroid Build Coastguard Worker }
283*0e209d39SAndroid Build Coastguard Worker else {
284*0e209d39SAndroid Build Coastguard Worker // Compute proportional error
285*0e209d39SAndroid Build Coastguard Worker double error = proportionalError(value, n);
286*0e209d39SAndroid Build Coastguard Worker
287*0e209d39SAndroid Build Coastguard Worker if(error > MAX_ERROR) {
288*0e209d39SAndroid Build Coastguard Worker errln(UnicodeString("*** NUMERIC ERROR ") + error);
289*0e209d39SAndroid Build Coastguard Worker show = true;
290*0e209d39SAndroid Build Coastguard Worker }
291*0e209d39SAndroid Build Coastguard Worker
292*0e209d39SAndroid Build Coastguard Worker if (error > max_numeric_error)
293*0e209d39SAndroid Build Coastguard Worker max_numeric_error = error;
294*0e209d39SAndroid Build Coastguard Worker if (error < min_numeric_error)
295*0e209d39SAndroid Build Coastguard Worker min_numeric_error = error;
296*0e209d39SAndroid Build Coastguard Worker }
297*0e209d39SAndroid Build Coastguard Worker
298*0e209d39SAndroid Build Coastguard Worker if (show) {
299*0e209d39SAndroid Build Coastguard Worker errln(/*value.getString(temp) +*/ typeOf(value, temp) + " F> " +
300*0e209d39SAndroid Build Coastguard Worker escape(s) + " P> " + (n.getType() == Formattable::kDouble ? n.getDouble() : (double)n.getLong())
301*0e209d39SAndroid Build Coastguard Worker /*n.getString(temp) */ + typeOf(n, temp) + " F> " +
302*0e209d39SAndroid Build Coastguard Worker escape(s2));
303*0e209d39SAndroid Build Coastguard Worker }
304*0e209d39SAndroid Build Coastguard Worker }
305*0e209d39SAndroid Build Coastguard Worker
306*0e209d39SAndroid Build Coastguard Worker double
proportionalError(const Formattable & a,const Formattable & b)307*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::proportionalError(const Formattable& a, const Formattable& b)
308*0e209d39SAndroid Build Coastguard Worker {
309*0e209d39SAndroid Build Coastguard Worker double aa,bb;
310*0e209d39SAndroid Build Coastguard Worker
311*0e209d39SAndroid Build Coastguard Worker if(isDouble(a))
312*0e209d39SAndroid Build Coastguard Worker aa = a.getDouble();
313*0e209d39SAndroid Build Coastguard Worker else
314*0e209d39SAndroid Build Coastguard Worker aa = a.getLong();
315*0e209d39SAndroid Build Coastguard Worker
316*0e209d39SAndroid Build Coastguard Worker if(isDouble(b))
317*0e209d39SAndroid Build Coastguard Worker bb = b.getDouble();
318*0e209d39SAndroid Build Coastguard Worker else
319*0e209d39SAndroid Build Coastguard Worker bb = b.getLong();
320*0e209d39SAndroid Build Coastguard Worker
321*0e209d39SAndroid Build Coastguard Worker double error = aa - bb;
322*0e209d39SAndroid Build Coastguard Worker if(aa != 0 && bb != 0)
323*0e209d39SAndroid Build Coastguard Worker error /= aa;
324*0e209d39SAndroid Build Coastguard Worker
325*0e209d39SAndroid Build Coastguard Worker return uprv_fabs(error);
326*0e209d39SAndroid Build Coastguard Worker }
327*0e209d39SAndroid Build Coastguard Worker
328*0e209d39SAndroid Build Coastguard Worker UnicodeString&
typeOf(const Formattable & n,UnicodeString & result)329*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::typeOf(const Formattable& n, UnicodeString& result)
330*0e209d39SAndroid Build Coastguard Worker {
331*0e209d39SAndroid Build Coastguard Worker if(n.getType() == Formattable::kLong) {
332*0e209d39SAndroid Build Coastguard Worker result = UnicodeString(" Long");
333*0e209d39SAndroid Build Coastguard Worker }
334*0e209d39SAndroid Build Coastguard Worker else if(n.getType() == Formattable::kDouble) {
335*0e209d39SAndroid Build Coastguard Worker result = UnicodeString(" Double");
336*0e209d39SAndroid Build Coastguard Worker }
337*0e209d39SAndroid Build Coastguard Worker else if(n.getType() == Formattable::kString) {
338*0e209d39SAndroid Build Coastguard Worker result = UnicodeString(" UnicodeString");
339*0e209d39SAndroid Build Coastguard Worker UnicodeString temp;
340*0e209d39SAndroid Build Coastguard Worker }
341*0e209d39SAndroid Build Coastguard Worker
342*0e209d39SAndroid Build Coastguard Worker return result;
343*0e209d39SAndroid Build Coastguard Worker }
344*0e209d39SAndroid Build Coastguard Worker
345*0e209d39SAndroid Build Coastguard Worker
346*0e209d39SAndroid Build Coastguard Worker UnicodeString&
escape(UnicodeString & s)347*0e209d39SAndroid Build Coastguard Worker NumberFormatRoundTripTest::escape(UnicodeString& s)
348*0e209d39SAndroid Build Coastguard Worker {
349*0e209d39SAndroid Build Coastguard Worker UnicodeString copy(s);
350*0e209d39SAndroid Build Coastguard Worker s.remove();
351*0e209d39SAndroid Build Coastguard Worker for(int i = 0; i < copy.length(); ++i) {
352*0e209d39SAndroid Build Coastguard Worker UChar32 c = copy.char32At(i);
353*0e209d39SAndroid Build Coastguard Worker if (c >= 0x10000) {
354*0e209d39SAndroid Build Coastguard Worker ++i;
355*0e209d39SAndroid Build Coastguard Worker }
356*0e209d39SAndroid Build Coastguard Worker if(c < 0x00FF) {
357*0e209d39SAndroid Build Coastguard Worker s += c;
358*0e209d39SAndroid Build Coastguard Worker } else {
359*0e209d39SAndroid Build Coastguard Worker s += "+U";
360*0e209d39SAndroid Build Coastguard Worker char temp[16];
361*0e209d39SAndroid Build Coastguard Worker snprintf(temp, sizeof(temp), "%4X", c); // might not work
362*0e209d39SAndroid Build Coastguard Worker s += temp;
363*0e209d39SAndroid Build Coastguard Worker }
364*0e209d39SAndroid Build Coastguard Worker }
365*0e209d39SAndroid Build Coastguard Worker return s;
366*0e209d39SAndroid Build Coastguard Worker }
367*0e209d39SAndroid Build Coastguard Worker
368*0e209d39SAndroid Build Coastguard Worker #endif /* #if !UCONFIG_NO_FORMATTING */
369