1/* 2 ******************************************************************************* 3 * Copyright (C) 1996-2011, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7package com.ibm.icu.text; 8 9import java.math.BigInteger; 10 11/** 12 * <code>DigitList</code> handles the transcoding between numeric values and 13 * strings of characters. It only represents non-negative numbers. The 14 * division of labor between <code>DigitList</code> and 15 * <code>DecimalFormat</code> is that <code>DigitList</code> handles the radix 16 * 10 representation issues and numeric conversion, including rounding; 17 * <code>DecimalFormat</code> handles the locale-specific issues such as 18 * positive and negative representation, digit grouping, decimal point, 19 * currency, and so on. 20 * 21 * <p>A <code>DigitList</code> is a representation of a finite numeric value. 22 * <code>DigitList</code> objects do not represent <code>NaN</code> or infinite 23 * values. A <code>DigitList</code> value can be converted to a 24 * <code>BigDecimal</code> without loss of precision. Conversion to other 25 * numeric formats may involve loss of precision, depending on the specific 26 * value. 27 * 28 * <p>The <code>DigitList</code> representation consists of a string of 29 * characters, which are the digits radix 10, from '0' to '9'. It also has a 30 * base 10 exponent associated with it. The value represented by a 31 * <code>DigitList</code> object can be computed by mulitplying the fraction 32 * <em>f</em>, where 0 <= <em>f</em> < 1, derived by placing all the digits of 33 * the list to the right of the decimal point, by 10^exponent. 34 * 35 * @see java.util.Locale 36 * @see java.text.Format 37 * @see NumberFormat 38 * @see DecimalFormat 39 * @see java.text.ChoiceFormat 40 * @see java.text.MessageFormat 41 * @version 1.18 08/12/98 42 * @author Mark Davis, Alan Liu 43 * */ 44final class DigitList { 45 /** 46 * The maximum number of significant digits in an IEEE 754 double, that 47 * is, in a Java double. This must not be increased, or garbage digits 48 * will be generated, and should not be decreased, or accuracy will be lost. 49 */ 50 public static final int MAX_LONG_DIGITS = 19; // == Long.toString(Long.MAX_VALUE).length() 51 public static final int DBL_DIG = 17; 52 53 /** 54 * These data members are intentionally public and can be set directly. 55 * 56 * The value represented is given by placing the decimal point before 57 * digits[decimalAt]. If decimalAt is < 0, then leading zeros between 58 * the decimal point and the first nonzero digit are implied. If decimalAt 59 * is > count, then trailing zeros between the digits[count-1] and the 60 * decimal point are implied. 61 * 62 * Equivalently, the represented value is given by f * 10^decimalAt. Here 63 * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to 64 * the right of the decimal. 65 * 66 * DigitList is normalized, so if it is non-zero, figits[0] is non-zero. We 67 * don't allow denormalized numbers because our exponent is effectively of 68 * unlimited magnitude. The count value contains the number of significant 69 * digits present in digits[]. 70 * 71 * Zero is represented by any DigitList with count == 0 or with each digits[i] 72 * for all i <= count == '0'. 73 */ 74 public int decimalAt = 0; 75 public int count = 0; 76 public byte[] digits = new byte[MAX_LONG_DIGITS]; 77 78 private final void ensureCapacity(int digitCapacity, int digitsToCopy) { 79 if (digitCapacity > digits.length) { 80 byte[] newDigits = new byte[digitCapacity * 2]; 81 System.arraycopy(digits, 0, newDigits, 0, digitsToCopy); 82 digits = newDigits; 83 } 84 } 85 86 /** 87 * Return true if the represented number is zero. 88 */ 89 boolean isZero() 90 { 91 for (int i=0; i<count; ++i) if (digits[i] != '0') return false; 92 return true; 93 } 94 95// Unused as of ICU 2.6 - alan 96// /** 97// * Clears out the digits. 98// * Use before appending them. 99// * Typically, you set a series of digits with append, then at the point 100// * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count; 101// * then go on appending digits. 102// */ 103// public void clear () { 104// decimalAt = 0; 105// count = 0; 106// } 107 108 /** 109 * Appends digits to the list. 110 */ 111 public void append (int digit) { 112 ensureCapacity(count+1, count); 113 digits[count++] = (byte) digit; 114 } 115 116 public byte getDigitValue(int i) { 117 return (byte) (digits[i] - '0'); 118 } 119 120 /** 121 * Utility routine to get the value of the digit list 122 * If (count == 0) this throws a NumberFormatException, which 123 * mimics Long.parseLong(). 124 */ 125 public final double getDouble() { 126 if (count == 0) return 0.0; 127 StringBuilder temp = new StringBuilder(count); 128 temp.append('.'); 129 for (int i = 0; i < count; ++i) temp.append((char)(digits[i])); 130 temp.append('E'); 131 temp.append(Integer.toString(decimalAt)); 132 return Double.valueOf(temp.toString()).doubleValue(); 133 // long value = Long.parseLong(temp.toString()); 134 // return (value * Math.pow(10, decimalAt - count)); 135 } 136 137 /** 138 * Utility routine to get the value of the digit list. 139 * If (count == 0) this returns 0, unlike Long.parseLong(). 140 */ 141 public final long getLong() { 142 // for now, simple implementation; later, do proper IEEE native stuff 143 144 if (count == 0) return 0; 145 146 // We have to check for this, because this is the one NEGATIVE value 147 // we represent. If we tried to just pass the digits off to parseLong, 148 // we'd get a parse failure. 149 if (isLongMIN_VALUE()) return Long.MIN_VALUE; 150 151 StringBuilder temp = new StringBuilder(count); 152 for (int i = 0; i < decimalAt; ++i) 153 { 154 temp.append((i < count) ? (char)(digits[i]) : '0'); 155 } 156 return Long.parseLong(temp.toString()); 157 } 158 159 /** 160 * Return a <code>BigInteger</code> representing the value stored in this 161 * <code>DigitList</code>. This method assumes that this object contains 162 * an integral value; if not, it will return an incorrect value. 163 * [bnf] 164 * @param isPositive determines the sign of the returned result 165 * @return the value of this object as a <code>BigInteger</code> 166 */ 167 public BigInteger getBigInteger(boolean isPositive) { 168 if (isZero()) return BigInteger.valueOf(0); 169 //Eclipse stated the following is "dead code" 170 /*if (false) { 171 StringBuilder stringRep = new StringBuilder(count); 172 if (!isPositive) { 173 stringRep.append('-'); 174 } 175 for (int i=0; i<count; ++i) { 176 stringRep.append((char) digits[i]); 177 } 178 int d = decimalAt; 179 while (d-- > count) { 180 stringRep.append('0'); 181 } 182 return new BigInteger(stringRep.toString()); 183 } else*/ { 184 int len = decimalAt > count ? decimalAt : count; 185 if (!isPositive) { 186 len += 1; 187 } 188 char[] text = new char[len]; 189 int n = 0; 190 if (!isPositive) { 191 text[0] = '-'; 192 for (int i = 0; i < count; ++i) { 193 text[i+1] = (char)digits[i]; 194 } 195 n = count+1; 196 } else { 197 for (int i = 0; i < count; ++i) { 198 text[i] = (char)digits[i]; 199 } 200 n = count; 201 } 202 for (int i = n; i < text.length; ++i) { 203 text[i] = '0'; 204 } 205 return new BigInteger(new String(text)); 206 } 207 } 208 209 private String getStringRep(boolean isPositive) { 210 if (isZero()) return "0"; 211 StringBuilder stringRep = new StringBuilder(count+1); 212 if (!isPositive) { 213 stringRep.append('-'); 214 } 215 int d = decimalAt; 216 if (d < 0) { 217 stringRep.append('.'); 218 while (d < 0) { 219 stringRep.append('0'); 220 ++d; 221 } 222 d = -1; 223 } 224 for (int i=0; i<count; ++i) { 225 if (d == i) { 226 stringRep.append('.'); 227 } 228 stringRep.append((char) digits[i]); 229 } 230 while (d-- > count) { 231 stringRep.append('0'); 232 } 233 return stringRep.toString(); 234 } 235 236 /** 237 * Return a <code>BigDecimal</code> representing the value stored in this 238 * <code>DigitList</code>. 239 * [bnf] 240 * @param isPositive determines the sign of the returned result 241 * @return the value of this object as a <code>BigDecimal</code> 242 */ 243 ///CLOVER:OFF 244 // The method is in a protected class and is not called by anything 245 public java.math.BigDecimal getBigDecimal(boolean isPositive) { 246 if (isZero()) { 247 return java.math.BigDecimal.valueOf(0); 248 } 249 // if exponential notion is negative, 250 // we prefer to use BigDecimal constructor with scale, 251 // because it works better when extremely small value 252 // is used. See #5698. 253 long scale = (long)count - (long)decimalAt; 254 if (scale > 0) { 255 int numDigits = count; 256 if (scale > (long)Integer.MAX_VALUE) { 257 // try to reduce the scale 258 long numShift = scale - (long)Integer.MAX_VALUE; 259 if (numShift < count) { 260 numDigits -= numShift; 261 } else { 262 // fallback to 0 263 return new java.math.BigDecimal(0); 264 } 265 } 266 StringBuilder significantDigits = new StringBuilder(numDigits + 1); 267 if (!isPositive) { 268 significantDigits.append('-'); 269 } 270 for (int i = 0; i < numDigits; i++) { 271 significantDigits.append((char)digits[i]); 272 } 273 BigInteger unscaledVal = new BigInteger(significantDigits.toString()); 274 return new java.math.BigDecimal(unscaledVal, (int)scale); 275 } else { 276 // We should be able to use a negative scale value for a positive exponential 277 // value on JDK1.5. But it is not supported by older JDK. So, for now, 278 // we always use BigDecimal constructor which takes String. 279 return new java.math.BigDecimal(getStringRep(isPositive)); 280 } 281 } 282 ///CLOVER:ON 283 284 /** 285 * Return an <code>ICU BigDecimal</code> representing the value stored in this 286 * <code>DigitList</code>. 287 * [bnf] 288 * @param isPositive determines the sign of the returned result 289 * @return the value of this object as a <code>BigDecimal</code> 290 */ 291 public com.ibm.icu.math.BigDecimal getBigDecimalICU(boolean isPositive) { 292 if (isZero()) { 293 return com.ibm.icu.math.BigDecimal.valueOf(0); 294 } 295 // if exponential notion is negative, 296 // we prefer to use BigDecimal constructor with scale, 297 // because it works better when extremely small value 298 // is used. See #5698. 299 long scale = (long)count - (long)decimalAt; 300 if (scale > 0) { 301 int numDigits = count; 302 if (scale > (long)Integer.MAX_VALUE) { 303 // try to reduce the scale 304 long numShift = scale - (long)Integer.MAX_VALUE; 305 if (numShift < count) { 306 numDigits -= numShift; 307 } else { 308 // fallback to 0 309 return new com.ibm.icu.math.BigDecimal(0); 310 } 311 } 312 StringBuilder significantDigits = new StringBuilder(numDigits + 1); 313 if (!isPositive) { 314 significantDigits.append('-'); 315 } 316 for (int i = 0; i < numDigits; i++) { 317 significantDigits.append((char)digits[i]); 318 } 319 BigInteger unscaledVal = new BigInteger(significantDigits.toString()); 320 return new com.ibm.icu.math.BigDecimal(unscaledVal, (int)scale); 321 } else { 322 return new com.ibm.icu.math.BigDecimal(getStringRep(isPositive)); 323 } 324 } 325 326 /** 327 * Return whether or not this objects represented value is an integer. 328 * [bnf] 329 * @return true if the represented value of this object is an integer 330 */ 331 boolean isIntegral() { 332 // Trim trailing zeros. This does not change the represented value. 333 while (count > 0 && digits[count - 1] == (byte)'0') --count; 334 return count == 0 || decimalAt >= count; 335 } 336 337// Unused as of ICU 2.6 - alan 338// /** 339// * Return true if the number represented by this object can fit into 340// * a long. 341// */ 342// boolean fitsIntoLong(boolean isPositive) 343// { 344// // Figure out if the result will fit in a long. We have to 345// // first look for nonzero digits after the decimal point; 346// // then check the size. If the digit count is 18 or less, then 347// // the value can definitely be represented as a long. If it is 19 348// // then it may be too large. 349// 350// // Trim trailing zeros. This does not change the represented value. 351// while (count > 0 && digits[count - 1] == (byte)'0') --count; 352// 353// if (count == 0) { 354// // Positive zero fits into a long, but negative zero can only 355// // be represented as a double. - bug 4162852 356// return isPositive; 357// } 358// 359// if (decimalAt < count || decimalAt > MAX_LONG_DIGITS) return false; 360// 361// if (decimalAt < MAX_LONG_DIGITS) return true; 362// 363// // At this point we have decimalAt == count, and count == MAX_LONG_DIGITS. 364// // The number will overflow if it is larger than 9223372036854775807 365// // or smaller than -9223372036854775808. 366// for (int i=0; i<count; ++i) 367// { 368// byte dig = digits[i], max = LONG_MIN_REP[i]; 369// if (dig > max) return false; 370// if (dig < max) return true; 371// } 372// 373// // At this point the first count digits match. If decimalAt is less 374// // than count, then the remaining digits are zero, and we return true. 375// if (count < decimalAt) return true; 376// 377// // Now we have a representation of Long.MIN_VALUE, without the leading 378// // negative sign. If this represents a positive value, then it does 379// // not fit; otherwise it fits. 380// return !isPositive; 381// } 382 383// Unused as of ICU 2.6 - alan 384// /** 385// * Set the digit list to a representation of the given double value. 386// * This method supports fixed-point notation. 387// * @param source Value to be converted; must not be Inf, -Inf, Nan, 388// * or a value <= 0. 389// * @param maximumFractionDigits The most fractional digits which should 390// * be converted. 391// */ 392// public final void set(double source, int maximumFractionDigits) 393// { 394// set(source, maximumFractionDigits, true); 395// } 396 397 /** 398 * Set the digit list to a representation of the given double value. 399 * This method supports both fixed-point and exponential notation. 400 * @param source Value to be converted; must not be Inf, -Inf, Nan, 401 * or a value <= 0. 402 * @param maximumDigits The most fractional or total digits which should 403 * be converted. 404 * @param fixedPoint If true, then maximumDigits is the maximum 405 * fractional digits to be converted. If false, total digits. 406 */ 407 final void set(double source, int maximumDigits, boolean fixedPoint) 408 { 409 if (source == 0) source = 0; 410 // Generate a representation of the form DDDDD, DDDDD.DDDDD, or 411 // DDDDDE+/-DDDDD. 412 String rep = Double.toString(source); 413 414 set(rep, MAX_LONG_DIGITS); 415 416 if (fixedPoint) { 417 // The negative of the exponent represents the number of leading 418 // zeros between the decimal and the first non-zero digit, for 419 // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this 420 // is more than the maximum fraction digits, then we have an underflow 421 // for the printed representation. 422 if (-decimalAt > maximumDigits) { 423 count = 0; 424 return; 425 } else if (-decimalAt == maximumDigits) { 426 if (shouldRoundUp(0)) { 427 count = 1; 428 ++decimalAt; 429 digits[0] = (byte)'1'; 430 } else { 431 count = 0; 432 } 433 return; 434 } 435 // else fall through 436 } 437 438 // Eliminate trailing zeros. 439 while (count > 1 && digits[count - 1] == '0') 440 --count; 441 442 // Eliminate digits beyond maximum digits to be displayed. 443 // Round up if appropriate. 444 round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits == 0 ? -1 : maximumDigits); 445 } 446 447 /** 448 * Given a string representation of the form DDDDD, DDDDD.DDDDD, 449 * or DDDDDE+/-DDDDD, set this object's value to it. Ignore 450 * any leading '-'. 451 */ 452 private void set(String rep, int maxCount) { 453 decimalAt = -1; 454 count = 0; 455 int exponent = 0; 456 // Number of zeros between decimal point and first non-zero digit after 457 // decimal point, for numbers < 1. 458 int leadingZerosAfterDecimal = 0; 459 boolean nonZeroDigitSeen = false; 460 // Skip over leading '-' 461 int i=0; 462 if (rep.charAt(i) == '-') { 463 ++i; 464 } 465 for (; i < rep.length(); ++i) { 466 char c = rep.charAt(i); 467 if (c == '.') { 468 decimalAt = count; 469 } else if (c == 'e' || c == 'E') { 470 ++i; 471 // Integer.parseInt doesn't handle leading '+' signs 472 if (rep.charAt(i) == '+') { 473 ++i; 474 } 475 exponent = Integer.valueOf(rep.substring(i)).intValue(); 476 break; 477 } else if (count < maxCount) { 478 if (!nonZeroDigitSeen) { 479 nonZeroDigitSeen = (c != '0'); 480 if (!nonZeroDigitSeen && decimalAt != -1) { 481 ++leadingZerosAfterDecimal; 482 } 483 } 484 485 if (nonZeroDigitSeen) { 486 ensureCapacity(count+1, count); 487 digits[count++] = (byte)c; 488 } 489 } 490 } 491 if (decimalAt == -1) { 492 decimalAt = count; 493 } 494 decimalAt += exponent - leadingZerosAfterDecimal; 495 } 496 497 /** 498 * Return true if truncating the representation to the given number 499 * of digits will result in an increment to the last digit. This 500 * method implements half-even rounding, the default rounding mode. 501 * [bnf] 502 * @param maximumDigits the number of digits to keep, from 0 to 503 * <code>count-1</code>. If 0, then all digits are rounded away, and 504 * this method returns true if a one should be generated (e.g., formatting 505 * 0.09 with "#.#"). 506 * @return true if digit <code>maximumDigits-1</code> should be 507 * incremented 508 */ 509 private boolean shouldRoundUp(int maximumDigits) { 510 // variable not used boolean increment = false; 511 // Implement IEEE half-even rounding 512 /*Bug 4243108 513 format(0.0) gives "0.1" if preceded by parse("99.99") [Richard/GCL] 514 */ 515 if (maximumDigits < count) { 516 if (digits[maximumDigits] > '5') { 517 return true; 518 } else if (digits[maximumDigits] == '5' ) { 519 for (int i=maximumDigits+1; i<count; ++i) { 520 if (digits[i] != '0') { 521 return true; 522 } 523 } 524 return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0); 525 } 526 } 527 return false; 528 } 529 530 /** 531 * Round the representation to the given number of digits. 532 * @param maximumDigits The maximum number of digits to be shown. 533 * Upon return, count will be less than or equal to maximumDigits. 534 * This now performs rounding when maximumDigits is 0, formerly it did not. 535 */ 536 public final void round(int maximumDigits) { 537 // Eliminate digits beyond maximum digits to be displayed. 538 // Round up if appropriate. 539 // [bnf] rewritten to fix 4179818 540 if (maximumDigits >= 0 && maximumDigits < count) { 541 if (shouldRoundUp(maximumDigits)) { 542 // Rounding up involves incrementing digits from LSD to MSD. 543 // In most cases this is simple, but in a worst case situation 544 // (9999..99) we have to adjust the decimalAt value. 545 for (;;) 546 { 547 --maximumDigits; 548 if (maximumDigits < 0) 549 { 550 // We have all 9's, so we increment to a single digit 551 // of one and adjust the exponent. 552 digits[0] = (byte) '1'; 553 ++decimalAt; 554 maximumDigits = 0; // Adjust the count 555 break; 556 } 557 558 ++digits[maximumDigits]; 559 if (digits[maximumDigits] <= '9') break; 560 // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this 561 } 562 ++maximumDigits; // Increment for use as count 563 } 564 count = maximumDigits; 565 } 566 // Bug 4217661 DecimalFormat formats 1.001 to "1.00" instead of "1" 567 // Eliminate trailing zeros. [Richard/GCL] 568 // [dlf] moved outside if block, see ticket #6408 569 while (count > 1 && digits[count-1] == '0') { 570 --count; 571 } 572 } 573 574 /** 575 * Utility routine to set the value of the digit list from a long 576 */ 577 public final void set(long source) 578 { 579 set(source, 0); 580 } 581 582 /** 583 * Set the digit list to a representation of the given long value. 584 * @param source Value to be converted; must be >= 0 or == 585 * Long.MIN_VALUE. 586 * @param maximumDigits The most digits which should be converted. 587 * If maximumDigits is lower than the number of significant digits 588 * in source, the representation will be rounded. Ignored if <= 0. 589 */ 590 public final void set(long source, int maximumDigits) 591 { 592 // This method does not expect a negative number. However, 593 // "source" can be a Long.MIN_VALUE (-9223372036854775808), 594 // if the number being formatted is a Long.MIN_VALUE. In that 595 // case, it will be formatted as -Long.MIN_VALUE, a number 596 // which is outside the legal range of a long, but which can 597 // be represented by DigitList. 598 // [NEW] Faster implementation 599 if (source <= 0) { 600 if (source == Long.MIN_VALUE) { 601 decimalAt = count = MAX_LONG_DIGITS; 602 System.arraycopy(LONG_MIN_REP, 0, digits, 0, count); 603 } else { 604 count = 0; 605 decimalAt = 0; 606 } 607 } else { 608 int left = MAX_LONG_DIGITS; 609 int right; 610 while (source > 0) { 611 digits[--left] = (byte) (((long) '0') + (source % 10)); 612 source /= 10; 613 } 614 decimalAt = MAX_LONG_DIGITS-left; 615 // Don't copy trailing zeros 616 // we are guaranteed that there is at least one non-zero digit, 617 // so we don't have to check lower bounds 618 for (right = MAX_LONG_DIGITS - 1; digits[right] == (byte) '0'; --right) {} 619 count = right - left + 1; 620 System.arraycopy(digits, left, digits, 0, count); 621 } 622 if (maximumDigits > 0) round(maximumDigits); 623 } 624 625 /** 626 * Set the digit list to a representation of the given BigInteger value. 627 * [bnf] 628 * @param source Value to be converted 629 * @param maximumDigits The most digits which should be converted. 630 * If maximumDigits is lower than the number of significant digits 631 * in source, the representation will be rounded. Ignored if <= 0. 632 */ 633 public final void set(BigInteger source, int maximumDigits) { 634 String stringDigits = source.toString(); 635 636 count = decimalAt = stringDigits.length(); 637 638 // Don't copy trailing zeros 639 while (count > 1 && stringDigits.charAt(count - 1) == '0') --count; 640 641 int offset = 0; 642 if (stringDigits.charAt(0) == '-') { 643 ++offset; 644 --count; 645 --decimalAt; 646 } 647 648 ensureCapacity(count, 0); 649 for (int i = 0; i < count; ++i) { 650 digits[i] = (byte) stringDigits.charAt(i + offset); 651 } 652 653 if (maximumDigits > 0) round(maximumDigits); 654 } 655 656 /** 657 * Internal method that sets this digit list to represent the 658 * given value. The value is given as a String of the format 659 * returned by BigDecimal. 660 * @param stringDigits value to be represented with the following 661 * syntax, expressed as a regular expression: -?\d*.?\d* 662 * Must not be an empty string. 663 * @param maximumDigits The most digits which should be converted. 664 * If maximumDigits is lower than the number of significant digits 665 * in source, the representation will be rounded. Ignored if <= 0. 666 * @param fixedPoint If true, then maximumDigits is the maximum 667 * fractional digits to be converted. If false, total digits. 668 */ 669 private void setBigDecimalDigits(String stringDigits, 670 int maximumDigits, boolean fixedPoint) { 671//| // Find the first non-zero digit, the decimal, and the last non-zero digit. 672//| int first=-1, last=stringDigits.length()-1, decimal=-1; 673//| for (int i=0; (first<0 || decimal<0) && i<=last; ++i) { 674//| char c = stringDigits.charAt(i); 675//| if (c == '.') { 676//| decimal = i; 677//| } else if (first < 0 && (c >= '1' && c <= '9')) { 678//| first = i; 679//| } 680//| } 681//| 682//| if (first < 0) { 683//| clear(); 684//| return; 685//| } 686//| 687//| // At this point we know there is at least one non-zero digit, so the 688//| // following loop is safe. 689//| for (;;) { 690//| char c = stringDigits.charAt(last); 691//| if (c != '0' && c != '.') { 692//| break; 693//| } 694//| --last; 695//| } 696//| 697//| if (decimal < 0) { 698//| decimal = stringDigits.length(); 699//| } 700//| 701//| count = last - first; 702//| if (decimal < first || decimal > last) { 703//| ++count; 704//| } 705//| decimalAt = decimal - first; 706//| if (decimalAt < 0) { 707//| ++decimalAt; 708//| } 709//| 710//| ensureCapacity(count, 0); 711//| for (int i = 0; i < count; ++i) { 712//| digits[i] = (byte) stringDigits.charAt(first++); 713//| if (first == decimal) { 714//| ++first; 715//| } 716//| } 717 718 // The maxDigits here could also be Integer.MAX_VALUE 719 set(stringDigits, stringDigits.length()); 720 721 // Eliminate digits beyond maximum digits to be displayed. 722 // Round up if appropriate. 723 // {dlf} Some callers depend on passing '0' to round to mean 'don't round', but 724 // rather than pass that information explicitly, we rely on some magic with maximumDigits 725 // and decimalAt. Unfortunately, this is no good, because there are cases where maximumDigits 726 // is zero and we do want to round, e.g. BigDecimal values -1 < x < 1. So since round 727 // changed to perform rounding when the argument is 0, we now force the argument 728 // to -1 in the situations where it matters. 729 round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits == 0 ? -1 : maximumDigits); 730 } 731 732 /** 733 * Set the digit list to a representation of the given BigDecimal value. 734 * [bnf] 735 * @param source Value to be converted 736 * @param maximumDigits The most digits which should be converted. 737 * If maximumDigits is lower than the number of significant digits 738 * in source, the representation will be rounded. Ignored if <= 0. 739 * @param fixedPoint If true, then maximumDigits is the maximum 740 * fractional digits to be converted. If false, total digits. 741 */ 742 public final void set(java.math.BigDecimal source, 743 int maximumDigits, boolean fixedPoint) { 744 setBigDecimalDigits(source.toString(), maximumDigits, fixedPoint); 745 } 746 747 /* 748 * Set the digit list to a representation of the given BigDecimal value. 749 * [bnf] 750 * @param source Value to be converted 751 * @param maximumDigits The most digits which should be converted. 752 * If maximumDigits is lower than the number of significant digits 753 * in source, the representation will be rounded. Ignored if <= 0. 754 * @param fixedPoint If true, then maximumDigits is the maximum 755 * fractional digits to be converted. If false, total digits. 756 */ 757 public final void set(com.ibm.icu.math.BigDecimal source, 758 int maximumDigits, boolean fixedPoint) { 759 setBigDecimalDigits(source.toString(), maximumDigits, fixedPoint); 760 } 761 762 /** 763 * Returns true if this DigitList represents Long.MIN_VALUE; 764 * false, otherwise. This is required so that getLong() works. 765 */ 766 private boolean isLongMIN_VALUE() 767 { 768 if (decimalAt != count || count != MAX_LONG_DIGITS) 769 return false; 770 771 for (int i = 0; i < count; ++i) 772 { 773 if (digits[i] != LONG_MIN_REP[i]) return false; 774 } 775 776 return true; 777 } 778 779 private static byte[] LONG_MIN_REP; 780 781 static 782 { 783 // Store the representation of LONG_MIN without the leading '-' 784 String s = Long.toString(Long.MIN_VALUE); 785 LONG_MIN_REP = new byte[MAX_LONG_DIGITS]; 786 for (int i=0; i < MAX_LONG_DIGITS; ++i) 787 { 788 LONG_MIN_REP[i] = (byte)s.charAt(i + 1); 789 } 790 } 791 792// Unused -- Alan 2003-05 793// /** 794// * Return the floor of the log base 10 of a given double. 795// * This method compensates for inaccuracies which arise naturally when 796// * computing logs, and always give the correct value. The parameter 797// * must be positive and finite. 798// */ 799// private static final int log10(double d) 800// { 801// // The reason this routine is needed is that simply taking the 802// // log and dividing by log10 yields a result which may be off 803// // by 1 due to rounding errors. For example, the naive log10 804// // of 1.0e300 taken this way is 299, rather than 300. 805// double log10 = Math.log(d) / LOG10; 806// int ilog10 = (int)Math.floor(log10); 807// // Positive logs could be too small, e.g. 0.99 instead of 1.0 808// if (log10 > 0 && d >= Math.pow(10, ilog10 + 1)) 809// { 810// ++ilog10; 811// } 812// // Negative logs could be too big, e.g. -0.99 instead of -1.0 813// else if (log10 < 0 && d < Math.pow(10, ilog10)) 814// { 815// --ilog10; 816// } 817// return ilog10; 818// } 819// 820// private static final double LOG10 = Math.log(10.0); 821 822 // (The following boilerplate methods are currently not called, 823 // and cannot be called by tests since this class is 824 // package-private. The methods may be useful in the future, so 825 // we do not delete them. 2003-06-11 ICU 2.6 Alan) 826 ///CLOVER:OFF 827 /** 828 * equality test between two digit lists. 829 */ 830 public boolean equals(Object obj) { 831 if (this == obj) // quick check 832 return true; 833 if (!(obj instanceof DigitList)) // (1) same object? 834 return false; 835 DigitList other = (DigitList) obj; 836 if (count != other.count || 837 decimalAt != other.decimalAt) 838 return false; 839 for (int i = 0; i < count; i++) 840 if (digits[i] != other.digits[i]) 841 return false; 842 return true; 843 } 844 845 /** 846 * Generates the hash code for the digit list. 847 */ 848 public int hashCode() { 849 int hashcode = decimalAt; 850 851 for (int i = 0; i < count; i++) 852 hashcode = hashcode * 37 + digits[i]; 853 854 return hashcode; 855 } 856 857 public String toString() 858 { 859 if (isZero()) return "0"; 860 StringBuilder buf = new StringBuilder("0."); 861 for (int i=0; i<count; ++i) buf.append((char)digits[i]); 862 buf.append("x10^"); 863 buf.append(decimalAt); 864 return buf.toString(); 865 } 866 ///CLOVER:ON 867} 868