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.MathContext; 8 import java.math.RoundingMode; 9 10 import ohos.global.icu.impl.StandardPlural; 11 import ohos.global.icu.number.Precision; 12 import ohos.global.icu.number.Scale; 13 import ohos.global.icu.text.PluralRules; 14 15 /** @author sffc 16 * @hide exposed on OHOS*/ 17 public class RoundingUtils { 18 19 public static final int SECTION_LOWER = 1; 20 public static final int SECTION_MIDPOINT = 2; 21 public static final int SECTION_UPPER = 3; 22 23 /** 24 * The default rounding mode. 25 */ 26 public static final RoundingMode DEFAULT_ROUNDING_MODE = RoundingMode.HALF_EVEN; 27 28 /** 29 * The maximum number of fraction places, integer numerals, or significant digits. TODO: This does 30 * not feel like the best home for this value. 31 */ 32 public static final int MAX_INT_FRAC_SIG = 999; 33 34 /** 35 * Converts a rounding mode and metadata about the quantity being rounded to a boolean determining 36 * whether the value should be rounded toward infinity or toward zero. 37 * 38 * <p> 39 * The parameters are of type int because benchmarks on an x86-64 processor against OpenJDK showed 40 * that ints were demonstrably faster than enums in switch statements. 41 * 42 * @param isEven 43 * Whether the digit immediately before the rounding magnitude is even. 44 * @param isNegative 45 * Whether the quantity is negative. 46 * @param section 47 * Whether the part of the quantity to the right of the rounding magnitude is exactly 48 * halfway between two digits, whether it is in the lower part (closer to zero), or 49 * whether it is in the upper part (closer to infinity). See {@link #SECTION_LOWER}, 50 * {@link #SECTION_MIDPOINT}, and {@link #SECTION_UPPER}. 51 * @param roundingMode 52 * The integer version of the {@link RoundingMode}, which you can get via 53 * {@link RoundingMode#ordinal}. 54 * @param reference 55 * A reference object to be used when throwing an ArithmeticException. 56 * @return true if the number should be rounded toward zero; false if it should be rounded toward 57 * infinity. 58 */ getRoundingDirection( boolean isEven, boolean isNegative, int section, int roundingMode, Object reference)59 public static boolean getRoundingDirection( 60 boolean isEven, 61 boolean isNegative, 62 int section, 63 int roundingMode, 64 Object reference) { 65 switch (roundingMode) { 66 case BigDecimal.ROUND_UP: 67 // round away from zero 68 return false; 69 70 case BigDecimal.ROUND_DOWN: 71 // round toward zero 72 return true; 73 74 case BigDecimal.ROUND_CEILING: 75 // round toward positive infinity 76 return isNegative; 77 78 case BigDecimal.ROUND_FLOOR: 79 // round toward negative infinity 80 return !isNegative; 81 82 case BigDecimal.ROUND_HALF_UP: 83 switch (section) { 84 case SECTION_MIDPOINT: 85 return false; 86 case SECTION_LOWER: 87 return true; 88 case SECTION_UPPER: 89 return false; 90 } 91 break; 92 93 case BigDecimal.ROUND_HALF_DOWN: 94 switch (section) { 95 case SECTION_MIDPOINT: 96 return true; 97 case SECTION_LOWER: 98 return true; 99 case SECTION_UPPER: 100 return false; 101 } 102 break; 103 104 case BigDecimal.ROUND_HALF_EVEN: 105 switch (section) { 106 case SECTION_MIDPOINT: 107 return isEven; 108 case SECTION_LOWER: 109 return true; 110 case SECTION_UPPER: 111 return false; 112 } 113 break; 114 } 115 116 // Rounding mode UNNECESSARY 117 throw new ArithmeticException("Rounding is required on " + reference.toString()); 118 } 119 120 /** 121 * Gets whether the given rounding mode's rounding boundary is at the midpoint. The rounding boundary 122 * is the point at which a number switches from being rounded down to being rounded up. For example, 123 * with rounding mode HALF_EVEN, HALF_UP, or HALF_DOWN, the rounding boundary is at the midpoint, and 124 * this function would return true. However, for UP, DOWN, CEILING, and FLOOR, the rounding boundary 125 * is at the "edge", and this function would return false. 126 * 127 * @param roundingMode 128 * The integer version of the {@link RoundingMode}. 129 * @return true if rounding mode is HALF_EVEN, HALF_UP, or HALF_DOWN; false otherwise. 130 */ roundsAtMidpoint(int roundingMode)131 public static boolean roundsAtMidpoint(int roundingMode) { 132 switch (roundingMode) { 133 case BigDecimal.ROUND_UP: 134 case BigDecimal.ROUND_DOWN: 135 case BigDecimal.ROUND_CEILING: 136 case BigDecimal.ROUND_FLOOR: 137 return false; 138 139 default: 140 return true; 141 } 142 } 143 144 private static final MathContext[] MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED = new MathContext[RoundingMode 145 .values().length]; 146 147 private static final MathContext[] MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS = new MathContext[RoundingMode 148 .values().length]; 149 150 static { 151 for (int i = 0; i < MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS.length; i++) { 152 MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED[i] = new MathContext(0, RoundingMode.valueOf(i)); 153 MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS[i] = new MathContext(34); 154 } 155 } 156 157 /** The default MathContext, unlimited-precision version. */ 158 public static final MathContext DEFAULT_MATH_CONTEXT_UNLIMITED 159 = MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED[DEFAULT_ROUNDING_MODE.ordinal()]; 160 161 /** The default MathContext, 34-digit version. */ 162 public static final MathContext DEFAULT_MATH_CONTEXT_34_DIGITS 163 = MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS[DEFAULT_ROUNDING_MODE.ordinal()]; 164 165 /** 166 * Gets the user-specified math context out of the property bag. If there is none, falls back to a 167 * math context with unlimited precision and the user-specified rounding mode, which defaults to 168 * HALF_EVEN (the IEEE 754R default). 169 * 170 * @param properties 171 * The property bag. 172 * @return A {@link MathContext}. Never null. 173 */ getMathContextOrUnlimited(DecimalFormatProperties properties)174 public static MathContext getMathContextOrUnlimited(DecimalFormatProperties properties) { 175 MathContext mathContext = properties.getMathContext(); 176 if (mathContext == null) { 177 RoundingMode roundingMode = properties.getRoundingMode(); 178 if (roundingMode == null) 179 roundingMode = RoundingMode.HALF_EVEN; 180 mathContext = MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED[roundingMode.ordinal()]; 181 } 182 return mathContext; 183 } 184 185 /** 186 * Gets the user-specified math context out of the property bag. If there is none, falls back to a 187 * math context with 34 digits of precision (the 128-bit IEEE 754R default) and the user-specified 188 * rounding mode, which defaults to HALF_EVEN (the IEEE 754R default). 189 * 190 * @param properties 191 * The property bag. 192 * @return A {@link MathContext}. Never null. 193 */ getMathContextOr34Digits(DecimalFormatProperties properties)194 public static MathContext getMathContextOr34Digits(DecimalFormatProperties properties) { 195 MathContext mathContext = properties.getMathContext(); 196 if (mathContext == null) { 197 RoundingMode roundingMode = properties.getRoundingMode(); 198 if (roundingMode == null) 199 roundingMode = RoundingMode.HALF_EVEN; 200 mathContext = MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS[roundingMode.ordinal()]; 201 } 202 return mathContext; 203 } 204 205 /** 206 * Gets a MathContext with unlimited precision and the specified RoundingMode. Equivalent to "new 207 * MathContext(0, roundingMode)", but pulls from a singleton to prevent object thrashing. 208 * 209 * @param roundingMode 210 * The {@link RoundingMode} to use. 211 * @return The corresponding {@link MathContext}. 212 */ mathContextUnlimited(RoundingMode roundingMode)213 public static MathContext mathContextUnlimited(RoundingMode roundingMode) { 214 return MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED[roundingMode.ordinal()]; 215 } 216 scaleFromProperties(DecimalFormatProperties properties)217 public static Scale scaleFromProperties(DecimalFormatProperties properties) { 218 MathContext mc = getMathContextOr34Digits(properties); 219 if (properties.getMagnitudeMultiplier() != 0) { 220 return Scale.powerOfTen(properties.getMagnitudeMultiplier()).withMathContext(mc); 221 } else if (properties.getMultiplier() != null) { 222 return Scale.byBigDecimal(properties.getMultiplier()).withMathContext(mc); 223 } else { 224 return null; 225 } 226 } 227 228 /** 229 * Computes the plural form after copying the number and applying rounding rules. 230 */ getPluralSafe( Precision rounder, PluralRules rules, DecimalQuantity dq)231 public static StandardPlural getPluralSafe( 232 Precision rounder, PluralRules rules, DecimalQuantity dq) { 233 if (rounder == null) { 234 return dq.getStandardPlural(rules); 235 } 236 // TODO(ICU-20500): Avoid the copy? 237 DecimalQuantity copy = dq.createCopy(); 238 rounder.apply(copy); 239 return copy.getStandardPlural(rules); 240 } 241 } 242