]>
Commit | Line | Data |
---|---|---|
0f5d89e8 A |
1 | // © 2017 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
3 | ||
4 | #include "unicode/utypes.h" | |
5 | ||
6 | #if !UCONFIG_NO_FORMATTING | |
7 | ||
8 | #include "number_decimalquantity.h" | |
9 | #include "number_decnum.h" | |
10 | #include "math.h" | |
11 | #include <cmath> | |
12 | #include "number_utils.h" | |
13 | #include "numbertest.h" | |
14 | ||
15 | void DecimalQuantityTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char *) { | |
16 | if (exec) { | |
17 | logln("TestSuite DecimalQuantityTest: "); | |
18 | } | |
19 | TESTCASE_AUTO_BEGIN; | |
20 | TESTCASE_AUTO(testDecimalQuantityBehaviorStandalone); | |
21 | TESTCASE_AUTO(testSwitchStorage);; | |
22 | TESTCASE_AUTO(testCopyMove); | |
23 | TESTCASE_AUTO(testAppend); | |
3d1f044b A |
24 | if (!quick) { |
25 | // Slow test: run in exhaustive mode only | |
26 | TESTCASE_AUTO(testConvertToAccurateDouble); | |
27 | } | |
0f5d89e8 A |
28 | TESTCASE_AUTO(testUseApproximateDoubleWhenAble); |
29 | TESTCASE_AUTO(testHardDoubleConversion); | |
30 | TESTCASE_AUTO(testToDouble); | |
31 | TESTCASE_AUTO(testMaxDigits); | |
3d1f044b | 32 | TESTCASE_AUTO(testNickelRounding); |
0f5d89e8 A |
33 | TESTCASE_AUTO_END; |
34 | } | |
35 | ||
36 | void DecimalQuantityTest::assertDoubleEquals(UnicodeString message, double a, double b) { | |
37 | if (a == b) { | |
38 | return; | |
39 | } | |
40 | ||
41 | double diff = a - b; | |
42 | diff = diff < 0 ? -diff : diff; | |
43 | double bound = a < 0 ? -a * 1e-6 : a * 1e-6; | |
44 | if (diff > bound) { | |
45 | errln(message + u": " + DoubleToUnicodeString(a) + u" vs " + DoubleToUnicodeString(b) + u" differ by " + DoubleToUnicodeString(diff)); | |
46 | } | |
47 | } | |
48 | ||
49 | void DecimalQuantityTest::assertHealth(const DecimalQuantity &fq) { | |
50 | const char16_t* health = fq.checkHealth(); | |
51 | if (health != nullptr) { | |
52 | errln(UnicodeString(u"HEALTH FAILURE: ") + UnicodeString(health) + u": " + fq.toString()); | |
53 | } | |
54 | } | |
55 | ||
56 | void | |
57 | DecimalQuantityTest::assertToStringAndHealth(const DecimalQuantity &fq, const UnicodeString &expected) { | |
58 | UnicodeString actual = fq.toString(); | |
59 | assertEquals("DecimalQuantity toString failed", expected, actual); | |
60 | assertHealth(fq); | |
61 | } | |
62 | ||
63 | void DecimalQuantityTest::checkDoubleBehavior(double d, bool explicitRequired) { | |
64 | DecimalQuantity fq; | |
65 | fq.setToDouble(d); | |
66 | if (explicitRequired) { | |
67 | assertTrue("Should be using approximate double", !fq.isExplicitExactDouble()); | |
68 | } | |
69 | UnicodeString baseStr = fq.toString(); | |
70 | fq.roundToInfinity(); | |
71 | UnicodeString newStr = fq.toString(); | |
72 | if (explicitRequired) { | |
73 | assertTrue("Should not be using approximate double", fq.isExplicitExactDouble()); | |
74 | } | |
75 | assertDoubleEquals( | |
76 | UnicodeString(u"After conversion to exact BCD (double): ") + baseStr + u" vs " + newStr, | |
77 | d, fq.toDouble()); | |
78 | } | |
79 | ||
80 | void DecimalQuantityTest::testDecimalQuantityBehaviorStandalone() { | |
81 | UErrorCode status = U_ZERO_ERROR; | |
82 | DecimalQuantity fq; | |
3d1f044b | 83 | assertToStringAndHealth(fq, u"<DecimalQuantity 0:0 long 0E0>"); |
0f5d89e8 | 84 | fq.setToInt(51423); |
3d1f044b | 85 | assertToStringAndHealth(fq, u"<DecimalQuantity 0:0 long 51423E0>"); |
0f5d89e8 | 86 | fq.adjustMagnitude(-3); |
3d1f044b A |
87 | assertToStringAndHealth(fq, u"<DecimalQuantity 0:0 long 51423E-3>"); |
88 | ||
89 | fq.setToLong(90909090909000L); | |
90 | assertToStringAndHealth(fq, u"<DecimalQuantity 0:0 long 90909090909E3>"); | |
91 | fq.setMinInteger(2); | |
92 | fq.applyMaxInteger(5); | |
93 | assertToStringAndHealth(fq, u"<DecimalQuantity 2:0 long 9E3>"); | |
94 | fq.setMinFraction(3); | |
95 | assertToStringAndHealth(fq, u"<DecimalQuantity 2:-3 long 9E3>"); | |
96 | ||
0f5d89e8 | 97 | fq.setToDouble(987.654321); |
3d1f044b | 98 | assertToStringAndHealth(fq, u"<DecimalQuantity 2:-3 long 987654321E-6>"); |
0f5d89e8 | 99 | fq.roundToInfinity(); |
3d1f044b A |
100 | assertToStringAndHealth(fq, u"<DecimalQuantity 2:-3 long 987654321E-6>"); |
101 | fq.roundToIncrement(0.005, RoundingMode::UNUM_ROUND_HALFEVEN, status); | |
0f5d89e8 | 102 | assertSuccess("Rounding to increment", status); |
3d1f044b | 103 | assertToStringAndHealth(fq, u"<DecimalQuantity 2:-3 long 987655E-3>"); |
0f5d89e8 A |
104 | fq.roundToMagnitude(-2, RoundingMode::UNUM_ROUND_HALFEVEN, status); |
105 | assertSuccess("Rounding to magnitude", status); | |
3d1f044b | 106 | assertToStringAndHealth(fq, u"<DecimalQuantity 2:-3 long 98766E-2>"); |
0f5d89e8 A |
107 | } |
108 | ||
109 | void DecimalQuantityTest::testSwitchStorage() { | |
110 | UErrorCode status = U_ZERO_ERROR; | |
111 | DecimalQuantity fq; | |
112 | ||
113 | fq.setToLong(1234123412341234L); | |
114 | assertFalse("Should not be using byte array", fq.isUsingBytes()); | |
115 | assertEquals("Failed on initialize", u"1.234123412341234E+15", fq.toScientificString()); | |
116 | assertHealth(fq); | |
117 | // Long -> Bytes | |
118 | fq.appendDigit(5, 0, true); | |
119 | assertTrue("Should be using byte array", fq.isUsingBytes()); | |
120 | assertEquals("Failed on multiply", u"1.2341234123412345E+16", fq.toScientificString()); | |
121 | assertHealth(fq); | |
122 | // Bytes -> Long | |
123 | fq.roundToMagnitude(5, RoundingMode::UNUM_ROUND_HALFEVEN, status); | |
124 | assertSuccess("Rounding to magnitude", status); | |
125 | assertFalse("Should not be using byte array", fq.isUsingBytes()); | |
126 | assertEquals("Failed on round", u"1.23412341234E+16", fq.toScientificString()); | |
127 | assertHealth(fq); | |
3d1f044b A |
128 | // Bytes with popFromLeft |
129 | fq.setToDecNumber({"999999999999999999"}, status); | |
130 | assertToStringAndHealth(fq, u"<DecimalQuantity 0:0 bytes 999999999999999999E0>"); | |
131 | fq.applyMaxInteger(17); | |
132 | assertToStringAndHealth(fq, u"<DecimalQuantity 0:0 bytes 99999999999999999E0>"); | |
133 | fq.applyMaxInteger(16); | |
134 | assertToStringAndHealth(fq, u"<DecimalQuantity 0:0 long 9999999999999999E0>"); | |
135 | fq.applyMaxInteger(15); | |
136 | assertToStringAndHealth(fq, u"<DecimalQuantity 0:0 long 999999999999999E0>"); | |
0f5d89e8 A |
137 | } |
138 | ||
139 | void DecimalQuantityTest::testCopyMove() { | |
140 | // Small numbers (fits in BCD long) | |
141 | { | |
142 | DecimalQuantity a; | |
143 | a.setToLong(1234123412341234L); | |
144 | DecimalQuantity b = a; // copy constructor | |
3d1f044b A |
145 | assertToStringAndHealth(a, u"<DecimalQuantity 0:0 long 1234123412341234E0>"); |
146 | assertToStringAndHealth(b, u"<DecimalQuantity 0:0 long 1234123412341234E0>"); | |
0f5d89e8 | 147 | DecimalQuantity c(std::move(a)); // move constructor |
3d1f044b | 148 | assertToStringAndHealth(c, u"<DecimalQuantity 0:0 long 1234123412341234E0>"); |
0f5d89e8 | 149 | c.setToLong(54321L); |
3d1f044b | 150 | assertToStringAndHealth(c, u"<DecimalQuantity 0:0 long 54321E0>"); |
0f5d89e8 | 151 | c = b; // copy assignment |
3d1f044b A |
152 | assertToStringAndHealth(b, u"<DecimalQuantity 0:0 long 1234123412341234E0>"); |
153 | assertToStringAndHealth(c, u"<DecimalQuantity 0:0 long 1234123412341234E0>"); | |
0f5d89e8 A |
154 | b.setToLong(45678); |
155 | c.setToLong(56789); | |
156 | c = std::move(b); // move assignment | |
3d1f044b | 157 | assertToStringAndHealth(c, u"<DecimalQuantity 0:0 long 45678E0>"); |
0f5d89e8 | 158 | a = std::move(c); // move assignment to a defunct object |
3d1f044b | 159 | assertToStringAndHealth(a, u"<DecimalQuantity 0:0 long 45678E0>"); |
0f5d89e8 A |
160 | } |
161 | ||
162 | // Large numbers (requires byte allocation) | |
163 | { | |
164 | IcuTestErrorCode status(*this, "testCopyMove"); | |
165 | DecimalQuantity a; | |
166 | a.setToDecNumber({"1234567890123456789", -1}, status); | |
167 | DecimalQuantity b = a; // copy constructor | |
3d1f044b A |
168 | assertToStringAndHealth(a, u"<DecimalQuantity 0:0 bytes 1234567890123456789E0>"); |
169 | assertToStringAndHealth(b, u"<DecimalQuantity 0:0 bytes 1234567890123456789E0>"); | |
0f5d89e8 | 170 | DecimalQuantity c(std::move(a)); // move constructor |
3d1f044b | 171 | assertToStringAndHealth(c, u"<DecimalQuantity 0:0 bytes 1234567890123456789E0>"); |
0f5d89e8 | 172 | c.setToDecNumber({"9876543210987654321", -1}, status); |
3d1f044b | 173 | assertToStringAndHealth(c, u"<DecimalQuantity 0:0 bytes 9876543210987654321E0>"); |
0f5d89e8 | 174 | c = b; // copy assignment |
3d1f044b A |
175 | assertToStringAndHealth(b, u"<DecimalQuantity 0:0 bytes 1234567890123456789E0>"); |
176 | assertToStringAndHealth(c, u"<DecimalQuantity 0:0 bytes 1234567890123456789E0>"); | |
0f5d89e8 A |
177 | b.setToDecNumber({"876543210987654321", -1}, status); |
178 | c.setToDecNumber({"987654321098765432", -1}, status); | |
179 | c = std::move(b); // move assignment | |
3d1f044b | 180 | assertToStringAndHealth(c, u"<DecimalQuantity 0:0 bytes 876543210987654321E0>"); |
0f5d89e8 | 181 | a = std::move(c); // move assignment to a defunct object |
3d1f044b | 182 | assertToStringAndHealth(a, u"<DecimalQuantity 0:0 bytes 876543210987654321E0>"); |
0f5d89e8 A |
183 | } |
184 | } | |
185 | ||
186 | void DecimalQuantityTest::testAppend() { | |
187 | DecimalQuantity fq; | |
188 | fq.appendDigit(1, 0, true); | |
189 | assertEquals("Failed on append", u"1E+0", fq.toScientificString()); | |
190 | assertHealth(fq); | |
191 | fq.appendDigit(2, 0, true); | |
192 | assertEquals("Failed on append", u"1.2E+1", fq.toScientificString()); | |
193 | assertHealth(fq); | |
194 | fq.appendDigit(3, 1, true); | |
195 | assertEquals("Failed on append", u"1.203E+3", fq.toScientificString()); | |
196 | assertHealth(fq); | |
197 | fq.appendDigit(0, 1, true); | |
198 | assertEquals("Failed on append", u"1.203E+5", fq.toScientificString()); | |
199 | assertHealth(fq); | |
200 | fq.appendDigit(4, 0, true); | |
201 | assertEquals("Failed on append", u"1.203004E+6", fq.toScientificString()); | |
202 | assertHealth(fq); | |
203 | fq.appendDigit(0, 0, true); | |
204 | assertEquals("Failed on append", u"1.203004E+7", fq.toScientificString()); | |
205 | assertHealth(fq); | |
206 | fq.appendDigit(5, 0, false); | |
207 | assertEquals("Failed on append", u"1.20300405E+7", fq.toScientificString()); | |
208 | assertHealth(fq); | |
209 | fq.appendDigit(6, 0, false); | |
210 | assertEquals("Failed on append", u"1.203004056E+7", fq.toScientificString()); | |
211 | assertHealth(fq); | |
212 | fq.appendDigit(7, 3, false); | |
213 | assertEquals("Failed on append", u"1.2030040560007E+7", fq.toScientificString()); | |
214 | assertHealth(fq); | |
215 | UnicodeString baseExpected(u"1.2030040560007"); | |
216 | for (int i = 0; i < 10; i++) { | |
217 | fq.appendDigit(8, 0, false); | |
218 | baseExpected.append(u'8'); | |
219 | UnicodeString expected(baseExpected); | |
220 | expected.append(u"E+7"); | |
221 | assertEquals("Failed on append", expected, fq.toScientificString()); | |
222 | assertHealth(fq); | |
223 | } | |
224 | fq.appendDigit(9, 2, false); | |
225 | baseExpected.append(u"009"); | |
226 | UnicodeString expected(baseExpected); | |
227 | expected.append(u"E+7"); | |
228 | assertEquals("Failed on append", expected, fq.toScientificString()); | |
229 | assertHealth(fq); | |
230 | } | |
231 | ||
232 | void DecimalQuantityTest::testConvertToAccurateDouble() { | |
233 | // based on https://github.com/google/double-conversion/issues/28 | |
234 | static double hardDoubles[] = { | |
235 | 1651087494906221570.0, | |
236 | -5074790912492772E-327, | |
237 | 83602530019752571E-327, | |
238 | 2.207817077636718750000000000000, | |
239 | 1.818351745605468750000000000000, | |
240 | 3.941719055175781250000000000000, | |
241 | 3.738609313964843750000000000000, | |
242 | 3.967735290527343750000000000000, | |
243 | 1.328025817871093750000000000000, | |
244 | 3.920967102050781250000000000000, | |
245 | 1.015235900878906250000000000000, | |
246 | 1.335227966308593750000000000000, | |
247 | 1.344520568847656250000000000000, | |
248 | 2.879127502441406250000000000000, | |
249 | 3.695838928222656250000000000000, | |
250 | 1.845344543457031250000000000000, | |
251 | 3.793952941894531250000000000000, | |
252 | 3.211402893066406250000000000000, | |
253 | 2.565971374511718750000000000000, | |
254 | 0.965156555175781250000000000000, | |
255 | 2.700004577636718750000000000000, | |
256 | 0.767097473144531250000000000000, | |
257 | 1.780448913574218750000000000000, | |
258 | 2.624839782714843750000000000000, | |
259 | 1.305290222167968750000000000000, | |
260 | 3.834922790527343750000000000000,}; | |
261 | ||
262 | static double integerDoubles[] = { | |
263 | 51423, | |
264 | 51423e10, | |
265 | 4.503599627370496E15, | |
266 | 6.789512076111555E15, | |
267 | 9.007199254740991E15, | |
268 | 9.007199254740992E15}; | |
269 | ||
270 | for (double d : hardDoubles) { | |
271 | checkDoubleBehavior(d, true); | |
272 | } | |
273 | ||
274 | for (double d : integerDoubles) { | |
275 | checkDoubleBehavior(d, false); | |
276 | } | |
277 | ||
278 | assertDoubleEquals(u"NaN check failed", NAN, DecimalQuantity().setToDouble(NAN).toDouble()); | |
279 | assertDoubleEquals( | |
280 | u"Inf check failed", INFINITY, DecimalQuantity().setToDouble(INFINITY).toDouble()); | |
281 | assertDoubleEquals( | |
282 | u"-Inf check failed", -INFINITY, DecimalQuantity().setToDouble(-INFINITY).toDouble()); | |
283 | ||
284 | // Generate random doubles | |
285 | for (int32_t i = 0; i < 10000; i++) { | |
286 | uint8_t bytes[8]; | |
287 | for (int32_t j = 0; j < 8; j++) { | |
288 | bytes[j] = static_cast<uint8_t>(rand() % 256); | |
289 | } | |
290 | double d; | |
291 | uprv_memcpy(&d, bytes, 8); | |
292 | if (std::isnan(d) || !std::isfinite(d)) { continue; } | |
293 | checkDoubleBehavior(d, false); | |
294 | } | |
295 | } | |
296 | ||
297 | void DecimalQuantityTest::testUseApproximateDoubleWhenAble() { | |
298 | static const struct TestCase { | |
299 | double d; | |
300 | int32_t maxFrac; | |
301 | RoundingMode roundingMode; | |
302 | bool usesExact; | |
303 | } cases[] = {{1.2345678, 1, RoundingMode::UNUM_ROUND_HALFEVEN, false}, | |
304 | {1.2345678, 7, RoundingMode::UNUM_ROUND_HALFEVEN, false}, | |
305 | {1.2345678, 12, RoundingMode::UNUM_ROUND_HALFEVEN, false}, | |
306 | {1.2345678, 13, RoundingMode::UNUM_ROUND_HALFEVEN, true}, | |
307 | {1.235, 1, RoundingMode::UNUM_ROUND_HALFEVEN, false}, | |
308 | {1.235, 2, RoundingMode::UNUM_ROUND_HALFEVEN, true}, | |
309 | {1.235, 3, RoundingMode::UNUM_ROUND_HALFEVEN, false}, | |
310 | {1.000000000000001, 0, RoundingMode::UNUM_ROUND_HALFEVEN, false}, | |
311 | {1.000000000000001, 0, RoundingMode::UNUM_ROUND_CEILING, true}, | |
312 | {1.235, 1, RoundingMode::UNUM_ROUND_CEILING, false}, | |
313 | {1.235, 2, RoundingMode::UNUM_ROUND_CEILING, false}, | |
314 | {1.235, 3, RoundingMode::UNUM_ROUND_CEILING, true}}; | |
315 | ||
316 | UErrorCode status = U_ZERO_ERROR; | |
317 | for (TestCase cas : cases) { | |
318 | DecimalQuantity fq; | |
319 | fq.setToDouble(cas.d); | |
320 | assertTrue("Should be using approximate double", !fq.isExplicitExactDouble()); | |
321 | fq.roundToMagnitude(-cas.maxFrac, cas.roundingMode, status); | |
322 | assertSuccess("Rounding to magnitude", status); | |
323 | if (cas.usesExact != fq.isExplicitExactDouble()) { | |
324 | errln(UnicodeString(u"Using approximate double after rounding: ") + fq.toString()); | |
325 | } | |
326 | } | |
327 | } | |
328 | ||
329 | void DecimalQuantityTest::testHardDoubleConversion() { | |
330 | static const struct TestCase { | |
331 | double input; | |
332 | const char16_t* expectedOutput; | |
333 | } cases[] = { | |
334 | { 512.0000000000017, u"512.0000000000017" }, | |
335 | { 4095.9999999999977, u"4095.9999999999977" }, | |
336 | { 4095.999999999998, u"4095.999999999998" }, | |
337 | { 4095.9999999999986, u"4095.9999999999986" }, | |
338 | { 4095.999999999999, u"4095.999999999999" }, | |
339 | { 4095.9999999999995, u"4095.9999999999995" }, | |
340 | { 4096.000000000001, u"4096.000000000001" }, | |
341 | { 4096.000000000002, u"4096.000000000002" }, | |
342 | { 4096.000000000003, u"4096.000000000003" }, | |
343 | { 4096.000000000004, u"4096.000000000004" }, | |
344 | { 4096.000000000005, u"4096.000000000005" }, | |
345 | { 4096.0000000000055, u"4096.0000000000055" }, | |
346 | { 4096.000000000006, u"4096.000000000006" }, | |
347 | { 4096.000000000007, u"4096.000000000007" } }; | |
348 | ||
349 | for (auto& cas : cases) { | |
350 | DecimalQuantity q; | |
351 | q.setToDouble(cas.input); | |
352 | q.roundToInfinity(); | |
353 | UnicodeString actualOutput = q.toPlainString(); | |
354 | assertEquals("", cas.expectedOutput, actualOutput); | |
355 | } | |
356 | } | |
357 | ||
358 | void DecimalQuantityTest::testToDouble() { | |
359 | IcuTestErrorCode status(*this, "testToDouble"); | |
360 | static const struct TestCase { | |
361 | const char* input; // char* for the decNumber constructor | |
362 | double expected; | |
363 | } cases[] = { | |
364 | { "0", 0.0 }, | |
365 | { "514.23", 514.23 }, | |
366 | { "-3.142E-271", -3.142e-271 } }; | |
367 | ||
368 | for (auto& cas : cases) { | |
369 | status.setScope(cas.input); | |
370 | DecimalQuantity q; | |
371 | q.setToDecNumber({cas.input, -1}, status); | |
372 | double actual = q.toDouble(); | |
373 | assertEquals("Doubles should exactly equal", cas.expected, actual); | |
374 | } | |
375 | } | |
376 | ||
377 | void DecimalQuantityTest::testMaxDigits() { | |
378 | IcuTestErrorCode status(*this, "testMaxDigits"); | |
379 | DecimalQuantity dq; | |
380 | dq.setToDouble(876.543); | |
381 | dq.roundToInfinity(); | |
3d1f044b A |
382 | dq.setMinInteger(0); |
383 | dq.applyMaxInteger(2); | |
384 | dq.setMinFraction(0); | |
385 | dq.roundToMagnitude(-2, UNUM_ROUND_FLOOR, status); | |
0f5d89e8 A |
386 | assertEquals("Should trim, toPlainString", "76.54", dq.toPlainString()); |
387 | assertEquals("Should trim, toScientificString", "7.654E+1", dq.toScientificString()); | |
388 | assertEquals("Should trim, toLong", 76LL, dq.toLong(true)); | |
389 | assertEquals("Should trim, toFractionLong", (int64_t) 54, (int64_t) dq.toFractionLong(false)); | |
390 | assertEquals("Should trim, toDouble", 76.54, dq.toDouble()); | |
391 | // To test DecNum output, check the round-trip. | |
392 | DecNum dn; | |
393 | dq.toDecNum(dn, status); | |
394 | DecimalQuantity copy; | |
395 | copy.setToDecNum(dn, status); | |
3d1f044b A |
396 | assertEquals("Should trim, toDecNum", "76.54", copy.toPlainString()); |
397 | } | |
398 | ||
399 | void DecimalQuantityTest::testNickelRounding() { | |
400 | IcuTestErrorCode status(*this, "testNickelRounding"); | |
401 | struct TestCase { | |
402 | double input; | |
403 | int32_t magnitude; | |
404 | UNumberFormatRoundingMode roundingMode; | |
405 | const char16_t* expected; | |
406 | } cases[] = { | |
407 | {1.000, -2, UNUM_ROUND_HALFEVEN, u"1"}, | |
408 | {1.001, -2, UNUM_ROUND_HALFEVEN, u"1"}, | |
409 | {1.010, -2, UNUM_ROUND_HALFEVEN, u"1"}, | |
410 | {1.020, -2, UNUM_ROUND_HALFEVEN, u"1"}, | |
411 | {1.024, -2, UNUM_ROUND_HALFEVEN, u"1"}, | |
412 | {1.025, -2, UNUM_ROUND_HALFEVEN, u"1"}, | |
413 | {1.025, -2, UNUM_ROUND_HALFDOWN, u"1"}, | |
414 | {1.025, -2, UNUM_ROUND_HALFUP, u"1.05"}, | |
415 | {1.026, -2, UNUM_ROUND_HALFEVEN, u"1.05"}, | |
416 | {1.030, -2, UNUM_ROUND_HALFEVEN, u"1.05"}, | |
417 | {1.040, -2, UNUM_ROUND_HALFEVEN, u"1.05"}, | |
418 | {1.050, -2, UNUM_ROUND_HALFEVEN, u"1.05"}, | |
419 | {1.060, -2, UNUM_ROUND_HALFEVEN, u"1.05"}, | |
420 | {1.070, -2, UNUM_ROUND_HALFEVEN, u"1.05"}, | |
421 | {1.074, -2, UNUM_ROUND_HALFEVEN, u"1.05"}, | |
422 | {1.075, -2, UNUM_ROUND_HALFDOWN, u"1.05"}, | |
423 | {1.075, -2, UNUM_ROUND_HALFUP, u"1.1"}, | |
424 | {1.075, -2, UNUM_ROUND_HALFEVEN, u"1.1"}, | |
425 | {1.076, -2, UNUM_ROUND_HALFEVEN, u"1.1"}, | |
426 | {1.080, -2, UNUM_ROUND_HALFEVEN, u"1.1"}, | |
427 | {1.090, -2, UNUM_ROUND_HALFEVEN, u"1.1"}, | |
428 | {1.099, -2, UNUM_ROUND_HALFEVEN, u"1.1"}, | |
429 | {1.999, -2, UNUM_ROUND_HALFEVEN, u"2"}, | |
430 | {2.25, -1, UNUM_ROUND_HALFEVEN, u"2"}, | |
431 | {2.25, -1, UNUM_ROUND_HALFUP, u"2.5"}, | |
432 | {2.75, -1, UNUM_ROUND_HALFDOWN, u"2.5"}, | |
433 | {2.75, -1, UNUM_ROUND_HALFEVEN, u"3"}, | |
434 | {3.00, -1, UNUM_ROUND_CEILING, u"3"}, | |
435 | {3.25, -1, UNUM_ROUND_CEILING, u"3.5"}, | |
436 | {3.50, -1, UNUM_ROUND_CEILING, u"3.5"}, | |
437 | {3.75, -1, UNUM_ROUND_CEILING, u"4"}, | |
438 | {4.00, -1, UNUM_ROUND_FLOOR, u"4"}, | |
439 | {4.25, -1, UNUM_ROUND_FLOOR, u"4"}, | |
440 | {4.50, -1, UNUM_ROUND_FLOOR, u"4.5"}, | |
441 | {4.75, -1, UNUM_ROUND_FLOOR, u"4.5"}, | |
442 | {5.00, -1, UNUM_ROUND_UP, u"5"}, | |
443 | {5.25, -1, UNUM_ROUND_UP, u"5.5"}, | |
444 | {5.50, -1, UNUM_ROUND_UP, u"5.5"}, | |
445 | {5.75, -1, UNUM_ROUND_UP, u"6"}, | |
446 | {6.00, -1, UNUM_ROUND_DOWN, u"6"}, | |
447 | {6.25, -1, UNUM_ROUND_DOWN, u"6"}, | |
448 | {6.50, -1, UNUM_ROUND_DOWN, u"6.5"}, | |
449 | {6.75, -1, UNUM_ROUND_DOWN, u"6.5"}, | |
450 | {7.00, -1, UNUM_ROUND_UNNECESSARY, u"7"}, | |
451 | {7.50, -1, UNUM_ROUND_UNNECESSARY, u"7.5"}, | |
452 | }; | |
453 | for (const auto& cas : cases) { | |
454 | UnicodeString message = DoubleToUnicodeString(cas.input) + u" @ " + Int64ToUnicodeString(cas.magnitude) + u" / " + Int64ToUnicodeString(cas.roundingMode); | |
455 | status.setScope(message); | |
456 | DecimalQuantity dq; | |
457 | dq.setToDouble(cas.input); | |
458 | dq.roundToNickel(cas.magnitude, cas.roundingMode, status); | |
459 | status.errIfFailureAndReset(); | |
460 | UnicodeString actual = dq.toPlainString(); | |
461 | assertEquals(message, cas.expected, actual); | |
0f5d89e8 | 462 | } |
3d1f044b A |
463 | status.setScope(""); |
464 | DecimalQuantity dq; | |
465 | dq.setToDouble(7.1); | |
466 | dq.roundToNickel(-1, UNUM_ROUND_UNNECESSARY, status); | |
467 | status.expectErrorAndReset(U_FORMAT_INEXACT_ERROR); | |
0f5d89e8 A |
468 | } |
469 | ||
470 | #endif /* #if !UCONFIG_NO_FORMATTING */ |