1. /*
  2. * @(#)DigitList.java 1.24 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * @(#)DigitList.java 1.22 00/09/05
  9. *
  10. * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  11. * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  12. *
  13. * Portions copyright (c) 1996-1998 Sun Microsystems, Inc.
  14. * All Rights Reserved.
  15. *
  16. * The original version of this source code and documentation is copyrighted
  17. * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  18. * materials are provided under terms of a License Agreement between Taligent
  19. * and Sun. This technology is protected by multiple US and International
  20. * patents. This notice and attribution to Taligent may not be removed.
  21. * Taligent is a registered trademark of Taligent, Inc.
  22. *
  23. * Permission to use, copy, modify, and distribute this software
  24. * and its documentation for NON-COMMERCIAL purposes and without
  25. * fee is hereby granted provided that this copyright notice
  26. * appears in all copies. Please refer to the file "copyright.html"
  27. * for further important copyright and licensing information.
  28. *
  29. * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  30. * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  31. * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  32. * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  33. * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  34. * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  35. *
  36. */
  37. package java.text;
  38. /**
  39. * Digit List. Private to DecimalFormat.
  40. * Handles the transcoding
  41. * between numeric values and strings of characters. Only handles
  42. * non-negative numbers. The division of labor between DigitList and
  43. * DecimalFormat is that DigitList handles the radix 10 representation
  44. * issues; DecimalFormat handles the locale-specific issues such as
  45. * positive/negative, grouping, decimal point, currency, and so on.
  46. *
  47. * A DigitList is really a representation of a floating point value.
  48. * It may be an integer value; we assume that a double has sufficient
  49. * precision to represent all digits of a long.
  50. *
  51. * The DigitList representation consists of a string of characters,
  52. * which are the digits radix 10, from '0' to '9'. It also has a radix
  53. * 10 exponent associated with it. The value represented by a DigitList
  54. * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
  55. * derived by placing all the digits of the list to the right of the
  56. * decimal point, by 10^exponent.
  57. *
  58. * @see Locale
  59. * @see Format
  60. * @see NumberFormat
  61. * @see DecimalFormat
  62. * @see ChoiceFormat
  63. * @see MessageFormat
  64. * @version 1.22 09/05/00
  65. * @author Mark Davis, Alan Liu
  66. */
  67. final class DigitList implements Cloneable {
  68. /**
  69. * The maximum number of significant digits in an IEEE 754 double, that
  70. * is, in a Java double. This must not be increased, or garbage digits
  71. * will be generated, and should not be decreased, or accuracy will be lost.
  72. */
  73. public static final int MAX_COUNT = 19; // == Long.toString(Long.MAX_VALUE).length()
  74. public static final int DBL_DIG = 17;
  75. /**
  76. * These data members are intentionally public and can be set directly.
  77. *
  78. * The value represented is given by placing the decimal point before
  79. * digits[decimalAt]. If decimalAt is < 0, then leading zeros between
  80. * the decimal point and the first nonzero digit are implied. If decimalAt
  81. * is > count, then trailing zeros between the digits[count-1] and the
  82. * decimal point are implied.
  83. *
  84. * Equivalently, the represented value is given by f * 10^decimalAt. Here
  85. * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
  86. * the right of the decimal.
  87. *
  88. * DigitList is normalized, so if it is non-zero, figits[0] is non-zero. We
  89. * don't allow denormalized numbers because our exponent is effectively of
  90. * unlimited magnitude. The count value contains the number of significant
  91. * digits present in digits[].
  92. *
  93. * Zero is represented by any DigitList with count == 0 or with each digits[i]
  94. * for all i <= count == '0'.
  95. */
  96. public int decimalAt = 0;
  97. public int count = 0;
  98. public byte[] digits = new byte[MAX_COUNT];
  99. /**
  100. * Return true if the represented number is zero.
  101. */
  102. boolean isZero()
  103. {
  104. for (int i=0; i<count; ++i) if (digits[i] != '0') return false;
  105. return true;
  106. }
  107. /**
  108. * Clears out the digits.
  109. * Use before appending them.
  110. * Typically, you set a series of digits with append, then at the point
  111. * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
  112. * then go on appending digits.
  113. */
  114. public void clear () {
  115. decimalAt = 0;
  116. count = 0;
  117. }
  118. /**
  119. * Appends digits to the list. Ignores all digits over MAX_COUNT,
  120. * since they are not significant for either longs or doubles.
  121. */
  122. public void append (int digit) {
  123. if (count < MAX_COUNT)
  124. digits[count++] = (byte) digit;
  125. }
  126. /**
  127. * Utility routine to get the value of the digit list
  128. * If (count == 0) this throws a NumberFormatException, which
  129. * mimics Long.parseLong().
  130. */
  131. public final double getDouble() {
  132. if (count == 0) return 0.0;
  133. StringBuffer temp = new StringBuffer(count);
  134. temp.append('.');
  135. for (int i = 0; i < count; ++i) temp.append((char)(digits[i]));
  136. temp.append('E');
  137. temp.append(Integer.toString(decimalAt));
  138. return Double.valueOf(temp.toString()).doubleValue();
  139. // long value = Long.parseLong(temp.toString());
  140. // return (value * Math.pow(10, decimalAt - count));
  141. }
  142. /**
  143. * Utility routine to get the value of the digit list.
  144. * If (count == 0) this returns 0, unlike Long.parseLong().
  145. */
  146. public final long getLong() {
  147. // for now, simple implementation; later, do proper IEEE native stuff
  148. if (count == 0) return 0;
  149. // We have to check for this, because this is the one NEGATIVE value
  150. // we represent. If we tried to just pass the digits off to parseLong,
  151. // we'd get a parse failure.
  152. if (isLongMIN_VALUE()) return Long.MIN_VALUE;
  153. StringBuffer temp = new StringBuffer(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. * Return true if the number represented by this object can fit into
  162. * a long.
  163. * @param isPositive true if this number should be regarded as positive
  164. * @param ignoreNegativeZero true if -0 should be regarded as identical to
  165. * +0; otherwise they are considered distinct
  166. * @return true if this number fits into a Java long
  167. */
  168. boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero)
  169. {
  170. // Figure out if the result will fit in a long. We have to
  171. // first look for nonzero digits after the decimal point;
  172. // then check the size. If the digit count is 18 or less, then
  173. // the value can definitely be represented as a long. If it is 19
  174. // then it may be too large.
  175. // Trim trailing zeros. This does not change the represented value.
  176. while (count > 0 && digits[count - 1] == (byte)'0') --count;
  177. if (count == 0) {
  178. // Positive zero fits into a long, but negative zero can only
  179. // be represented as a double. - bug 4162852
  180. return isPositive || ignoreNegativeZero;
  181. }
  182. if (decimalAt < count || decimalAt > MAX_COUNT) return false;
  183. if (decimalAt < MAX_COUNT) return true;
  184. // At this point we have decimalAt == count, and count == MAX_COUNT.
  185. // The number will overflow if it is larger than 9223372036854775807
  186. // or smaller than -9223372036854775808.
  187. for (int i=0; i<count; ++i)
  188. {
  189. byte dig = digits[i], max = LONG_MIN_REP[i];
  190. if (dig > max) return false;
  191. if (dig < max) return true;
  192. }
  193. // At this point the first count digits match. If decimalAt is less
  194. // than count, then the remaining digits are zero, and we return true.
  195. if (count < decimalAt) return true;
  196. // Now we have a representation of Long.MIN_VALUE, without the leading
  197. // negative sign. If this represents a positive value, then it does
  198. // not fit; otherwise it fits.
  199. return !isPositive;
  200. }
  201. private static final boolean DEBUG = false;
  202. /**
  203. * Set the digit list to a representation of the given double value.
  204. * This method supports fixed-point notation.
  205. * @param source Value to be converted; must not be Inf, -Inf, Nan,
  206. * or a value <= 0.
  207. * @param maximumFractionDigits The most fractional digits which should
  208. * be converted.
  209. */
  210. public final void set(double source, int maximumFractionDigits)
  211. {
  212. set(source, maximumFractionDigits, true);
  213. }
  214. /**
  215. * Set the digit list to a representation of the given double value.
  216. * This method supports both fixed-point and exponential notation.
  217. * @param source Value to be converted; must not be Inf, -Inf, Nan,
  218. * or a value <= 0.
  219. * @param maximumDigits The most fractional or total digits which should
  220. * be converted.
  221. * @param fixedPoint If true, then maximumDigits is the maximum
  222. * fractional digits to be converted. If false, total digits.
  223. */
  224. final void set(double source, int maximumDigits, boolean fixedPoint)
  225. {
  226. if (source == 0) source = 0;
  227. // Generate a representation of the form DDDDD, DDDDD.DDDDD, or
  228. // DDDDDE+/-DDDDD.
  229. String rep = Double.toString(source);
  230. decimalAt = -1;
  231. count = 0;
  232. int exponent = 0;
  233. // Number of zeros between decimal point and first non-zero digit after
  234. // decimal point, for numbers < 1.
  235. int leadingZerosAfterDecimal = 0;
  236. boolean nonZeroDigitSeen = false;
  237. for (int i=0; i < rep.length(); ++i)
  238. {
  239. char c = rep.charAt(i);
  240. if (c == '.')
  241. {
  242. decimalAt = count;
  243. }
  244. else if (c == 'e' || c == 'E')
  245. {
  246. exponent = Integer.valueOf(rep.substring(i+1)).intValue();
  247. break;
  248. }
  249. else if (count < MAX_COUNT)
  250. {
  251. if (!nonZeroDigitSeen)
  252. {
  253. nonZeroDigitSeen = (c != '0');
  254. if (!nonZeroDigitSeen && decimalAt != -1) ++leadingZerosAfterDecimal;
  255. }
  256. if (nonZeroDigitSeen) digits[count++] = (byte)c;
  257. }
  258. }
  259. if (decimalAt == -1) decimalAt = count;
  260. if (nonZeroDigitSeen) {
  261. decimalAt += exponent - leadingZerosAfterDecimal;
  262. }
  263. if (fixedPoint)
  264. {
  265. // The negative of the exponent represents the number of leading
  266. // zeros between the decimal and the first non-zero digit, for
  267. // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
  268. // is more than the maximum fraction digits, then we have an underflow
  269. // for the printed representation.
  270. if (-decimalAt > maximumDigits) {
  271. // Handle an underflow to zero when we round something like
  272. // 0.0009 to 2 fractional digits.
  273. count = 0;
  274. return;
  275. } else if (-decimalAt == maximumDigits) {
  276. // If we round 0.0009 to 3 fractional digits, then we have to
  277. // create a new one digit in the least significant location.
  278. if (shouldRoundUp(0)) {
  279. count = 1;
  280. ++decimalAt;
  281. digits[0] = (byte)'1';
  282. } else {
  283. count = 0;
  284. }
  285. return;
  286. }
  287. // else fall through
  288. }
  289. // Eliminate trailing zeros.
  290. while (count > 1 && digits[count - 1] == '0')
  291. --count;
  292. if (DEBUG)
  293. {
  294. System.out.print("Before rounding 0.");
  295. for (int i=0; i<count; ++i) System.out.print((char)digits[i]);
  296. System.out.println("x10^" + decimalAt);
  297. }
  298. // Eliminate digits beyond maximum digits to be displayed.
  299. // Round up if appropriate.
  300. round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
  301. if (DEBUG)
  302. {
  303. System.out.print("After rounding 0.");
  304. for (int i=0; i<count; ++i) System.out.print((char)digits[i]);
  305. System.out.println("x10^" + decimalAt);
  306. }
  307. // The following method also works, and does not rely on the specific
  308. // format generated by Double.toString(). However, it introduces significant
  309. // errors in the least-significant digits, which cause round-trip parse and
  310. // format operations to fail. We retain this code for future reference;
  311. // the compiler will ignore it.
  312. if (false)
  313. {
  314. // Find the exponent for this value. Our convention is 0.mmmm * 10^decimalAt,
  315. // so we need to add one.
  316. decimalAt = log10(source) + 1;
  317. // Compute the number of digits to generate based on the maximum fraction
  318. // digits and the exponent. For example, if the exponent is -95 and the
  319. // maximum fraction digits is 100, then we'll have 95 leading zeros and only
  320. // 5 significant digits.
  321. count = maximumDigits + decimalAt;
  322. if (count > DBL_DIG) count = DBL_DIG;
  323. if (count < 0) count = 0;
  324. if (count == 0) return; // Return if we've underflowed to zero
  325. // Put the mantissa into a long. We create a mantissa value in the
  326. // range 10^n-1 <= mantissa < 10^n, where n is the desired number of
  327. // digits. If this is a small number << 1, decimalAt may be negative,
  328. // indicating leading zeros between the decimal point an digits[0]. A
  329. // decimalAt value of 0 indicates that the decimal point is before
  330. // digits[0].
  331. //System.out.println("d = " + source + " log = " + (Math.log(source) / LOG10));
  332. //System.out.println("d == 0.1 " + (source == 0.1));
  333. long mantissa = Math.round(source * Math.pow(10, count - decimalAt));
  334. String longRep = Long.toString(mantissa);
  335. // At this point we have a representation of exactly maxDecimalCount
  336. // characters.
  337. // FOLLOWING LINE FOR DEBUGGING ONLY. THIS catches problems with log10 computation.
  338. if (longRep.length() != count)
  339. throw new Error("Rep=" + longRep + " rep.length=" + longRep.length() +
  340. " exp.len=" + count + " " +
  341. "val=" + source + " mant=" + mantissa +
  342. " decimalAt=" + decimalAt);
  343. // Eliminate trailing zeros.
  344. while (count > 1 && longRep.charAt(count - 1) == '0')
  345. --count;
  346. // Copy digits over
  347. for (int i=0; i<count; ++i)
  348. digits[i] = (byte)longRep.charAt(i);
  349. }
  350. }
  351. /**
  352. * Round the representation to the given number of digits.
  353. * @param maximumDigits The maximum number of digits to be shown.
  354. * Upon return, count will be less than or equal to maximumDigits.
  355. */
  356. private final void round(int maximumDigits)
  357. {
  358. // Eliminate digits beyond maximum digits to be displayed.
  359. // Round up if appropriate.
  360. if (maximumDigits >= 0 && maximumDigits < count)
  361. {
  362. if (shouldRoundUp(maximumDigits)) {
  363. // Rounding up involved incrementing digits from LSD to MSD.
  364. // In most cases this is simple, but in a worst case situation
  365. // (9999..99) we have to adjust the decimalAt value.
  366. for (;;)
  367. {
  368. --maximumDigits;
  369. if (maximumDigits < 0)
  370. {
  371. // We have all 9's, so we increment to a single digit
  372. // of one and adjust the exponent.
  373. digits[0] = (byte) '1';
  374. ++decimalAt;
  375. maximumDigits = 0; // Adjust the count
  376. break;
  377. }
  378. ++digits[maximumDigits];
  379. if (digits[maximumDigits] <= '9') break;
  380. // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
  381. }
  382. ++maximumDigits; // Increment for use as count
  383. }
  384. count = maximumDigits;
  385. }
  386. }
  387. /**
  388. * Return true if truncating the representation to the given number
  389. * of digits will result in an increment to the last digit. This
  390. * method implements half-even rounding, the default rounding mode.
  391. * [bnf]
  392. * @param maximumDigits the number of digits to keep, from 0 to
  393. * <code>count-1</code>. If 0, then all digits are rounded away, and
  394. * this method returns true if a one should be generated (e.g., formatting
  395. * 0.09 with "#.#").
  396. * @return true if digit <code>maximumDigits-1</code> should be
  397. * incremented
  398. */
  399. private boolean shouldRoundUp(int maximumDigits) {
  400. boolean increment = false;
  401. // Implement IEEE half-even rounding
  402. if (maximumDigits < count) {
  403. if (digits[maximumDigits] > '5') {
  404. return true;
  405. } else if (digits[maximumDigits] == '5' ) {
  406. for (int i=maximumDigits+1; i<count; ++i) {
  407. if (digits[i] != '0') {
  408. return true;
  409. }
  410. }
  411. return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0);
  412. }
  413. }
  414. return false;
  415. }
  416. /**
  417. * Utility routine to set the value of the digit list from a long
  418. */
  419. public final void set(long source)
  420. {
  421. set(source, 0);
  422. }
  423. /**
  424. * Set the digit list to a representation of the given long value.
  425. * @param source Value to be converted; must be >= 0 or ==
  426. * Long.MIN_VALUE.
  427. * @param maximumDigits The most digits which should be converted.
  428. * If maximumDigits is lower than the number of significant digits
  429. * in source, the representation will be rounded. Ignored if <= 0.
  430. */
  431. public final void set(long source, int maximumDigits)
  432. {
  433. // for now, simple implementation; later, do proper IEEE stuff
  434. // String stringDigits = Long.toString(source);
  435. String stringDigits = Long.toString(source);
  436. // This method does not expect a negative number. However,
  437. // "source" can be a Long.MIN_VALUE (-9223372036854775808),
  438. // if the number being formatted is a Long.MIN_VALUE. In that
  439. // case, it will be formatted as -Long.MIN_VALUE, a number
  440. // which is outside the legal range of a long, but which can
  441. // be represented by DigitList.
  442. if (stringDigits.charAt(0) == '-') stringDigits = stringDigits.substring(1);
  443. count = decimalAt = stringDigits.length();
  444. // Don't copy trailing zeros
  445. while (count > 1 && stringDigits.charAt(count - 1) == '0') --count;
  446. for (int i = 0; i < count; ++i)
  447. digits[i] = (byte) stringDigits.charAt(i);
  448. if (maximumDigits > 0) round(maximumDigits);
  449. }
  450. /**
  451. * equality test between two digit lists.
  452. */
  453. public boolean equals(Object obj) {
  454. if (this == obj) // quick check
  455. return true;
  456. if (!(obj instanceof DigitList)) // (1) same object?
  457. return false;
  458. DigitList other = (DigitList) obj;
  459. if (count != other.count ||
  460. decimalAt != other.decimalAt)
  461. return false;
  462. for (int i = 0; i < count; i++)
  463. if (digits[i] != other.digits[i])
  464. return false;
  465. return true;
  466. }
  467. /**
  468. * Generates the hash code for the digit list.
  469. */
  470. public int hashCode() {
  471. int hashcode = decimalAt;
  472. for (int i = 0; i < count; i++)
  473. hashcode = hashcode * 37 + digits[i];
  474. return hashcode;
  475. }
  476. /**
  477. * Returns true if this DigitList represents Long.MIN_VALUE;
  478. * false, otherwise. This is required so that getLong() works.
  479. */
  480. private boolean isLongMIN_VALUE()
  481. {
  482. if (decimalAt != count || count != MAX_COUNT)
  483. return false;
  484. for (int i = 0; i < count; ++i)
  485. {
  486. if (digits[i] != LONG_MIN_REP[i]) return false;
  487. }
  488. return true;
  489. }
  490. private static byte[] LONG_MIN_REP;
  491. static
  492. {
  493. // Store the representation of LONG_MIN without the leading '-'
  494. String s = Long.toString(Long.MIN_VALUE);
  495. LONG_MIN_REP = new byte[MAX_COUNT];
  496. for (int i=0; i < MAX_COUNT; ++i)
  497. {
  498. LONG_MIN_REP[i] = (byte)s.charAt(i + 1);
  499. }
  500. }
  501. /**
  502. * Return the floor of the log base 10 of a given double.
  503. * This method compensates for inaccuracies which arise naturally when
  504. * computing logs, and always give the correct value. The parameter
  505. * must be positive and finite.
  506. */
  507. private static final int log10(double d)
  508. {
  509. // The reason this routine is needed is that simply taking the
  510. // log and dividing by log10 yields a result which may be off
  511. // by 1 due to rounding errors. For example, the naive log10
  512. // of 1.0e300 taken this way is 299, rather than 300.
  513. double log10 = Math.log(d) / LOG10;
  514. int ilog10 = (int)Math.floor(log10);
  515. // Positive logs could be too small, e.g. 0.99 instead of 1.0
  516. if (log10 > 0 && d >= Math.pow(10, ilog10 + 1))
  517. {
  518. ++ilog10;
  519. }
  520. // Negative logs could be too big, e.g. -0.99 instead of -1.0
  521. else if (log10 < 0 && d < Math.pow(10, ilog10))
  522. {
  523. --ilog10;
  524. }
  525. return ilog10;
  526. }
  527. private static final double LOG10 = Math.log(10.0);
  528. public String toString()
  529. {
  530. if (isZero()) return "0";
  531. StringBuffer buf = new StringBuffer("0.");
  532. for (int i=0; i<count; ++i) buf.append((char)digits[i]);
  533. buf.append("x10^");
  534. buf.append(decimalAt);
  535. return buf.toString();
  536. }
  537. }