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