• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2017 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 package ohos.global.icu.impl.number;
5 
6 import java.math.BigDecimal;
7 import java.math.BigInteger;
8 import java.math.MathContext;
9 import java.text.FieldPosition;
10 
11 import ohos.global.icu.impl.StandardPlural;
12 import ohos.global.icu.impl.Utility;
13 import ohos.global.icu.impl.number.Modifier.Signum;
14 import ohos.global.icu.text.PluralRules;
15 import ohos.global.icu.text.PluralRules.Operand;
16 import ohos.global.icu.text.UFieldPosition;
17 
18 /**
19  * Represents numbers and digit display properties using Binary Coded Decimal (BCD).
20  *
21  * @implements {@link DecimalQuantity}
22  * @hide exposed on OHOS
23  */
24 public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
25 
26     /**
27      * The power of ten corresponding to the least significant digit in the BCD. For example, if this
28      * object represents the number "3.14", the BCD will be "0x314" and the scale will be -2.
29      *
30      * <p>
31      * Note that in {@link java.math.BigDecimal}, the scale is defined differently: the number of digits
32      * after the decimal place, which is the negative of our definition of scale.
33      */
34     protected int scale;
35 
36     /**
37      * The number of digits in the BCD. For example, "1007" has BCD "0x1007" and precision 4. A long
38      * cannot represent precisions greater than 16.
39      *
40      * <p>
41      * This value must be re-calculated whenever the value in bcd changes by using
42      * {@link #computePrecisionAndCompact()}.
43      */
44     protected int precision;
45 
46     /**
47      * A bitmask of properties relating to the number represented by this object.
48      *
49      * @see #NEGATIVE_FLAG
50      * @see #INFINITY_FLAG
51      * @see #NAN_FLAG
52      */
53     protected byte flags;
54 
55     protected static final int NEGATIVE_FLAG = 1;
56     protected static final int INFINITY_FLAG = 2;
57     protected static final int NAN_FLAG = 4;
58 
59     // The following three fields relate to the double-to-ascii fast path algorithm.
60     // When a double is given to DecimalQuantityBCD, it is converted to using a fast algorithm. The
61     // fast algorithm guarantees correctness to only the first ~12 digits of the double. The process
62     // of rounding the number ensures that the converted digits are correct, falling back to a slow-
63     // path algorithm if required. Therefore, if a DecimalQuantity is constructed from a double, it
64     // is *required* that roundToMagnitude(), roundToIncrement(), or roundToInfinity() is called. If
65     // you don't round, assertions will fail in certain other methods if you try calling them.
66 
67     /**
68      * The original number provided by the user and which is represented in BCD. Used when we need to
69      * re-compute the BCD for an exact double representation.
70      */
71     protected double origDouble;
72 
73     /**
74      * The change in magnitude relative to the original double. Used when we need to re-compute the BCD
75      * for an exact double representation.
76      */
77     protected int origDelta;
78 
79     /**
80      * Whether the value in the BCD comes from the double fast path without having been rounded to ensure
81      * correctness
82      */
83     protected boolean isApproximate;
84 
85     // Positions to keep track of leading and trailing zeros.
86     // lReqPos is the magnitude of the first required leading zero.
87     // rReqPos is the magnitude of the last required trailing zero.
88     protected int lReqPos = 0;
89     protected int rReqPos = 0;
90 
91     /**
92      * The value of the (suppressed) exponent after the number has been put into
93      * a notation with exponents (ex: compact, scientific).
94      */
95     protected int exponent = 0;
96 
97     @Override
copyFrom(DecimalQuantity _other)98     public void copyFrom(DecimalQuantity _other) {
99         copyBcdFrom(_other);
100         DecimalQuantity_AbstractBCD other = (DecimalQuantity_AbstractBCD) _other;
101         lReqPos = other.lReqPos;
102         rReqPos = other.rReqPos;
103         scale = other.scale;
104         precision = other.precision;
105         flags = other.flags;
106         origDouble = other.origDouble;
107         origDelta = other.origDelta;
108         isApproximate = other.isApproximate;
109         exponent = other.exponent;
110     }
111 
clear()112     public DecimalQuantity_AbstractBCD clear() {
113         lReqPos = 0;
114         rReqPos = 0;
115         flags = 0;
116         setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, exponent, and BCD data
117         return this;
118     }
119 
120     @Override
setMinInteger(int minInt)121     public void setMinInteger(int minInt) {
122         // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
123         assert minInt >= 0;
124 
125         // Special behavior: do not set minInt to be less than what is already set.
126         // This is so significant digits rounding can set the integer length.
127         if (minInt < lReqPos) {
128             minInt = lReqPos;
129         }
130 
131         // Save values into internal state
132         lReqPos = minInt;
133     }
134 
135     @Override
setMinFraction(int minFrac)136     public void setMinFraction(int minFrac) {
137         // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
138         assert minFrac >= 0;
139 
140         // Save values into internal state
141         // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
142         rReqPos = -minFrac;
143     }
144 
145     @Override
applyMaxInteger(int maxInt)146     public void applyMaxInteger(int maxInt) {
147         // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
148         assert maxInt >= 0;
149 
150         if (precision == 0) {
151             return;
152         }
153 
154         if (maxInt <= scale) {
155             setBcdToZero();
156             return;
157         }
158 
159         int magnitude = getMagnitude();
160         if (maxInt <= magnitude) {
161             popFromLeft(magnitude - maxInt + 1);
162             compact();
163         }
164     }
165 
166     @Override
getPositionFingerprint()167     public long getPositionFingerprint() {
168         long fingerprint = 0;
169         fingerprint ^= (lReqPos << 16);
170         fingerprint ^= ((long) rReqPos << 32);
171         return fingerprint;
172     }
173 
174     @Override
roundToIncrement(BigDecimal roundingIncrement, MathContext mathContext)175     public void roundToIncrement(BigDecimal roundingIncrement, MathContext mathContext) {
176         // Do not call this method with an increment having only a 1 or a 5 digit!
177         // Use a more efficient call to either roundToMagnitude() or roundToNickel().
178         // Note: The check, which is somewhat expensive, is performed in an assertion
179         // to disable it in production.
180         assert roundingIncrement.stripTrailingZeros().precision() != 1
181                 || roundingIncrement.stripTrailingZeros().unscaledValue().intValue() != 5
182                 || roundingIncrement.stripTrailingZeros().unscaledValue().intValue() != 1;
183         BigDecimal temp = toBigDecimal();
184         temp = temp.divide(roundingIncrement, 0, mathContext.getRoundingMode())
185                 .multiply(roundingIncrement)
186                 .round(mathContext);
187         if (temp.signum() == 0) {
188             setBcdToZero(); // keeps negative flag for -0.0
189         } else {
190             setToBigDecimal(temp);
191         }
192     }
193 
194     @Override
multiplyBy(BigDecimal multiplicand)195     public void multiplyBy(BigDecimal multiplicand) {
196         if (isZeroish()) {
197             return;
198         }
199         BigDecimal temp = toBigDecimal();
200         temp = temp.multiply(multiplicand);
201         setToBigDecimal(temp);
202     }
203 
204     @Override
negate()205     public void negate() {
206       flags ^= NEGATIVE_FLAG;
207     }
208 
209     @Override
getMagnitude()210     public int getMagnitude() throws ArithmeticException {
211         if (precision == 0) {
212             throw new ArithmeticException("Magnitude is not well-defined for zero");
213         } else {
214             return scale + precision - 1;
215         }
216     }
217 
218     @Override
adjustMagnitude(int delta)219     public void adjustMagnitude(int delta) {
220         if (precision != 0) {
221             scale = Utility.addExact(scale, delta);
222             origDelta = Utility.addExact(origDelta, delta);
223             // Make sure that precision + scale won't overflow, either
224             Utility.addExact(scale, precision);
225         }
226     }
227 
228     @Override
getExponent()229     public int getExponent() {
230         return exponent;
231     }
232 
233     @Override
adjustExponent(int delta)234     public void adjustExponent(int delta) {
235         exponent = exponent + delta;
236     }
237 
238     @Override
getStandardPlural(PluralRules rules)239     public StandardPlural getStandardPlural(PluralRules rules) {
240         if (rules == null) {
241             // Fail gracefully if the user didn't provide a PluralRules
242             return StandardPlural.OTHER;
243         } else {
244             @SuppressWarnings("deprecation")
245             String ruleString = rules.select(this);
246             return StandardPlural.orOtherFromString(ruleString);
247         }
248     }
249 
250     @Override
getPluralOperand(Operand operand)251     public double getPluralOperand(Operand operand) {
252         // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
253         // See the comment at the top of this file explaining the "isApproximate" field.
254         assert !isApproximate;
255 
256         switch (operand) {
257         case i:
258             // Invert the negative sign if necessary
259             return isNegative() ? -toLong(true) : toLong(true);
260         case f:
261             return toFractionLong(true);
262         case t:
263             return toFractionLong(false);
264         case v:
265             return fractionCount();
266         case w:
267             return fractionCountWithoutTrailingZeros();
268         case e:
269             return getExponent();
270         default:
271             return Math.abs(toDouble());
272         }
273     }
274 
275     @Override
populateUFieldPosition(FieldPosition fp)276     public void populateUFieldPosition(FieldPosition fp) {
277         if (fp instanceof UFieldPosition) {
278             ((UFieldPosition) fp).setFractionDigits((int) getPluralOperand(Operand.v),
279                     (long) getPluralOperand(Operand.f));
280         }
281     }
282 
283     @Override
getUpperDisplayMagnitude()284     public int getUpperDisplayMagnitude() {
285         // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
286         // See the comment at the top of this file explaining the "isApproximate" field.
287         assert !isApproximate;
288 
289         int magnitude = scale + precision;
290         int result = (lReqPos > magnitude) ? lReqPos : magnitude;
291         return result - 1;
292     }
293 
294     @Override
getLowerDisplayMagnitude()295     public int getLowerDisplayMagnitude() {
296         // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
297         // See the comment at the top of this file explaining the "isApproximate" field.
298         assert !isApproximate;
299 
300         int magnitude = scale;
301         int result = (rReqPos < magnitude) ? rReqPos : magnitude;
302         return result;
303     }
304 
305     @Override
getDigit(int magnitude)306     public byte getDigit(int magnitude) {
307         // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
308         // See the comment at the top of this file explaining the "isApproximate" field.
309         assert !isApproximate;
310 
311         return getDigitPos(magnitude - scale);
312     }
313 
fractionCount()314     private int fractionCount() {
315         return Math.max(0, -getLowerDisplayMagnitude() - exponent);
316     }
317 
fractionCountWithoutTrailingZeros()318     private int fractionCountWithoutTrailingZeros() {
319         return Math.max(-scale - exponent, 0);
320     }
321 
322     @Override
isNegative()323     public boolean isNegative() {
324         return (flags & NEGATIVE_FLAG) != 0;
325     }
326 
327     @Override
signum()328     public Signum signum() {
329         boolean isZero = (isZeroish() && !isInfinite());
330         boolean isNeg = isNegative();
331         if (isZero && isNeg) {
332             return Signum.NEG_ZERO;
333         } else if (isZero) {
334             return Signum.POS_ZERO;
335         } else if (isNeg) {
336             return Signum.NEG;
337         } else {
338             return Signum.POS;
339         }
340     }
341 
342     @Override
isInfinite()343     public boolean isInfinite() {
344         return (flags & INFINITY_FLAG) != 0;
345     }
346 
347     @Override
isNaN()348     public boolean isNaN() {
349         return (flags & NAN_FLAG) != 0;
350     }
351 
352     @Override
isZeroish()353     public boolean isZeroish() {
354         return precision == 0;
355     }
356 
setToInt(int n)357     public void setToInt(int n) {
358         setBcdToZero();
359         flags = 0;
360         if (n < 0) {
361             flags |= NEGATIVE_FLAG;
362             n = -n;
363         }
364         if (n != 0) {
365             _setToInt(n);
366             compact();
367         }
368     }
369 
_setToInt(int n)370     private void _setToInt(int n) {
371         if (n == Integer.MIN_VALUE) {
372             readLongToBcd(-(long) n);
373         } else {
374             readIntToBcd(n);
375         }
376     }
377 
setToLong(long n)378     public void setToLong(long n) {
379         setBcdToZero();
380         flags = 0;
381         if (n < 0) {
382             flags |= NEGATIVE_FLAG;
383             n = -n;
384         }
385         if (n != 0) {
386             _setToLong(n);
387             compact();
388         }
389     }
390 
_setToLong(long n)391     private void _setToLong(long n) {
392         if (n == Long.MIN_VALUE) {
393             readBigIntegerToBcd(BigInteger.valueOf(n).negate());
394         } else if (n <= Integer.MAX_VALUE) {
395             readIntToBcd((int) n);
396         } else {
397             readLongToBcd(n);
398         }
399     }
400 
setToBigInteger(BigInteger n)401     public void setToBigInteger(BigInteger n) {
402         setBcdToZero();
403         flags = 0;
404         if (n.signum() == -1) {
405             flags |= NEGATIVE_FLAG;
406             n = n.negate();
407         }
408         if (n.signum() != 0) {
409             _setToBigInteger(n);
410             compact();
411         }
412     }
413 
_setToBigInteger(BigInteger n)414     private void _setToBigInteger(BigInteger n) {
415         if (n.bitLength() < 32) {
416             readIntToBcd(n.intValue());
417         } else if (n.bitLength() < 64) {
418             readLongToBcd(n.longValue());
419         } else {
420             readBigIntegerToBcd(n);
421         }
422     }
423 
424     /**
425      * Sets the internal BCD state to represent the value in the given double.
426      *
427      * @param n
428      *            The value to consume.
429      */
setToDouble(double n)430     public void setToDouble(double n) {
431         setBcdToZero();
432         flags = 0;
433         // The sign bit is the top bit in both double and long, so we can
434         // get the long bits for the double and compare it to zero to check
435         // the sign of the double.
436         if (Double.doubleToRawLongBits(n) < 0) {
437             flags |= NEGATIVE_FLAG;
438             n = -n;
439         }
440         if (Double.isNaN(n)) {
441             flags |= NAN_FLAG;
442         } else if (Double.isInfinite(n)) {
443             flags |= INFINITY_FLAG;
444         } else if (n != 0) {
445             _setToDoubleFast(n);
446             compact();
447         }
448     }
449 
450     private static final double[] DOUBLE_MULTIPLIERS = {
451             1e0,
452             1e1,
453             1e2,
454             1e3,
455             1e4,
456             1e5,
457             1e6,
458             1e7,
459             1e8,
460             1e9,
461             1e10,
462             1e11,
463             1e12,
464             1e13,
465             1e14,
466             1e15,
467             1e16,
468             1e17,
469             1e18,
470             1e19,
471             1e20,
472             1e21 };
473 
474     /**
475      * Uses double multiplication and division to get the number into integer space before converting to
476      * digits. Since double arithmetic is inexact, the resulting digits may not be accurate.
477      */
_setToDoubleFast(double n)478     private void _setToDoubleFast(double n) {
479         isApproximate = true;
480         origDouble = n;
481         origDelta = 0;
482 
483         // NOTE: Unlike ICU4C, doubles are always IEEE 754 doubles.
484         long ieeeBits = Double.doubleToLongBits(n);
485         int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff;
486 
487         // Not all integers can be represented exactly for exponent > 52
488         if (exponent <= 52 && (long) n == n) {
489             _setToLong((long) n);
490             return;
491         }
492 
493         if (exponent == -1023 || exponent == 1024) {
494             // The extreme values of exponent are special; use slow path.
495             convertToAccurateDouble();
496             return;
497         }
498 
499         // 3.3219... is log2(10)
500         int fracLength = (int) ((52 - exponent) / 3.32192809488736234787031942948939017586);
501         if (fracLength >= 0) {
502             int i = fracLength;
503             // 1e22 is the largest exact double.
504             for (; i >= 22; i -= 22)
505                 n *= 1e22;
506             n *= DOUBLE_MULTIPLIERS[i];
507         } else {
508             int i = fracLength;
509             // 1e22 is the largest exact double.
510             for (; i <= -22; i += 22)
511                 n /= 1e22;
512             n /= DOUBLE_MULTIPLIERS[-i];
513         }
514         long result = Math.round(n);
515         if (result != 0) {
516             _setToLong(result);
517             scale -= fracLength;
518         }
519     }
520 
521     /**
522      * Uses Double.toString() to obtain an exact accurate representation of the double, overwriting it
523      * into the BCD. This method can be called at any point after {@link #_setToDoubleFast} while
524      * {@link #isApproximate} is still true.
525      */
convertToAccurateDouble()526     private void convertToAccurateDouble() {
527         double n = origDouble;
528         assert n != 0;
529         int delta = origDelta;
530         setBcdToZero();
531 
532         // Call the slow oracle function (Double.toString in Java, sprintf in C++).
533         String dstr = Double.toString(n);
534 
535         if (dstr.indexOf('E') != -1) {
536             // Case 1: Exponential notation.
537             assert dstr.indexOf('.') == 1;
538             int expPos = dstr.indexOf('E');
539             _setToLong(Long.parseLong(dstr.charAt(0) + dstr.substring(2, expPos)));
540             scale += Integer.parseInt(dstr.substring(expPos + 1)) - (expPos - 1) + 1;
541         } else if (dstr.charAt(0) == '0') {
542             // Case 2: Fraction-only number.
543             assert dstr.indexOf('.') == 1;
544             _setToLong(Long.parseLong(dstr.substring(2)));
545             scale += 2 - dstr.length();
546         } else if (dstr.charAt(dstr.length() - 1) == '0') {
547             // Case 3: Integer-only number.
548             // Note: this path should not normally happen, because integer-only numbers are captured
549             // before the approximate double logic is performed.
550             assert dstr.indexOf('.') == dstr.length() - 2;
551             assert dstr.length() - 2 <= 18;
552             _setToLong(Long.parseLong(dstr.substring(0, dstr.length() - 2)));
553             // no need to adjust scale
554         } else {
555             // Case 4: Number with both a fraction and an integer.
556             int decimalPos = dstr.indexOf('.');
557             _setToLong(Long.parseLong(dstr.substring(0, decimalPos) + dstr.substring(decimalPos + 1)));
558             scale += decimalPos - dstr.length() + 1;
559         }
560 
561         scale += delta;
562         compact();
563         explicitExactDouble = true;
564     }
565 
566     /**
567      * Whether this {@link DecimalQuantity_DualStorageBCD} has been explicitly converted to an exact
568      * double. true if backed by a double that was explicitly converted via convertToAccurateDouble;
569      * false otherwise. Used for testing.
570      *
571      * @deprecated This API is ICU internal only.
572      * @hide draft / provisional / internal are hidden on OHOS
573      */
574     @Deprecated
575     public boolean explicitExactDouble = false;
576 
577     /**
578      * Sets the internal BCD state to represent the value in the given BigDecimal.
579      *
580      * @param n
581      *            The value to consume.
582      */
583     @Override
setToBigDecimal(BigDecimal n)584     public void setToBigDecimal(BigDecimal n) {
585         setBcdToZero();
586         flags = 0;
587         if (n.signum() == -1) {
588             flags |= NEGATIVE_FLAG;
589             n = n.negate();
590         }
591         if (n.signum() != 0) {
592             _setToBigDecimal(n);
593             compact();
594         }
595     }
596 
_setToBigDecimal(BigDecimal n)597     private void _setToBigDecimal(BigDecimal n) {
598         int fracLength = n.scale();
599         n = n.scaleByPowerOfTen(fracLength);
600         BigInteger bi = n.toBigInteger();
601         _setToBigInteger(bi);
602         scale -= fracLength;
603     }
604 
605     /**
606      * Returns a long approximating the internal BCD. A long can only represent the integral part of the
607      * number.  Note: this method incorporates the value of {@code exponent}
608      * (for cases such as compact notation) to return the proper long value
609      * represented by the result.
610      *
611      * @param truncateIfOverflow if false and the number does NOT fit, fails with an assertion error.
612      * @return A 64-bit integer representation of the internal BCD.
613      */
toLong(boolean truncateIfOverflow)614     public long toLong(boolean truncateIfOverflow) {
615         // NOTE: Call sites should be guarded by fitsInLong(), like this:
616         // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ }
617         // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits.
618         assert(truncateIfOverflow || fitsInLong());
619         long result = 0L;
620         int upperMagnitude = exponent + scale + precision - 1;
621         if (truncateIfOverflow) {
622             upperMagnitude = Math.min(upperMagnitude, 17);
623         }
624         for (int magnitude = upperMagnitude; magnitude >= 0; magnitude--) {
625             result = result * 10 + getDigitPos(magnitude - scale - exponent);
626         }
627         if (isNegative()) {
628             result = -result;
629         }
630         return result;
631     }
632 
633     /**
634      * This returns a long representing the fraction digits of the number, as required by PluralRules.
635      * For example, if we represent the number "1.20" (including optional and required digits), then this
636      * function returns "20" if includeTrailingZeros is true or "2" if false.
637      * Note: this method incorporates the value of {@code exponent}
638      * (for cases such as compact notation) to return the proper long value
639      * represented by the result.
640      */
toFractionLong(boolean includeTrailingZeros)641     public long toFractionLong(boolean includeTrailingZeros) {
642         long result = 0L;
643         int magnitude = -1 - exponent;
644         int lowerMagnitude = scale;
645         if (includeTrailingZeros) {
646             lowerMagnitude = Math.min(lowerMagnitude, rReqPos);
647         }
648         // NOTE: Java has only signed longs, so we check result <= 1e17 instead of 1e18
649         for (; magnitude >= lowerMagnitude && result <= 1e17; magnitude--) {
650             result = result * 10 + getDigitPos(magnitude - scale);
651         }
652         // Remove trailing zeros; this can happen during integer overflow cases.
653         if (!includeTrailingZeros) {
654             while (result > 0 && (result % 10) == 0) {
655                 result /= 10;
656             }
657         }
658         return result;
659     }
660 
661     static final byte[] INT64_BCD = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 };
662 
663     /**
664      * Returns whether or not a Long can fully represent the value stored in this DecimalQuantity.
665      */
fitsInLong()666     public boolean fitsInLong() {
667         if (isInfinite() || isNaN()) {
668             return false;
669         }
670         if (isZeroish()) {
671             return true;
672         }
673         if (exponent + scale < 0) {
674             return false;
675         }
676         int magnitude = getMagnitude();
677         if (magnitude < 18) {
678             return true;
679         }
680         if (magnitude > 18) {
681             return false;
682         }
683         // Hard case: the magnitude is 10^18.
684         // The largest int64 is: 9,223,372,036,854,775,807
685         for (int p = 0; p < precision; p++) {
686             byte digit = getDigit(18 - p);
687             if (digit < INT64_BCD[p]) {
688                 return true;
689             } else if (digit > INT64_BCD[p]) {
690                 return false;
691             }
692         }
693         // Exactly equal to max long plus one.
694         return isNegative();
695     }
696 
697     /**
698      * Returns a double approximating the internal BCD. The double may not retain all of the information
699      * encoded in the BCD if the BCD represents a number out of range of a double.
700      *
701      * @return A double representation of the internal BCD.
702      */
703     @Override
toDouble()704     public double toDouble() {
705         // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
706         // See the comment at the top of this file explaining the "isApproximate" field.
707         assert !isApproximate;
708 
709         if (isNaN()) {
710             return Double.NaN;
711         } else if (isInfinite()) {
712             return isNegative() ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
713         }
714 
715         StringBuilder sb = new StringBuilder();
716         toScientificString(sb);
717         return Double.valueOf(sb.toString());
718     }
719 
720     @Override
toBigDecimal()721     public BigDecimal toBigDecimal() {
722         if (isApproximate) {
723             // Converting to a BigDecimal requires Double.toString().
724             convertToAccurateDouble();
725         }
726         return bcdToBigDecimal();
727     }
728 
safeSubtract(int a, int b)729     private static int safeSubtract(int a, int b) {
730         int diff = a - b;
731         if (b < 0 && diff < a)
732             return Integer.MAX_VALUE;
733         if (b > 0 && diff > a)
734             return Integer.MIN_VALUE;
735         return diff;
736     }
737 
738     private static final int SECTION_LOWER_EDGE = -1;
739     private static final int SECTION_UPPER_EDGE = -2;
740 
741     /** Removes all fraction digits. */
truncate()742     public void truncate() {
743         if (scale < 0) {
744             shiftRight(-scale);
745             scale = 0;
746             compact();
747         }
748     }
749 
750     @Override
roundToNickel(int magnitude, MathContext mathContext)751     public void roundToNickel(int magnitude, MathContext mathContext) {
752         roundToMagnitude(magnitude, mathContext, true);
753     }
754 
755     @Override
roundToMagnitude(int magnitude, MathContext mathContext)756     public void roundToMagnitude(int magnitude, MathContext mathContext) {
757         roundToMagnitude(magnitude, mathContext, false);
758     }
759 
roundToMagnitude(int magnitude, MathContext mathContext, boolean nickel)760     private void roundToMagnitude(int magnitude, MathContext mathContext, boolean nickel) {
761         // The position in the BCD at which rounding will be performed; digits to the right of position
762         // will be rounded away.
763         int position = safeSubtract(magnitude, scale);
764 
765         // Enforce the number of digits required by the MathContext.
766         int _mcPrecision = mathContext.getPrecision();
767         if (_mcPrecision > 0 && precision - _mcPrecision > position) {
768             position = precision - _mcPrecision;
769         }
770 
771         // "trailing" = least significant digit to the left of rounding
772         byte trailingDigit = getDigitPos(position);
773 
774         if (position <= 0 && !isApproximate && (!nickel || trailingDigit == 0 || trailingDigit == 5)) {
775             // All digits are to the left of the rounding magnitude.
776         } else if (precision == 0) {
777             // No rounding for zero.
778         } else {
779             // Perform rounding logic.
780             // "leading" = most significant digit to the right of rounding
781             byte leadingDigit = getDigitPos(safeSubtract(position, 1));
782 
783             // Compute which section of the number we are in.
784             // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles)
785             // LOWER means we are between the bottom edge and the midpoint, like 1.391
786             // MIDPOINT means we are exactly in the middle, like 1.500
787             // UPPER means we are between the midpoint and the top edge, like 1.916
788             int section;
789             if (!isApproximate) {
790                 if (nickel && trailingDigit != 2 && trailingDigit != 7) {
791                     // Nickel rounding, and not at .02x or .07x
792                     if (trailingDigit < 2) {
793                         // .00, .01 => down to .00
794                         section = RoundingUtils.SECTION_LOWER;
795                     } else if (trailingDigit < 5) {
796                         // .03, .04 => up to .05
797                         section = RoundingUtils.SECTION_UPPER;
798                     } else if (trailingDigit < 7) {
799                         // .05, .06 => down to .05
800                         section = RoundingUtils.SECTION_LOWER;
801                     } else {
802                         // .08, .09 => up to .10
803                         section = RoundingUtils.SECTION_UPPER;
804                     }
805                 } else if (leadingDigit < 5) {
806                     // Includes nickel rounding .020-.024 and .070-.074
807                     section = RoundingUtils.SECTION_LOWER;
808                 } else if (leadingDigit > 5) {
809                     // Includes nickel rounding .026-.029 and .076-.079
810                     section = RoundingUtils.SECTION_UPPER;
811                 } else {
812                     // Includes nickel rounding .025 and .075
813                     section = RoundingUtils.SECTION_MIDPOINT;
814                     for (int p = safeSubtract(position, 2); p >= 0; p--) {
815                         if (getDigitPos(p) != 0) {
816                             section = RoundingUtils.SECTION_UPPER;
817                             break;
818                         }
819                     }
820                 }
821             } else {
822                 int p = safeSubtract(position, 2);
823                 int minP = Math.max(0, precision - 14);
824                 if (leadingDigit == 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) {
825                     section = SECTION_LOWER_EDGE;
826                     for (; p >= minP; p--) {
827                         if (getDigitPos(p) != 0) {
828                             section = RoundingUtils.SECTION_LOWER;
829                             break;
830                         }
831                     }
832                 } else if (leadingDigit == 4 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) {
833                     section = RoundingUtils.SECTION_MIDPOINT;
834                     for (; p >= minP; p--) {
835                         if (getDigitPos(p) != 9) {
836                             section = RoundingUtils.SECTION_LOWER;
837                             break;
838                         }
839                     }
840                 } else if (leadingDigit == 5 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) {
841                     section = RoundingUtils.SECTION_MIDPOINT;
842                     for (; p >= minP; p--) {
843                         if (getDigitPos(p) != 0) {
844                             section = RoundingUtils.SECTION_UPPER;
845                             break;
846                         }
847                     }
848                 } else if (leadingDigit == 9 && (!nickel || trailingDigit == 4 || trailingDigit == 9)) {
849                     section = SECTION_UPPER_EDGE;
850                     for (; p >= minP; p--) {
851                         if (getDigitPos(p) != 9) {
852                             section = RoundingUtils.SECTION_UPPER;
853                             break;
854                         }
855                     }
856                 } else if (nickel && trailingDigit != 2 && trailingDigit != 7) {
857                     // Nickel rounding, and not at .02x or .07x
858                     if (trailingDigit < 2) {
859                         // .00, .01 => down to .00
860                         section = RoundingUtils.SECTION_LOWER;
861                     } else if (trailingDigit < 5) {
862                         // .03, .04 => up to .05
863                         section = RoundingUtils.SECTION_UPPER;
864                     } else if (trailingDigit < 7) {
865                         // .05, .06 => down to .05
866                         section = RoundingUtils.SECTION_LOWER;
867                     } else {
868                         // .08, .09 => up to .10
869                         section = RoundingUtils.SECTION_UPPER;
870                     }
871                 } else if (leadingDigit < 5) {
872                     // Includes nickel rounding .020-.024 and .070-.074
873                     section = RoundingUtils.SECTION_LOWER;
874                 } else {
875                     // Includes nickel rounding .026-.029 and .076-.079
876                     section = RoundingUtils.SECTION_UPPER;
877                 }
878 
879                 boolean roundsAtMidpoint = RoundingUtils
880                         .roundsAtMidpoint(mathContext.getRoundingMode().ordinal());
881                 if (safeSubtract(position, 1) < precision - 14
882                         || (roundsAtMidpoint && section == RoundingUtils.SECTION_MIDPOINT)
883                         || (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) {
884                     // Oops! This means that we have to get the exact representation of the double,
885                     // because the zone of uncertainty is along the rounding boundary.
886                     convertToAccurateDouble();
887                     roundToMagnitude(magnitude, mathContext, nickel); // start over
888                     return;
889                 }
890 
891                 // Turn off the approximate double flag, since the value is now confirmed to be exact.
892                 isApproximate = false;
893                 origDouble = 0.0;
894                 origDelta = 0;
895 
896                 if (position <= 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) {
897                     // All digits are to the left of the rounding magnitude.
898                     return;
899                 }
900 
901                 // Good to continue rounding.
902                 if (section == SECTION_LOWER_EDGE)
903                     section = RoundingUtils.SECTION_LOWER;
904                 if (section == SECTION_UPPER_EDGE)
905                     section = RoundingUtils.SECTION_UPPER;
906             }
907 
908             // Nickel rounding "half even" goes to the nearest whole (away from the 5).
909             boolean isEven = nickel
910                     ? (trailingDigit < 2 || trailingDigit > 7
911                             || (trailingDigit == 2 && section != RoundingUtils.SECTION_UPPER)
912                             || (trailingDigit == 7 && section == RoundingUtils.SECTION_UPPER))
913                     : (trailingDigit % 2) == 0;
914 
915             boolean roundDown = RoundingUtils.getRoundingDirection(isEven,
916                     isNegative(),
917                     section,
918                     mathContext.getRoundingMode().ordinal(),
919                     this);
920 
921             // Perform truncation
922             if (position >= precision) {
923                 setBcdToZero();
924                 scale = magnitude;
925             } else {
926                 shiftRight(position);
927             }
928 
929             if (nickel) {
930                 if (trailingDigit < 5 && roundDown) {
931                     setDigitPos(0, (byte) 0);
932                     compact();
933                     return;
934                 } else if (trailingDigit >= 5 && !roundDown) {
935                     setDigitPos(0, (byte) 9);
936                     trailingDigit = 9;
937                     // do not return: use the bubbling logic below
938                 } else {
939                     setDigitPos(0, (byte) 5);
940                     // compact not necessary: digit at position 0 is nonzero
941                     return;
942                 }
943             }
944 
945             // Bubble the result to the higher digits
946             if (!roundDown) {
947                 if (trailingDigit == 9) {
948                     int bubblePos = 0;
949                     // Note: in the long implementation, the most digits BCD can have at this point is
950                     // 15, so bubblePos <= 15 and getDigitPos(bubblePos) is safe.
951                     for (; getDigitPos(bubblePos) == 9; bubblePos++) {
952                     }
953                     shiftRight(bubblePos); // shift off the trailing 9s
954                 }
955                 byte digit0 = getDigitPos(0);
956                 assert digit0 != 9;
957                 setDigitPos(0, (byte) (digit0 + 1));
958                 precision += 1; // in case an extra digit got added
959             }
960 
961             compact();
962         }
963     }
964 
965     @Override
roundToInfinity()966     public void roundToInfinity() {
967         if (isApproximate) {
968             convertToAccurateDouble();
969         }
970     }
971 
972     /**
973      * Appends a digit, optionally with one or more leading zeros, to the end of the value represented by
974      * this DecimalQuantity.
975      *
976      * <p>
977      * The primary use of this method is to construct numbers during a parsing loop. It allows parsing to
978      * take advantage of the digit list infrastructure primarily designed for formatting.
979      *
980      * @param value
981      *            The digit to append.
982      * @param leadingZeros
983      *            The number of zeros to append before the digit. For example, if the value in this
984      *            instance starts as 12.3, and you append a 4 with 1 leading zero, the value becomes
985      *            12.304.
986      * @param appendAsInteger
987      *            If true, increase the magnitude of existing digits to make room for the new digit. If
988      *            false, append to the end like a fraction digit. If true, there must not be any fraction
989      *            digits already in the number.
990      * @deprecated This API is ICU internal only.
991      * @hide draft / provisional / internal are hidden on OHOS
992      */
993     @Deprecated
appendDigit(byte value, int leadingZeros, boolean appendAsInteger)994     public void appendDigit(byte value, int leadingZeros, boolean appendAsInteger) {
995         assert leadingZeros >= 0;
996 
997         // Zero requires special handling to maintain the invariant that the least-significant digit
998         // in the BCD is nonzero.
999         if (value == 0) {
1000             if (appendAsInteger && precision != 0) {
1001                 scale += leadingZeros + 1;
1002             }
1003             return;
1004         }
1005 
1006         // Deal with trailing zeros
1007         if (scale > 0) {
1008             leadingZeros += scale;
1009             if (appendAsInteger) {
1010                 scale = 0;
1011             }
1012         }
1013 
1014         // Append digit
1015         shiftLeft(leadingZeros + 1);
1016         setDigitPos(0, value);
1017 
1018         // Fix scale if in integer mode
1019         if (appendAsInteger) {
1020             scale += leadingZeros + 1;
1021         }
1022     }
1023 
1024     @Override
toPlainString()1025     public String toPlainString() {
1026         StringBuilder sb = new StringBuilder();
1027         toPlainString(sb);
1028         return sb.toString();
1029     }
1030 
toPlainString(StringBuilder result)1031     public void toPlainString(StringBuilder result) {
1032         assert(!isApproximate);
1033         if (isNegative()) {
1034             result.append('-');
1035         }
1036         if (precision == 0) {
1037             result.append('0');
1038             return;
1039         }
1040 
1041         int upper = scale + precision + exponent - 1;
1042         int lower = scale + exponent;
1043         if (upper < lReqPos - 1) {
1044             upper = lReqPos - 1;
1045         }
1046         if (lower > rReqPos) {
1047             lower = rReqPos;
1048         }
1049 
1050         int p = upper;
1051         if (p < 0) {
1052             result.append('0');
1053         }
1054         for (; p >= 0; p--) {
1055             result.append((char) ('0' + getDigitPos(p - scale - exponent)));
1056         }
1057         if (lower < 0) {
1058             result.append('.');
1059         }
1060         for(; p >= lower; p--) {
1061             result.append((char) ('0' + getDigitPos(p - scale - exponent)));
1062         }
1063     }
1064 
toScientificString()1065     public String toScientificString() {
1066         StringBuilder sb = new StringBuilder();
1067         toScientificString(sb);
1068         return sb.toString();
1069     }
1070 
toScientificString(StringBuilder result)1071     public void toScientificString(StringBuilder result) {
1072         assert(!isApproximate);
1073         if (isNegative()) {
1074             result.append('-');
1075         }
1076         if (precision == 0) {
1077             result.append("0E+0");
1078             return;
1079         }
1080         // NOTE: It is not safe to add to lOptPos (aka maxInt) or subtract from
1081         // rOptPos (aka -maxFrac) due to overflow.
1082         int upperPos = precision - 1;
1083         int lowerPos = 0;
1084         int p = upperPos;
1085         result.append((char) ('0' + getDigitPos(p)));
1086         if ((--p) >= lowerPos) {
1087             result.append('.');
1088             for (; p >= lowerPos; p--) {
1089                 result.append((char) ('0' + getDigitPos(p)));
1090             }
1091         }
1092         result.append('E');
1093         int _scale = upperPos + scale + exponent;
1094         if (_scale == Integer.MIN_VALUE) {
1095             result.append("-2147483648");
1096             return;
1097         } else if (_scale < 0) {
1098             _scale *= -1;
1099             result.append('-');
1100         } else {
1101             result.append('+');
1102         }
1103         if (_scale == 0) {
1104             result.append('0');
1105         }
1106         int insertIndex = result.length();
1107         while (_scale > 0) {
1108             int quot = _scale / 10;
1109             int rem = _scale % 10;
1110             result.insert(insertIndex, (char) ('0' + rem));
1111             _scale = quot;
1112         }
1113     }
1114 
1115     @Override
equals(Object other)1116     public boolean equals(Object other) {
1117         if (this == other) {
1118             return true;
1119         }
1120         if (other == null) {
1121             return false;
1122         }
1123         if (!(other instanceof DecimalQuantity_AbstractBCD)) {
1124             return false;
1125         }
1126         DecimalQuantity_AbstractBCD _other = (DecimalQuantity_AbstractBCD) other;
1127 
1128         boolean basicEquals =
1129                 scale == _other.scale
1130                 && precision == _other.precision
1131                 && flags == _other.flags
1132                 && lReqPos == _other.lReqPos
1133                 && rReqPos == _other.rReqPos
1134                 && isApproximate == _other.isApproximate;
1135         if (!basicEquals) {
1136             return false;
1137         }
1138 
1139         if (precision == 0) {
1140             return true;
1141         } else if (isApproximate) {
1142             return origDouble == _other.origDouble && origDelta == _other.origDelta;
1143         } else {
1144             for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
1145                 if (getDigit(m) != _other.getDigit(m)) {
1146                     return false;
1147                 }
1148             }
1149             return true;
1150         }
1151     }
1152 
1153     /**
1154      * Returns a single digit from the BCD list. No internal state is changed by calling this method.
1155      *
1156      * @param position
1157      *            The position of the digit to pop, counted in BCD units from the least significant
1158      *            digit. If outside the range supported by the implementation, zero is returned.
1159      * @return The digit at the specified location.
1160      */
getDigitPos(int position)1161     protected abstract byte getDigitPos(int position);
1162 
1163     /**
1164      * Sets the digit in the BCD list. This method only sets the digit; it is the caller's responsibility
1165      * to call {@link #compact} after setting the digit.
1166      *
1167      * @param position
1168      *            The position of the digit to pop, counted in BCD units from the least significant
1169      *            digit. If outside the range supported by the implementation, an AssertionError is
1170      *            thrown.
1171      * @param value
1172      *            The digit to set at the specified location.
1173      */
setDigitPos(int position, byte value)1174     protected abstract void setDigitPos(int position, byte value);
1175 
1176     /**
1177      * Adds zeros to the end of the BCD list. This will result in an invalid BCD representation; it is
1178      * the caller's responsibility to do further manipulation and then call {@link #compact}.
1179      *
1180      * @param numDigits
1181      *            The number of zeros to add.
1182      */
shiftLeft(int numDigits)1183     protected abstract void shiftLeft(int numDigits);
1184 
1185     /**
1186      * Removes digits from the end of the BCD list. This may result in an invalid BCD representation; it
1187      * is the caller's responsibility to follow-up with a call to {@link #compact}.
1188      *
1189      * @param numDigits
1190      *            The number of digits to remove.
1191      */
shiftRight(int numDigits)1192     protected abstract void shiftRight(int numDigits);
1193 
1194     /**
1195      * Directly removes digits from the front of the BCD list.
1196      * Updates precision.
1197      *
1198      * CAUTION: it is the caller's responsibility to call {@link #compact} after this method.
1199      */
popFromLeft(int numDigits)1200     protected abstract void popFromLeft(int numDigits);
1201 
1202     /**
1203      * Sets the internal representation to zero. Clears any values stored in scale, precision, hasDouble,
1204      * origDouble, origDelta, exponent, and BCD data.
1205      */
setBcdToZero()1206     protected abstract void setBcdToZero();
1207 
1208     /**
1209      * Sets the internal BCD state to represent the value in the given int. The int is guaranteed to be
1210      * either positive. The internal state is guaranteed to be empty when this method is called.
1211      *
1212      * @param n
1213      *            The value to consume.
1214      */
readIntToBcd(int input)1215     protected abstract void readIntToBcd(int input);
1216 
1217     /**
1218      * Sets the internal BCD state to represent the value in the given long. The long is guaranteed to be
1219      * either positive. The internal state is guaranteed to be empty when this method is called.
1220      *
1221      * @param n
1222      *            The value to consume.
1223      */
readLongToBcd(long input)1224     protected abstract void readLongToBcd(long input);
1225 
1226     /**
1227      * Sets the internal BCD state to represent the value in the given BigInteger. The BigInteger is
1228      * guaranteed to be positive, and it is guaranteed to be larger than Long.MAX_VALUE. The internal
1229      * state is guaranteed to be empty when this method is called.
1230      *
1231      * @param n
1232      *            The value to consume.
1233      */
readBigIntegerToBcd(BigInteger input)1234     protected abstract void readBigIntegerToBcd(BigInteger input);
1235 
1236     /**
1237      * Returns a BigDecimal encoding the internal BCD value.
1238      *
1239      * @return A BigDecimal representation of the internal BCD.
1240      */
bcdToBigDecimal()1241     protected abstract BigDecimal bcdToBigDecimal();
1242 
copyBcdFrom(DecimalQuantity _other)1243     protected abstract void copyBcdFrom(DecimalQuantity _other);
1244 
1245     /**
1246      * Removes trailing zeros from the BCD (adjusting the scale as required) and then computes the
1247      * precision. The precision is the number of digits in the number up through the greatest nonzero
1248      * digit.
1249      *
1250      * <p>
1251      * This method must always be called when bcd changes in order for assumptions to be correct in
1252      * methods like {@link #fractionCount()}.
1253      */
compact()1254     protected abstract void compact();
1255 }
1256