1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2017 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 package ohos.global.icu.impl.number; 5 6 import java.math.BigDecimal; 7 import java.math.BigInteger; 8 import java.math.MathContext; 9 import java.text.FieldPosition; 10 11 import ohos.global.icu.impl.StandardPlural; 12 import ohos.global.icu.impl.Utility; 13 import ohos.global.icu.impl.number.Modifier.Signum; 14 import ohos.global.icu.text.PluralRules; 15 import ohos.global.icu.text.PluralRules.Operand; 16 import ohos.global.icu.text.UFieldPosition; 17 18 /** 19 * Represents numbers and digit display properties using Binary Coded Decimal (BCD). 20 * 21 * @implements {@link DecimalQuantity} 22 * @hide exposed on OHOS 23 */ 24 public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity { 25 26 /** 27 * The power of ten corresponding to the least significant digit in the BCD. For example, if this 28 * object represents the number "3.14", the BCD will be "0x314" and the scale will be -2. 29 * 30 * <p> 31 * Note that in {@link java.math.BigDecimal}, the scale is defined differently: the number of digits 32 * after the decimal place, which is the negative of our definition of scale. 33 */ 34 protected int scale; 35 36 /** 37 * The number of digits in the BCD. For example, "1007" has BCD "0x1007" and precision 4. A long 38 * cannot represent precisions greater than 16. 39 * 40 * <p> 41 * This value must be re-calculated whenever the value in bcd changes by using 42 * {@link #computePrecisionAndCompact()}. 43 */ 44 protected int precision; 45 46 /** 47 * A bitmask of properties relating to the number represented by this object. 48 * 49 * @see #NEGATIVE_FLAG 50 * @see #INFINITY_FLAG 51 * @see #NAN_FLAG 52 */ 53 protected byte flags; 54 55 protected static final int NEGATIVE_FLAG = 1; 56 protected static final int INFINITY_FLAG = 2; 57 protected static final int NAN_FLAG = 4; 58 59 // The following three fields relate to the double-to-ascii fast path algorithm. 60 // When a double is given to DecimalQuantityBCD, it is converted to using a fast algorithm. The 61 // fast algorithm guarantees correctness to only the first ~12 digits of the double. The process 62 // of rounding the number ensures that the converted digits are correct, falling back to a slow- 63 // path algorithm if required. Therefore, if a DecimalQuantity is constructed from a double, it 64 // is *required* that roundToMagnitude(), roundToIncrement(), or roundToInfinity() is called. If 65 // you don't round, assertions will fail in certain other methods if you try calling them. 66 67 /** 68 * The original number provided by the user and which is represented in BCD. Used when we need to 69 * re-compute the BCD for an exact double representation. 70 */ 71 protected double origDouble; 72 73 /** 74 * The change in magnitude relative to the original double. Used when we need to re-compute the BCD 75 * for an exact double representation. 76 */ 77 protected int origDelta; 78 79 /** 80 * Whether the value in the BCD comes from the double fast path without having been rounded to ensure 81 * correctness 82 */ 83 protected boolean isApproximate; 84 85 // Positions to keep track of leading and trailing zeros. 86 // lReqPos is the magnitude of the first required leading zero. 87 // rReqPos is the magnitude of the last required trailing zero. 88 protected int lReqPos = 0; 89 protected int rReqPos = 0; 90 91 /** 92 * The value of the (suppressed) exponent after the number has been put into 93 * a notation with exponents (ex: compact, scientific). 94 */ 95 protected int exponent = 0; 96 97 @Override copyFrom(DecimalQuantity _other)98 public void copyFrom(DecimalQuantity _other) { 99 copyBcdFrom(_other); 100 DecimalQuantity_AbstractBCD other = (DecimalQuantity_AbstractBCD) _other; 101 lReqPos = other.lReqPos; 102 rReqPos = other.rReqPos; 103 scale = other.scale; 104 precision = other.precision; 105 flags = other.flags; 106 origDouble = other.origDouble; 107 origDelta = other.origDelta; 108 isApproximate = other.isApproximate; 109 exponent = other.exponent; 110 } 111 clear()112 public DecimalQuantity_AbstractBCD clear() { 113 lReqPos = 0; 114 rReqPos = 0; 115 flags = 0; 116 setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, exponent, and BCD data 117 return this; 118 } 119 120 @Override setMinInteger(int minInt)121 public void setMinInteger(int minInt) { 122 // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class. 123 assert minInt >= 0; 124 125 // Special behavior: do not set minInt to be less than what is already set. 126 // This is so significant digits rounding can set the integer length. 127 if (minInt < lReqPos) { 128 minInt = lReqPos; 129 } 130 131 // Save values into internal state 132 lReqPos = minInt; 133 } 134 135 @Override setMinFraction(int minFrac)136 public void setMinFraction(int minFrac) { 137 // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class. 138 assert minFrac >= 0; 139 140 // Save values into internal state 141 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE 142 rReqPos = -minFrac; 143 } 144 145 @Override applyMaxInteger(int maxInt)146 public void applyMaxInteger(int maxInt) { 147 // Validation should happen outside of DecimalQuantity, e.g., in the Precision class. 148 assert maxInt >= 0; 149 150 if (precision == 0) { 151 return; 152 } 153 154 if (maxInt <= scale) { 155 setBcdToZero(); 156 return; 157 } 158 159 int magnitude = getMagnitude(); 160 if (maxInt <= magnitude) { 161 popFromLeft(magnitude - maxInt + 1); 162 compact(); 163 } 164 } 165 166 @Override getPositionFingerprint()167 public long getPositionFingerprint() { 168 long fingerprint = 0; 169 fingerprint ^= (lReqPos << 16); 170 fingerprint ^= ((long) rReqPos << 32); 171 return fingerprint; 172 } 173 174 @Override roundToIncrement(BigDecimal roundingIncrement, MathContext mathContext)175 public void roundToIncrement(BigDecimal roundingIncrement, MathContext mathContext) { 176 // Do not call this method with an increment having only a 1 or a 5 digit! 177 // Use a more efficient call to either roundToMagnitude() or roundToNickel(). 178 // Note: The check, which is somewhat expensive, is performed in an assertion 179 // to disable it in production. 180 assert roundingIncrement.stripTrailingZeros().precision() != 1 181 || roundingIncrement.stripTrailingZeros().unscaledValue().intValue() != 5 182 || roundingIncrement.stripTrailingZeros().unscaledValue().intValue() != 1; 183 BigDecimal temp = toBigDecimal(); 184 temp = temp.divide(roundingIncrement, 0, mathContext.getRoundingMode()) 185 .multiply(roundingIncrement) 186 .round(mathContext); 187 if (temp.signum() == 0) { 188 setBcdToZero(); // keeps negative flag for -0.0 189 } else { 190 setToBigDecimal(temp); 191 } 192 } 193 194 @Override multiplyBy(BigDecimal multiplicand)195 public void multiplyBy(BigDecimal multiplicand) { 196 if (isZeroish()) { 197 return; 198 } 199 BigDecimal temp = toBigDecimal(); 200 temp = temp.multiply(multiplicand); 201 setToBigDecimal(temp); 202 } 203 204 @Override negate()205 public void negate() { 206 flags ^= NEGATIVE_FLAG; 207 } 208 209 @Override getMagnitude()210 public int getMagnitude() throws ArithmeticException { 211 if (precision == 0) { 212 throw new ArithmeticException("Magnitude is not well-defined for zero"); 213 } else { 214 return scale + precision - 1; 215 } 216 } 217 218 @Override adjustMagnitude(int delta)219 public void adjustMagnitude(int delta) { 220 if (precision != 0) { 221 scale = Utility.addExact(scale, delta); 222 origDelta = Utility.addExact(origDelta, delta); 223 // Make sure that precision + scale won't overflow, either 224 Utility.addExact(scale, precision); 225 } 226 } 227 228 @Override getExponent()229 public int getExponent() { 230 return exponent; 231 } 232 233 @Override adjustExponent(int delta)234 public void adjustExponent(int delta) { 235 exponent = exponent + delta; 236 } 237 238 @Override getStandardPlural(PluralRules rules)239 public StandardPlural getStandardPlural(PluralRules rules) { 240 if (rules == null) { 241 // Fail gracefully if the user didn't provide a PluralRules 242 return StandardPlural.OTHER; 243 } else { 244 @SuppressWarnings("deprecation") 245 String ruleString = rules.select(this); 246 return StandardPlural.orOtherFromString(ruleString); 247 } 248 } 249 250 @Override getPluralOperand(Operand operand)251 public double getPluralOperand(Operand operand) { 252 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 253 // See the comment at the top of this file explaining the "isApproximate" field. 254 assert !isApproximate; 255 256 switch (operand) { 257 case i: 258 // Invert the negative sign if necessary 259 return isNegative() ? -toLong(true) : toLong(true); 260 case f: 261 return toFractionLong(true); 262 case t: 263 return toFractionLong(false); 264 case v: 265 return fractionCount(); 266 case w: 267 return fractionCountWithoutTrailingZeros(); 268 case e: 269 return getExponent(); 270 default: 271 return Math.abs(toDouble()); 272 } 273 } 274 275 @Override populateUFieldPosition(FieldPosition fp)276 public void populateUFieldPosition(FieldPosition fp) { 277 if (fp instanceof UFieldPosition) { 278 ((UFieldPosition) fp).setFractionDigits((int) getPluralOperand(Operand.v), 279 (long) getPluralOperand(Operand.f)); 280 } 281 } 282 283 @Override getUpperDisplayMagnitude()284 public int getUpperDisplayMagnitude() { 285 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 286 // See the comment at the top of this file explaining the "isApproximate" field. 287 assert !isApproximate; 288 289 int magnitude = scale + precision; 290 int result = (lReqPos > magnitude) ? lReqPos : magnitude; 291 return result - 1; 292 } 293 294 @Override getLowerDisplayMagnitude()295 public int getLowerDisplayMagnitude() { 296 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 297 // See the comment at the top of this file explaining the "isApproximate" field. 298 assert !isApproximate; 299 300 int magnitude = scale; 301 int result = (rReqPos < magnitude) ? rReqPos : magnitude; 302 return result; 303 } 304 305 @Override getDigit(int magnitude)306 public byte getDigit(int magnitude) { 307 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 308 // See the comment at the top of this file explaining the "isApproximate" field. 309 assert !isApproximate; 310 311 return getDigitPos(magnitude - scale); 312 } 313 fractionCount()314 private int fractionCount() { 315 return Math.max(0, -getLowerDisplayMagnitude() - exponent); 316 } 317 fractionCountWithoutTrailingZeros()318 private int fractionCountWithoutTrailingZeros() { 319 return Math.max(-scale - exponent, 0); 320 } 321 322 @Override isNegative()323 public boolean isNegative() { 324 return (flags & NEGATIVE_FLAG) != 0; 325 } 326 327 @Override signum()328 public Signum signum() { 329 boolean isZero = (isZeroish() && !isInfinite()); 330 boolean isNeg = isNegative(); 331 if (isZero && isNeg) { 332 return Signum.NEG_ZERO; 333 } else if (isZero) { 334 return Signum.POS_ZERO; 335 } else if (isNeg) { 336 return Signum.NEG; 337 } else { 338 return Signum.POS; 339 } 340 } 341 342 @Override isInfinite()343 public boolean isInfinite() { 344 return (flags & INFINITY_FLAG) != 0; 345 } 346 347 @Override isNaN()348 public boolean isNaN() { 349 return (flags & NAN_FLAG) != 0; 350 } 351 352 @Override isZeroish()353 public boolean isZeroish() { 354 return precision == 0; 355 } 356 setToInt(int n)357 public void setToInt(int n) { 358 setBcdToZero(); 359 flags = 0; 360 if (n < 0) { 361 flags |= NEGATIVE_FLAG; 362 n = -n; 363 } 364 if (n != 0) { 365 _setToInt(n); 366 compact(); 367 } 368 } 369 _setToInt(int n)370 private void _setToInt(int n) { 371 if (n == Integer.MIN_VALUE) { 372 readLongToBcd(-(long) n); 373 } else { 374 readIntToBcd(n); 375 } 376 } 377 setToLong(long n)378 public void setToLong(long n) { 379 setBcdToZero(); 380 flags = 0; 381 if (n < 0) { 382 flags |= NEGATIVE_FLAG; 383 n = -n; 384 } 385 if (n != 0) { 386 _setToLong(n); 387 compact(); 388 } 389 } 390 _setToLong(long n)391 private void _setToLong(long n) { 392 if (n == Long.MIN_VALUE) { 393 readBigIntegerToBcd(BigInteger.valueOf(n).negate()); 394 } else if (n <= Integer.MAX_VALUE) { 395 readIntToBcd((int) n); 396 } else { 397 readLongToBcd(n); 398 } 399 } 400 setToBigInteger(BigInteger n)401 public void setToBigInteger(BigInteger n) { 402 setBcdToZero(); 403 flags = 0; 404 if (n.signum() == -1) { 405 flags |= NEGATIVE_FLAG; 406 n = n.negate(); 407 } 408 if (n.signum() != 0) { 409 _setToBigInteger(n); 410 compact(); 411 } 412 } 413 _setToBigInteger(BigInteger n)414 private void _setToBigInteger(BigInteger n) { 415 if (n.bitLength() < 32) { 416 readIntToBcd(n.intValue()); 417 } else if (n.bitLength() < 64) { 418 readLongToBcd(n.longValue()); 419 } else { 420 readBigIntegerToBcd(n); 421 } 422 } 423 424 /** 425 * Sets the internal BCD state to represent the value in the given double. 426 * 427 * @param n 428 * The value to consume. 429 */ setToDouble(double n)430 public void setToDouble(double n) { 431 setBcdToZero(); 432 flags = 0; 433 // The sign bit is the top bit in both double and long, so we can 434 // get the long bits for the double and compare it to zero to check 435 // the sign of the double. 436 if (Double.doubleToRawLongBits(n) < 0) { 437 flags |= NEGATIVE_FLAG; 438 n = -n; 439 } 440 if (Double.isNaN(n)) { 441 flags |= NAN_FLAG; 442 } else if (Double.isInfinite(n)) { 443 flags |= INFINITY_FLAG; 444 } else if (n != 0) { 445 _setToDoubleFast(n); 446 compact(); 447 } 448 } 449 450 private static final double[] DOUBLE_MULTIPLIERS = { 451 1e0, 452 1e1, 453 1e2, 454 1e3, 455 1e4, 456 1e5, 457 1e6, 458 1e7, 459 1e8, 460 1e9, 461 1e10, 462 1e11, 463 1e12, 464 1e13, 465 1e14, 466 1e15, 467 1e16, 468 1e17, 469 1e18, 470 1e19, 471 1e20, 472 1e21 }; 473 474 /** 475 * Uses double multiplication and division to get the number into integer space before converting to 476 * digits. Since double arithmetic is inexact, the resulting digits may not be accurate. 477 */ _setToDoubleFast(double n)478 private void _setToDoubleFast(double n) { 479 isApproximate = true; 480 origDouble = n; 481 origDelta = 0; 482 483 // NOTE: Unlike ICU4C, doubles are always IEEE 754 doubles. 484 long ieeeBits = Double.doubleToLongBits(n); 485 int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff; 486 487 // Not all integers can be represented exactly for exponent > 52 488 if (exponent <= 52 && (long) n == n) { 489 _setToLong((long) n); 490 return; 491 } 492 493 if (exponent == -1023 || exponent == 1024) { 494 // The extreme values of exponent are special; use slow path. 495 convertToAccurateDouble(); 496 return; 497 } 498 499 // 3.3219... is log2(10) 500 int fracLength = (int) ((52 - exponent) / 3.32192809488736234787031942948939017586); 501 if (fracLength >= 0) { 502 int i = fracLength; 503 // 1e22 is the largest exact double. 504 for (; i >= 22; i -= 22) 505 n *= 1e22; 506 n *= DOUBLE_MULTIPLIERS[i]; 507 } else { 508 int i = fracLength; 509 // 1e22 is the largest exact double. 510 for (; i <= -22; i += 22) 511 n /= 1e22; 512 n /= DOUBLE_MULTIPLIERS[-i]; 513 } 514 long result = Math.round(n); 515 if (result != 0) { 516 _setToLong(result); 517 scale -= fracLength; 518 } 519 } 520 521 /** 522 * Uses Double.toString() to obtain an exact accurate representation of the double, overwriting it 523 * into the BCD. This method can be called at any point after {@link #_setToDoubleFast} while 524 * {@link #isApproximate} is still true. 525 */ convertToAccurateDouble()526 private void convertToAccurateDouble() { 527 double n = origDouble; 528 assert n != 0; 529 int delta = origDelta; 530 setBcdToZero(); 531 532 // Call the slow oracle function (Double.toString in Java, sprintf in C++). 533 String dstr = Double.toString(n); 534 535 if (dstr.indexOf('E') != -1) { 536 // Case 1: Exponential notation. 537 assert dstr.indexOf('.') == 1; 538 int expPos = dstr.indexOf('E'); 539 _setToLong(Long.parseLong(dstr.charAt(0) + dstr.substring(2, expPos))); 540 scale += Integer.parseInt(dstr.substring(expPos + 1)) - (expPos - 1) + 1; 541 } else if (dstr.charAt(0) == '0') { 542 // Case 2: Fraction-only number. 543 assert dstr.indexOf('.') == 1; 544 _setToLong(Long.parseLong(dstr.substring(2))); 545 scale += 2 - dstr.length(); 546 } else if (dstr.charAt(dstr.length() - 1) == '0') { 547 // Case 3: Integer-only number. 548 // Note: this path should not normally happen, because integer-only numbers are captured 549 // before the approximate double logic is performed. 550 assert dstr.indexOf('.') == dstr.length() - 2; 551 assert dstr.length() - 2 <= 18; 552 _setToLong(Long.parseLong(dstr.substring(0, dstr.length() - 2))); 553 // no need to adjust scale 554 } else { 555 // Case 4: Number with both a fraction and an integer. 556 int decimalPos = dstr.indexOf('.'); 557 _setToLong(Long.parseLong(dstr.substring(0, decimalPos) + dstr.substring(decimalPos + 1))); 558 scale += decimalPos - dstr.length() + 1; 559 } 560 561 scale += delta; 562 compact(); 563 explicitExactDouble = true; 564 } 565 566 /** 567 * Whether this {@link DecimalQuantity_DualStorageBCD} has been explicitly converted to an exact 568 * double. true if backed by a double that was explicitly converted via convertToAccurateDouble; 569 * false otherwise. Used for testing. 570 * 571 * @deprecated This API is ICU internal only. 572 * @hide draft / provisional / internal are hidden on OHOS 573 */ 574 @Deprecated 575 public boolean explicitExactDouble = false; 576 577 /** 578 * Sets the internal BCD state to represent the value in the given BigDecimal. 579 * 580 * @param n 581 * The value to consume. 582 */ 583 @Override setToBigDecimal(BigDecimal n)584 public void setToBigDecimal(BigDecimal n) { 585 setBcdToZero(); 586 flags = 0; 587 if (n.signum() == -1) { 588 flags |= NEGATIVE_FLAG; 589 n = n.negate(); 590 } 591 if (n.signum() != 0) { 592 _setToBigDecimal(n); 593 compact(); 594 } 595 } 596 _setToBigDecimal(BigDecimal n)597 private void _setToBigDecimal(BigDecimal n) { 598 int fracLength = n.scale(); 599 n = n.scaleByPowerOfTen(fracLength); 600 BigInteger bi = n.toBigInteger(); 601 _setToBigInteger(bi); 602 scale -= fracLength; 603 } 604 605 /** 606 * Returns a long approximating the internal BCD. A long can only represent the integral part of the 607 * number. Note: this method incorporates the value of {@code exponent} 608 * (for cases such as compact notation) to return the proper long value 609 * represented by the result. 610 * 611 * @param truncateIfOverflow if false and the number does NOT fit, fails with an assertion error. 612 * @return A 64-bit integer representation of the internal BCD. 613 */ toLong(boolean truncateIfOverflow)614 public long toLong(boolean truncateIfOverflow) { 615 // NOTE: Call sites should be guarded by fitsInLong(), like this: 616 // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ } 617 // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits. 618 assert(truncateIfOverflow || fitsInLong()); 619 long result = 0L; 620 int upperMagnitude = exponent + scale + precision - 1; 621 if (truncateIfOverflow) { 622 upperMagnitude = Math.min(upperMagnitude, 17); 623 } 624 for (int magnitude = upperMagnitude; magnitude >= 0; magnitude--) { 625 result = result * 10 + getDigitPos(magnitude - scale - exponent); 626 } 627 if (isNegative()) { 628 result = -result; 629 } 630 return result; 631 } 632 633 /** 634 * This returns a long representing the fraction digits of the number, as required by PluralRules. 635 * For example, if we represent the number "1.20" (including optional and required digits), then this 636 * function returns "20" if includeTrailingZeros is true or "2" if false. 637 * Note: this method incorporates the value of {@code exponent} 638 * (for cases such as compact notation) to return the proper long value 639 * represented by the result. 640 */ toFractionLong(boolean includeTrailingZeros)641 public long toFractionLong(boolean includeTrailingZeros) { 642 long result = 0L; 643 int magnitude = -1 - exponent; 644 int lowerMagnitude = scale; 645 if (includeTrailingZeros) { 646 lowerMagnitude = Math.min(lowerMagnitude, rReqPos); 647 } 648 // NOTE: Java has only signed longs, so we check result <= 1e17 instead of 1e18 649 for (; magnitude >= lowerMagnitude && result <= 1e17; magnitude--) { 650 result = result * 10 + getDigitPos(magnitude - scale); 651 } 652 // Remove trailing zeros; this can happen during integer overflow cases. 653 if (!includeTrailingZeros) { 654 while (result > 0 && (result % 10) == 0) { 655 result /= 10; 656 } 657 } 658 return result; 659 } 660 661 static final byte[] INT64_BCD = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 }; 662 663 /** 664 * Returns whether or not a Long can fully represent the value stored in this DecimalQuantity. 665 */ fitsInLong()666 public boolean fitsInLong() { 667 if (isInfinite() || isNaN()) { 668 return false; 669 } 670 if (isZeroish()) { 671 return true; 672 } 673 if (exponent + scale < 0) { 674 return false; 675 } 676 int magnitude = getMagnitude(); 677 if (magnitude < 18) { 678 return true; 679 } 680 if (magnitude > 18) { 681 return false; 682 } 683 // Hard case: the magnitude is 10^18. 684 // The largest int64 is: 9,223,372,036,854,775,807 685 for (int p = 0; p < precision; p++) { 686 byte digit = getDigit(18 - p); 687 if (digit < INT64_BCD[p]) { 688 return true; 689 } else if (digit > INT64_BCD[p]) { 690 return false; 691 } 692 } 693 // Exactly equal to max long plus one. 694 return isNegative(); 695 } 696 697 /** 698 * Returns a double approximating the internal BCD. The double may not retain all of the information 699 * encoded in the BCD if the BCD represents a number out of range of a double. 700 * 701 * @return A double representation of the internal BCD. 702 */ 703 @Override toDouble()704 public double toDouble() { 705 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 706 // See the comment at the top of this file explaining the "isApproximate" field. 707 assert !isApproximate; 708 709 if (isNaN()) { 710 return Double.NaN; 711 } else if (isInfinite()) { 712 return isNegative() ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; 713 } 714 715 StringBuilder sb = new StringBuilder(); 716 toScientificString(sb); 717 return Double.valueOf(sb.toString()); 718 } 719 720 @Override toBigDecimal()721 public BigDecimal toBigDecimal() { 722 if (isApproximate) { 723 // Converting to a BigDecimal requires Double.toString(). 724 convertToAccurateDouble(); 725 } 726 return bcdToBigDecimal(); 727 } 728 safeSubtract(int a, int b)729 private static int safeSubtract(int a, int b) { 730 int diff = a - b; 731 if (b < 0 && diff < a) 732 return Integer.MAX_VALUE; 733 if (b > 0 && diff > a) 734 return Integer.MIN_VALUE; 735 return diff; 736 } 737 738 private static final int SECTION_LOWER_EDGE = -1; 739 private static final int SECTION_UPPER_EDGE = -2; 740 741 /** Removes all fraction digits. */ truncate()742 public void truncate() { 743 if (scale < 0) { 744 shiftRight(-scale); 745 scale = 0; 746 compact(); 747 } 748 } 749 750 @Override roundToNickel(int magnitude, MathContext mathContext)751 public void roundToNickel(int magnitude, MathContext mathContext) { 752 roundToMagnitude(magnitude, mathContext, true); 753 } 754 755 @Override roundToMagnitude(int magnitude, MathContext mathContext)756 public void roundToMagnitude(int magnitude, MathContext mathContext) { 757 roundToMagnitude(magnitude, mathContext, false); 758 } 759 roundToMagnitude(int magnitude, MathContext mathContext, boolean nickel)760 private void roundToMagnitude(int magnitude, MathContext mathContext, boolean nickel) { 761 // The position in the BCD at which rounding will be performed; digits to the right of position 762 // will be rounded away. 763 int position = safeSubtract(magnitude, scale); 764 765 // Enforce the number of digits required by the MathContext. 766 int _mcPrecision = mathContext.getPrecision(); 767 if (_mcPrecision > 0 && precision - _mcPrecision > position) { 768 position = precision - _mcPrecision; 769 } 770 771 // "trailing" = least significant digit to the left of rounding 772 byte trailingDigit = getDigitPos(position); 773 774 if (position <= 0 && !isApproximate && (!nickel || trailingDigit == 0 || trailingDigit == 5)) { 775 // All digits are to the left of the rounding magnitude. 776 } else if (precision == 0) { 777 // No rounding for zero. 778 } else { 779 // Perform rounding logic. 780 // "leading" = most significant digit to the right of rounding 781 byte leadingDigit = getDigitPos(safeSubtract(position, 1)); 782 783 // Compute which section of the number we are in. 784 // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles) 785 // LOWER means we are between the bottom edge and the midpoint, like 1.391 786 // MIDPOINT means we are exactly in the middle, like 1.500 787 // UPPER means we are between the midpoint and the top edge, like 1.916 788 int section; 789 if (!isApproximate) { 790 if (nickel && trailingDigit != 2 && trailingDigit != 7) { 791 // Nickel rounding, and not at .02x or .07x 792 if (trailingDigit < 2) { 793 // .00, .01 => down to .00 794 section = RoundingUtils.SECTION_LOWER; 795 } else if (trailingDigit < 5) { 796 // .03, .04 => up to .05 797 section = RoundingUtils.SECTION_UPPER; 798 } else if (trailingDigit < 7) { 799 // .05, .06 => down to .05 800 section = RoundingUtils.SECTION_LOWER; 801 } else { 802 // .08, .09 => up to .10 803 section = RoundingUtils.SECTION_UPPER; 804 } 805 } else if (leadingDigit < 5) { 806 // Includes nickel rounding .020-.024 and .070-.074 807 section = RoundingUtils.SECTION_LOWER; 808 } else if (leadingDigit > 5) { 809 // Includes nickel rounding .026-.029 and .076-.079 810 section = RoundingUtils.SECTION_UPPER; 811 } else { 812 // Includes nickel rounding .025 and .075 813 section = RoundingUtils.SECTION_MIDPOINT; 814 for (int p = safeSubtract(position, 2); p >= 0; p--) { 815 if (getDigitPos(p) != 0) { 816 section = RoundingUtils.SECTION_UPPER; 817 break; 818 } 819 } 820 } 821 } else { 822 int p = safeSubtract(position, 2); 823 int minP = Math.max(0, precision - 14); 824 if (leadingDigit == 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) { 825 section = SECTION_LOWER_EDGE; 826 for (; p >= minP; p--) { 827 if (getDigitPos(p) != 0) { 828 section = RoundingUtils.SECTION_LOWER; 829 break; 830 } 831 } 832 } else if (leadingDigit == 4 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) { 833 section = RoundingUtils.SECTION_MIDPOINT; 834 for (; p >= minP; p--) { 835 if (getDigitPos(p) != 9) { 836 section = RoundingUtils.SECTION_LOWER; 837 break; 838 } 839 } 840 } else if (leadingDigit == 5 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) { 841 section = RoundingUtils.SECTION_MIDPOINT; 842 for (; p >= minP; p--) { 843 if (getDigitPos(p) != 0) { 844 section = RoundingUtils.SECTION_UPPER; 845 break; 846 } 847 } 848 } else if (leadingDigit == 9 && (!nickel || trailingDigit == 4 || trailingDigit == 9)) { 849 section = SECTION_UPPER_EDGE; 850 for (; p >= minP; p--) { 851 if (getDigitPos(p) != 9) { 852 section = RoundingUtils.SECTION_UPPER; 853 break; 854 } 855 } 856 } else if (nickel && trailingDigit != 2 && trailingDigit != 7) { 857 // Nickel rounding, and not at .02x or .07x 858 if (trailingDigit < 2) { 859 // .00, .01 => down to .00 860 section = RoundingUtils.SECTION_LOWER; 861 } else if (trailingDigit < 5) { 862 // .03, .04 => up to .05 863 section = RoundingUtils.SECTION_UPPER; 864 } else if (trailingDigit < 7) { 865 // .05, .06 => down to .05 866 section = RoundingUtils.SECTION_LOWER; 867 } else { 868 // .08, .09 => up to .10 869 section = RoundingUtils.SECTION_UPPER; 870 } 871 } else if (leadingDigit < 5) { 872 // Includes nickel rounding .020-.024 and .070-.074 873 section = RoundingUtils.SECTION_LOWER; 874 } else { 875 // Includes nickel rounding .026-.029 and .076-.079 876 section = RoundingUtils.SECTION_UPPER; 877 } 878 879 boolean roundsAtMidpoint = RoundingUtils 880 .roundsAtMidpoint(mathContext.getRoundingMode().ordinal()); 881 if (safeSubtract(position, 1) < precision - 14 882 || (roundsAtMidpoint && section == RoundingUtils.SECTION_MIDPOINT) 883 || (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) { 884 // Oops! This means that we have to get the exact representation of the double, 885 // because the zone of uncertainty is along the rounding boundary. 886 convertToAccurateDouble(); 887 roundToMagnitude(magnitude, mathContext, nickel); // start over 888 return; 889 } 890 891 // Turn off the approximate double flag, since the value is now confirmed to be exact. 892 isApproximate = false; 893 origDouble = 0.0; 894 origDelta = 0; 895 896 if (position <= 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) { 897 // All digits are to the left of the rounding magnitude. 898 return; 899 } 900 901 // Good to continue rounding. 902 if (section == SECTION_LOWER_EDGE) 903 section = RoundingUtils.SECTION_LOWER; 904 if (section == SECTION_UPPER_EDGE) 905 section = RoundingUtils.SECTION_UPPER; 906 } 907 908 // Nickel rounding "half even" goes to the nearest whole (away from the 5). 909 boolean isEven = nickel 910 ? (trailingDigit < 2 || trailingDigit > 7 911 || (trailingDigit == 2 && section != RoundingUtils.SECTION_UPPER) 912 || (trailingDigit == 7 && section == RoundingUtils.SECTION_UPPER)) 913 : (trailingDigit % 2) == 0; 914 915 boolean roundDown = RoundingUtils.getRoundingDirection(isEven, 916 isNegative(), 917 section, 918 mathContext.getRoundingMode().ordinal(), 919 this); 920 921 // Perform truncation 922 if (position >= precision) { 923 setBcdToZero(); 924 scale = magnitude; 925 } else { 926 shiftRight(position); 927 } 928 929 if (nickel) { 930 if (trailingDigit < 5 && roundDown) { 931 setDigitPos(0, (byte) 0); 932 compact(); 933 return; 934 } else if (trailingDigit >= 5 && !roundDown) { 935 setDigitPos(0, (byte) 9); 936 trailingDigit = 9; 937 // do not return: use the bubbling logic below 938 } else { 939 setDigitPos(0, (byte) 5); 940 // compact not necessary: digit at position 0 is nonzero 941 return; 942 } 943 } 944 945 // Bubble the result to the higher digits 946 if (!roundDown) { 947 if (trailingDigit == 9) { 948 int bubblePos = 0; 949 // Note: in the long implementation, the most digits BCD can have at this point is 950 // 15, so bubblePos <= 15 and getDigitPos(bubblePos) is safe. 951 for (; getDigitPos(bubblePos) == 9; bubblePos++) { 952 } 953 shiftRight(bubblePos); // shift off the trailing 9s 954 } 955 byte digit0 = getDigitPos(0); 956 assert digit0 != 9; 957 setDigitPos(0, (byte) (digit0 + 1)); 958 precision += 1; // in case an extra digit got added 959 } 960 961 compact(); 962 } 963 } 964 965 @Override roundToInfinity()966 public void roundToInfinity() { 967 if (isApproximate) { 968 convertToAccurateDouble(); 969 } 970 } 971 972 /** 973 * Appends a digit, optionally with one or more leading zeros, to the end of the value represented by 974 * this DecimalQuantity. 975 * 976 * <p> 977 * The primary use of this method is to construct numbers during a parsing loop. It allows parsing to 978 * take advantage of the digit list infrastructure primarily designed for formatting. 979 * 980 * @param value 981 * The digit to append. 982 * @param leadingZeros 983 * The number of zeros to append before the digit. For example, if the value in this 984 * instance starts as 12.3, and you append a 4 with 1 leading zero, the value becomes 985 * 12.304. 986 * @param appendAsInteger 987 * If true, increase the magnitude of existing digits to make room for the new digit. If 988 * false, append to the end like a fraction digit. If true, there must not be any fraction 989 * digits already in the number. 990 * @deprecated This API is ICU internal only. 991 * @hide draft / provisional / internal are hidden on OHOS 992 */ 993 @Deprecated appendDigit(byte value, int leadingZeros, boolean appendAsInteger)994 public void appendDigit(byte value, int leadingZeros, boolean appendAsInteger) { 995 assert leadingZeros >= 0; 996 997 // Zero requires special handling to maintain the invariant that the least-significant digit 998 // in the BCD is nonzero. 999 if (value == 0) { 1000 if (appendAsInteger && precision != 0) { 1001 scale += leadingZeros + 1; 1002 } 1003 return; 1004 } 1005 1006 // Deal with trailing zeros 1007 if (scale > 0) { 1008 leadingZeros += scale; 1009 if (appendAsInteger) { 1010 scale = 0; 1011 } 1012 } 1013 1014 // Append digit 1015 shiftLeft(leadingZeros + 1); 1016 setDigitPos(0, value); 1017 1018 // Fix scale if in integer mode 1019 if (appendAsInteger) { 1020 scale += leadingZeros + 1; 1021 } 1022 } 1023 1024 @Override toPlainString()1025 public String toPlainString() { 1026 StringBuilder sb = new StringBuilder(); 1027 toPlainString(sb); 1028 return sb.toString(); 1029 } 1030 toPlainString(StringBuilder result)1031 public void toPlainString(StringBuilder result) { 1032 assert(!isApproximate); 1033 if (isNegative()) { 1034 result.append('-'); 1035 } 1036 if (precision == 0) { 1037 result.append('0'); 1038 return; 1039 } 1040 1041 int upper = scale + precision + exponent - 1; 1042 int lower = scale + exponent; 1043 if (upper < lReqPos - 1) { 1044 upper = lReqPos - 1; 1045 } 1046 if (lower > rReqPos) { 1047 lower = rReqPos; 1048 } 1049 1050 int p = upper; 1051 if (p < 0) { 1052 result.append('0'); 1053 } 1054 for (; p >= 0; p--) { 1055 result.append((char) ('0' + getDigitPos(p - scale - exponent))); 1056 } 1057 if (lower < 0) { 1058 result.append('.'); 1059 } 1060 for(; p >= lower; p--) { 1061 result.append((char) ('0' + getDigitPos(p - scale - exponent))); 1062 } 1063 } 1064 toScientificString()1065 public String toScientificString() { 1066 StringBuilder sb = new StringBuilder(); 1067 toScientificString(sb); 1068 return sb.toString(); 1069 } 1070 toScientificString(StringBuilder result)1071 public void toScientificString(StringBuilder result) { 1072 assert(!isApproximate); 1073 if (isNegative()) { 1074 result.append('-'); 1075 } 1076 if (precision == 0) { 1077 result.append("0E+0"); 1078 return; 1079 } 1080 // NOTE: It is not safe to add to lOptPos (aka maxInt) or subtract from 1081 // rOptPos (aka -maxFrac) due to overflow. 1082 int upperPos = precision - 1; 1083 int lowerPos = 0; 1084 int p = upperPos; 1085 result.append((char) ('0' + getDigitPos(p))); 1086 if ((--p) >= lowerPos) { 1087 result.append('.'); 1088 for (; p >= lowerPos; p--) { 1089 result.append((char) ('0' + getDigitPos(p))); 1090 } 1091 } 1092 result.append('E'); 1093 int _scale = upperPos + scale + exponent; 1094 if (_scale == Integer.MIN_VALUE) { 1095 result.append("-2147483648"); 1096 return; 1097 } else if (_scale < 0) { 1098 _scale *= -1; 1099 result.append('-'); 1100 } else { 1101 result.append('+'); 1102 } 1103 if (_scale == 0) { 1104 result.append('0'); 1105 } 1106 int insertIndex = result.length(); 1107 while (_scale > 0) { 1108 int quot = _scale / 10; 1109 int rem = _scale % 10; 1110 result.insert(insertIndex, (char) ('0' + rem)); 1111 _scale = quot; 1112 } 1113 } 1114 1115 @Override equals(Object other)1116 public boolean equals(Object other) { 1117 if (this == other) { 1118 return true; 1119 } 1120 if (other == null) { 1121 return false; 1122 } 1123 if (!(other instanceof DecimalQuantity_AbstractBCD)) { 1124 return false; 1125 } 1126 DecimalQuantity_AbstractBCD _other = (DecimalQuantity_AbstractBCD) other; 1127 1128 boolean basicEquals = 1129 scale == _other.scale 1130 && precision == _other.precision 1131 && flags == _other.flags 1132 && lReqPos == _other.lReqPos 1133 && rReqPos == _other.rReqPos 1134 && isApproximate == _other.isApproximate; 1135 if (!basicEquals) { 1136 return false; 1137 } 1138 1139 if (precision == 0) { 1140 return true; 1141 } else if (isApproximate) { 1142 return origDouble == _other.origDouble && origDelta == _other.origDelta; 1143 } else { 1144 for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) { 1145 if (getDigit(m) != _other.getDigit(m)) { 1146 return false; 1147 } 1148 } 1149 return true; 1150 } 1151 } 1152 1153 /** 1154 * Returns a single digit from the BCD list. No internal state is changed by calling this method. 1155 * 1156 * @param position 1157 * The position of the digit to pop, counted in BCD units from the least significant 1158 * digit. If outside the range supported by the implementation, zero is returned. 1159 * @return The digit at the specified location. 1160 */ getDigitPos(int position)1161 protected abstract byte getDigitPos(int position); 1162 1163 /** 1164 * Sets the digit in the BCD list. This method only sets the digit; it is the caller's responsibility 1165 * to call {@link #compact} after setting the digit. 1166 * 1167 * @param position 1168 * The position of the digit to pop, counted in BCD units from the least significant 1169 * digit. If outside the range supported by the implementation, an AssertionError is 1170 * thrown. 1171 * @param value 1172 * The digit to set at the specified location. 1173 */ setDigitPos(int position, byte value)1174 protected abstract void setDigitPos(int position, byte value); 1175 1176 /** 1177 * Adds zeros to the end of the BCD list. This will result in an invalid BCD representation; it is 1178 * the caller's responsibility to do further manipulation and then call {@link #compact}. 1179 * 1180 * @param numDigits 1181 * The number of zeros to add. 1182 */ shiftLeft(int numDigits)1183 protected abstract void shiftLeft(int numDigits); 1184 1185 /** 1186 * Removes digits from the end of the BCD list. This may result in an invalid BCD representation; it 1187 * is the caller's responsibility to follow-up with a call to {@link #compact}. 1188 * 1189 * @param numDigits 1190 * The number of digits to remove. 1191 */ shiftRight(int numDigits)1192 protected abstract void shiftRight(int numDigits); 1193 1194 /** 1195 * Directly removes digits from the front of the BCD list. 1196 * Updates precision. 1197 * 1198 * CAUTION: it is the caller's responsibility to call {@link #compact} after this method. 1199 */ popFromLeft(int numDigits)1200 protected abstract void popFromLeft(int numDigits); 1201 1202 /** 1203 * Sets the internal representation to zero. Clears any values stored in scale, precision, hasDouble, 1204 * origDouble, origDelta, exponent, and BCD data. 1205 */ setBcdToZero()1206 protected abstract void setBcdToZero(); 1207 1208 /** 1209 * Sets the internal BCD state to represent the value in the given int. The int is guaranteed to be 1210 * either positive. The internal state is guaranteed to be empty when this method is called. 1211 * 1212 * @param n 1213 * The value to consume. 1214 */ readIntToBcd(int input)1215 protected abstract void readIntToBcd(int input); 1216 1217 /** 1218 * Sets the internal BCD state to represent the value in the given long. The long is guaranteed to be 1219 * either positive. The internal state is guaranteed to be empty when this method is called. 1220 * 1221 * @param n 1222 * The value to consume. 1223 */ readLongToBcd(long input)1224 protected abstract void readLongToBcd(long input); 1225 1226 /** 1227 * Sets the internal BCD state to represent the value in the given BigInteger. The BigInteger is 1228 * guaranteed to be positive, and it is guaranteed to be larger than Long.MAX_VALUE. The internal 1229 * state is guaranteed to be empty when this method is called. 1230 * 1231 * @param n 1232 * The value to consume. 1233 */ readBigIntegerToBcd(BigInteger input)1234 protected abstract void readBigIntegerToBcd(BigInteger input); 1235 1236 /** 1237 * Returns a BigDecimal encoding the internal BCD value. 1238 * 1239 * @return A BigDecimal representation of the internal BCD. 1240 */ bcdToBigDecimal()1241 protected abstract BigDecimal bcdToBigDecimal(); 1242 copyBcdFrom(DecimalQuantity _other)1243 protected abstract void copyBcdFrom(DecimalQuantity _other); 1244 1245 /** 1246 * Removes trailing zeros from the BCD (adjusting the scale as required) and then computes the 1247 * precision. The precision is the number of digits in the number up through the greatest nonzero 1248 * digit. 1249 * 1250 * <p> 1251 * This method must always be called when bcd changes in order for assumptions to be correct in 1252 * methods like {@link #fractionCount()}. 1253 */ compact()1254 protected abstract void compact(); 1255 } 1256