LEFT | RIGHT |
(no file at all) | |
1 // © 2017 and later: Unicode, Inc. and others. | 1 // © 2017 and later: Unicode, Inc. and others. |
2 // License & terms of use: http://www.unicode.org/copyright.html | 2 // License & terms of use: http://www.unicode.org/copyright.html |
3 | 3 |
4 #include "unicode/utypes.h" | 4 #include "unicode/utypes.h" |
5 | 5 |
6 #if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT | 6 #if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT |
7 | 7 |
8 #include "uassert.h" | 8 #include "uassert.h" |
9 #include "unicode/numberformatter.h" | 9 #include "unicode/numberformatter.h" |
10 #include "number_types.h" | 10 #include "number_types.h" |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 | 244 |
245 void Rounder::setLocaleData(const CurrencyUnit ¤cy, UErrorCode &status) { | 245 void Rounder::setLocaleData(const CurrencyUnit ¤cy, UErrorCode &status) { |
246 if (fType == RND_CURRENCY) { | 246 if (fType == RND_CURRENCY) { |
247 *this = withCurrency(currency, status); | 247 *this = withCurrency(currency, status); |
248 } | 248 } |
249 } | 249 } |
250 | 250 |
251 int32_t | 251 int32_t |
252 Rounder::chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::Mult
iplierProducer &producer, | 252 Rounder::chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::Mult
iplierProducer &producer, |
253 UErrorCode &status) { | 253 UErrorCode &status) { |
254 // TODO: Make a better and more efficient implementation. | 254 // Do not call this method with zero. |
255 // TODO: Avoid the object creation here. | |
256 DecimalQuantity copy(input); | |
257 | |
258 U_ASSERT(!input.isZero()); | 255 U_ASSERT(!input.isZero()); |
259 int32_t magnitude = input.getMagnitude(); | 256 |
260 int32_t multiplier = producer.getMultiplier(magnitude); | 257 // Perform the first attempt at rounding. |
| 258 int magnitude = input.getMagnitude(); |
| 259 int multiplier = producer.getMultiplier(magnitude); |
261 input.adjustMagnitude(multiplier); | 260 input.adjustMagnitude(multiplier); |
262 apply(input, status); | 261 apply(input, status); |
263 | 262 |
264 // If the number turned to zero when rounding, do not re-attempt the roundin
g. | 263 // If the number rounded to zero, exit. |
265 if (!input.isZero() && input.getMagnitude() == magnitude + multiplier + 1) { | 264 if (input.isZero() || U_FAILURE(status)) { |
266 magnitude += 1; | 265 return multiplier; |
267 input = copy; | 266 } |
268 multiplier = producer.getMultiplier(magnitude); | 267 |
269 input.adjustMagnitude(multiplier); | 268 // If the new magnitude after rounding is the same as it was before rounding
, then we are done. |
270 U_ASSERT(input.getMagnitude() == magnitude + multiplier - 1); | 269 // This case applies to most numbers. |
271 apply(input, status); | 270 if (input.getMagnitude() == magnitude + multiplier) { |
272 U_ASSERT(input.getMagnitude() == magnitude + multiplier); | 271 return multiplier; |
273 } | 272 } |
274 | 273 |
275 return multiplier; | 274 // If the above case DIDN'T apply, then we have a case like 99.9 -> 100 or 9
99.9 -> 1000: |
| 275 // The number rounded up to the next magnitude. Check if the multiplier chan
ges; if it doesn't, |
| 276 // we do not need to make any more adjustments. |
| 277 int _multiplier = producer.getMultiplier(magnitude + 1); |
| 278 if (multiplier == _multiplier) { |
| 279 return multiplier; |
| 280 } |
| 281 |
| 282 // We have a case like 999.9 -> 1000, where the correct output is "1K", not
"1000". |
| 283 // Fix the magnitude and re-apply the rounding strategy. |
| 284 input.adjustMagnitude(_multiplier - multiplier); |
| 285 apply(input, status); |
| 286 return _multiplier; |
276 } | 287 } |
277 | 288 |
278 /** This is the method that contains the actual rounding logic. */ | 289 /** This is the method that contains the actual rounding logic. */ |
279 void Rounder::apply(impl::DecimalQuantity &value, UErrorCode& status) const { | 290 void Rounder::apply(impl::DecimalQuantity &value, UErrorCode& status) const { |
280 switch (fType) { | 291 switch (fType) { |
281 case RND_BOGUS: | 292 case RND_BOGUS: |
282 case RND_ERROR: | 293 case RND_ERROR: |
283 // Errors should be caught before the apply() method is called | 294 // Errors should be caught before the apply() method is called |
284 status = U_INTERNAL_PROGRAM_ERROR; | 295 status = U_INTERNAL_PROGRAM_ERROR; |
285 break; | 296 break; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 | 335 |
325 case RND_INCREMENT: | 336 case RND_INCREMENT: |
326 value.roundToIncrement( | 337 value.roundToIncrement( |
327 fUnion.increment.fIncrement, fRoundingMode, fUnion.increment.fMi
nFrac, status); | 338 fUnion.increment.fIncrement, fRoundingMode, fUnion.increment.fMi
nFrac, status); |
328 value.setFractionLength(fUnion.increment.fMinFrac, fUnion.increment.
fMinFrac); | 339 value.setFractionLength(fUnion.increment.fMinFrac, fUnion.increment.
fMinFrac); |
329 break; | 340 break; |
330 | 341 |
331 case RND_CURRENCY: | 342 case RND_CURRENCY: |
332 // Call .withCurrency() before .apply()! | 343 // Call .withCurrency() before .apply()! |
333 U_ASSERT(false); | 344 U_ASSERT(false); |
| 345 break; |
334 | 346 |
335 case RND_PASS_THROUGH: | 347 case RND_PASS_THROUGH: |
336 break; | 348 break; |
337 } | 349 } |
338 } | 350 } |
339 | 351 |
340 void Rounder::apply(impl::DecimalQuantity &value, int32_t minInt, UErrorCode /*s
tatus*/) { | 352 void Rounder::apply(impl::DecimalQuantity &value, int32_t minInt, UErrorCode /*s
tatus*/) { |
341 // This method is intended for the one specific purpose of helping print "00
.000E0". | 353 // This method is intended for the one specific purpose of helping print "00
.000E0". |
342 U_ASSERT(fType == RND_SIGNIFICANT); | 354 U_ASSERT(fType == RND_SIGNIFICANT); |
343 U_ASSERT(value.isZero()); | 355 U_ASSERT(value.isZero()); |
344 value.setFractionLength(fUnion.fracSig.fMinSig - minInt, INT32_MAX); | 356 value.setFractionLength(fUnion.fracSig.fMinSig - minInt, INT32_MAX); |
345 } | 357 } |
346 | 358 |
347 #endif /* #if !UCONFIG_NO_FORMATTING */ | 359 #endif /* #if !UCONFIG_NO_FORMATTING */ |
LEFT | RIGHT |