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 android.icu.dev.impl.number; 5 6 import java.math.BigDecimal; 7 import java.math.MathContext; 8 import java.math.RoundingMode; 9 import java.text.FieldPosition; 10 11 import android.icu.impl.StandardPlural; 12 import android.icu.impl.number.DecimalQuantity; 13 import android.icu.text.PluralRules; 14 import android.icu.text.PluralRules.Operand; 15 import android.icu.text.UFieldPosition; 16 import android.icu.testsharding.MainTestShard; 17 18 /** 19 * This is an older implementation of DecimalQuantity. A newer, faster implementation is 20 * DecimalQuantity2. I kept this implementation around because it was useful for testing purposes 21 * (being able to compare the output of one implementation with the other). 22 * 23 * <p>This class is NOT IMMUTABLE and NOT THREAD SAFE and is intended to be used by a single thread 24 * to format a number through a formatter, which is thread-safe. 25 */ 26 @MainTestShard 27 public class DecimalQuantity_SimpleStorage implements DecimalQuantity { 28 // Four positions: left optional '(', left required '[', right required ']', right optional ')'. 29 // These four positions determine which digits are displayed in the output string. They do NOT 30 // affect rounding. These positions are internal-only and can be specified only by the public 31 // endpoints like setFractionLength, setIntegerLength, and setSignificantDigits, among others. 32 // 33 // * Digits between lReqPos and rReqPos are in the "required zone" and are always displayed. 34 // * Digits between lOptPos and rOptPos but outside the required zone are in the "optional zone" 35 // and are displayed unless they are trailing off the left or right edge of the number and 36 // have a numerical value of zero. In order to be "trailing", the digits need to be beyond 37 // the decimal point in their respective directions. 38 // * Digits outside of the "optional zone" are never displayed. 39 // 40 // See the table below for illustrative examples. 41 // 42 // +---------+---------+---------+---------+------------+------------------------+--------------+ 43 // | lOptPos | lReqPos | rReqPos | rOptPos | number | positions | en-US string | 44 // +---------+---------+---------+---------+------------+------------------------+--------------+ 45 // | 5 | 2 | -1 | -5 | 1234.567 | ( 12[34.5]67 ) | 1,234.567 | 46 // | 3 | 2 | -1 | -5 | 1234.567 | 1(2[34.5]67 ) | 234.567 | 47 // | 3 | 2 | -1 | -2 | 1234.567 | 1(2[34.5]6)7 | 234.56 | 48 // | 6 | 4 | 2 | -5 | 123456789. | 123(45[67]89. ) | 456,789. | 49 // | 6 | 4 | 2 | 1 | 123456789. | 123(45[67]8)9. | 456,780. | 50 // | -1 | -1 | -3 | -4 | 0.123456 | 0.1([23]4)56 | .0234 | 51 // | 6 | 4 | -2 | -2 | 12.3 | ( [ 12.3 ]) | 0012.30 | 52 // +---------+---------+---------+---------+------------+------------------------+--------------+ 53 // 54 private int lOptPos = Integer.MAX_VALUE; 55 private int lReqPos = 0; 56 private int rReqPos = 0; 57 private int rOptPos = Integer.MIN_VALUE; 58 59 // Internally, attempt to use a long to store the number. A long can hold numbers between 18 and 60 // 19 digits, covering the vast majority of use cases. We store three values: the long itself, 61 // the "scale" of the long (the power of 10 represented by the rightmost digit in the long), and 62 // the "precision" (the number of digits in the long). "primary" and "primaryScale" are the only 63 // two variables that are required for representing the number in memory. "primaryPrecision" is 64 // saved only for the sake of performance enhancements when performing certain operations. It can 65 // always be re-computed from "primary" and "primaryScale". 66 private long primary; 67 private int primaryScale; 68 private int primaryPrecision; 69 70 // If the decimal can't fit into the long, fall back to a BigDecimal. 71 private BigDecimal fallback; 72 73 // Other properties 74 private int flags; 75 private static final int NEGATIVE_FLAG = 1; 76 private static final int INFINITY_FLAG = 2; 77 private static final int NAN_FLAG = 4; 78 private static final long[] POWERS_OF_TEN = { 79 1L, 80 10L, 81 100L, 82 1000L, 83 10000L, 84 100000L, 85 1000000L, 86 10000000L, 87 100000000L, 88 1000000000L, 89 10000000000L, 90 100000000000L, 91 1000000000000L, 92 10000000000000L, 93 100000000000000L, 94 1000000000000000L, 95 10000000000000000L, 96 100000000000000000L, 97 1000000000000000000L 98 }; 99 100 @Override 101 public int maxRepresentableDigits() { 102 return Integer.MAX_VALUE; 103 } 104 105 public DecimalQuantity_SimpleStorage(long input) { 106 if (input < 0) { 107 setNegative(true); 108 input *= -1; 109 } 110 111 primary = input; 112 primaryScale = 0; 113 primaryPrecision = computePrecision(primary); 114 fallback = null; 115 } 116 117 /** 118 * Creates a DecimalQuantity from the given double value. Internally attempts several strategies 119 * for converting the double to an exact representation, falling back on a BigDecimal if it fails 120 * to do so. 121 * 122 * @param input The double to represent by this DecimalQuantity. 123 */ 124 public DecimalQuantity_SimpleStorage(double input) { 125 if (input < 0) { 126 setNegative(true); 127 input *= -1; 128 } 129 130 // First try reading from IEEE bits. This is trivial only for doubles in [2^52, 2^64). If it 131 // fails, we wasted only a few CPU cycles. 132 long ieeeBits = Double.doubleToLongBits(input); 133 int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff; 134 if (exponent >= 52 && exponent <= 63) { 135 // We can convert this double directly to a long. 136 long mantissa = (ieeeBits & 0x000fffffffffffffL) + 0x0010000000000000L; 137 primary = (mantissa << (exponent - 52)); 138 primaryScale = 0; 139 primaryPrecision = computePrecision(primary); 140 return; 141 } 142 143 // Now try parsing the string produced by Double.toString(). 144 String temp = Double.toString(input); 145 try { 146 if (temp.length() == 3 && temp.equals("0.0")) { 147 // Case 1: Zero. 148 primary = 0L; 149 primaryScale = 0; 150 primaryPrecision = 0; 151 } else if (temp.indexOf('E') != -1) { 152 // Case 2: Exponential notation. 153 assert temp.indexOf('.') == 1; 154 int expPos = temp.indexOf('E'); 155 primary = Long.parseLong(temp.charAt(0) + temp.substring(2, expPos)); 156 primaryScale = Integer.parseInt(temp.substring(expPos + 1)) - (expPos - 1) + 1; 157 primaryPrecision = expPos - 1; 158 } else if (temp.charAt(0) == '0') { 159 // Case 3: Fraction-only number. 160 assert temp.indexOf('.') == 1; 161 primary = Long.parseLong(temp.substring(2)); // ignores leading zeros 162 primaryScale = 2 - temp.length(); 163 primaryPrecision = computePrecision(primary); 164 } else if (temp.charAt(temp.length() - 1) == '0') { 165 // Case 4: Integer-only number. 166 assert temp.indexOf('.') == temp.length() - 2; 167 int rightmostNonzeroDigitIndex = temp.length() - 3; 168 while (temp.charAt(rightmostNonzeroDigitIndex) == '0') { 169 rightmostNonzeroDigitIndex -= 1; 170 } 171 primary = Long.parseLong(temp.substring(0, rightmostNonzeroDigitIndex + 1)); 172 primaryScale = temp.length() - rightmostNonzeroDigitIndex - 3; 173 primaryPrecision = rightmostNonzeroDigitIndex + 1; 174 } else if (temp.equals("Infinity")) { 175 // Case 5: Infinity. 176 primary = 0; 177 setInfinity(true); 178 } else if (temp.equals("NaN")) { 179 // Case 6: NaN. 180 primary = 0; 181 setNaN(true); 182 } else { 183 // Case 7: Number with both a fraction and an integer. 184 int decimalPos = temp.indexOf('.'); 185 primary = Long.parseLong(temp.substring(0, decimalPos) + temp.substring(decimalPos + 1)); 186 primaryScale = decimalPos - temp.length() + 1; 187 primaryPrecision = temp.length() - 1; 188 } 189 } catch (NumberFormatException e) { 190 // The digits of the double can't fit into the long. 191 primary = -1; 192 fallback = new BigDecimal(temp); 193 } 194 } 195 196 static final double LOG_2_OF_TEN = 3.32192809489; 197 198 public DecimalQuantity_SimpleStorage(double input, boolean fast) { 199 if (input < 0) { 200 setNegative(true); 201 input *= -1; 202 } 203 204 // Our strategy is to read all digits that are *guaranteed* to be valid without delving into 205 // the IEEE rounding rules. This strategy might not end up with a perfect representation of 206 // the fractional part of the double. 207 long ieeeBits = Double.doubleToLongBits(input); 208 int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff; 209 long mantissa = (ieeeBits & 0x000fffffffffffffL) + 0x0010000000000000L; 210 if (exponent > 63) { 211 throw new IllegalArgumentException(); // FIXME 212 } else if (exponent >= 52) { 213 primary = (mantissa << (exponent - 52)); 214 primaryScale = 0; 215 primaryPrecision = computePrecision(primary); 216 return; 217 } else if (exponent >= 0) { 218 int shift = 52 - exponent; 219 primary = (mantissa >> shift); // integer part 220 int fractionCount = (int) (shift / LOG_2_OF_TEN); 221 long fraction = (mantissa - (primary << shift)) + 1L; // TODO: Explain the +1L 222 primary *= POWERS_OF_TEN[fractionCount]; 223 for (int i = 0; i < fractionCount; i++) { 224 long times10 = (fraction * 10L); 225 long digit = times10 >> shift; 226 assert digit >= 0 && digit < 10; 227 primary += digit * POWERS_OF_TEN[fractionCount - i - 1]; 228 fraction = times10 & ((1L << shift) - 1); 229 } 230 primaryScale = -fractionCount; 231 primaryPrecision = computePrecision(primary); 232 } else { 233 throw new IllegalArgumentException(); // FIXME 234 } 235 } 236 237 public DecimalQuantity_SimpleStorage(BigDecimal decimal) { 238 setToBigDecimal(decimal); 239 } 240 241 public DecimalQuantity_SimpleStorage(DecimalQuantity_SimpleStorage other) { 242 copyFrom(other); 243 } 244 245 @Override 246 public void setToBigDecimal(BigDecimal decimal) { 247 if (decimal.compareTo(BigDecimal.ZERO) < 0) { 248 setNegative(true); 249 decimal = decimal.negate(); 250 } 251 252 primary = -1; 253 if (decimal.compareTo(BigDecimal.ZERO) == 0) { 254 fallback = BigDecimal.ZERO; 255 } else { 256 fallback = decimal; 257 } 258 } 259 260 @Override 261 public DecimalQuantity_SimpleStorage createCopy() { 262 return new DecimalQuantity_SimpleStorage(this); 263 } 264 265 /** 266 * Make the internal state of this DecimalQuantity equal to another DecimalQuantity. 267 * 268 * @param other The template DecimalQuantity. All properties from this DecimalQuantity will be 269 * copied into this DecimalQuantity. 270 */ 271 @Override 272 public void copyFrom(DecimalQuantity other) { 273 // TODO: Check before casting 274 DecimalQuantity_SimpleStorage _other = (DecimalQuantity_SimpleStorage) other; 275 lOptPos = _other.lOptPos; 276 lReqPos = _other.lReqPos; 277 rReqPos = _other.rReqPos; 278 rOptPos = _other.rOptPos; 279 primary = _other.primary; 280 primaryScale = _other.primaryScale; 281 primaryPrecision = _other.primaryPrecision; 282 fallback = _other.fallback; 283 flags = _other.flags; 284 } 285 286 @Override 287 public long getPositionFingerprint() { 288 long fingerprint = 0; 289 fingerprint ^= lOptPos; 290 fingerprint ^= (lReqPos << 16); 291 fingerprint ^= ((long) rReqPos << 32); 292 fingerprint ^= ((long) rOptPos << 48); 293 return fingerprint; 294 } 295 296 /** 297 * Utility method to compute the number of digits ("precision") in a long. 298 * 299 * @param input The long (which can't contain more than 19 digits). 300 * @return The precision of the long. 301 */ 302 private static int computePrecision(long input) { 303 int precision = 0; 304 while (input > 0) { 305 input /= 10; 306 precision++; 307 } 308 return precision; 309 } 310 311 /** 312 * Changes the internal representation from a long to a BigDecimal. Used only for operations that 313 * don't support longs. 314 */ 315 private void convertToBigDecimal() { 316 if (primary == -1) { 317 return; 318 } 319 320 fallback = new BigDecimal(primary).scaleByPowerOfTen(primaryScale); 321 primary = -1; 322 } 323 324 @Override 325 public void setIntegerLength(int minInt, int maxInt) { 326 // Graceful failures for bogus input 327 minInt = Math.max(0, minInt); 328 maxInt = Math.max(0, maxInt); 329 330 // The minima must be less than or equal to the maxima 331 if (maxInt < minInt) { 332 minInt = maxInt; 333 } 334 335 // Save values into internal state 336 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE 337 lOptPos = maxInt; 338 lReqPos = minInt; 339 } 340 341 @Override 342 public void setFractionLength(int minFrac, int maxFrac) { 343 // Graceful failures for bogus input 344 minFrac = Math.max(0, minFrac); 345 maxFrac = Math.max(0, maxFrac); 346 347 // The minima must be less than or equal to the maxima 348 if (maxFrac < minFrac) { 349 minFrac = maxFrac; 350 } 351 352 // Save values into internal state 353 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE 354 rReqPos = -minFrac; 355 rOptPos = -maxFrac; 356 } 357 358 @Override 359 public void roundToIncrement(BigDecimal roundingInterval, MathContext mathContext) { 360 BigDecimal d = 361 (primary == -1) ? fallback : new BigDecimal(primary).scaleByPowerOfTen(primaryScale); 362 if (isNegative()) d = d.negate(); 363 d = d.divide(roundingInterval, 0, mathContext.getRoundingMode()).multiply(roundingInterval); 364 if (isNegative()) d = d.negate(); 365 fallback = d; 366 primary = -1; 367 } 368 369 @Override 370 public void roundToMagnitude(int roundingMagnitude, MathContext mathContext) { 371 if (roundingMagnitude < -1000) { 372 roundToInfinity(); 373 return; 374 } 375 if (primary == -1) { 376 if (isNegative()) fallback = fallback.negate(); 377 fallback = fallback.setScale(-roundingMagnitude, mathContext.getRoundingMode()); 378 if (isNegative()) fallback = fallback.negate(); 379 // Enforce the math context. 380 fallback = fallback.round(mathContext); 381 } else { 382 int relativeScale = primaryScale - roundingMagnitude; 383 if (relativeScale < -18) { 384 // No digits will remain after rounding the number. 385 primary = 0L; 386 primaryScale = roundingMagnitude; 387 primaryPrecision = 0; 388 } else if (relativeScale < 0) { 389 // This is the harder case, when we need to perform the rounding logic. 390 // First check if the rightmost digits are already zero, where we can skip rounding. 391 if ((primary % POWERS_OF_TEN[0 - relativeScale]) == 0) { 392 // No rounding is necessary. 393 } else { 394 // TODO: Make this more efficient. Temporarily, convert to a BigDecimal and back again. 395 BigDecimal temp = new BigDecimal(primary).scaleByPowerOfTen(primaryScale); 396 if (isNegative()) temp = temp.negate(); 397 temp = temp.setScale(-roundingMagnitude, mathContext.getRoundingMode()); 398 if (isNegative()) temp = temp.negate(); 399 temp = temp.scaleByPowerOfTen(-roundingMagnitude); 400 primary = temp.longValueExact(); // should never throw 401 primaryScale = roundingMagnitude; 402 primaryPrecision = computePrecision(primary); 403 } 404 } else { 405 // No rounding is necessary. All digits are to the left of the rounding magnitude. 406 } 407 // Enforce the math context. 408 primary = new BigDecimal(primary).round(mathContext).longValueExact(); 409 primaryPrecision = computePrecision(primary); 410 } 411 } 412 413 @Override 414 public void roundToInfinity() { 415 // noop 416 } 417 418 /** 419 * Multiply the internal number by the specified multiplicand. This method forces the internal 420 * representation into a BigDecimal. If you are multiplying by a power of 10, use {@link 421 * #adjustMagnitude} instead. 422 * 423 * @param multiplicand The number to be passed to {@link BigDecimal#multiply}. 424 */ 425 @Override 426 public void multiplyBy(BigDecimal multiplicand) { 427 convertToBigDecimal(); 428 fallback = fallback.multiply(multiplicand); 429 if (fallback.compareTo(BigDecimal.ZERO) < 0) { 430 setNegative(!isNegative()); 431 fallback = fallback.negate(); 432 } 433 } 434 435 @Override 436 public void negate() { 437 flags ^= NEGATIVE_FLAG; 438 } 439 440 /** 441 * Divide the internal number by the specified quotient. This method forces the internal 442 * representation into a BigDecimal. If you are dividing by a power of 10, use {@link 443 * #adjustMagnitude} instead. 444 * 445 * @param divisor The number to be passed to {@link BigDecimal#divide}. 446 * @param scale The scale of the final rounded number. More negative means more decimal places. 447 * @param mathContext The math context to use if rounding is necessary. 448 */ 449 @SuppressWarnings("unused") 450 private void divideBy(BigDecimal divisor, int scale, MathContext mathContext) { 451 convertToBigDecimal(); 452 // Negate the scale because BigDecimal's scale is defined as the inverse of our scale 453 fallback = fallback.divide(divisor, -scale, mathContext.getRoundingMode()); 454 if (fallback.compareTo(BigDecimal.ZERO) < 0) { 455 setNegative(!isNegative()); 456 fallback = fallback.negate(); 457 } 458 } 459 460 @Override 461 public boolean isZero() { 462 if (primary == -1) { 463 return fallback.compareTo(BigDecimal.ZERO) == 0; 464 } else { 465 return primary == 0; 466 } 467 } 468 469 /** @return The power of ten of the highest digit represented by this DecimalQuantity */ 470 @Override 471 public int getMagnitude() throws ArithmeticException { 472 int scale = (primary == -1) ? scaleBigDecimal(fallback) : primaryScale; 473 int precision = (primary == -1) ? precisionBigDecimal(fallback) : primaryPrecision; 474 if (precision == 0) { 475 throw new ArithmeticException("Magnitude is not well-defined for zero"); 476 } else { 477 return scale + precision - 1; 478 } 479 } 480 481 /** 482 * Changes the magnitude of this DecimalQuantity. If the indices of the represented digits had been 483 * previously specified, those indices are moved relative to the DecimalQuantity. 484 * 485 * <p>This method does NOT perform rounding. 486 * 487 * @param delta The number of powers of ten to shift (positive shifts to the left). 488 */ 489 @Override 490 public void adjustMagnitude(int delta) { 491 if (primary == -1) { 492 fallback = fallback.scaleByPowerOfTen(delta); 493 } else { 494 primaryScale = addOrMaxValue(primaryScale, delta); 495 } 496 } 497 498 private static int addOrMaxValue(int a, int b) { 499 // Check for overflow, and return min/max value if overflow occurs. 500 if (b < 0 && a + b > a) { 501 return Integer.MIN_VALUE; 502 } else if (b > 0 && a + b < a) { 503 return Integer.MAX_VALUE; 504 } 505 return a + b; 506 } 507 508 /** @return If the number represented by this DecimalQuantity is less than zero */ 509 @Override 510 public boolean isNegative() { 511 return (flags & NEGATIVE_FLAG) != 0; 512 } 513 514 @Override 515 public int signum() { 516 return isNegative() ? -1 : isZero() ? 0 : 1; 517 } 518 519 private void setNegative(boolean isNegative) { 520 flags = (flags & (~NEGATIVE_FLAG)) | (isNegative ? NEGATIVE_FLAG : 0); 521 } 522 523 @Override 524 public boolean isInfinite() { 525 return (flags & INFINITY_FLAG) != 0; 526 } 527 528 private void setInfinity(boolean isInfinity) { 529 flags = (flags & (~INFINITY_FLAG)) | (isInfinity ? INFINITY_FLAG : 0); 530 } 531 532 @Override 533 public boolean isNaN() { 534 return (flags & NAN_FLAG) != 0; 535 } 536 537 private void setNaN(boolean isNaN) { 538 flags = (flags & (~NAN_FLAG)) | (isNaN ? NAN_FLAG : 0); 539 } 540 541 /** 542 * Returns a representation of this DecimalQuantity as a double, with possible loss of information. 543 */ 544 @Override 545 public double toDouble() { 546 double result; 547 if (primary == -1) { 548 result = fallback.doubleValue(); 549 } else { 550 // TODO: Make this more efficient 551 result = primary; 552 for (int i = 0; i < primaryScale; i++) { 553 result *= 10.; 554 } 555 for (int i = 0; i > primaryScale; i--) { 556 result /= 10.; 557 } 558 } 559 return isNegative() ? -result : result; 560 } 561 562 @Override 563 public BigDecimal toBigDecimal() { 564 BigDecimal result; 565 if (primary != -1) { 566 result = new BigDecimal(primary).scaleByPowerOfTen(primaryScale); 567 } else { 568 result = fallback; 569 } 570 return isNegative() ? result.negate() : result; 571 } 572 573 @Override 574 public StandardPlural getStandardPlural(PluralRules rules) { 575 if (rules == null) { 576 // Fail gracefully if the user didn't provide a PluralRules 577 return StandardPlural.OTHER; 578 } else { 579 // TODO: Avoid converting to a double for the sake of PluralRules 580 String ruleString = rules.select(toDouble()); 581 return StandardPlural.orOtherFromString(ruleString); 582 } 583 } 584 585 @Override 586 public double getPluralOperand(Operand operand) { 587 // TODO: This is a temporary hack. 588 return new PluralRules.FixedDecimal(toDouble()).getPluralOperand(operand); 589 } 590 591 public boolean hasNextFraction() { 592 if (rReqPos < 0) { 593 // We are in the required zone. 594 return true; 595 } else if (rOptPos >= 0) { 596 // We are in the forbidden zone. 597 return false; 598 } else { 599 // We are in the optional zone. 600 if (primary == -1) { 601 return fallback.remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO) > 0; 602 } else { 603 if (primaryScale <= -19) { 604 // The number is a fraction so small that it consists of only fraction digits. 605 return primary > 0; 606 } else if (primaryScale < 0) { 607 // Check if we have a fraction part. 608 long factor = POWERS_OF_TEN[0 - primaryScale]; 609 return ((primary % factor) != 0); 610 } else { 611 // The lowest digit in the long has magnitude greater than -1. 612 return false; 613 } 614 } 615 } 616 } 617 618 public byte nextFraction() { 619 byte returnValue; 620 if (primary == -1) { 621 BigDecimal temp = fallback.multiply(BigDecimal.TEN); 622 returnValue = temp.setScale(0, RoundingMode.FLOOR).remainder(BigDecimal.TEN).byteValue(); 623 fallback = fallback.setScale(0, RoundingMode.FLOOR).add(temp.remainder(BigDecimal.ONE)); 624 } else { 625 if (primaryScale <= -20) { 626 // The number is a fraction so small that it has no first fraction digit. 627 primaryScale += 1; 628 returnValue = 0; 629 } else if (primaryScale < 0) { 630 // Extract the fraction digit out of the middle of the long. 631 long factor = POWERS_OF_TEN[0 - primaryScale - 1]; 632 long temp1 = primary / factor; 633 long temp2 = primary % factor; 634 returnValue = (byte) (temp1 % 10); // not necessarily nonzero 635 primary = ((temp1 / 10) * factor) + temp2; 636 primaryScale += 1; 637 if (temp1 != 0) { 638 primaryPrecision -= 1; 639 } 640 } else { 641 // The lowest digit in the long has magnitude greater than -1. 642 returnValue = 0; 643 } 644 } 645 646 // Update digit brackets 647 if (lOptPos < 0) { 648 lOptPos += 1; 649 } 650 if (lReqPos < 0) { 651 lReqPos += 1; 652 } 653 if (rReqPos < 0) { 654 rReqPos += 1; 655 } 656 if (rOptPos < 0) { 657 rOptPos += 1; 658 } 659 660 assert returnValue >= 0; 661 return returnValue; 662 } 663 664 public boolean hasNextInteger() { 665 if (lReqPos > 0) { 666 // We are in the required zone. 667 return true; 668 } else if (lOptPos <= 0) { 669 // We are in the forbidden zone. 670 return false; 671 } else { 672 // We are in the optional zone. 673 if (primary == -1) { 674 return fallback.setScale(0, RoundingMode.FLOOR).compareTo(BigDecimal.ZERO) > 0; 675 } else { 676 if (primaryScale < -18) { 677 // The number is a fraction so small that it has no integer part. 678 return false; 679 } else if (primaryScale < 0) { 680 // Check if we have an integer part. 681 long factor = POWERS_OF_TEN[0 - primaryScale]; 682 return ((primary % factor) != primary); // equivalent: ((primary / 10) != 0) 683 } else { 684 // The lowest digit in the long has magnitude of at least 0. 685 return primary != 0; 686 } 687 } 688 } 689 } 690 691 private int integerCount() { 692 int digitsRemaining; 693 if (primary == -1) { 694 digitsRemaining = precisionBigDecimal(fallback) + scaleBigDecimal(fallback); 695 } else { 696 digitsRemaining = primaryPrecision + primaryScale; 697 } 698 return Math.min(Math.max(digitsRemaining, lReqPos), lOptPos); 699 } 700 701 private int fractionCount() { 702 // TODO: This is temporary. 703 DecimalQuantity_SimpleStorage copy = new DecimalQuantity_SimpleStorage(this); 704 int fractionCount = 0; 705 while (copy.hasNextFraction()) { 706 copy.nextFraction(); 707 fractionCount++; 708 } 709 return fractionCount; 710 } 711 712 @Override 713 public int getUpperDisplayMagnitude() { 714 return integerCount() - 1; 715 } 716 717 @Override 718 public int getLowerDisplayMagnitude() { 719 return -fractionCount(); 720 } 721 722 // @Override 723 // public byte getIntegerDigit(int index) { 724 // return getDigitPos(index); 725 // } 726 // 727 // @Override 728 // public byte getFractionDigit(int index) { 729 // return getDigitPos(-index - 1); 730 // } 731 732 @Override 733 public byte getDigit(int magnitude) { 734 // TODO: This is temporary. 735 DecimalQuantity_SimpleStorage copy = new DecimalQuantity_SimpleStorage(this); 736 if (magnitude < 0) { 737 for (int p = -1; p > magnitude; p--) { 738 copy.nextFraction(); 739 } 740 return copy.nextFraction(); 741 } else { 742 for (int p = 0; p < magnitude; p++) { 743 copy.nextInteger(); 744 } 745 return copy.nextInteger(); 746 } 747 } 748 749 public byte nextInteger() { 750 byte returnValue; 751 if (primary == -1) { 752 returnValue = fallback.setScale(0, RoundingMode.FLOOR).remainder(BigDecimal.TEN).byteValue(); 753 BigDecimal temp = fallback.divide(BigDecimal.TEN).setScale(0, RoundingMode.FLOOR); 754 fallback = fallback.remainder(BigDecimal.ONE).add(temp); 755 } else { 756 if (primaryScale < -18) { 757 // The number is a fraction so small that it has no integer part. 758 returnValue = 0; 759 } else if (primaryScale < 0) { 760 // Extract the integer digit out of the middle of the long. In many ways, this is the heart 761 // of the digit iterator algorithm. 762 long factor = POWERS_OF_TEN[0 - primaryScale]; 763 if ((primary % factor) != primary) { // equivalent: ((primary / 10) != 0) 764 returnValue = (byte) ((primary / factor) % 10); 765 long temp = (primary / 10); 766 primary = temp - (temp % factor) + (primary % factor); 767 primaryPrecision -= 1; 768 } else { 769 returnValue = 0; 770 } 771 } else if (primaryScale == 0) { 772 // Fast-path for primaryScale == 0 (otherwise equivalent to previous step). 773 if (primary != 0) { 774 returnValue = (byte) (primary % 10); 775 primary /= 10; 776 primaryPrecision -= 1; 777 } else { 778 returnValue = 0; 779 } 780 } else { 781 // The lowest digit in the long has magnitude greater than 0. 782 primaryScale -= 1; 783 returnValue = 0; 784 } 785 } 786 787 // Update digit brackets 788 if (lOptPos > 0) { 789 lOptPos -= 1; 790 } 791 if (lReqPos > 0) { 792 lReqPos -= 1; 793 } 794 if (rReqPos > 0) { 795 rReqPos -= 1; 796 } 797 if (rOptPos > 0) { 798 rOptPos -= 1; 799 } 800 801 assert returnValue >= 0; 802 return returnValue; 803 } 804 805 /** 806 * Helper method to compute the precision of a BigDecimal by our definition of precision, which is 807 * that the number zero gets precision zero. 808 * 809 * @param decimal The BigDecimal whose precision to compute. 810 * @return The precision by our definition. 811 */ 812 private static int precisionBigDecimal(BigDecimal decimal) { 813 if (decimal.compareTo(BigDecimal.ZERO) == 0) { 814 return 0; 815 } else { 816 return decimal.precision(); 817 } 818 } 819 820 /** 821 * Helper method to compute the scale of a BigDecimal by our definition of scale, which is that 822 * deeper fractions result in negative scales as opposed to positive scales. 823 * 824 * @param decimal The BigDecimal whose scale to compute. 825 * @return The scale by our definition. 826 */ 827 private static int scaleBigDecimal(BigDecimal decimal) { 828 return -decimal.scale(); 829 } 830 831 @Override 832 public String toString() { 833 StringBuilder sb = new StringBuilder(); 834 sb.append("<DecimalQuantity1 "); 835 if (primary == -1) { 836 sb.append(lOptPos > 1000 ? "max" : lOptPos); 837 sb.append(":"); 838 sb.append(lReqPos); 839 sb.append(":"); 840 sb.append(rReqPos); 841 sb.append(":"); 842 sb.append(rOptPos < -1000 ? "min" : rOptPos); 843 sb.append(" "); 844 sb.append(fallback.toString()); 845 } else { 846 String digits = Long.toString(primary); 847 int iDec = digits.length() + primaryScale; 848 int iLP = iDec - toRange(lOptPos, -1000, 1000); 849 int iLB = iDec - toRange(lReqPos, -1000, 1000); 850 int iRB = iDec - toRange(rReqPos, -1000, 1000); 851 int iRP = iDec - toRange(rOptPos, -1000, 1000); 852 iDec = Math.max(Math.min(iDec, digits.length() + 1), -1); 853 iLP = Math.max(Math.min(iLP, digits.length() + 1), -1); 854 iLB = Math.max(Math.min(iLB, digits.length() + 1), -1); 855 iRB = Math.max(Math.min(iRB, digits.length() + 1), -1); 856 iRP = Math.max(Math.min(iRP, digits.length() + 1), -1); 857 858 for (int i = -1; i <= digits.length() + 1; i++) { 859 if (i == iLP) sb.append('('); 860 if (i == iLB) sb.append('['); 861 if (i == iDec) sb.append('.'); 862 if (i == iRB) sb.append(']'); 863 if (i == iRP) sb.append(')'); 864 if (i >= 0 && i < digits.length()) sb.append(digits.charAt(i)); 865 else sb.append('\u00A0'); 866 } 867 } 868 sb.append(">"); 869 return sb.toString(); 870 } 871 872 @Override 873 public String toPlainString() { 874 // NOTE: This logic is duplicated between here and DecimalQuantity_AbstractBCD. 875 StringBuilder sb = new StringBuilder(); 876 if (isNegative()) { 877 sb.append('-'); 878 } 879 for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) { 880 sb.append(getDigit(m)); 881 if (m == 0) sb.append('.'); 882 } 883 return sb.toString(); 884 } 885 886 private static int toRange(int i, int lo, int hi) { 887 if (i < lo) { 888 return lo; 889 } else if (i > hi) { 890 return hi; 891 } else { 892 return i; 893 } 894 } 895 896 @Override 897 public void populateUFieldPosition(FieldPosition fp) { 898 if (fp instanceof UFieldPosition) { 899 ((UFieldPosition) fp) 900 .setFractionDigits((int) getPluralOperand(Operand.v), (long) getPluralOperand(Operand.f)); 901 } 902 } 903 } 904