xref: /aosp_15_r20/external/icu/icu4c/source/test/intltest/nmfmtrt.cpp (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
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