1 // 2017 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 package com.ibm.icu.impl.number; 4 5 import java.math.BigDecimal; 6 import java.math.BigInteger; 7 import java.math.MathContext; 8 import java.text.FieldPosition; 9 10 import com.ibm.icu.impl.StandardPlural; 11 import com.ibm.icu.text.PluralRules; 12 import com.ibm.icu.text.PluralRules.Operand; 13 import com.ibm.icu.text.UFieldPosition; 14 15 /** 16 * Represents numbers and digit display properties using Binary Coded Decimal (BCD). 17 * 18 * @implements {@link DecimalQuantity} 19 */ 20 public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity { 21 22 /** 23 * The power of ten corresponding to the least significant digit in the BCD. For example, if this 24 * object represents the number "3.14", the BCD will be "0x314" and the scale will be -2. 25 * 26 * <p>Note that in {@link java.math.BigDecimal}, the scale is defined differently: the number of 27 * digits after the decimal place, which is the negative of our definition of scale. 28 */ 29 protected int scale; 30 31 /** 32 * The number of digits in the BCD. For example, "1007" has BCD "0x1007" and precision 4. The 33 * maximum precision is 16 since a long can hold only 16 digits. 34 * 35 * <p>This value must be re-calculated whenever the value in bcd changes by using {@link 36 * #computePrecisionAndCompact()}. 37 */ 38 protected int precision; 39 40 /** 41 * A bitmask of properties relating to the number represented by this object. 42 * 43 * @see #NEGATIVE_FLAG 44 * @see #INFINITY_FLAG 45 * @see #NAN_FLAG 46 */ 47 protected byte flags; 48 49 protected static final int NEGATIVE_FLAG = 1; 50 protected static final int INFINITY_FLAG = 2; 51 protected static final int NAN_FLAG = 4; 52 53 // The following three fields relate to the double-to-ascii fast path algorithm. 54 // When a double is given to DecimalQuantityBCD, it is converted to using a fast algorithm. The 55 // fast algorithm guarantees correctness to only the first ~12 digits of the double. The process 56 // of rounding the number ensures that the converted digits are correct, falling back to a slow- 57 // path algorithm if required. Therefore, if a DecimalQuantity is constructed from a double, it 58 // is *required* that roundToMagnitude(), roundToIncrement(), or roundToInfinity() is called. If 59 // you don't round, assertions will fail in certain other methods if you try calling them. 60 61 /** 62 * The original number provided by the user and which is represented in BCD. Used when we need to 63 * re-compute the BCD for an exact double representation. 64 */ 65 protected double origDouble; 66 67 /** 68 * The change in magnitude relative to the original double. Used when we need to re-compute the 69 * BCD for an exact double representation. 70 */ 71 protected int origDelta; 72 73 /** 74 * Whether the value in the BCD comes from the double fast path without having been rounded to 75 * ensure correctness 76 */ 77 protected boolean isApproximate; 78 79 // Four positions: left optional '(', left required '[', right required ']', right optional ')'. 80 // These four positions determine which digits are displayed in the output string. They do NOT 81 // affect rounding. These positions are internal-only and can be specified only by the public 82 // endpoints like setFractionLength, setIntegerLength, and setSignificantDigits, among others. 83 // 84 // * Digits between lReqPos and rReqPos are in the "required zone" and are always displayed. 85 // * Digits between lOptPos and rOptPos but outside the required zone are in the "optional zone" 86 // and are displayed unless they are trailing off the left or right edge of the number and 87 // have a numerical value of zero. In order to be "trailing", the digits need to be beyond 88 // the decimal point in their respective directions. 89 // * Digits outside of the "optional zone" are never displayed. 90 // 91 // See the table below for illustrative examples. 92 // 93 // +---------+---------+---------+---------+------------+------------------------+--------------+ 94 // | lOptPos | lReqPos | rReqPos | rOptPos | number | positions | en-US string | 95 // +---------+---------+---------+---------+------------+------------------------+--------------+ 96 // | 5 | 2 | -1 | -5 | 1234.567 | ( 12[34.5]67 ) | 1,234.567 | 97 // | 3 | 2 | -1 | -5 | 1234.567 | 1(2[34.5]67 ) | 234.567 | 98 // | 3 | 2 | -1 | -2 | 1234.567 | 1(2[34.5]6)7 | 234.56 | 99 // | 6 | 4 | 2 | -5 | 123456789. | 123(45[67]89. ) | 456,789. | 100 // | 6 | 4 | 2 | 1 | 123456789. | 123(45[67]8)9. | 456,780. | 101 // | -1 | -1 | -3 | -4 | 0.123456 | 0.1([23]4)56 | .0234 | 102 // | 6 | 4 | -2 | -2 | 12.3 | ( [ 12.3 ]) | 0012.30 | 103 // +---------+---------+---------+---------+------------+------------------------+--------------+ 104 // 105 protected int lOptPos = Integer.MAX_VALUE; 106 protected int lReqPos = 0; 107 protected int rReqPos = 0; 108 protected int rOptPos = Integer.MIN_VALUE; 109 110 @Override 111 public void copyFrom(DecimalQuantity _other) { 112 copyBcdFrom(_other); 113 DecimalQuantity_AbstractBCD other = (DecimalQuantity_AbstractBCD) _other; 114 lOptPos = other.lOptPos; 115 lReqPos = other.lReqPos; 116 rReqPos = other.rReqPos; 117 rOptPos = other.rOptPos; 118 scale = other.scale; 119 precision = other.precision; 120 flags = other.flags; 121 origDouble = other.origDouble; 122 origDelta = other.origDelta; 123 isApproximate = other.isApproximate; 124 } 125 126 public DecimalQuantity_AbstractBCD clear() { 127 lOptPos = Integer.MAX_VALUE; 128 lReqPos = 0; 129 rReqPos = 0; 130 rOptPos = Integer.MIN_VALUE; 131 flags = 0; 132 setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data 133 return this; 134 } 135 136 @Override 137 public void setIntegerLength(int minInt, int maxInt) { 138 // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class. 139 assert minInt >= 0; 140 assert maxInt >= minInt; 141 142 // Save values into internal state 143 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE 144 lOptPos = maxInt; 145 lReqPos = minInt; 146 } 147 148 @Override 149 public void setFractionLength(int minFrac, int maxFrac) { 150 // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class. 151 assert minFrac >= 0; 152 assert maxFrac >= minFrac; 153 154 // Save values into internal state 155 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE 156 rReqPos = -minFrac; 157 rOptPos = -maxFrac; 158 } 159 160 @Override 161 public long getPositionFingerprint() { 162 long fingerprint = 0; 163 fingerprint ^= lOptPos; 164 fingerprint ^= (lReqPos << 16); 165 fingerprint ^= ((long) rReqPos << 32); 166 fingerprint ^= ((long) rOptPos << 48); 167 return fingerprint; 168 } 169 170 @Override 171 public void roundToIncrement(BigDecimal roundingIncrement, MathContext mathContext) { 172 // TODO: Avoid converting back and forth to BigDecimal. 173 BigDecimal temp = toBigDecimal(); 174 temp = 175 temp.divide(roundingIncrement, 0, mathContext.getRoundingMode()) 176 .multiply(roundingIncrement) 177 .round(mathContext); 178 if (temp.signum() == 0) { 179 setBcdToZero(); // keeps negative flag for -0.0 180 } else { 181 setToBigDecimal(temp); 182 } 183 } 184 185 @Override 186 public void multiplyBy(BigDecimal multiplicand) { 187 if (isInfinite() || isZero() || isNaN()) { 188 return; 189 } 190 BigDecimal temp = toBigDecimal(); 191 temp = temp.multiply(multiplicand); 192 setToBigDecimal(temp); 193 } 194 195 @Override 196 public int getMagnitude() throws ArithmeticException { 197 if (precision == 0) { 198 throw new ArithmeticException("Magnitude is not well-defined for zero"); 199 } else { 200 return scale + precision - 1; 201 } 202 } 203 204 @Override 205 public void adjustMagnitude(int delta) { 206 if (precision != 0) { 207 scale += delta; 208 origDelta += delta; 209 } 210 } 211 212 @Override 213 public StandardPlural getStandardPlural(PluralRules rules) { 214 if (rules == null) { 215 // Fail gracefully if the user didn't provide a PluralRules 216 return StandardPlural.OTHER; 217 } else { 218 @SuppressWarnings("deprecation") 219 String ruleString = rules.select(this); 220 return StandardPlural.orOtherFromString(ruleString); 221 } 222 } 223 224 @Override 225 public double getPluralOperand(Operand operand) { 226 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 227 // See the comment at the top of this file explaining the "isApproximate" field. 228 assert !isApproximate; 229 230 switch (operand) { 231 case i: 232 return toLong(); 233 case f: 234 return toFractionLong(true); 235 case t: 236 return toFractionLong(false); 237 case v: 238 return fractionCount(); 239 case w: 240 return fractionCountWithoutTrailingZeros(); 241 default: 242 return Math.abs(toDouble()); 243 } 244 } 245 246 @Override 247 public void populateUFieldPosition(FieldPosition fp) { 248 if (fp instanceof UFieldPosition) { 249 ((UFieldPosition) fp) 250 .setFractionDigits((int) getPluralOperand(Operand.v), (long) getPluralOperand(Operand.f)); 251 } 252 } 253 254 @Override 255 public int getUpperDisplayMagnitude() { 256 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 257 // See the comment at the top of this file explaining the "isApproximate" field. 258 assert !isApproximate; 259 260 int magnitude = scale + precision; 261 int result = (lReqPos > magnitude) ? lReqPos : (lOptPos < magnitude) ? lOptPos : magnitude; 262 return result - 1; 263 } 264 265 @Override 266 public int getLowerDisplayMagnitude() { 267 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 268 // See the comment at the top of this file explaining the "isApproximate" field. 269 assert !isApproximate; 270 271 int magnitude = scale; 272 int result = (rReqPos < magnitude) ? rReqPos : (rOptPos > magnitude) ? rOptPos : magnitude; 273 return result; 274 } 275 276 @Override 277 public byte getDigit(int magnitude) { 278 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 279 // See the comment at the top of this file explaining the "isApproximate" field. 280 assert !isApproximate; 281 282 return getDigitPos(magnitude - scale); 283 } 284 285 private int fractionCount() { 286 return -getLowerDisplayMagnitude(); 287 } 288 289 private int fractionCountWithoutTrailingZeros() { 290 return Math.max(-scale, 0); 291 } 292 293 @Override 294 public boolean isNegative() { 295 return (flags & NEGATIVE_FLAG) != 0; 296 } 297 298 @Override 299 public boolean isInfinite() { 300 return (flags & INFINITY_FLAG) != 0; 301 } 302 303 @Override 304 public boolean isNaN() { 305 return (flags & NAN_FLAG) != 0; 306 } 307 308 @Override 309 public boolean isZero() { 310 return precision == 0; 311 } 312 313 public void setToInt(int n) { 314 setBcdToZero(); 315 flags = 0; 316 if (n < 0) { 317 flags |= NEGATIVE_FLAG; 318 n = -n; 319 } 320 if (n != 0) { 321 _setToInt(n); 322 compact(); 323 } 324 } 325 326 private void _setToInt(int n) { 327 if (n == Integer.MIN_VALUE) { 328 readLongToBcd(-(long) n); 329 } else { 330 readIntToBcd(n); 331 } 332 } 333 334 public void setToLong(long n) { 335 setBcdToZero(); 336 flags = 0; 337 if (n < 0) { 338 flags |= NEGATIVE_FLAG; 339 n = -n; 340 } 341 if (n != 0) { 342 _setToLong(n); 343 compact(); 344 } 345 } 346 347 private void _setToLong(long n) { 348 if (n == Long.MIN_VALUE) { 349 readBigIntegerToBcd(BigInteger.valueOf(n).negate()); 350 } else if (n <= Integer.MAX_VALUE) { 351 readIntToBcd((int) n); 352 } else { 353 readLongToBcd(n); 354 } 355 } 356 357 public void setToBigInteger(BigInteger n) { 358 setBcdToZero(); 359 flags = 0; 360 if (n.signum() == -1) { 361 flags |= NEGATIVE_FLAG; 362 n = n.negate(); 363 } 364 if (n.signum() != 0) { 365 _setToBigInteger(n); 366 compact(); 367 } 368 } 369 370 private void _setToBigInteger(BigInteger n) { 371 if (n.bitLength() < 32) { 372 readIntToBcd(n.intValue()); 373 } else if (n.bitLength() < 64) { 374 readLongToBcd(n.longValue()); 375 } else { 376 readBigIntegerToBcd(n); 377 } 378 } 379 380 /** 381 * Sets the internal BCD state to represent the value in the given double. 382 * 383 * @param n The value to consume. 384 */ 385 public void setToDouble(double n) { 386 setBcdToZero(); 387 flags = 0; 388 // Double.compare() handles +0.0 vs -0.0 389 if (Double.compare(n, 0.0) < 0) { 390 flags |= NEGATIVE_FLAG; 391 n = -n; 392 } 393 if (Double.isNaN(n)) { 394 flags |= NAN_FLAG; 395 } else if (Double.isInfinite(n)) { 396 flags |= INFINITY_FLAG; 397 } else if (n != 0) { 398 _setToDoubleFast(n); 399 compact(); 400 } 401 } 402 403 private static final double[] DOUBLE_MULTIPLIERS = { 404 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 405 1e17, 1e18, 1e19, 1e20, 1e21 406 }; 407 408 /** 409 * Uses double multiplication and division to get the number into integer space before converting 410 * to digits. Since double arithmetic is inexact, the resulting digits may not be accurate. 411 */ 412 private void _setToDoubleFast(double n) { 413 isApproximate = true; 414 origDouble = n; 415 origDelta = 0; 416 417 // NOTE: Unlike ICU4C, doubles are always IEEE 754 doubles. 418 long ieeeBits = Double.doubleToLongBits(n); 419 int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff; 420 421 // Not all integers can be represented exactly for exponent > 52 422 if (exponent <= 52 && (long) n == n) { 423 _setToLong((long) n); 424 return; 425 } 426 427 // 3.3219... is log2(10) 428 int fracLength = (int) ((52 - exponent) / 3.32192809489); 429 if (fracLength >= 0) { 430 int i = fracLength; 431 // 1e22 is the largest exact double. 432 for (; i >= 22; i -= 22) n *= 1e22; 433 n *= DOUBLE_MULTIPLIERS[i]; 434 } else { 435 int i = fracLength; 436 // 1e22 is the largest exact double. 437 for (; i <= -22; i += 22) n /= 1e22; 438 n /= DOUBLE_MULTIPLIERS[-i]; 439 } 440 long result = Math.round(n); 441 if (result != 0) { 442 _setToLong(result); 443 scale -= fracLength; 444 } 445 } 446 447 /** 448 * Uses Double.toString() to obtain an exact accurate representation of the double, overwriting it 449 * into the BCD. This method can be called at any point after {@link #_setToDoubleFast} while 450 * {@link #isApproximate} is still true. 451 */ 452 private void convertToAccurateDouble() { 453 double n = origDouble; 454 assert n != 0; 455 int delta = origDelta; 456 setBcdToZero(); 457 458 // Call the slow oracle function (Double.toString in Java, sprintf in C++). 459 String dstr = Double.toString(n); 460 461 if (dstr.indexOf('E') != -1) { 462 // Case 1: Exponential notation. 463 assert dstr.indexOf('.') == 1; 464 int expPos = dstr.indexOf('E'); 465 _setToLong(Long.parseLong(dstr.charAt(0) + dstr.substring(2, expPos))); 466 scale += Integer.parseInt(dstr.substring(expPos + 1)) - (expPos - 1) + 1; 467 } else if (dstr.charAt(0) == '0') { 468 // Case 2: Fraction-only number. 469 assert dstr.indexOf('.') == 1; 470 _setToLong(Long.parseLong(dstr.substring(2))); 471 scale += 2 - dstr.length(); 472 } else if (dstr.charAt(dstr.length() - 1) == '0') { 473 // Case 3: Integer-only number. 474 // Note: this path should not normally happen, because integer-only numbers are captured 475 // before the approximate double logic is performed. 476 assert dstr.indexOf('.') == dstr.length() - 2; 477 assert dstr.length() - 2 <= 18; 478 _setToLong(Long.parseLong(dstr.substring(0, dstr.length() - 2))); 479 // no need to adjust scale 480 } else { 481 // Case 4: Number with both a fraction and an integer. 482 int decimalPos = dstr.indexOf('.'); 483 _setToLong(Long.parseLong(dstr.substring(0, decimalPos) + dstr.substring(decimalPos + 1))); 484 scale += decimalPos - dstr.length() + 1; 485 } 486 487 scale += delta; 488 compact(); 489 explicitExactDouble = true; 490 } 491 492 /** 493 * Whether this {@link DecimalQuantity_DualStorageBCD} has been explicitly converted to an exact double. true if 494 * backed by a double that was explicitly converted via convertToAccurateDouble; false otherwise. 495 * Used for testing. 496 * 497 * @internal 498 * @deprecated This API is ICU internal only. 499 */ 500 @Deprecated public boolean explicitExactDouble = false; 501 502 /** 503 * Sets the internal BCD state to represent the value in the given BigDecimal. 504 * 505 * @param n The value to consume. 506 */ 507 @Override 508 public void setToBigDecimal(BigDecimal n) { 509 setBcdToZero(); 510 flags = 0; 511 if (n.signum() == -1) { 512 flags |= NEGATIVE_FLAG; 513 n = n.negate(); 514 } 515 if (n.signum() != 0) { 516 _setToBigDecimal(n); 517 compact(); 518 } 519 } 520 521 private void _setToBigDecimal(BigDecimal n) { 522 int fracLength = n.scale(); 523 n = n.scaleByPowerOfTen(fracLength); 524 BigInteger bi = n.toBigInteger(); 525 _setToBigInteger(bi); 526 scale -= fracLength; 527 } 528 529 /** 530 * Returns a long approximating the internal BCD. A long can only represent the integral part of 531 * the number. 532 * 533 * @return A double representation of the internal BCD. 534 */ 535 protected long toLong() { 536 long result = 0L; 537 for (int magnitude = scale + precision - 1; magnitude >= 0; magnitude--) { 538 result = result * 10 + getDigitPos(magnitude - scale); 539 } 540 return result; 541 } 542 543 /** 544 * This returns a long representing the fraction digits of the number, as required by PluralRules. 545 * For example, if we represent the number "1.20" (including optional and required digits), then 546 * this function returns "20" if includeTrailingZeros is true or "2" if false. 547 */ 548 protected long toFractionLong(boolean includeTrailingZeros) { 549 long result = 0L; 550 int magnitude = -1; 551 for (; 552 (magnitude >= scale || (includeTrailingZeros && magnitude >= rReqPos)) 553 && magnitude >= rOptPos; 554 magnitude--) { 555 result = result * 10 + getDigitPos(magnitude - scale); 556 } 557 return result; 558 } 559 560 /** 561 * Returns a double approximating the internal BCD. The double may not retain all of the 562 * information encoded in the BCD if the BCD represents a number out of range of a double. 563 * 564 * @return A double representation of the internal BCD. 565 */ 566 @Override 567 public double toDouble() { 568 if (isApproximate) { 569 return toDoubleFromOriginal(); 570 } 571 572 if (isNaN()) { 573 return Double.NaN; 574 } else if (isInfinite()) { 575 return isNegative() ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; 576 } 577 578 long tempLong = 0L; 579 int lostDigits = precision - Math.min(precision, 17); 580 for (int shift = precision - 1; shift >= lostDigits; shift--) { 581 tempLong = tempLong * 10 + getDigitPos(shift); 582 } 583 double result = tempLong; 584 int _scale = scale + lostDigits; 585 if (_scale >= 0) { 586 // 1e22 is the largest exact double. 587 int i = _scale; 588 for (; i >= 22; i -= 22) result *= 1e22; 589 result *= DOUBLE_MULTIPLIERS[i]; 590 } else { 591 // 1e22 is the largest exact double. 592 int i = _scale; 593 for (; i <= -22; i += 22) result /= 1e22; 594 result /= DOUBLE_MULTIPLIERS[-i]; 595 } 596 if (isNegative()) result = -result; 597 return result; 598 } 599 600 @Override 601 public BigDecimal toBigDecimal() { 602 if (isApproximate) { 603 // Converting to a BigDecimal requires Double.toString(). 604 convertToAccurateDouble(); 605 } 606 return bcdToBigDecimal(); 607 } 608 609 protected double toDoubleFromOriginal() { 610 double result = origDouble; 611 int delta = origDelta; 612 if (delta >= 0) { 613 // 1e22 is the largest exact double. 614 for (; delta >= 22; delta -= 22) result *= 1e22; 615 result *= DOUBLE_MULTIPLIERS[delta]; 616 } else { 617 // 1e22 is the largest exact double. 618 for (; delta <= -22; delta += 22) result /= 1e22; 619 result /= DOUBLE_MULTIPLIERS[-delta]; 620 } 621 if (isNegative()) result *= -1; 622 return result; 623 } 624 625 private static int safeSubtract(int a, int b) { 626 int diff = a - b; 627 if (b < 0 && diff < a) return Integer.MAX_VALUE; 628 if (b > 0 && diff > a) return Integer.MIN_VALUE; 629 return diff; 630 } 631 632 private static final int SECTION_LOWER_EDGE = -1; 633 private static final int SECTION_UPPER_EDGE = -2; 634 635 @Override 636 public void roundToMagnitude(int magnitude, MathContext mathContext) { 637 // The position in the BCD at which rounding will be performed; digits to the right of position 638 // will be rounded away. 639 // TODO: Andy: There was a test failure because of integer overflow here. Should I do 640 // "safe subtraction" everywhere in the code? What's the nicest way to do it? 641 int position = safeSubtract(magnitude, scale); 642 643 // Enforce the number of digits required by the MathContext. 644 int _mcPrecision = mathContext.getPrecision(); 645 if (magnitude == Integer.MAX_VALUE 646 || (_mcPrecision > 0 && precision - position > _mcPrecision)) { 647 position = precision - _mcPrecision; 648 } 649 650 if (position <= 0 && !isApproximate) { 651 // All digits are to the left of the rounding magnitude. 652 } else if (precision == 0) { 653 // No rounding for zero. 654 } else { 655 // Perform rounding logic. 656 // "leading" = most significant digit to the right of rounding 657 // "trailing" = least significant digit to the left of rounding 658 byte leadingDigit = getDigitPos(safeSubtract(position, 1)); 659 byte trailingDigit = getDigitPos(position); 660 661 // Compute which section of the number we are in. 662 // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles) 663 // LOWER means we are between the bottom edge and the midpoint, like 1.391 664 // MIDPOINT means we are exactly in the middle, like 1.500 665 // UPPER means we are between the midpoint and the top edge, like 1.916 666 int section = RoundingUtils.SECTION_MIDPOINT; 667 if (!isApproximate) { 668 if (leadingDigit < 5) { 669 section = RoundingUtils.SECTION_LOWER; 670 } else if (leadingDigit > 5) { 671 section = RoundingUtils.SECTION_UPPER; 672 } else { 673 for (int p = safeSubtract(position, 2); p >= 0; p--) { 674 if (getDigitPos(p) != 0) { 675 section = RoundingUtils.SECTION_UPPER; 676 break; 677 } 678 } 679 } 680 } else { 681 int p = safeSubtract(position, 2); 682 int minP = Math.max(0, precision - 14); 683 if (leadingDigit == 0) { 684 section = SECTION_LOWER_EDGE; 685 for (; p >= minP; p--) { 686 if (getDigitPos(p) != 0) { 687 section = RoundingUtils.SECTION_LOWER; 688 break; 689 } 690 } 691 } else if (leadingDigit == 4) { 692 for (; p >= minP; p--) { 693 if (getDigitPos(p) != 9) { 694 section = RoundingUtils.SECTION_LOWER; 695 break; 696 } 697 } 698 } else if (leadingDigit == 5) { 699 for (; p >= minP; p--) { 700 if (getDigitPos(p) != 0) { 701 section = RoundingUtils.SECTION_UPPER; 702 break; 703 } 704 } 705 } else if (leadingDigit == 9) { 706 section = SECTION_UPPER_EDGE; 707 for (; p >= minP; p--) { 708 if (getDigitPos(p) != 9) { 709 section = RoundingUtils.SECTION_UPPER; 710 break; 711 } 712 } 713 } else if (leadingDigit < 5) { 714 section = RoundingUtils.SECTION_LOWER; 715 } else { 716 section = RoundingUtils.SECTION_UPPER; 717 } 718 719 boolean roundsAtMidpoint = 720 RoundingUtils.roundsAtMidpoint(mathContext.getRoundingMode().ordinal()); 721 if (safeSubtract(position, 1) < precision - 14 722 || (roundsAtMidpoint && section == RoundingUtils.SECTION_MIDPOINT) 723 || (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) { 724 // Oops! This means that we have to get the exact representation of the double, because 725 // the zone of uncertainty is along the rounding boundary. 726 convertToAccurateDouble(); 727 roundToMagnitude(magnitude, mathContext); // start over 728 return; 729 } 730 731 // Turn off the approximate double flag, since the value is now confirmed to be exact. 732 isApproximate = false; 733 origDouble = 0.0; 734 origDelta = 0; 735 736 if (position <= 0) { 737 // All digits are to the left of the rounding magnitude. 738 return; 739 } 740 741 // Good to continue rounding. 742 if (section == SECTION_LOWER_EDGE) section = RoundingUtils.SECTION_LOWER; 743 if (section == SECTION_UPPER_EDGE) section = RoundingUtils.SECTION_UPPER; 744 } 745 746 boolean roundDown = 747 RoundingUtils.getRoundingDirection( 748 (trailingDigit % 2) == 0, 749 isNegative(), 750 section, 751 mathContext.getRoundingMode().ordinal(), 752 this); 753 754 // Perform truncation 755 if (position >= precision) { 756 setBcdToZero(); 757 scale = magnitude; 758 } else { 759 shiftRight(position); 760 } 761 762 // Bubble the result to the higher digits 763 if (!roundDown) { 764 if (trailingDigit == 9) { 765 int bubblePos = 0; 766 // Note: in the long implementation, the most digits BCD can have at this point is 15, 767 // so bubblePos <= 15 and getDigitPos(bubblePos) is safe. 768 for (; getDigitPos(bubblePos) == 9; bubblePos++) {} 769 shiftRight(bubblePos); // shift off the trailing 9s 770 } 771 byte digit0 = getDigitPos(0); 772 assert digit0 != 9; 773 setDigitPos(0, (byte) (digit0 + 1)); 774 precision += 1; // in case an extra digit got added 775 } 776 777 compact(); 778 } 779 } 780 781 @Override 782 public void roundToInfinity() { 783 if (isApproximate) { 784 convertToAccurateDouble(); 785 } 786 } 787 788 /** 789 * Appends a digit, optionally with one or more leading zeros, to the end of the value represented 790 * by this DecimalQuantity. 791 * 792 * <p>The primary use of this method is to construct numbers during a parsing loop. It allows 793 * parsing to take advantage of the digit list infrastructure primarily designed for formatting. 794 * 795 * @param value The digit to append. 796 * @param leadingZeros The number of zeros to append before the digit. For example, if the value 797 * in this instance starts as 12.3, and you append a 4 with 1 leading zero, the value becomes 798 * 12.304. 799 * @param appendAsInteger If true, increase the magnitude of existing digits to make room for the 800 * new digit. If false, append to the end like a fraction digit. If true, there must not be 801 * any fraction digits already in the number. 802 * @internal 803 * @deprecated This API is ICU internal only. 804 */ 805 @Deprecated 806 public void appendDigit(byte value, int leadingZeros, boolean appendAsInteger) { 807 assert leadingZeros >= 0; 808 809 // Zero requires special handling to maintain the invariant that the least-significant digit 810 // in the BCD is nonzero. 811 if (value == 0) { 812 if (appendAsInteger && precision != 0) { 813 scale += leadingZeros + 1; 814 } 815 return; 816 } 817 818 // Deal with trailing zeros 819 if (scale > 0) { 820 leadingZeros += scale; 821 if (appendAsInteger) { 822 scale = 0; 823 } 824 } 825 826 // Append digit 827 shiftLeft(leadingZeros + 1); 828 setDigitPos(0, value); 829 830 // Fix scale if in integer mode 831 if (appendAsInteger) { 832 scale += leadingZeros + 1; 833 } 834 } 835 836 @Override 837 public String toPlainString() { 838 // NOTE: This logic is duplicated between here and DecimalQuantity_SimpleStorage. 839 StringBuilder sb = new StringBuilder(); 840 if (isNegative()) { 841 sb.append('-'); 842 } 843 for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) { 844 sb.append(getDigit(m)); 845 if (m == 0) sb.append('.'); 846 } 847 return sb.toString(); 848 } 849 850 /** 851 * Returns a single digit from the BCD list. No internal state is changed by calling this method. 852 * 853 * @param position The position of the digit to pop, counted in BCD units from the least 854 * significant digit. If outside the range supported by the implementation, zero is returned. 855 * @return The digit at the specified location. 856 */ 857 protected abstract byte getDigitPos(int position); 858 859 /** 860 * Sets the digit in the BCD list. This method only sets the digit; it is the caller's 861 * responsibility to call {@link #compact} after setting the digit. 862 * 863 * @param position The position of the digit to pop, counted in BCD units from the least 864 * significant digit. If outside the range supported by the implementation, an AssertionError 865 * is thrown. 866 * @param value The digit to set at the specified location. 867 */ 868 protected abstract void setDigitPos(int position, byte value); 869 870 /** 871 * Adds zeros to the end of the BCD list. This will result in an invalid BCD representation; it is 872 * the caller's responsibility to do further manipulation and then call {@link #compact}. 873 * 874 * @param numDigits The number of zeros to add. 875 */ 876 protected abstract void shiftLeft(int numDigits); 877 878 protected abstract void shiftRight(int numDigits); 879 880 /** 881 * Sets the internal representation to zero. Clears any values stored in scale, precision, 882 * hasDouble, origDouble, origDelta, and BCD data. 883 */ 884 protected abstract void setBcdToZero(); 885 886 /** 887 * Sets the internal BCD state to represent the value in the given int. The int is guaranteed to 888 * be either positive. The internal state is guaranteed to be empty when this method is called. 889 * 890 * @param n The value to consume. 891 */ 892 protected abstract void readIntToBcd(int input); 893 894 /** 895 * Sets the internal BCD state to represent the value in the given long. The long is guaranteed to 896 * be either positive. The internal state is guaranteed to be empty when this method is called. 897 * 898 * @param n The value to consume. 899 */ 900 protected abstract void readLongToBcd(long input); 901 902 /** 903 * Sets the internal BCD state to represent the value in the given BigInteger. The BigInteger is 904 * guaranteed to be positive, and it is guaranteed to be larger than Long.MAX_VALUE. The internal 905 * state is guaranteed to be empty when this method is called. 906 * 907 * @param n The value to consume. 908 */ 909 protected abstract void readBigIntegerToBcd(BigInteger input); 910 911 /** 912 * Returns a BigDecimal encoding the internal BCD value. 913 * 914 * @return A BigDecimal representation of the internal BCD. 915 */ 916 protected abstract BigDecimal bcdToBigDecimal(); 917 918 protected abstract void copyBcdFrom(DecimalQuantity _other); 919 920 /** 921 * Removes trailing zeros from the BCD (adjusting the scale as required) and then computes the 922 * precision. The precision is the number of digits in the number up through the greatest nonzero 923 * digit. 924 * 925 * <p>This method must always be called when bcd changes in order for assumptions to be correct in 926 * methods like {@link #fractionCount()}. 927 */ 928 protected abstract void compact(); 929 } 930