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